Page MenuHomeWMGMC Issues

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/data/web/edit.php b/data/web/edit.php
index a2eb4fb7..d97b0ffa 100644
--- a/data/web/edit.php
+++ b/data/web/edit.php
@@ -1,1026 +1,1089 @@
<?php
require_once("inc/prerequisites.inc.php");
$AuthUsers = array("admin", "domainadmin", "user");
if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role'], $AuthUsers)) {
header('Location: /');
exit();
}
require_once("inc/header.inc.php");
?>
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><?=$lang['edit']['title'];?></h3>
</div>
<div class="panel-body">
<?php
if (isset($_SESSION['mailcow_cc_role'])) {
if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin") {
if (isset($_GET["alias"]) &&
!empty($_GET["alias"])) {
$alias = html_entity_decode(rawurldecode($_GET["alias"]));
$result = mailbox('get', 'alias_details', $alias);
if (!empty($result)) {
?>
<h4><?=$lang['edit']['alias'];?></h4>
<br />
<form class="form-horizontal" data-id="editalias" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="address"><?=$lang['edit']['alias'];?></label>
<div class="col-sm-10">
<input class="form-control" type="text" name="address" value="<?=htmlspecialchars($result['address']);?>" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="goto"><?=$lang['edit']['target_address'];?></label>
<div class="col-sm-10">
<textarea id="textarea_alias_goto" class="form-control" autocapitalize="none" autocorrect="off" rows="10" id="goto" name="goto" required><?= (!preg_match('/^(null|ham|spam)@localhost$/i', $result['goto'])) ? htmlspecialchars($result['goto']) : null; ?></textarea>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_null" <?= ($result['goto'] == "null@localhost") ? "checked" : null; ?>> <?=$lang['add']['goto_null'];?></label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_spam" <?= ($result['goto'] == "spam@localhost") ? "checked" : null; ?>> <?=$lang['add']['goto_spam'];?></label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_ham" <?= ($result['goto'] == "ham@localhost") ? "checked" : null; ?>> <?=$lang['add']['goto_ham'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editalias" data-item="<?=htmlspecialchars($alias);?>" data-api-url='edit/alias' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
elseif (isset($_GET['domainadmin']) &&
ctype_alnum(str_replace(array('_', '.', '-'), '', $_GET["domainadmin"])) &&
!empty($_GET["domainadmin"]) &&
$_GET["domainadmin"] != 'admin' &&
$_SESSION['mailcow_cc_role'] == "admin") {
$domain_admin = $_GET["domainadmin"];
$result = domain_admin('details', $domain_admin);
if (!empty($result)) {
?>
<h4><?=$lang['edit']['domain_admin'];?></h4>
<br />
<form class="form-horizontal" data-id="editdomainadmin" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="username_new"><?=$lang['edit']['username'];?></label>
<div class="col-sm-10">
<input class="form-control" type="text" name="username_new" value="<?=htmlspecialchars($domain_admin);?>" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domains"><?=$lang['edit']['domains'];?></label>
<div class="col-sm-10">
<select data-live-search="true" class="full-width-select" name="domains" multiple required>
<?php
foreach ($result['selected_domains'] as $domain):
?>
<option selected><?=htmlspecialchars($domain);?></option>
<?php
endforeach;
foreach ($result['unselected_domains'] as $domain):
?>
<option><?=htmlspecialchars($domain);?></option>
<?php
endforeach;
?>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
<div class="col-sm-10">
<input type="password" data-hibp="true" class="form-control" name="password" placeholder="">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2"><?=$lang['edit']['password_repeat'];?></label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password2">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="disable_tfa"> <?=$lang['tfa']['disable_tfa'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editdomainadmin" data-item="<?=$domain_admin;?>" data-api-url='edit/domain-admin' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<form data-id="daacl" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="help-block">ACL</p>
</div>
<div class="col-sm-10">
<div class="form-group">
<select id="da_acl" name="da_acl" size="10" multiple>
<?php
$da_acls = acl('get', 'domainadmin', $domain_admin);
foreach ($da_acls as $acl => $val):
?>
<option value="<?=$acl;?>" <?=($val == 1) ? 'selected' : null;?>><?=$lang['acl'][$acl];?></option>
<?php
endforeach;
?>
</select>
</div>
<div class="form-group">
<button class="btn btn-default" data-action="edit_selected" data-id="daacl" data-item="<?=htmlspecialchars($domain_admin);?>" data-api-url='edit/da-acl' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
</div>
</div>
</div>
</form>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
elseif (isset($_GET['domain']) &&
is_valid_domain_name($_GET["domain"]) &&
!empty($_GET["domain"])) {
$domain = $_GET["domain"];
$result = mailbox('get', 'domain_details', $domain);
$rl = ratelimit('get', 'domain', $domain);
$rlyhosts = relayhost('get');
if (!empty($result)) {
?>
<h4><?=$lang['edit']['domain'];?></h4>
<form data-id="editdomain" class="form-horizontal" role="form" method="post">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="backupmx">
<input type="hidden" value="0" name="relay_all_recipients">
<div class="form-group">
<label class="control-label col-sm-2" for="description"><?=$lang['edit']['description'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" value="<?=htmlspecialchars($result['description']);?>">
</div>
</div>
<?php
if ($_SESSION['mailcow_cc_role'] == "admin") {
?>
<div class="form-group">
<label class="control-label col-sm-2" for="aliases"><?=$lang['edit']['max_aliases'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="aliases" value="<?=intval($result['max_num_aliases_for_domain']);?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mailboxes"><?=$lang['edit']['max_mailboxes'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mailboxes" value="<?=intval($result['max_num_mboxes_for_domain']);?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxquota"><?=$lang['edit']['max_quota'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxquota" value="<?=intval($result['max_quota_for_mbox'] / 1048576);?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="quota"><?=$lang['edit']['domain_quota'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="quota" value="<?=intval($result['max_quota_for_domain'] / 1048576);?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="quota">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">
<label class="control-label col-sm-2"><?=$lang['edit']['backup_mx_options'];?></label>
<div class="col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="backupmx" <?=(isset($result['backupmx_int']) && $result['backupmx_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['relay_domain'];?></label>
<br />
<label><input type="checkbox" value="1" name="relay_all_recipients" <?=(isset($result['relay_all_recipients_int']) && $result['relay_all_recipients_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['relay_all'];?></label>
<p><?=$lang['edit']['relay_all_info'];?></p>
</div>
</div>
</div>
<?php
}
?>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?=(isset($result['active_int']) && $result['active_int']=="1") ? "checked" : null;?> <?=($_SESSION['mailcow_cc_role'] == "admin") ? null : "disabled";?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editdomain" data-item="<?=$domain;?>" data-api-url='edit/domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
</div>
</div>
</form>
<?php
if (!empty($dkim = dkim('details', $domain))) {
?>
<hr>
<div class="row">
<div class="col-xs-2">
<p>Domain: <strong><?=htmlspecialchars($result['domain_name']);?></strong> (<?=$dkim['dkim_selector'];?>._domainkey)</p>
</div>
<div class="col-xs-10">
<pre><?=$dkim['dkim_txt'];?></pre>
</div>
</div>
<?php
}
?>
<hr>
<form data-id="domratelimit" class="form-inline well" method="post">
<div class="form-group">
<label class="control-label">Ratelimit</label>
<input name="rl_value" type="number" value="<?=(!empty($rl['value'])) ? $rl['value'] : null;?>" autocomplete="off" class="form-control" placeholder="disabled">
</div>
<div class="form-group">
<select name="rl_frame" class="form-control">
<option value="s" <?=(isset($rl['frame']) && $rl['frame'] == 's') ? 'selected' : null;?>>msgs / second</option>
<option value="m" <?=(isset($rl['frame']) && $rl['frame'] == 'm') ? 'selected' : null;?>>msgs / minute</option>
<option value="h" <?=(isset($rl['frame']) && $rl['frame'] == 'h') ? 'selected' : null;?>>msgs / hour</option>
</select>
</div>
<div class="form-group">
<button data-acl="<?=$_SESSION['acl']['ratelimit'];?>" class="btn btn-default" data-action="edit_selected" data-id="domratelimit" data-item="<?=$domain;?>" data-api-url='edit/rl-domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
</div>
</form>
<hr>
<div class="row">
<div class="col-sm-6">
<h4><?=$lang['user']['spamfilter_wl'];?></h4>
<p><?=$lang['user']['spamfilter_wl_desc'];?></p>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="wl_policy_domain_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_wl_domain" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-danger" data-action="delete_selected" data-id="policy_wl_domain" data-api-url='delete/domain-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
</div>
</div>
<form class="form-inline" data-id="add_wl_policy_domain">
<div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-default" data-action="add_item" data-id="add_wl_policy_domain" data-api-url='add/domain-policy' data-api-attr='{"domain":"<?= $domain; ?>","object_list":"wl"}' href="#"><?=$lang['user']['spamfilter_table_add'];?></button>
</span>
</div>
</form>
</div>
<div class="col-sm-6">
<h4><?=$lang['user']['spamfilter_bl'];?></h4>
<p><?=$lang['user']['spamfilter_bl_desc'];?></p>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="bl_policy_domain_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_bl_domain" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-danger" data-action="delete_selected" data-id="policy_bl_domain" data-api-url='delete/domain-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
</div>
</div>
<form class="form-inline" data-id="add_bl_policy_domain">
<div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
<input type="text" class="form-control" name="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-default" data-action="add_item" data-id="add_bl_policy_domain" data-api-url='add/domain-policy' data-api-attr='{"domain":"<?= $domain; ?>","object_list":"bl"}' href="#"><?=$lang['user']['spamfilter_table_add'];?></button>
</span>
</div>
</form>
</div>
</div>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
elseif (isset($_GET['aliasdomain']) &&
is_valid_domain_name(html_entity_decode(rawurldecode($_GET["aliasdomain"]))) &&
!empty($_GET["aliasdomain"])) {
$alias_domain = html_entity_decode(rawurldecode($_GET["aliasdomain"]));
$result = mailbox('get', 'alias_domain_details', $alias_domain);
$rl = ratelimit('get', 'domain', $alias_domain);
if (!empty($result)) {
?>
<h4><?=$lang['edit']['edit_alias_domain'];?></h4>
<form class="form-horizontal" data-id="editaliasdomain" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="target_domain"><?=$lang['edit']['target_domain'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="target_domain" value="<?=htmlspecialchars($result['target_domain']);?>">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?=(isset($result['active_int']) && $result['active_int']=="1") ? "checked" : null ?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editaliasdomain" data-item="<?=$alias_domain;?>" data-api-url='edit/alias-domain' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<hr>
<form data-id="domratelimit" class="form-inline well" method="post">
<div class="form-group">
<label class="control-label">Ratelimit</label>
<input name="rl_value" type="number" value="<?=(!empty($rl['value'])) ? $rl['value'] : null;?>" autocomplete="off" class="form-control" placeholder="disabled">
</div>
<div class="form-group">
<select name="rl_frame" class="form-control">
<option value="s" <?=(isset($rl['frame']) && $rl['frame'] == 's') ? 'selected' : null;?>>msgs / second</option>
<option value="m" <?=(isset($rl['frame']) && $rl['frame'] == 'm') ? 'selected' : null;?>>msgs / minute</option>
<option value="h" <?=(isset($rl['frame']) && $rl['frame'] == 'h') ? 'selected' : null;?>>msgs / hour</option>
</select>
</div>
<div class="form-group">
<button class="btn btn-default" data-action="edit_selected" data-id="domratelimit" data-item="<?=$alias_domain;?>" data-api-url='edit/rl-domain' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
</div>
</form>
<?php
if (!empty($dkim = dkim('details', $alias_domain))) {
?>
<hr>
<div class="row">
<div class="col-xs-2">
<p>Domain: <strong><?=htmlspecialchars($result['alias_domain']);?></strong> (<?=$dkim['dkim_selector'];?>._domainkey)</p>
</div>
<div class="col-xs-10">
<pre><?=$dkim['dkim_txt'];?></pre>
</div>
</div>
<?php
}
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
elseif (isset($_GET['mailbox']) && filter_var(html_entity_decode(rawurldecode($_GET["mailbox"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
$mailbox = html_entity_decode(rawurldecode($_GET["mailbox"]));
$result = mailbox('get', 'mailbox_details', $mailbox);
$rl = ratelimit('get', 'mailbox', $mailbox);
if (!empty($result)) {
?>
<h4><?=$lang['edit']['mailbox'];?></h4>
<form class="form-horizontal" data-id="editmailbox" role="form" method="post">
<input type="hidden" value="default" name="sender_acl">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="force_pw_update">
<div class="form-group">
<label class="control-label col-sm-2" for="name"><?=$lang['edit']['full_name'];?>:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name" value="<?=htmlspecialchars($result['name'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="quota"><?=$lang['edit']['quota_mb'];?>:
<br /><span id="quotaBadge" class="badge">max. <?=intval($result['max_new_quota'] / 1048576)?> MiB</span>
</label>
<div class="col-sm-10">
<input type="number" name="quota" style="width:100%" min="1" max="<?=intval($result['max_new_quota'] / 1048576);?>" value="<?=intval($result['quota']) / 1048576;?>" class="form-control">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="sender_acl"><?=$lang['edit']['sender_acl'];?>:</label>
<div class="col-sm-10">
<select data-live-search="true" data-width="100%" style="width:100%" id="editSelectSenderACL" name="sender_acl" size="10" multiple>
<?php
$sender_acl_handles = mailbox('get', 'sender_acl_handles', $mailbox);
foreach ($sender_acl_handles['sender_acl_domains']['ro'] as $domain):
?>
<option data-subtext="Admin" value="<?=htmlspecialchars($domain);?>" disabled selected><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
<?php
endforeach;
foreach ($sender_acl_handles['sender_acl_addresses']['ro'] as $domain):
?>
<option data-subtext="Admin" disabled selected><?=htmlspecialchars($alias);?></option>
<?php
endforeach;
foreach ($sender_acl_handles['fixed_sender_aliases'] as $alias):
?>
<option data-subtext="Alias" disabled selected><?=htmlspecialchars($alias);?></option>
<?php
endforeach;
foreach ($sender_acl_handles['sender_acl_domains']['rw'] as $domain):
?>
<option value="<?=htmlspecialchars($domain);?>" selected><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
<?php
endforeach;
foreach ($sender_acl_handles['sender_acl_domains']['selectable'] as $domain):
?>
<option value="<?=htmlspecialchars($domain);?>"><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
<?php
endforeach;
foreach ($sender_acl_handles['sender_acl_addresses']['rw'] as $address):
?>
<option selected><?=htmlspecialchars($address);?></option>
<?php
endforeach;
foreach ($sender_acl_handles['sender_acl_addresses']['selectable'] as $address):
?>
<option><?=htmlspecialchars($address);?></option>
<?php
endforeach;
?>
</select>
<div style="display:none" id="sender_acl_disabled"><?=$lang['edit']['sender_acl_disabled'];?></div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
<div class="col-sm-10">
<input type="password" data-hibp="true" class="form-control" name="password" placeholder="<?=$lang['edit']['unchanged_if_empty'];?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2"><?=$lang['edit']['password_repeat'];?></label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password2">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?=($result['active_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="force_pw_update" <?=($result['attributes']['force_pw_update']=="1") ? "checked" : null;?>> <?=$lang['edit']['force_pw_update'];?></label>
<small class="help-block"><?=$lang['edit']['force_pw_update_info'];?></small>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editmailbox" data-item="<?=htmlspecialchars($result['username']);?>" data-api-url='edit/mailbox' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<hr>
<form data-id="mboxratelimit" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="help-block">Ratelimit</p>
</div>
<div class="col-sm-10">
<div class="form-group">
<input name="rl_value" type="number" autocomplete="off" value="<?=(!empty($rl['value'])) ? $rl['value'] : null;?>" class="form-control" placeholder="disabled">
</div>
<div class="form-group">
<select name="rl_frame" class="form-control">
<option value="s" <?=(isset($rl['frame']) && $rl['frame'] == 's') ? 'selected' : null;?>>msgs / second</option>
<option value="m" <?=(isset($rl['frame']) && $rl['frame'] == 'm') ? 'selected' : null;?>>msgs / minute</option>
<option value="h" <?=(isset($rl['frame']) && $rl['frame'] == 'h') ? 'selected' : null;?>>msgs / hour</option>
</select>
</div>
<div class="form-group">
<button class="btn btn-default" data-action="edit_selected" data-id="mboxratelimit" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/rl-mbox' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
</div>
</div>
</div>
</form>
<form data-id="useracl" class="form-inline well" method="post">
<div class="row">
<div class="col-sm-1">
<p class="help-block">ACL</p>
</div>
<div class="col-sm-10">
<div class="form-group">
<select id="user_acl" name="user_acl" size="10" multiple>
<?php
$user_acls = acl('get', 'user', $mailbox);
foreach ($user_acls as $acl => $val):
?>
<option value="<?=$acl;?>" <?=($val == 1) ? 'selected' : null;?>><?=$lang['acl'][$acl];?></option>
<?php
endforeach;
?>
</select>
</div>
<div class="form-group">
<button class="btn btn-default" data-action="edit_selected" data-id="useracl" data-item="<?=htmlspecialchars($mailbox);?>" data-api-url='edit/user-acl' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
</div>
</div>
</div>
</form>
<?php
}
}
elseif (isset($_GET['relayhost']) && is_numeric($_GET["relayhost"]) && !empty($_GET["relayhost"])) {
$relayhost = intval($_GET["relayhost"]);
$result = relayhost('details', $relayhost);
if (!empty($result)) {
?>
<h4><?=$lang['edit']['resource'];?></h4>
<form class="form-horizontal" role="form" method="post" data-id="editrelayhost">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="hostname"><?=$lang['add']['hostname'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="hostname" value="<?=htmlspecialchars($result['hostname'], ENT_QUOTES, 'UTF-8');?>" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="username"><?=$lang['add']['username'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="username" value="<?=htmlspecialchars($result['username'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password"><?=$lang['add']['password'];?></label>
<div class="col-sm-10">
<input type="password" data-hibp="true" class="form-control" name="password" value="<?=htmlspecialchars($result['password'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?=($result['active_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editrelayhost" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/relayhost' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
elseif (isset($_GET['resource']) && filter_var(html_entity_decode(rawurldecode($_GET["resource"])), FILTER_VALIDATE_EMAIL) && !empty($_GET["resource"])) {
$resource = html_entity_decode(rawurldecode($_GET["resource"]));
$result = mailbox('get', 'resource_details', $resource);
if (!empty($result)) {
?>
<h4><?=$lang['edit']['resource'];?></h4>
<form class="form-horizontal" role="form" method="post" data-id="editresource">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" value="<?=htmlspecialchars($result['description'], ENT_QUOTES, 'UTF-8');?>" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domain"><?=$lang['edit']['kind'];?>:</label>
<div class="col-sm-10">
<select name="kind" title="<?=$lang['edit']['select'];?>" required>
<option value="location" <?=($result['kind'] == "location") ? "selected" : null;?>>Location</option>
<option value="group" <?=($result['kind'] == "group") ? "selected" : null;?>>Group</option>
<option value="thing" <?=($result['kind'] == "thing") ? "selected" : null;?>>Thing</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="multiple_bookings_select"><?=$lang['add']['multiple_bookings'];?>:</label>
<div class="col-sm-10">
<select name="multiple_bookings_select" id="editSelectMultipleBookings" title="<?=$lang['add']['select'];?>" required>
<option value="0" <?=($result['multiple_bookings'] == 0) ? "selected" : null;?>><?=$lang['mailbox']['booking_0'];?></option>
<option value="-1" <?=($result['multiple_bookings'] == -1) ? "selected" : null;?>><?=$lang['mailbox']['booking_lt0'];?></option>
<option value="custom" <?=($result['multiple_bookings'] >= 1) ? "selected" : null;?>><?=$lang['mailbox']['booking_custom'];?></option>
</select>
<div style="display:none" id="multiple_bookings_custom_div">
<hr>
<input type="number" class="form-control" name="multiple_bookings_custom" id="multiple_bookings_custom" value="<?=($result['multiple_bookings'] >= 1) ? $result['multiple_bookings'] : null;?>">
</div>
<input type="hidden" name="multiple_bookings" id="multiple_bookings">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?=($result['active_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editresource" data-item="<?=htmlspecialchars($result['name']);?>" data-api-url='edit/resource' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
elseif (isset($_GET['bcc']) && !empty($_GET["bcc"])) {
$bcc = intval($_GET["bcc"]);
$result = bcc('details', $bcc);
if (!empty($result)) {
?>
<h4><?=$lang['mailbox']['bcc_map'];?></h4>
<br />
<form class="form-horizontal" data-id="editbcc" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="bcc_dest"><?=$lang['mailbox']['bcc_destination'];?></label>
<div class="col-sm-10">
<input value="<?=$result['bcc_dest'];?>" type="text" class="form-control" name="bcc_dest" id="bcc_dest">
<small><?=$lang['edit']['bcc_dest_format'];?></small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="type"><?=$lang['mailbox']['bcc_map_type'];?></label>
<div class="col-sm-10">
<select id="addFilterType" name="type" id="type" required>
<option value="sender" <?=($result['type'] == 'sender') ? 'selected' : null;?>><?=$lang['mailbox']['bcc_sender_map'];?></option>
<option value="rcpt" <?=($result['type'] == 'rcpt') ? 'selected' : null;?>><?=$lang['mailbox']['bcc_rcpt_map'];?></option>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editbcc" data-item="<?=$bcc;?>" data-api-url='edit/bcc' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
- elseif (isset($_GET['recipient_map']) && !empty($_GET["recipient_map"])) {
+ elseif (isset($_GET['recipient_map']) &&
+ !empty($_GET["recipient_map"]) &&
+ $_SESSION['mailcow_cc_role'] == "admin") {
$map = intval($_GET["recipient_map"]);
$result = recipient_map('details', $map);
if (substr($result['recipient_map_old'], 0, 1) == '@') {
$result['recipient_map_old'] = substr($result['recipient_map_old'], 1);
}
if (!empty($result)) {
?>
<h4><?=$lang['mailbox']['recipient_map']?>: <?=$result['recipient_map_old'];?></h4>
<br />
<form class="form-horizontal" data-id="edit_recipient_map" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="recipient_map_new"><?=$lang['mailbox']['recipient_map_old'];?></label>
<div class="col-sm-10">
<input value="<?=$result['recipient_map_old'];?>" type="text" class="form-control" name="recipient_map_old" id="recipient_map_old">
<small><?=$lang['mailbox']['recipient_map_old_info'];?></small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="recipient_map_new"><?=$lang['mailbox']['recipient_map_new'];?></label>
<div class="col-sm-10">
<input value="<?=$result['recipient_map_new'];?>" type="text" class="form-control" name="recipient_map_new" id="recipient_map_new">
<small><?=$lang['mailbox']['recipient_map_new_info'];?></small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="edit_recipient_map" data-item="<?=$map;?>" data-api-url='edit/recipient_map' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
+ elseif (isset($_GET['tls_policy_map']) &&
+ !empty($_GET["tls_policy_map"]) &&
+ $_SESSION['mailcow_cc_role'] == "admin") {
+ $map = intval($_GET["tls_policy_map"]);
+ $result = tls_policy_maps('details', $map);
+ if (!empty($result)) {
+ ?>
+ <h4><?=$lang['mailbox']['tls_policy_maps']?>: <?=$result['dest'];?></h4>
+ <br />
+ <form class="form-horizontal" data-id="edit_tls_policy_maps" role="form" method="post">
+ <input type="hidden" value="0" name="active">
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="dest"><?=$lang['mailbox']['tls_map_dest'];?></label>
+ <div class="col-sm-10">
+ <input value="<?=$result['dest'];?>" type="text" class="form-control" name="dest" id="dest">
+ <small><?=$lang['mailbox']['tls_map_dest_info'];?></small>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="policy"><?=$lang['mailbox']['tls_map_policy'];?></label>
+ <div class="col-sm-10">
+ <select class="full-width-select" name="policy" required>
+ <option value="none" <?=($result['policy'] != 'none') ?: 'selected';?>>none</option>
+ <option value="may" <?=($result['policy'] != 'may') ?: 'selected';?>>may</option>
+ <option value="encrypt" <?=($result['policy'] != 'encrypt') ?: 'selected';?>>encrypt</option>
+ <option value="dane" <?=($result['policy'] != 'dane') ?: 'selected';?>>dane-only</option>
+ <option value="dane-only" <?=($result['policy'] != 'dane-only') ?: 'selected';?>>dane-only</option>
+ <option value="fingerprint" <?=($result['policy'] != 'fingerprint') ?: 'selected';?>>fingerprint</option>
+ <option value="verify" <?=($result['policy'] != 'verify') ?: 'selected';?>>verify</option>
+ <option value="secure" <?=($result['policy'] != 'secure') ?: 'selected';?>>secure</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="parameters"><?=$lang['mailbox']['tls_map_parameters'];?></label>
+ <div class="col-sm-10">
+ <input value="<?=$result['parameters'];?>" type="text" class="form-control" name="parameters" id="parameters">
+ <small><?=$lang['mailbox']['tls_map_parameters_info'];?></small>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <div class="checkbox">
+ <label><input type="checkbox" value="1" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button class="btn btn-success" data-action="edit_selected" data-id="edit_tls_policy_maps" data-item="<?=$map;?>" data-api-url='edit/tls-policy-map' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
+ </div>
+ </div>
+ </form>
+ <?php
+ }
+ else {
+ ?>
+ <div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
+ <?php
+ }
+ }
}
if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin" || $_SESSION['mailcow_cc_role'] == "user") {
if (isset($_GET['syncjob']) &&
is_numeric($_GET['syncjob'])) {
$id = $_GET["syncjob"];
$result = mailbox('get', 'syncjob_details', $id);
if (!empty($result)) {
?>
<h4><?=$lang['edit']['syncjob'];?></h4>
<form class="form-horizontal" data-id="editsyncjob" role="form" method="post">
<input type="hidden" value="0" name="delete2duplicates">
<input type="hidden" value="0" name="delete1">
<input type="hidden" value="0" name="delete2">
<input type="hidden" value="0" name="automap">
<input type="hidden" value="0" name="skipcrossduplicates">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="subscribeall">
<div class="form-group">
<label class="control-label col-sm-2" for="host1"><?=$lang['edit']['hostname'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="host1" id="host1" value="<?=htmlspecialchars($result['host1'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="port1">Port</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="port1" id="port1" min="1" max="65535" value="<?=htmlspecialchars($result['port1'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="user1"><?=$lang['edit']['username'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="user1" id="user1" value="<?=htmlspecialchars($result['user1'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password1"><?=$lang['edit']['password'];?></label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password1" id="password1" value="<?=htmlspecialchars($result['password1'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="enc1"><?=$lang['edit']['encryption'];?>:</label>
<div class="col-sm-10">
<select id="enc1" name="enc1">
<option <?=($result['enc1'] == "TLS") ? "selected" : null;?>>TLS</option>
<option <?=($result['enc1'] == "SSL") ? "selected" : null;?>>SSL</option>
<option <?=($result['enc1'] == "PLAIN") ? "selected" : null;?>>PLAIN</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mins_interval"><?=$lang['edit']['mins_interval'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mins_interval" min="1" max="3600" value="<?=htmlspecialchars($result['mins_interval'], ENT_QUOTES, 'UTF-8');?>" required>
<small class="help-block">1-3600</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="subfolder2"><?=$lang['edit']['subfolder2'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="subfolder2" id="subfolder2" value="<?=htmlspecialchars($result['subfolder2'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxage"><?=$lang['edit']['maxage'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxage" id="maxage" min="0" max="32000" value="<?=htmlspecialchars($result['maxage'], ENT_QUOTES, 'UTF-8');?>">
<small class="help-block">0-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxbytespersecond"><?=$lang['edit']['maxbytespersecond'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxbytespersecond" id="maxbytespersecond" min="0" max="125000000" value="<?=htmlspecialchars($result['maxbytespersecond'], ENT_QUOTES, 'UTF-8');?>">
<small class="help-block">0-125000000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout1"><?=$lang['add']['timeout1'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout1" id="timeout1" min="1" max="32000" value="<?=htmlspecialchars($result['timeout1'], ENT_QUOTES, 'UTF-8');?>">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout2"><?=$lang['add']['timeout2'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout2" id="timeout2" min="1" max="32000" value="<?=htmlspecialchars($result['timeout2'], ENT_QUOTES, 'UTF-8');?>">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="exclude"><?=$lang['edit']['exclude'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="exclude" id="exclude" value="<?=htmlspecialchars($result['exclude'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="custom_params"><?=$lang['add']['custom_params'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="custom_params" id="custom_params" value="<?=htmlspecialchars($result['custom_params'], ENT_QUOTES, 'UTF-8');?>">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2duplicates" <?=($result['delete2duplicates']=="1") ? "checked" : "";?>> <?=$lang['edit']['delete2duplicates'];?> (--delete2duplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete1" <?=($result['delete1']=="1") ? "checked" : "";?>> <?=$lang['edit']['delete1'];?> (--delete1)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2" <?=($result['delete2']=="1") ? "checked" : "";?>> <?=$lang['edit']['delete2'];?> (--delete2)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="automap" <?=($result['automap']=="1") ? "checked" : "";?>> <?=$lang['edit']['automap'];?> (--automap)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="skipcrossduplicates" <?=($result['skipcrossduplicates']=="1") ? "checked" : "";?>> <?=$lang['edit']['skipcrossduplicates'];?> (--skipcrossduplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="subscribeall" <?=($result['subscribeall']=="1") ? "checked" : "";?>> <?=$lang['add']['subscribeall'];?> (--subscribeall)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?=($result['active_int']=="1") ? "checked" : "";?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editsyncjob" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/syncjob' data-api-attr='{}' href="#"><?=$lang['edit']['save'];?></button>
</div>
</div>
</form>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
elseif (isset($_GET['filter']) &&
is_numeric($_GET['filter'])) {
$id = $_GET["filter"];
$result = mailbox('get', 'filter_details', $id);
if (!empty($result)) {
?>
<h4>Filter</h4>
<form class="form-horizontal" data-id="editfilter" role="form" method="post">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="script_desc"><?=$lang['edit']['sieve_desc'];?>:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="script_desc" id="script_desc" value="<?=htmlspecialchars($result['script_desc'], ENT_QUOTES, 'UTF-8');?>" required maxlength="255">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="filter_type"><?=$lang['edit']['sieve_type'];?>:</label>
<div class="col-sm-10">
<select id="addFilterType" name="filter_type" id="filter_type" required>
<option value="prefilter" <?=($result['filter_type'] == 'prefilter') ? 'selected' : null;?>>Prefilter</option>
<option value="postfilter" <?=($result['filter_type'] == 'postfilter') ? 'selected' : null;?>>Postfilter</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="script_data">Script:</label>
<div class="col-sm-10">
<textarea spellcheck="false" autocorrect="off" autocapitalize="none" class="form-control" rows="20" id="script_data" name="script_data" required><?=$result['script_data'];?></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" <?=($result['active_int']=="1") ? "checked" : "";?>> <?=$lang['edit']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="edit_selected" data-id="editfilter" data-item="<?=htmlspecialchars($result['id']);?>" data-api-url='edit/filter' data-api-attr='{}' href="#"><?=$lang['edit']['validate_save'];?></button>
</div>
</div>
</form>
<?php
}
else {
?>
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
<?php
}
}
}
}
else {
?>
<div class="alert alert-danger" role="alert"><?=$lang['danger']['access_denied'];?></div>
<?php
}
?>
</div>
</div>
</div>
</div>
<a href="<?=$_SESSION['return_to'];?>">&#8592; <?=$lang['edit']['previous'];?></a>
</div> <!-- /container -->
<script type='text/javascript'>
<?php
$lang_user = json_encode($lang['user']);
echo "var lang_user = ". $lang_user . ";\n";
echo "var table_for_domain = '". ((isset($domain)) ? $domain : null) . "';\n";
echo "var csrf_token = '". $_SESSION['CSRF']['TOKEN'] . "';\n";
echo "var pagination_size = '". $PAGINATION_SIZE . "';\n";
?>
</script>
<script src="js/footable.min.js"></script>
<script src="js/edit.js"></script>
<?php
require_once("inc/footer.inc.php");
?>
diff --git a/data/web/inc/functions.address_rewriting.inc.php b/data/web/inc/functions.address_rewriting.inc.php
index 994429f2..bbf36c42 100644
--- a/data/web/inc/functions.address_rewriting.inc.php
+++ b/data/web/inc/functions.address_rewriting.inc.php
@@ -1,494 +1,432 @@
<?php
function bcc($_action, $_data = null, $attr = null) {
global $pdo;
global $lang;
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
return false;
}
switch ($_action) {
case 'add':
if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied'
);
return false;
}
$local_dest = strtolower(trim($_data['local_dest']));
$bcc_dest = $_data['bcc_dest'];
$active = intval($_data['active']);
$type = $_data['type'];
if ($type != 'sender' && $type != 'rcpt') {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'invalid_bcc_map_type'
);
return false;
}
if (empty($bcc_dest)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'bcc_empty'
);
return false;
}
if (is_valid_domain_name($local_dest)) {
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied'
);
return false;
}
$domain = idn_to_ascii($local_dest);
$local_dest_sane = '@' . idn_to_ascii($local_dest);
}
elseif (filter_var($local_dest, FILTER_VALIDATE_EMAIL)) {
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $local_dest)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied'
);
return false;
}
$domain = mailbox('get', 'mailbox_details', $local_dest)['domain'];
if (empty($domain)) {
return false;
}
$local_dest_sane = $local_dest;
}
else {
return false;
}
if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'bcc_must_be_email'
);
return false;
}
$stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
WHERE `local_dest` = :local_dest AND `type` = :type");
$stmt->execute(array(':local_dest' => $local_dest_sane, ':type' => $type));
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_exists', htmlspecialchars($local_dest_sane), $type)
);
return false;
}
- try {
- $stmt = $pdo->prepare("INSERT INTO `bcc_maps` (`local_dest`, `bcc_dest`, `domain`, `active`, `type`) VALUES
- (:local_dest, :bcc_dest, :domain, :active, :type)");
- $stmt->execute(array(
- ':local_dest' => $local_dest_sane,
- ':bcc_dest' => $bcc_dest,
- ':domain' => $domain,
- ':active' => $active,
- ':type' => $type
- ));
- }
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
- );
- return false;
- }
+ $stmt = $pdo->prepare("INSERT INTO `bcc_maps` (`local_dest`, `bcc_dest`, `domain`, `active`, `type`) VALUES
+ (:local_dest, :bcc_dest, :domain, :active, :type)");
+ $stmt->execute(array(
+ ':local_dest' => $local_dest_sane,
+ ':bcc_dest' => $bcc_dest,
+ ':domain' => $domain,
+ ':active' => $active,
+ ':type' => $type
+ ));
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'bcc_saved'
);
break;
case 'edit':
if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied'
);
return false;
}
$ids = (array)$_data['id'];
foreach ($ids as $id) {
$is_now = bcc('details', $id);
if (!empty($is_now)) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int'];
$bcc_dest = (!empty($_data['bcc_dest'])) ? $_data['bcc_dest'] : $is_now['bcc_dest'];
$local_dest = $is_now['local_dest'];
$type = (!empty($_data['type'])) ? $_data['type'] : $is_now['type'];
}
else {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied'
);
continue;
}
$active = intval($_data['active']);
if (!filter_var($bcc_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_must_be_email', $bcc_dest)
);
continue;
}
if (empty($bcc_dest)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_must_be_email', $bcc_dest)
);
continue;
}
- try {
- $stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
- WHERE `local_dest` = :local_dest AND `type` = :type");
- $stmt->execute(array(':local_dest' => $local_dest, ':type' => $type));
- $id_now = $stmt->fetch(PDO::FETCH_ASSOC)['id'];
+ $stmt = $pdo->prepare("SELECT `id` FROM `bcc_maps`
+ WHERE `local_dest` = :local_dest AND `type` = :type");
+ $stmt->execute(array(':local_dest' => $local_dest, ':type' => $type));
+ $id_now = $stmt->fetch(PDO::FETCH_ASSOC)['id'];
- if (isset($id_now) && $id_now != $id) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('bcc_exists', htmlspecialchars($local_dest), $type)
- );
- continue;
- }
-
- $stmt = $pdo->prepare("UPDATE `bcc_maps` SET `bcc_dest` = :bcc_dest, `active` = :active, `type` = :type WHERE `id`= :id");
- $stmt->execute(array(
- ':bcc_dest' => $bcc_dest,
- ':active' => $active,
- ':type' => $type,
- ':id' => $id
- ));
- }
- catch (PDOException $e) {
+ if (isset($id_now) && $id_now != $id) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
+ 'msg' => array('bcc_exists', htmlspecialchars($local_dest), $type)
);
continue;
}
+
+ $stmt = $pdo->prepare("UPDATE `bcc_maps` SET `bcc_dest` = :bcc_dest, `active` = :active, `type` = :type WHERE `id`= :id");
+ $stmt->execute(array(
+ ':bcc_dest' => $bcc_dest,
+ ':active' => $active,
+ ':type' => $type,
+ ':id' => $id
+ ));
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_edited', $bcc_dest)
);
}
break;
case 'details':
$bccdata = array();
$id = intval($_data);
$stmt = $pdo->prepare("SELECT `id`,
`local_dest`,
`bcc_dest`,
`active` AS `active_int`,
CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
`type`,
`created`,
`domain`,
`modified` FROM `bcc_maps`
WHERE `id` = :id");
$stmt->execute(array(':id' => $id));
$bccdata = $stmt->fetch(PDO::FETCH_ASSOC);
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $bccdata['domain'])) {
$bccdata = null;
return false;
}
return $bccdata;
break;
case 'get':
$bccdata = array();
$all_items = array();
$id = intval($_data);
$stmt = $pdo->query("SELECT `id`, `domain` FROM `bcc_maps`");
$all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($all_items as $i) {
if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $i['domain'])) {
$bccdata[] = $i['id'];
}
}
$all_items = null;
return $bccdata;
break;
case 'delete':
if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied'
);
return false;
}
$ids = (array)$_data['id'];
foreach ($ids as $id) {
if (!is_numeric($id)) {
return false;
}
- try {
- $stmt = $pdo->prepare("SELECT `domain` FROM `bcc_maps` WHERE id = :id");
- $stmt->execute(array(':id' => $id));
- $domain = $stmt->fetch(PDO::FETCH_ASSOC)['domain'];
- if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => 'access_denied'
- );
- continue;
- }
- $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `id`= :id");
- $stmt->execute(array(':id' => $id));
- }
- catch (PDOException $e) {
+ $stmt = $pdo->prepare("SELECT `domain` FROM `bcc_maps` WHERE id = :id");
+ $stmt->execute(array(':id' => $id));
+ $domain = $stmt->fetch(PDO::FETCH_ASSOC)['domain'];
+ if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
+ 'msg' => 'access_denied'
);
continue;
}
+ $stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `id`= :id");
+ $stmt->execute(array(':id' => $id));
+
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('bcc_deleted', $id)
);
}
break;
}
}
function recipient_map($_action, $_data = null, $attr = null) {
global $pdo;
global $lang;
if ($_SESSION['mailcow_cc_role'] != "admin") {
return false;
}
switch ($_action) {
case 'add':
$old_dest = strtolower(trim($_data['recipient_map_old']));
if (substr($old_dest, 0, 1) == '@') {
$old_dest = substr($old_dest, 1);
}
$new_dest = strtolower(trim($_data['recipient_map_new']));
$active = intval($_data['active']);
if (is_valid_domain_name($old_dest)) {
$old_dest_sane = '@' . idn_to_ascii($old_dest);
}
elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) {
$old_dest_sane = $old_dest;
}
else {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest))
);
return false;
}
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest))
);
return false;
}
$rmaps = recipient_map('get');
foreach ($rmaps as $rmap) {
- $old_dests_existing[] = recipient_map('details', $rmap)['recipient_map_old'];
- }
- if (in_array($old_dest_sane, $old_dests_existing)) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest))
- );
- return false;
- }
- try {
- $stmt = $pdo->prepare("INSERT INTO `recipient_maps` (`old_dest`, `new_dest`, `active`) VALUES
- (:old_dest, :new_dest, :active)");
- $stmt->execute(array(
- ':old_dest' => $old_dest_sane,
- ':new_dest' => $new_dest,
- ':active' => $active
- ));
- }
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
- );
- return false;
+ if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane))
+ );
+ return false;
+ }
}
+ $stmt = $pdo->prepare("INSERT INTO `recipient_maps` (`old_dest`, `new_dest`, `active`) VALUES
+ (:old_dest, :new_dest, :active)");
+ $stmt->execute(array(
+ ':old_dest' => $old_dest_sane,
+ ':new_dest' => $new_dest,
+ ':active' => $active
+ ));
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane))
);
break;
case 'edit':
$ids = (array)$_data['id'];
foreach ($ids as $id) {
$is_now = recipient_map('details', $id);
if (!empty($is_now)) {
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int'];
$new_dest = (!empty($_data['recipient_map_new'])) ? $_data['recipient_map_new'] : $is_now['recipient_map_new'];
$old_dest = (!empty($_data['recipient_map_old'])) ? $_data['recipient_map_old'] : $is_now['recipient_map_old'];
if (substr($old_dest, 0, 1) == '@') {
$old_dest = substr($old_dest, 1);
}
}
else {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => 'access_denied'
);
continue;
}
if (is_valid_domain_name($old_dest)) {
$old_dest_sane = '@' . idn_to_ascii($old_dest);
}
elseif (filter_var($old_dest, FILTER_VALIDATE_EMAIL)) {
$old_dest_sane = $old_dest;
}
else {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('invalid_recipient_map_old', htmlspecialchars($old_dest))
);
continue;
}
- $active = intval($_data['active']);
if (!filter_var($new_dest, FILTER_VALIDATE_EMAIL)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('invalid_recipient_map_new', htmlspecialchars($new_dest))
);
continue;
}
$rmaps = recipient_map('get');
foreach ($rmaps as $rmap) {
- $old_dests_existing[] = recipient_map('details', $rmap)['recipient_map_old'];
- }
- if (in_array($old_dest_sane, $old_dests_existing) &&
- recipient_map('details', $id)['recipient_map_old'] != $old_dest_sane) {
+ if ($rmap == $id) { continue; }
+ if (recipient_map('details', $rmap)['recipient_map_old'] == $old_dest_sane) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_exists', htmlspecialchars($old_dest_sane))
);
- continue;
- }
- try {
- $stmt = $pdo->prepare("UPDATE `recipient_maps` SET
- `old_dest` = :old_dest,
- `new_dest` = :new_dest,
- `active` = :active
- WHERE `id`= :id");
- $stmt->execute(array(
- ':old_dest' => $old_dest_sane,
- ':new_dest' => $new_dest,
- ':active' => $active,
- ':id' => $id
- ));
- }
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
- );
- return false;
+ return false;
+ }
}
+ $stmt = $pdo->prepare("UPDATE `recipient_maps` SET
+ `old_dest` = :old_dest,
+ `new_dest` = :new_dest,
+ `active` = :active
+ WHERE `id`= :id");
+ $stmt->execute(array(
+ ':old_dest' => $old_dest_sane,
+ ':new_dest' => $new_dest,
+ ':active' => $active,
+ ':id' => $id
+ ));
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_data, $_attr),
'msg' => array('recipient_map_entry_saved', htmlspecialchars($old_dest_sane))
);
}
break;
case 'details':
$mapdata = array();
$id = intval($_data);
$stmt = $pdo->prepare("SELECT `id`,
`old_dest` AS `recipient_map_old`,
`new_dest` AS `recipient_map_new`,
`active` AS `active_int`,
CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
`created`,
`modified` FROM `recipient_maps`
WHERE `id` = :id");
$stmt->execute(array(':id' => $id));
$mapdata = $stmt->fetch(PDO::FETCH_ASSOC);
return $mapdata;
break;
case 'get':
$mapdata = array();
$all_items = array();
$id = intval($_data);
$stmt = $pdo->query("SELECT `id` FROM `recipient_maps`");
$all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($all_items as $i) {
$mapdata[] = $i['id'];
}
$all_items = null;
return $mapdata;
break;
case 'delete':
$ids = (array)$_data['id'];
foreach ($ids as $id) {
if (!is_numeric($id)) {
return false;
}
- try {
- $stmt = $pdo->prepare("DELETE FROM `recipient_maps` WHERE `id`= :id");
- $stmt->execute(array(':id' => $id));
- }
- catch (PDOException $e) {
- $_SESSION['return'][] = array(
- 'type' => 'danger',
- 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
- 'msg' => array('mysql_error', $e)
- );
- return false;
- }
+ $stmt = $pdo->prepare("DELETE FROM `recipient_maps` WHERE `id`= :id");
+ $stmt->execute(array(':id' => $id));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('recipient_map_entry_deleted', htmlspecialchars($id))
+ );
}
- $_SESSION['return'][] = array(
- 'type' => 'success',
- 'msg' => array('recipient_map_entry_deleted', htmlspecialchars($old_dest))
- );
- return true;
break;
}
}
diff --git a/data/web/inc/functions.tls_policy_maps.inc.php b/data/web/inc/functions.tls_policy_maps.inc.php
new file mode 100644
index 00000000..6581b60d
--- /dev/null
+++ b/data/web/inc/functions.tls_policy_maps.inc.php
@@ -0,0 +1,157 @@
+<?php
+function tls_policy_maps($_action, $_data = null, $attr = null) {
+ global $pdo;
+ global $lang;
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ return false;
+ }
+ switch ($_action) {
+ case 'add':
+ $dest = idn_to_ascii(trim($_data['dest']));
+ $policy = strtolower(trim($_data['policy']));
+ $parameters = (isset($_data['parameters']) && !empty($_data['parameters'])) ? $_data['parameters'] : '';
+ if (!empty($parameters)) {
+ foreach (explode(' ', $parameters) as $parameter) {
+ if (!preg_match('/(.+)\=(.+)/i', $parameter)) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => 'tls_policy_map_parameter_invalid'
+ );
+ return false;
+ }
+ }
+ }
+ $active = intval($_data['active']);
+ $tls_policy_maps = tls_policy_maps('get');
+ foreach ($tls_policy_maps as $tls_policy_map) {
+ if (tls_policy_maps('details', $tls_policy_map)['dest'] == $dest) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('tls_policy_map_entry_exists', htmlspecialchars($dest))
+ );
+ return false;
+ }
+ }
+ $stmt = $pdo->prepare("INSERT INTO `tls_policy_override` (`dest`, `policy`, `parameters`, `active`) VALUES
+ (:dest, :policy, :parameters, :active)");
+ $stmt->execute(array(
+ ':dest' => $dest,
+ ':policy' => $policy,
+ ':parameters' => $parameters,
+ ':active' => $active
+ ));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('tls_policy_map_entry_saved', htmlspecialchars($dest))
+ );
+ break;
+ case 'edit':
+ $ids = (array)$_data['id'];
+ foreach ($ids as $id) {
+ $is_now = tls_policy_maps('details', $id);
+ if (!empty($is_now)) {
+ $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active_int'];
+ $dest = (!empty($_data['dest'])) ? $_data['dest'] : $is_now['dest'];
+ $policy = (!empty($_data['policy'])) ? $_data['policy'] : $is_now['policy'];
+ $parameters = (isset($_data['parameters'])) ? $_data['parameters'] : $is_now['parameters'];
+ }
+ else {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => 'access_denied'
+ );
+ continue;
+ }
+ if (!empty($parameters)) {
+ foreach (explode(' ', $parameters) as $parameter) {
+ if (!preg_match('/(.+)\=(.+)/i', $parameter)) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => 'tls_policy_map_parameter_invalid'
+ );
+ return false;
+ }
+ }
+ }
+ $tls_policy_maps = tls_policy_maps('get');
+ foreach ($tls_policy_maps as $tls_policy_map) {
+ if ($tls_policy_map == $id) { continue; }
+ if (tls_policy_maps('details', $tls_policy_map)['dest'] == $dest) {
+ $_SESSION['return'][] = array(
+ 'type' => 'danger',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('recipient_map_entry_exists', htmlspecialchars($dest))
+ );
+ return false;
+ }
+ }
+ $stmt = $pdo->prepare("UPDATE `tls_policy_override` SET
+ `dest` = :dest,
+ `policy` = :policy,
+ `parameters` = :parameters,
+ `active` = :active
+ WHERE `id`= :id");
+ $stmt->execute(array(
+ ':dest' => $dest,
+ ':policy' => $policy,
+ ':parameters' => $parameters,
+ ':active' => $active,
+ ':id' => $id
+ ));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('tls_policy_map_entry_saved', htmlspecialchars($dest))
+ );
+ }
+ break;
+ case 'details':
+ $mapdata = array();
+ $id = intval($_data);
+ $stmt = $pdo->prepare("SELECT `id`,
+ `dest`,
+ `policy`,
+ `parameters`,
+ `active` AS `active_int`,
+ CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
+ `created`,
+ `modified` FROM `tls_policy_override`
+ WHERE `id` = :id");
+ $stmt->execute(array(':id' => $id));
+ $mapdata = $stmt->fetch(PDO::FETCH_ASSOC);
+ return $mapdata;
+ break;
+ case 'get':
+ $mapdata = array();
+ $all_items = array();
+ $id = intval($_data);
+ $stmt = $pdo->query("SELECT `id` FROM `tls_policy_override`");
+ $all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ foreach ($all_items as $i) {
+ $mapdata[] = $i['id'];
+ }
+ $all_items = null;
+ return $mapdata;
+ break;
+ case 'delete':
+ $ids = (array)$_data['id'];
+ foreach ($ids as $id) {
+ if (!is_numeric($id)) {
+ return false;
+ }
+ $stmt = $pdo->prepare("DELETE FROM `tls_policy_override` WHERE `id`= :id");
+ $stmt->execute(array(':id' => $id));
+ $_SESSION['return'][] = array(
+ 'type' => 'success',
+ 'log' => array(__FUNCTION__, $_action, $_data, $_attr),
+ 'msg' => array('tls_policy_map_entry_deleted', htmlspecialchars($id))
+ );
+ }
+ break;
+ }
+}
diff --git a/data/web/inc/header.inc.php b/data/web/inc/header.inc.php
index 46384b7b..15dc4f02 100644
--- a/data/web/inc/header.inc.php
+++ b/data/web/inc/header.inc.php
@@ -1,145 +1,145 @@
<!DOCTYPE html>
<html lang="<?= $_SESSION['mailcow_locale'] ?>">
<head>
-<meta charset="utf-8">
-<meta http-equiv="X-UA-Compatible" content="IE=edge">
-<meta name="viewport" content="width=device-width, initial-scale=1">
-<meta name="theme-color" content="#F5D76E"/>
-<meta http-equiv="Referrer-Policy" content="same-origin">
-<title><?=$UI_TEXTS['title_name'];?></title>
-<!--[if lt IE 9]>
- <script src="/js/html5shiv.min.js"></script>
- <script src="/js/respond.min.js"></script>
-<![endif]-->
-<script src="/js/jquery-1.12.4.min.js"></script>
-<?php if (strtolower(trim($DEFAULT_THEME)) != "lumen"): ?>
-<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.7/<?= strtolower(trim($DEFAULT_THEME)); ?>/bootstrap.min.css">
-<?php else: ?>
-<link rel="stylesheet" href="/css/bootstrap.min.css">
-<?php endif; ?>
-<link rel="stylesheet" href="/css/breakpoint.min.css">
-<link rel="stylesheet" href="/css/bootstrap-select.min.css">
-<link rel="stylesheet" href="/css/bootstrap-slider.min.css">
-<link rel="stylesheet" href="/css/bootstrap-switch.min.css">
-<link rel="stylesheet" href="/css/footable.bootstrap.min.css">
-<link rel="stylesheet" href="/inc/languages.min.css">
-<link rel="stylesheet" href="/css/mailcow.css">
-<link rel="stylesheet" href="/css/animate.min.css">
-<link rel="stylesheet" href="/css/numberedtextarea.min.css">
-<link rel="stylesheet" href="/css/jquery.jqplot.min.css">
-<?= (preg_match("/mailbox.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/mailbox.css">' : null; ?>
-<?= (preg_match("/admin.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/admin.css">' : null; ?>
-<?= (preg_match("/user.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/user.css">' : null; ?>
-<?= (preg_match("/edit.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/edit.css">' : null; ?>
-<?= (preg_match("/quarantine.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/quarantine.css">' : null; ?>
-<?= (preg_match("/debug.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/debug.css">' : null; ?>
-<link rel="shortcut icon" href="/favicon.png" type="image/png">
-<link rel="icon" href="/favicon.png" type="image/png">
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="theme-color" content="#F5D76E"/>
+ <meta http-equiv="Referrer-Policy" content="same-origin">
+ <title><?=$UI_TEXTS['title_name'];?></title>
+ <!--[if lt IE 9]>
+ <script src="/js/html5shiv.min.js"></script>
+ <script src="/js/respond.min.js"></script>
+ <![endif]-->
+ <script src="/js/jquery-1.12.4.min.js"></script>
+ <?php if (strtolower(trim($DEFAULT_THEME)) != "lumen"): ?>
+ <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootswatch/3.3.7/<?= strtolower(trim($DEFAULT_THEME)); ?>/bootstrap.min.css">
+ <?php else: ?>
+ <link rel="stylesheet" href="/css/bootstrap.min.css">
+ <?php endif; ?>
+ <link rel="stylesheet" href="/css/breakpoint.min.css">
+ <link rel="stylesheet" href="/css/bootstrap-select.min.css">
+ <link rel="stylesheet" href="/css/bootstrap-slider.min.css">
+ <link rel="stylesheet" href="/css/bootstrap-switch.min.css">
+ <link rel="stylesheet" href="/css/footable.bootstrap.min.css">
+ <link rel="stylesheet" href="/inc/languages.min.css">
+ <link rel="stylesheet" href="/css/mailcow.css">
+ <link rel="stylesheet" href="/css/animate.min.css">
+ <link rel="stylesheet" href="/css/numberedtextarea.min.css">
+ <link rel="stylesheet" href="/css/jquery.jqplot.min.css">
+ <?= (preg_match("/mailbox/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/mailbox.css">' : null; ?>
+ <?= (preg_match("/admin/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/admin.css">' : null; ?>
+ <?= (preg_match("/user/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/user.css">' : null; ?>
+ <?= (preg_match("/edit/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/edit.css">' : null; ?>
+ <?= (preg_match("/quarantine/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/quarantine.css">' : null; ?>
+ <?= (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/debug.css">' : null; ?>
+ <link rel="shortcut icon" href="/favicon.png" type="image/png">
+ <link rel="icon" href="/favicon.png" type="image/png">
</head>
<body id="top">
-<div class="overlay"></div>
-<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
- <div class="container-fluid">
- <div class="navbar-header">
- <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- <span class="icon-bar"></span>
- </button>
- <a class="navbar-brand" href="/"><img alt="mailcow-logo" src="<?=($main_logo = customize('get', 'main_logo')) ? $main_logo : '/img/cow_mailcow.svg';?>"></a>
- </div>
- <div id="navbar" class="navbar-collapse collapse">
- <ul class="nav navbar-nav navbar-right">
- <?php
- if (isset($_SESSION['mailcow_locale'])) {
- ?>
- <li class="dropdown<?=(isset($_SESSION['mailcow_locale']) && count($AVAILABLE_LANGUAGES) === 1) ? ' lang-link-disabled"' : '' ?>">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="lang-sm lang-lbl" lang="<?= $_SESSION['mailcow_locale']; ?>"></span><span class="caret"></span></a>
- <ul class="dropdown-menu" role="menu">
- <?php
- foreach ($AVAILABLE_LANGUAGES as $language) {
- ?>
- <li<?= ($_SESSION['mailcow_locale'] == $language) ? ' class="active"' : ''; ?>><a href="?<?= http_build_query(array_merge($_GET, array('lang' => $language))); ?>"><span class="lang-xs lang-lbl-full" lang="<?= $language; ?>"></span></a></li>
- <?php
- }
- ?>
- </ul>
- </li>
- <?php
- }
- if (isset($_SESSION['mailcow_cc_role'])) {
- ?>
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><?= $lang['header']['mailcow_settings']; ?> <span class="caret"></span></a>
- <ul class="dropdown-menu" role="menu">
- <?php
- if (isset($_SESSION['mailcow_cc_role'])) {
- if ($_SESSION['mailcow_cc_role'] == 'admin') {
- ?>
- <li<?= (preg_match("/admin/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/admin.php"><?= $lang['header']['administration']; ?></a></li>
- <li<?= (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/debug.php"><?= $lang['header']['debug']; ?></a></li>
+ <div class="overlay"></div>
+ <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
+ <div class="container-fluid">
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="/"><img alt="mailcow-logo" src="<?=($main_logo = customize('get', 'main_logo')) ? $main_logo : '/img/cow_mailcow.svg';?>"></a>
+ </div>
+ <div id="navbar" class="navbar-collapse collapse">
+ <ul class="nav navbar-nav navbar-right">
+ <?php
+ if (isset($_SESSION['mailcow_locale'])) {
+ ?>
+ <li class="dropdown<?=(isset($_SESSION['mailcow_locale']) && count($AVAILABLE_LANGUAGES) === 1) ? ' lang-link-disabled"' : '' ?>">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="lang-sm lang-lbl" lang="<?= $_SESSION['mailcow_locale']; ?>"></span><span class="caret"></span></a>
+ <ul class="dropdown-menu" role="menu">
<?php
- }
- if ($_SESSION['mailcow_cc_role'] == 'admin' || $_SESSION['mailcow_cc_role'] == 'domainadmin') {
+ foreach ($AVAILABLE_LANGUAGES as $language) {
?>
- <li<?= (preg_match("/mailbox/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/mailbox.php"><?= $lang['header']['mailboxes']; ?></a></li>
+ <li<?= ($_SESSION['mailcow_locale'] == $language) ? ' class="active"' : ''; ?>><a href="?<?= http_build_query(array_merge($_GET, array('lang' => $language))); ?>"><span class="lang-xs lang-lbl-full" lang="<?= $language; ?>"></span></a></li>
<?php
}
- if ($_SESSION['mailcow_cc_role'] != 'admin') {
?>
- <li<?= (preg_match("/user/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/user.php"><?= $lang['header']['user_settings']; ?></a></li>
+ </ul>
+ </li>
+ <?php
+ }
+ if (isset($_SESSION['mailcow_cc_role'])) {
+ ?>
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><?= $lang['header']['mailcow_settings']; ?> <span class="caret"></span></a>
+ <ul class="dropdown-menu" role="menu">
<?php
+ if (isset($_SESSION['mailcow_cc_role'])) {
+ if ($_SESSION['mailcow_cc_role'] == 'admin') {
+ ?>
+ <li<?= (preg_match("/admin/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/admin"><?= $lang['header']['administration']; ?></a></li>
+ <li<?= (preg_match("/debug/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/debug"><?= $lang['header']['debug']; ?></a></li>
+ <?php
+ }
+ if ($_SESSION['mailcow_cc_role'] == 'admin' || $_SESSION['mailcow_cc_role'] == 'domainadmin') {
+ ?>
+ <li<?= (preg_match("/mailbox/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/mailbox"><?= $lang['header']['mailboxes']; ?></a></li>
+ <?php
+ }
+ if ($_SESSION['mailcow_cc_role'] != 'admin') {
+ ?>
+ <li<?= (preg_match("/user/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/user"><?= $lang['header']['user_settings']; ?></a></li>
+ <?php
+ }
}
- }
- ?>
- </ul>
- </li>
- <?php
- if (isset($_SESSION['mailcow_cc_role'])) {
- ?>
- <li<?= (preg_match("/quarantine/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/quarantine.php"><span class="glyphicon glyphicon-briefcase"></span> <?= $lang['header']['quarantine']; ?></a></li>
- <?php
- }
- if ($_SESSION['mailcow_cc_role'] == 'admin') {
- ?>
- <li><a href data-toggle="modal" data-container="sogo-mailcow" data-target="#RestartContainer"><span class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_sogo']; ?></a></li>
- <?php
- }
- ?>
- <li class="dropdown">
- <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="glyphicon glyphicon-link"></span> Apps <span class="caret"></span></a>
- <ul class="dropdown-menu" role="menu">
+ ?>
+ </ul>
+ </li>
<?php
- foreach ($MAILCOW_APPS as $app):
+ if (isset($_SESSION['mailcow_cc_role'])) {
?>
- <li title="<?= htmlspecialchars($app['description']); ?>"><a href="<?= htmlspecialchars($app['link']); ?>"><?= htmlspecialchars($app['name']); ?></a></li>
+ <li<?= (preg_match("/quarantine/i", $_SERVER['REQUEST_URI'])) ? ' class="active"' : ''; ?>><a href="/quarantine"><span class="glyphicon glyphicon-briefcase"></span> <?= $lang['header']['quarantine']; ?></a></li>
<?php
- endforeach;
- $app_links = customize('get', 'app_links');
- foreach ($app_links as $row) {
- foreach ($row as $key => $val):
+ }
+ if ($_SESSION['mailcow_cc_role'] == 'admin') {
?>
- <li><a href="<?= htmlspecialchars($val); ?>"><?= htmlspecialchars($key); ?></a></li>
+ <li><a href data-toggle="modal" data-container="sogo-mailcow" data-target="#RestartContainer"><span class="glyphicon glyphicon-refresh"></span> <?= $lang['header']['restart_sogo']; ?></a></li>
<?php
+ }
+ ?>
+ <li class="dropdown">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="glyphicon glyphicon-link"></span> Apps <span class="caret"></span></a>
+ <ul class="dropdown-menu" role="menu">
+ <?php
+ foreach ($MAILCOW_APPS as $app):
+ ?>
+ <li title="<?= htmlspecialchars($app['description']); ?>"><a href="<?= htmlspecialchars($app['link']); ?>"><?= htmlspecialchars($app['name']); ?></a></li>
+ <?php
endforeach;
+ $app_links = customize('get', 'app_links');
+ foreach ($app_links as $row) {
+ foreach ($row as $key => $val):
+ ?>
+ <li><a href="<?= htmlspecialchars($val); ?>"><?= htmlspecialchars($key); ?></a></li>
+ <?php
+ endforeach;
+ }
+ ?>
+ </ul>
+ </li>
+ <?php
}
+ if (!isset($_SESSION['dual-login']) && isset($_SESSION['mailcow_cc_username'])):
+ ?>
+ <li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?></b> <span class="glyphicon glyphicon-log-out"></span></a></li>
+ <?php
+ elseif (isset($_SESSION['dual-login'])):
+ ?>
+ <li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?> <span class="text-info">(<?= htmlspecialchars($_SESSION['dual-login']['username']); ?>)</span> </b><span class="glyphicon glyphicon-log-out"></span></a></li>
+ <?php
+ endif;
?>
- </ul>
- </li>
- <?php
- }
- if (!isset($_SESSION['dual-login']) && isset($_SESSION['mailcow_cc_username'])):
- ?>
- <li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?></b> <span class="glyphicon glyphicon-log-out"></span></a></li>
- <?php
- elseif (isset($_SESSION['dual-login'])):
- ?>
- <li class="logged-in-as"><a href="#" onclick="logout.submit()"><b class="username-lia"><?= htmlspecialchars($_SESSION['mailcow_cc_username']); ?> <span class="text-info">(<?= htmlspecialchars($_SESSION['dual-login']['username']); ?>)</span> </b><span class="glyphicon glyphicon-log-out"></span></a></li>
- <?php
- endif;
- ?>
- </ul>
- </div><!--/.nav-collapse -->
- </div><!--/.container-fluid -->
-</nav>
-<form action="/" method="post" id="logout"><input type="hidden" name="logout"></form>
+ </ul>
+ </div><!--/.nav-collapse -->
+ </div><!--/.container-fluid -->
+ </nav>
+ <form action="/" method="post" id="logout"><input type="hidden" name="logout"></form>
diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index 571713be..8ece2544 100644
--- a/data/web/inc/init_db.inc.php
+++ b/data/web/inc/init_db.inc.php
@@ -1,988 +1,1008 @@
<?php
function init_db_schema() {
try {
global $pdo;
- $db_version = "21092018_1902";
+ $db_version = "03102018_1502";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$stmt = $pdo->query("SELECT `version` FROM `versions`");
if ($stmt->fetch(PDO::FETCH_ASSOC)['version'] == $db_version) {
return true;
}
}
$views = array(
"grouped_mail_aliases" => "CREATE VIEW grouped_mail_aliases (username, aliases) AS
SELECT goto, IFNULL(GROUP_CONCAT(address SEPARATOR ' '), '') AS address FROM alias
WHERE address!=goto
AND active = '1'
AND address NOT LIKE '@%'
GROUP BY goto;",
"grouped_sender_acl" => "CREATE VIEW grouped_sender_acl (username, send_as_acl) AS
SELECT logged_in_as, IFNULL(GROUP_CONCAT(send_as SEPARATOR ' '), '') AS send_as_acl FROM sender_acl
WHERE send_as NOT LIKE '@%'
GROUP BY logged_in_as;",
"grouped_domain_alias_address" => "CREATE VIEW grouped_domain_alias_address (username, ad_alias) AS
SELECT username, IFNULL(GROUP_CONCAT(local_part, '@', alias_domain SEPARATOR ' '), '') AS ad_alias FROM mailbox
LEFT OUTER JOIN alias_domain ON target_domain=domain
GROUP BY username;",
"sieve_before" => "CREATE VIEW sieve_before (id, username, script_name, script_data) AS
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
WHERE filter_type = 'prefilter';",
"sieve_after" => "CREATE VIEW sieve_after (id, username, script_name, script_data) AS
SELECT md5(script_data), username, script_name, script_data FROM sieve_filters
WHERE filter_type = 'postfilter';"
);
$tables = array(
"versions" => array(
"cols" => array(
"application" => "VARCHAR(255) NOT NULL",
"version" => "VARCHAR(100) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
),
"keys" => array(
"primary" => array(
"" => array("application")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"admin" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"password" => "VARCHAR(255) NOT NULL",
"superadmin" => "TINYINT(1) NOT NULL DEFAULT '0'",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE NOW(0)",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("username")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"_sogo_static_view" => array(
"cols" => array(
"c_uid" => "VARCHAR(255) NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_password" => "VARCHAR(255) NOT NULL DEFAULT ''",
"c_cn" => "VARCHAR(255)",
"mail" => "VARCHAR(255) NOT NULL",
// TODO -> use TEXT and check if SOGo login breaks on empty aliases
"aliases" => "TEXT NOT NULL",
"ad_aliases" => "VARCHAR(6144) NOT NULL DEFAULT ''",
"home" => "VARCHAR(255)",
"kind" => "VARCHAR(100) NOT NULL DEFAULT ''",
"multiple_bookings" => "INT NOT NULL DEFAULT -1"
),
"keys" => array(
"primary" => array(
"" => array("c_uid")
),
"key" => array(
"domain" => array("domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"relayhosts" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"hostname" => "VARCHAR(255) NOT NULL",
"username" => "VARCHAR(255) NOT NULL",
"password" => "VARCHAR(255) NOT NULL",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("id")
),
"key" => array(
"hostname" => array("hostname")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"alias" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"address" => "VARCHAR(255) NOT NULL",
"goto" => "TEXT NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("id")
),
"unique" => array(
"address" => array("address")
),
"key" => array(
"domain" => array("domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"api" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"api_key" => "VARCHAR(255) NOT NULL",
"allow_from" => "VARCHAR(512) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE NOW(0)",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("username")
),
"fkey" => array(
"fk_username_api" => array(
"col" => "username",
"ref" => "admin.username",
"delete" => "CASCADE",
"update" => "CASCADE"
)
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sender_acl" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"logged_in_as" => "VARCHAR(255) NOT NULL",
"send_as" => "VARCHAR(255) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"domain" => array(
"cols" => array(
"domain" => "VARCHAR(255) NOT NULL",
"description" => "VARCHAR(255)",
"aliases" => "INT(10) NOT NULL DEFAULT '0'",
"mailboxes" => "INT(10) NOT NULL DEFAULT '0'",
"maxquota" => "BIGINT(20) NOT NULL DEFAULT '0'",
"quota" => "BIGINT(20) NOT NULL DEFAULT '102400'",
"relayhost" => "VARCHAR(255) NOT NULL DEFAULT '0'",
"backupmx" => "TINYINT(1) NOT NULL DEFAULT '0'",
"relay_all_recipients" => "TINYINT(1) NOT NULL DEFAULT '0'",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
+ "tls_policy_override" => array(
+ "cols" => array(
+ "id" => "INT NOT NULL AUTO_INCREMENT",
+ "dest" => "VARCHAR(255) NOT NULL",
+ "policy" => "ENUM('none', 'may', 'encrypt', 'dane', 'dane-only', 'fingerprint', 'verify', 'secure') NOT NULL",
+ "parameters" => "VARCHAR(255) DEFAULT ''",
+ "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
+ "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
+ "active" => "TINYINT(1) NOT NULL DEFAULT '1'"
+ ),
+ "keys" => array(
+ "primary" => array(
+ "" => array("id")
+ ),
+ "unique" => array(
+ "dest" => array("dest")
+ ),
+ ),
+ "attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
+ ),
"quarantine" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"qid" => "VARCHAR(30) NOT NULL",
"score" => "FLOAT(8,2)",
"ip" => "VARBINARY(16)",
"action" => "CHAR(20) NOT NULL DEFAULT 'unknown'",
"symbols" => "JSON",
"sender" => "VARCHAR(255) NOT NULL DEFAULT 'unknown'",
"rcpt" => "VARCHAR(255)",
"msg" => "LONGTEXT",
"domain" => "VARCHAR(255)",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"user" => "VARCHAR(255) NOT NULL DEFAULT 'unknown'",
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"mailbox" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"password" => "VARCHAR(255) NOT NULL",
"name" => "VARCHAR(255)",
"maildir" => "VARCHAR(255) NOT NULL",
"quota" => "BIGINT(20) NOT NULL DEFAULT '102400'",
"local_part" => "VARCHAR(255) NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"attributes" => "JSON",
"kind" => "VARCHAR(100) NOT NULL DEFAULT ''",
"multiple_bookings" => "INT NOT NULL DEFAULT -1",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("username")
),
"key" => array(
"domain" => array("domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sieve_filters" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"username" => "VARCHAR(255) NOT NULL",
"script_desc" => "VARCHAR(255) NOT NULL",
"script_name" => "ENUM('active','inactive')",
"script_data" => "TEXT NOT NULL",
"filter_type" => "ENUM('postfilter','prefilter')",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP"
),
"keys" => array(
"primary" => array(
"" => array("id")
),
"key" => array(
"username" => array("username"),
"script_desc" => array("script_desc")
),
"fkey" => array(
"fk_username_sieve_global_before" => array(
"col" => "username",
"ref" => "mailbox.username",
"delete" => "CASCADE",
"update" => "NO ACTION"
)
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"user_acl" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"spam_alias" => "TINYINT(1) NOT NULL DEFAULT '1'",
"tls_policy" => "TINYINT(1) NOT NULL DEFAULT '1'",
"spam_score" => "TINYINT(1) NOT NULL DEFAULT '1'",
"spam_policy" => "TINYINT(1) NOT NULL DEFAULT '1'",
"delimiter_action" => "TINYINT(1) NOT NULL DEFAULT '1'",
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
),
"keys" => array(
"primary" => array(
"" => array("username")
),
"fkey" => array(
"fk_username" => array(
"col" => "username",
"ref" => "mailbox.username",
"delete" => "CASCADE",
"update" => "NO ACTION"
)
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"alias_domain" => array(
"cols" => array(
"alias_domain" => "VARCHAR(255) NOT NULL",
"target_domain" => "VARCHAR(255) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("alias_domain")
),
"key" => array(
"active" => array("active"),
"target_domain" => array("target_domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"spamalias" => array(
"cols" => array(
"address" => "VARCHAR(255) NOT NULL",
"goto" => "TEXT NOT NULL",
"validity" => "INT(11) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("address")
),
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"filterconf" => array(
"cols" => array(
"object" => "VARCHAR(255) NOT NULL DEFAULT ''",
"option" => "VARCHAR(50) NOT NULL DEFAULT ''",
"value" => "VARCHAR(100) NOT NULL DEFAULT ''",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"prefid" => "INT(11) NOT NULL AUTO_INCREMENT"
),
"keys" => array(
"primary" => array(
"" => array("prefid")
),
"key" => array(
"object" => array("object")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"settingsmap" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"desc" => "VARCHAR(255) NOT NULL",
"content" => "LONGTEXT NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"logs" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"task" => "CHAR(32) NOT NULL DEFAULT '000000'",
"type" => "VARCHAR(32) DEFAULT ''",
"msg" => "TEXT",
"call" => "TEXT",
"user" => "VARCHAR(64) NOT NULL",
"role" => "VARCHAR(32) NOT NULL",
"remote" => "VARCHAR(39) NOT NULL",
"time" => "INT(11) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"quota2" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"bytes" => "BIGINT(20) NOT NULL DEFAULT '0'",
"messages" => "BIGINT(20) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("username")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"domain_admins" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"username" => "VARCHAR(255) NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("id")
),
"key" => array(
"username" => array("username")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"da_acl" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
"quarantine" => "TINYINT(1) NOT NULL DEFAULT '1'",
"login_as" => "TINYINT(1) NOT NULL DEFAULT '1'",
"bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'",
"filters" => "TINYINT(1) NOT NULL DEFAULT '1'",
"ratelimit" => "TINYINT(1) NOT NULL DEFAULT '1'",
"spam_policy" => "TINYINT(1) NOT NULL DEFAULT '1'",
),
"keys" => array(
"primary" => array(
"" => array("username")
),
"fkey" => array(
"fk_domain_admin_acl" => array(
"col" => "username",
"ref" => "domain_admins.username",
"delete" => "CASCADE",
"update" => "NO ACTION"
)
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"imapsync" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"user2" => "VARCHAR(255) NOT NULL",
"host1" => "VARCHAR(255) NOT NULL",
"authmech1" => "ENUM('PLAIN','LOGIN','CRAM-MD5') DEFAULT 'PLAIN'",
"regextrans2" => "VARCHAR(255) DEFAULT ''",
"authmd51" => "TINYINT(1) NOT NULL DEFAULT 0",
"domain2" => "VARCHAR(255) NOT NULL DEFAULT ''",
"subfolder2" => "VARCHAR(255) NOT NULL DEFAULT ''",
"user1" => "VARCHAR(255) NOT NULL",
"password1" => "VARCHAR(255) NOT NULL",
"exclude" => "VARCHAR(500) NOT NULL DEFAULT ''",
"maxage" => "SMALLINT NOT NULL DEFAULT '0'",
"mins_interval" => "VARCHAR(50) NOT NULL DEFAULT '0'",
"maxbytespersecond" => "VARCHAR(50) NOT NULL DEFAULT '0'",
"port1" => "SMALLINT NOT NULL",
"enc1" => "ENUM('TLS','SSL','PLAIN') DEFAULT 'TLS'",
"delete2duplicates" => "TINYINT(1) NOT NULL DEFAULT '1'",
"delete1" => "TINYINT(1) NOT NULL DEFAULT '0'",
"delete2" => "TINYINT(1) NOT NULL DEFAULT '0'",
"automap" => "TINYINT(1) NOT NULL DEFAULT '0'",
"skipcrossduplicates" => "TINYINT(1) NOT NULL DEFAULT '0'",
"custom_params" => "VARCHAR(512) NOT NULL DEFAULT ''",
"timeout1" => "SMALLINT NOT NULL DEFAULT '600'",
"timeout2" => "SMALLINT NOT NULL DEFAULT '600'",
"subscribeall" => "TINYINT(1) NOT NULL DEFAULT '1'",
"is_running" => "TINYINT(1) NOT NULL DEFAULT '0'",
"returned_text" => "MEDIUMTEXT",
"last_run" => "TIMESTAMP NULL DEFAULT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"bcc_maps" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"local_dest" => "VARCHAR(255) NOT NULL",
"bcc_dest" => "VARCHAR(255) NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"type" => "ENUM('sender','rcpt')",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("id")
),
"key" => array(
"local_dest" => array("local_dest"),
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"recipient_maps" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"old_dest" => "VARCHAR(255) NOT NULL",
"new_dest" => "VARCHAR(255) NOT NULL",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
"active" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("id")
),
"key" => array(
"local_dest" => array("old_dest"),
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"tfa" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"key_id" => "VARCHAR(255) NOT NULL",
"username" => "VARCHAR(255) NOT NULL",
"authmech" => "ENUM('yubi_otp', 'u2f', 'hotp', 'totp')",
"secret" => "VARCHAR(255) DEFAULT NULL",
"keyHandle" => "VARCHAR(255) DEFAULT NULL",
"publicKey" => "VARCHAR(255) DEFAULT NULL",
"counter" => "INT NOT NULL DEFAULT '0'",
"certificate" => "TEXT",
"active" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"forwarding_hosts" => array(
"cols" => array(
"host" => "VARCHAR(255) NOT NULL",
"source" => "VARCHAR(255) NOT NULL",
"filter_spam" => "TINYINT(1) NOT NULL DEFAULT '0'"
),
"keys" => array(
"primary" => array(
"" => array("host")
),
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_acl" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"c_folder_id" => "INT NOT NULL",
"c_object" => "VARCHAR(255) NOT NULL",
"c_uid" => "VARCHAR(255) NOT NULL",
"c_role" => "VARCHAR(80) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("id")
),
"key" => array(
"sogo_acl_c_folder_id_idx" => array("c_folder_id"),
"sogo_acl_c_uid_idx" => array("c_uid")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_alarms_folder" => array(
"cols" => array(
"id" => "INT NOT NULL AUTO_INCREMENT",
"c_path" => "VARCHAR(255) NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_uid" => "VARCHAR(255) NOT NULL",
"c_recurrence_id" => "INT(11) DEFAULT NULL",
"c_alarm_number" => "INT(11) NOT NULL",
"c_alarm_date" => "INT(11) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_cache_folder" => array(
"cols" => array(
"c_uid" => "VARCHAR(255) NOT NULL",
"c_path" => "VARCHAR(255) NOT NULL",
"c_parent_path" => "VARCHAR(255) DEFAULT NULL",
"c_type" => "TINYINT(3) unsigned NOT NULL",
"c_creationdate" => "INT(11) NOT NULL",
"c_lastmodified" => "INT(11) NOT NULL",
"c_version" => "INT(11) NOT NULL DEFAULT '0'",
"c_deleted" => "TINYINT(4) NOT NULL DEFAULT '0'",
"c_content" => "LONGTEXT"
),
"keys" => array(
"primary" => array(
"" => array("c_uid", "c_path")
),
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_folder_info" => array(
"cols" => array(
"c_folder_id" => "BIGINT(20) unsigned NOT NULL AUTO_INCREMENT",
"c_path" => "VARCHAR(255) NOT NULL",
"c_path1" => "VARCHAR(255) NOT NULL",
"c_path2" => "VARCHAR(255) DEFAULT NULL",
"c_path3" => "VARCHAR(255) DEFAULT NULL",
"c_path4" => "VARCHAR(255) DEFAULT NULL",
"c_foldername" => "VARCHAR(255) NOT NULL",
"c_location" => "VARCHAR(2048) DEFAULT NULL",
"c_quick_location" => "VARCHAR(2048) DEFAULT NULL",
"c_acl_location" => "VARCHAR(2048) DEFAULT NULL",
"c_folder_type" => "VARCHAR(255) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("c_path")
),
"unique" => array(
"c_folder_id" => array("c_folder_id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_quick_appointment" => array(
"cols" => array(
"c_folder_id" => "INT NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_uid" => "VARCHAR(255) NOT NULL",
"c_startdate" => "INT",
"c_enddate" => "INT",
"c_cycleenddate" => "INT",
"c_title" => "VARCHAR(1000) NOT NULL",
"c_participants" => "TEXT",
"c_isallday" => "INT",
"c_iscycle" => "INT",
"c_cycleinfo" => "TEXT",
"c_classification" => "INT NOT NULL",
"c_isopaque" => "INT NOT NULL",
"c_status" => "INT NOT NULL",
"c_priority" => "INT",
"c_location" => "VARCHAR(255)",
"c_orgmail" => "VARCHAR(255)",
"c_partmails" => "TEXT",
"c_partstates" => "TEXT",
"c_category" => "VARCHAR(255)",
"c_sequence" => "INT",
"c_component" => "VARCHAR(10) NOT NULL",
"c_nextalarm" => "INT",
"c_description" => "TEXT"
),
"keys" => array(
"primary" => array(
"" => array("c_folder_id", "c_name")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_quick_contact" => array(
"cols" => array(
"c_folder_id" => "INT NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_givenname" => "VARCHAR(255)",
"c_cn" => "VARCHAR(255)",
"c_sn" => "VARCHAR(255)",
"c_screenname" => "VARCHAR(255)",
"c_l" => "VARCHAR(255)",
"c_mail" => "TEXT",
"c_o" => "VARCHAR(255)",
"c_ou" => "VARCHAR(255)",
"c_telephonenumber" => "VARCHAR(255)",
"c_categories" => "VARCHAR(255)",
"c_component" => "VARCHAR(10) NOT NULL",
"c_hascertificate" => "INT4 DEFAULT 0"
),
"keys" => array(
"primary" => array(
"" => array("c_folder_id", "c_name")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_sessions_folder" => array(
"cols" => array(
"c_id" => "VARCHAR(255) NOT NULL",
"c_value" => "VARCHAR(255) NOT NULL",
"c_creationdate" => "INT(11) NOT NULL",
"c_lastseen" => "INT(11) NOT NULL"
),
"keys" => array(
"primary" => array(
"" => array("c_id")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_store" => array(
"cols" => array(
"c_folder_id" => "INT NOT NULL",
"c_name" => "VARCHAR(255) NOT NULL",
"c_content" => "MEDIUMTEXT NOT NULL",
"c_creationdate" => "INT NOT NULL",
"c_lastmodified" => "INT NOT NULL",
"c_version" => "INT NOT NULL",
"c_deleted" => "INT"
),
"keys" => array(
"primary" => array(
"" => array("c_folder_id", "c_name")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"sogo_user_profile" => array(
"cols" => array(
"c_uid" => "VARCHAR(255) NOT NULL",
"c_defaults" => "LONGTEXT",
"c_settings" => "LONGTEXT"
),
"keys" => array(
"primary" => array(
"" => array("c_uid")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
)
);
foreach ($tables as $table => $properties) {
// Migrate to quarantine
if ($table == 'quarantine') {
$stmt = $pdo->query("SHOW TABLES LIKE 'quarantaine'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$stmt = $pdo->query("SHOW TABLES LIKE 'quarantine'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$pdo->query("RENAME TABLE `quarantaine` TO `quarantine`");
}
}
}
// Migrate tls_enforce_* options
if ($table == 'mailbox') {
$stmt = $pdo->query("SHOW TABLES LIKE 'mailbox'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$stmt = $pdo->query("SHOW COLUMNS FROM `mailbox` LIKE '%tls_enforce%'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$stmt = $pdo->query("SELECT `username`, `tls_enforce_in`, `tls_enforce_out` FROM `mailbox`");
$tls_options_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($tls_options_rows)) {
$tls_options[$row['username']] = array('tls_enforce_in' => $row['tls_enforce_in'], 'tls_enforce_out' => $row['tls_enforce_out']);
}
}
}
}
$stmt = $pdo->query("SHOW TABLES LIKE '" . $table . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$stmt = $pdo->prepare("SELECT CONCAT('ALTER TABLE ', `table_schema`, '.', `table_name`, ' DROP FOREIGN KEY ', `constraint_name`, ';') AS `FKEY_DROP` FROM `information_schema`.`table_constraints`
WHERE `constraint_type` = 'FOREIGN KEY' AND `table_name` = :table;");
$stmt->execute(array(':table' => $table));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($rows)) {
$pdo->query($row['FKEY_DROP']);
}
foreach($properties['cols'] as $column => $type) {
$stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $column . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
if (strpos($type, 'AUTO_INCREMENT') !== false) {
$type = $type . ' PRIMARY KEY ';
// Adding an AUTO_INCREMENT key, need to drop primary keys first, if exists
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = 'PRIMARY'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$pdo->query("ALTER TABLE `" . $table . "` DROP PRIMARY KEY");
}
}
$pdo->query("ALTER TABLE `" . $table . "` ADD `" . $column . "` " . $type);
}
else {
$pdo->query("ALTER TABLE `" . $table . "` MODIFY COLUMN `" . $column . "` " . $type);
}
}
foreach($properties['keys'] as $key_type => $key_content) {
if (strtolower($key_type) == 'primary') {
foreach ($key_content as $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = 'PRIMARY'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
$is_drop = ($num_results != 0) ? "DROP PRIMARY KEY, " : "";
$pdo->query("ALTER TABLE `" . $table . "` " . $is_drop . "ADD PRIMARY KEY (" . $fields . ")");
}
}
if (strtolower($key_type) == 'key') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = '" . $key_name . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
$is_drop = ($num_results != 0) ? "DROP INDEX `" . $key_name . "`, " : "";
$pdo->query("ALTER TABLE `" . $table . "` " . $is_drop . "ADD KEY `" . $key_name . "` (" . $fields . ")");
}
}
if (strtolower($key_type) == 'unique') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = '" . $key_name . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
$is_drop = ($num_results != 0) ? "DROP INDEX `" . $key_name . "`, " : "";
$pdo->query("ALTER TABLE `" . $table . "` " . $is_drop . "ADD UNIQUE KEY `" . $key_name . "` (" . $fields . ")");
}
}
if (strtolower($key_type) == 'fkey') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = '" . $key_name . "'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$pdo->query("ALTER TABLE `" . $table . "` DROP INDEX `" . $key_name . "`");
}
@list($table_ref, $field_ref) = explode('.', $key_values['ref']);
$pdo->query("ALTER TABLE `" . $table . "` ADD FOREIGN KEY `" . $key_name . "` (" . $key_values['col'] . ") REFERENCES `" . $table_ref . "` (`" . $field_ref . "`)
ON DELETE " . $key_values['delete'] . " ON UPDATE " . $key_values['update']);
}
}
}
// Drop all vanished columns
$stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "`");
$cols_in_table = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($row = array_shift($cols_in_table)) {
if (!array_key_exists($row['Field'], $properties['cols'])) {
$pdo->query("ALTER TABLE `" . $table . "` DROP COLUMN `" . $row['Field'] . "`;");
}
}
// Step 1: Get all non-primary keys, that currently exist and those that should exist
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE `Key_name` != 'PRIMARY'");
$keys_in_table = $stmt->fetchAll(PDO::FETCH_ASSOC);
$keys_to_exist = array();
if (isset($properties['keys']['unique']) && is_array($properties['keys']['unique'])) {
foreach ($properties['keys']['unique'] as $key_name => $key_values) {
$keys_to_exist[] = $key_name;
}
}
if (isset($properties['keys']['key']) && is_array($properties['keys']['key'])) {
foreach ($properties['keys']['key'] as $key_name => $key_values) {
$keys_to_exist[] = $key_name;
}
}
// Index for foreign key must exist
if (isset($properties['keys']['fkey']) && is_array($properties['keys']['fkey'])) {
foreach ($properties['keys']['fkey'] as $key_name => $key_values) {
$keys_to_exist[] = $key_name;
}
}
// Step 2: Drop all vanished indexes
while ($row = array_shift($keys_in_table)) {
if (!in_array($row['Key_name'], $keys_to_exist)) {
$pdo->query("ALTER TABLE `" . $table . "` DROP INDEX `" . $row['Key_name'] . "`");
}
}
// Step 3: Drop all vanished primary keys
if (!isset($properties['keys']['primary'])) {
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = 'PRIMARY'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results != 0) {
$pdo->query("ALTER TABLE `" . $table . "` DROP PRIMARY KEY");
}
}
}
else {
// Create table if it is missing
$sql = "CREATE TABLE IF NOT EXISTS `" . $table . "` (";
foreach($properties['cols'] as $column => $type) {
$sql .= "`" . $column . "` " . $type . ",";
}
foreach($properties['keys'] as $key_type => $key_content) {
if (strtolower($key_type) == 'primary') {
foreach ($key_content as $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "PRIMARY KEY (" . $fields . ")" . ",";
}
}
elseif (strtolower($key_type) == 'key') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "KEY `" . $key_name . "` (" . $fields . ")" . ",";
}
}
elseif (strtolower($key_type) == 'unique') {
foreach ($key_content as $key_name => $key_values) {
$fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "UNIQUE KEY `" . $key_name . "` (" . $fields . ")" . ",";
}
}
elseif (strtolower($key_type) == 'fkey') {
foreach ($key_content as $key_name => $key_values) {
@list($table_ref, $field_ref) = explode('.', $key_values['ref']);
$fields = "`" . implode("`, `", $key_values) . "`";
$sql .= "FOREIGN KEY `" . $key_name . "` (" . $key_values['col'] . ") REFERENCES `" . $table_ref . "` (`" . $field_ref . "`)
ON DELETE " . $key_values['delete'] . " ON UPDATE " . $key_values['update'] . ",";
}
}
}
$sql = rtrim($sql, ",");
$sql .= ") " . $properties['attr'];
$pdo->query($sql);
}
// Reset table attributes
$pdo->query("ALTER TABLE `" . $table . "` " . $properties['attr'] . ";");
}
// Recreate SQL views
foreach ($views as $view => $create) {
$pdo->query("DROP VIEW IF EXISTS `" . $view . "`;");
$pdo->query($create);
}
// Create events to clean database
$events[] = 'DROP EVENT IF EXISTS clean_spamalias;
DELIMITER //
CREATE EVENT clean_spamalias
ON SCHEDULE EVERY 1 DAY DO
BEGIN
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
END;
//
DELIMITER ;';
foreach ($events as $event) {
$pdo->exec($event);
}
// Inject admin if not exists
$stmt = $pdo->query("SELECT NULL FROM `admin`");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
if ($num_results == 0) {
$stmt = $pdo->query("INSERT INTO `admin` (`username`, `password`, `superadmin`, `created`, `modified`, `active`)
VALUES ('admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1)");
$stmt = $pdo->query("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
SELECT `username`, 'ALL', NOW(), 1 FROM `admin`
WHERE superadmin='1' AND `username` NOT IN (SELECT `username` FROM `domain_admins`);");
$stmt = $pdo->query("DELETE FROM `admin` WHERE `username` NOT IN (SELECT `username` FROM `domain_admins`);");
}
// Insert new DB schema version
$stmt = $pdo->query("REPLACE INTO `versions` (`application`, `version`) VALUES ('db_schema', '" . $db_version . "');");
// Migrate tls_enforce_* options and add force_pw_update attribute
$stmt = $pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` IS NULL;");
$stmt = $pdo->query("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.force_pw_update', 0) WHERE JSON_EXTRACT(`attributes`, '$.force_pw_update') IS NULL;");
foreach($tls_options as $tls_user => $tls_options) {
$stmt = $pdo->prepare("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.tls_enforce_in', :tls_enforce_in),
`attributes` = JSON_SET(`attributes`, '$.tls_enforce_out', :tls_enforce_out)
WHERE `username` = :username");
$stmt->execute(array(':tls_enforce_in' => $tls_options['tls_enforce_in'], ':tls_enforce_out' => $tls_options['tls_enforce_out'], ':username' => $tls_user));
}
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__),
'msg' => 'db_init_complete'
);
// Fix ACL
$stmt = $pdo->query("INSERT INTO `user_acl` (`username`) SELECT `username` FROM `mailbox` WHERE `kind` = '' AND NOT EXISTS (SELECT `username` FROM `user_acl`);");
$stmt = $pdo->query("INSERT INTO `da_acl` (`username`) SELECT DISTINCT `username` FROM `domain_admins` WHERE `username` != 'admin' AND NOT EXISTS (SELECT `username` FROM `da_acl`);");
}
catch (PDOException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__),
'msg' => array('mysql_error', $e)
);
}
}
?>
diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php
index 209c7184..4cb742af 100644
--- a/data/web/inc/prerequisites.inc.php
+++ b/data/web/inc/prerequisites.inc.php
@@ -1,158 +1,159 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php';
$default_autodiscover_config = $autodiscover_config;
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php';
}
$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
header_remove("X-Powered-By");
// Yubi OTP API
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/Yubico.php';
// Autoload composer
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/vendor/autoload.php';
// Load Sieve
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/sieve/SieveParser.php';
// U2F API + T/HOTP API
$u2f = new u2flib_server\U2F('https://' . $_SERVER['HTTP_HOST']);
$tfa = new RobThree\Auth\TwoFactorAuth($OTP_LABEL);
// Redis
$redis = new Redis();
$redis->connect('redis-mailcow', 6379);
// PDO
// Calculate offset
$now = new DateTime();
$mins = $now->getOffset() / 60;
$sgn = ($mins < 0 ? -1 : 1);
$mins = abs($mins);
$hrs = floor($mins / 60);
$mins -= $hrs * 60;
$offset = sprintf('%+d:%02d', $hrs*$sgn, $mins);
$dsn = $database_type . ":unix_socket=" . $database_sock . ";dbname=" . $database_name;
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET time_zone = '" . $offset . "', group_concat_max_len = 3423543543;",
];
try {
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
}
catch (PDOException $e) {
// Stop when SQL connection fails
?>
<center style='font-family:sans-serif;'>Connection to database failed.<br /><br />The following error was reported:<br/> <?=$e->getMessage();?></center>
<?php
exit;
}
// Stop when dockerapi is not available
if (fsockopen("tcp://dockerapi", 443, $errno, $errstr) === false) {
?>
<center style='font-family:sans-serif;'>Connection to dockerapi container failed.<br /><br />The following error was reported:<br/><?=$errno;?> - <?=$errstr;?></center>
<?php
exit;
}
function pdo_exception_handler($e) {
print_r($e);
if ($e instanceof PDOException) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__),
'msg' => array('mysql_error', $e)
);
return false;
}
else {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__),
'msg' => array('mysql_error', 'unknown error')
);
return false;
}
}
set_exception_handler('pdo_exception_handler');
// TODO: Move function
function get_remote_ip($anonymize = null) {
global $ANONYMIZE_IPS;
if ($anonymize === null) {
$anonymize = $ANONYMIZE_IPS;
}
elseif ($anonymize !== true && $anonymize !== false) {
$anonymize = true;
}
$remote = $_SERVER['REMOTE_ADDR'];
if (filter_var($remote, FILTER_VALIDATE_IP) === false) {
return '0.0.0.0';
}
if ($anonymize) {
if (strlen(inet_pton($remote)) == 4) {
return inet_ntop(inet_pton($remote) & inet_pton("255.255.255.0"));
}
elseif (strlen(inet_pton($remote)) == 16) {
return inet_ntop(inet_pton($remote) & inet_pton('ffff:ffff:ffff:ffff:0000:0000:0000:0000'));
}
}
else {
return $remote;
}
}
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
// Set language
if (!isset($_SESSION['mailcow_locale']) && !isset($_COOKIE['mailcow_locale'])) {
if ($DETECT_LANGUAGE && isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$header_lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
foreach ($AVAILABLE_LANGUAGES as $available_lang) {
if ($header_lang == $available_lang) {
$_SESSION['mailcow_locale'] = strtolower(trim($header_lang));
}
}
}
else {
$_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
}
}
if (isset($_COOKIE['mailcow_locale'])) {
$_SESSION['mailcow_locale'] = $_COOKIE['mailcow_locale'];
}
if (isset($_GET['lang']) && in_array($_GET['lang'], $AVAILABLE_LANGUAGES)) {
$_SESSION['mailcow_locale'] = $_GET['lang'];
setcookie("mailcow_locale", $_GET['lang'], time()+30758400); // one year
}
require_once $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.en.php';
include $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.acl.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.quarantine.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.fwdhost.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.ratelimit.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.relayhost.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.rsettings.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/init_db.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/triggers.inc.php';
init_db_schema();
if (isset($_SESSION['mailcow_cc_role'])) {
acl('to_session');
}
$UI_TEXTS = customize('get', 'ui_texts');
diff --git a/data/web/index.php b/data/web/index.php
index 47339923..07fb4497 100644
--- a/data/web/index.php
+++ b/data/web/index.php
@@ -1,112 +1,112 @@
<?php
require_once 'inc/prerequisites.inc.php';
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'admin') {
- header('Location: /admin.php');
+ header('Location: /admin');
exit();
}
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'domainadmin') {
- header('Location: /mailbox.php');
+ header('Location: /mailbox');
exit();
}
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user') {
- header('Location: /user.php');
+ header('Location: /user');
exit();
}
require_once 'inc/header.inc.php';
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
?>
<div class="container">
<div class="row">
<div class="col-md-offset-3 col-md-6">
<div class="panel panel-default">
<div class="panel-heading"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> <?= $lang['login']['login']; ?></div>
<div class="panel-body">
<div class="text-center mailcow-logo"><img src="<?=($main_logo = customize('get', 'main_logo')) ? $main_logo : '/img/cow_mailcow.svg';?>" alt="mailcow"></div>
<legend><?=$UI_TEXTS['main_name'];?></legend>
<form method="post" autofill="off">
<div class="form-group">
<label class="sr-only" for="login_user"><?= $lang['login']['username']; ?></label>
<div class="input-group">
<div class="input-group-addon"><i class="glyphicon glyphicon-user"></i></div>
<input name="login_user" autocorrect="off" autocapitalize="none" type="text" id="login_user" class="form-control" placeholder="<?= $lang['login']['username']; ?>" required="" autofocus="">
</div>
</div>
<div class="form-group">
<label class="sr-only" for="pass_user"><?= $lang['login']['password']; ?></label>
<div class="input-group">
<div class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></div>
<input name="pass_user" type="password" id="pass_user" class="form-control" placeholder="<?= $lang['login']['password']; ?>" required="">
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success" value="Login"><?= $lang['login']['login']; ?></button>
<div class="btn-group pull-right">
<button type="button" <?=(isset($_SESSION['mailcow_locale']) && count($AVAILABLE_LANGUAGES) === 1) ? 'disabled="true"' : '' ?> class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="lang-sm lang-lbl" lang="<?= $_SESSION['mailcow_locale']; ?>"></span> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<?php
foreach ($AVAILABLE_LANGUAGES as $language):
?>
<li<?= ($_SESSION['mailcow_locale'] == $language) ? ' class="active"' : ''; ?>><a href="?<?= http_build_query(array_merge($_GET, array('lang' => $language))) ?>"><span class="lang-xs lang-lbl-full" lang="<?= $language; ?>"></span></a></li>
<?php
endforeach;
?>
</ul>
</div>
</div>
</form>
<?php
if (isset($_SESSION['ldelay']) && $_SESSION['ldelay'] != '0'):
?>
<p><div class="alert alert-info"><?= sprintf($lang['login']['delayed'], $_SESSION['ldelay']); ?></b></div></p>
<?php
endif;
?>
<legend><?=$UI_TEXTS['apps_name'];?></legend>
<?php
foreach ($MAILCOW_APPS as $app):
?>
<a href="<?= htmlspecialchars($app['link']); ?>" role="button" title="<?= htmlspecialchars($app['description']); ?>" class="btn btn-lg btn-default"><?= htmlspecialchars($app['name']); ?></a>&nbsp;
<?php
endforeach;
$app_links = customize('get', 'app_links');
if (!empty($app_links)) {
foreach ($app_links as $row) {
foreach ($row as $key => $val):
?>
<a href="<?= htmlspecialchars($val); ?>" role="button" class="btn btn-lg btn-default"><?= htmlspecialchars($key); ?></a>&nbsp;
<?php
endforeach;
}
}
?>
</div>
</div>
</div>
<div class="col-md-offset-3 col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<a data-toggle="collapse" href="#collapse1"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> <?= $lang['start']['help']; ?></a>
</div>
<div id="collapse1" class="panel-collapse collapse">
<div class="panel-body">
<?php if ($UI_TEXTS['help_text']): ?>
<p><?=$UI_TEXTS['help_text'];?></p>
<?php else: ?>
<p><span style="border-bottom: 1px dotted #999;"><?=$UI_TEXTS['main_name'];?></span></p>
<p><?= $lang['start']['mailcow_panel_detail']; ?></p>
<p><span style="border-bottom: 1px dotted #999;"><?=$UI_TEXTS['apps_name'];?></span></p>
<p><?= $lang['start']['mailcow_apps_detail']; ?></p>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
</div><!-- /.container -->
<script src="js/index.js"></script>
<?php
require_once 'inc/footer.inc.php';
diff --git a/data/web/js/admin.js b/data/web/js/admin.js
index 17df1cf0..d8f1e0ad 100644
--- a/data/web/js/admin.js
+++ b/data/web/js/admin.js
@@ -1,230 +1,230 @@
// Base64 functions
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(r){var t,e,o,a,h,n,c,d="",C=0;for(r=Base64._utf8_encode(r);C<r.length;)a=(t=r.charCodeAt(C++))>>2,h=(3&t)<<4|(e=r.charCodeAt(C++))>>4,n=(15&e)<<2|(o=r.charCodeAt(C++))>>6,c=63&o,isNaN(e)?n=c=64:isNaN(o)&&(c=64),d=d+this._keyStr.charAt(a)+this._keyStr.charAt(h)+this._keyStr.charAt(n)+this._keyStr.charAt(c);return d},decode:function(r){var t,e,o,a,h,n,c="",d=0;for(r=r.replace(/[^A-Za-z0-9\+\/\=]/g,"");d<r.length;)t=this._keyStr.indexOf(r.charAt(d++))<<2|(a=this._keyStr.indexOf(r.charAt(d++)))>>4,e=(15&a)<<4|(h=this._keyStr.indexOf(r.charAt(d++)))>>2,o=(3&h)<<6|(n=this._keyStr.indexOf(r.charAt(d++))),c+=String.fromCharCode(t),64!=h&&(c+=String.fromCharCode(e)),64!=n&&(c+=String.fromCharCode(o));return c=Base64._utf8_decode(c)},_utf8_encode:function(r){r=r.replace(/\r\n/g,"\n");for(var t="",e=0;e<r.length;e++){var o=r.charCodeAt(e);o<128?t+=String.fromCharCode(o):o>127&&o<2048?(t+=String.fromCharCode(o>>6|192),t+=String.fromCharCode(63&o|128)):(t+=String.fromCharCode(o>>12|224),t+=String.fromCharCode(o>>6&63|128),t+=String.fromCharCode(63&o|128))}return t},_utf8_decode:function(r){for(var t="",e=0,o=c1=c2=0;e<r.length;)(o=r.charCodeAt(e))<128?(t+=String.fromCharCode(o),e++):o>191&&o<224?(c2=r.charCodeAt(e+1),t+=String.fromCharCode((31&o)<<6|63&c2),e+=2):(c2=r.charCodeAt(e+1),c3=r.charCodeAt(e+2),t+=String.fromCharCode((15&o)<<12|(63&c2)<<6|63&c3),e+=3);return t}};
jQuery(function($){
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
var entityMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;","`":"&#x60;","=":"&#x3D;"};
function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
$("#import_dkim_legend").on('click', function(e) {
e.preventDefault();
$('#import_dkim_arrow').toggleClass("animation");
});
$("#duplicate_dkim_legend").on('click', function(e) {
e.preventDefault();
$('#duplicate_dkim_arrow').toggleClass("animation");
});
$("#api_legend").on('click', function(e) {
e.preventDefault();
$('#api_arrow').toggleClass("animation");
});
$("#rspamd_preset_1").on('click', function(e) {
e.preventDefault();
$("form[data-id=rsetting]").find("#adminRspamdSettingsDesc").val(lang.rsettings_preset_1);
$("form[data-id=rsetting]").find("#adminRspamdSettingsContent").val('priority = 10;\nauthenticated = yes;\napply "default" {\n symbols_enabled = ["DKIM_SIGNED", "RATELIMIT_UPDATE", "RATELIMIT_CHECK", "DYN_RL_CHECK", "HISTORY_SAVE", "MILTER_HEADERS", "ARC_SIGNED"];\n}');
});
$("#rspamd_preset_2").on('click', function(e) {
e.preventDefault();
$("form[data-id=rsetting]").find("#adminRspamdSettingsDesc").val(lang.rsettings_preset_2);
$("form[data-id=rsetting]").find("#adminRspamdSettingsContent").val('priority = 10;\nrcpt = "/postmaster@.*/";\nwant_spam = yes;');
});
$("#dkim_missing_keys").on('click', function(e) {
e.preventDefault();
var domains = [];
$('.dkim_missing').each(function() {
domains.push($(this).val());
});
$('#dkim_add_domains').val(domains);
});
function draw_domain_admins() {
ft_domainadmins = FooTable.init('#domainadminstable', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"username","title":lang.username,"style":{"width":"250px"}},
{"name":"selected_domains","title":lang.admin_domains,"breakpoints":"xs sm"},
{"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"}},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/domain-admin/all',
jsonp: false,
error: function () {
console.log('Cannot draw domain admin table');
},
success: function (data) {
return process_table_data(data, 'domainadminstable');
}
}),
"empty": lang.empty,
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
"filtering": {"enabled": true,"delay": 1,"position": "left","connectors": false,"placeholder": lang.filter_table
},
"sorting": {"enabled": true}
});
}
function draw_fwd_hosts() {
ft_forwardinghoststable = FooTable.init('#forwardinghoststable', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
{"name":"host","type":"text","title":lang.host,"style":{"width":"250px"}},
{"name":"source","title":lang.source,"breakpoints":"xs sm"},
{"name":"keep_spam","title":lang.spamfilter, "type": "text","style":{"maxWidth":"80px","width":"80px"}},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/fwdhost/all',
jsonp: false,
error: function () {
console.log('Cannot draw forwarding hosts table');
},
success: function (data) {
return process_table_data(data, 'forwardinghoststable');
}
}),
"empty": lang.empty,
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
"sorting": {"enabled": true}
});
}
function draw_relayhosts() {
ft_relayhoststable = FooTable.init('#relayhoststable', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
{"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
{"name":"hostname","type":"text","title":lang.host,"style":{"width":"250px"}},
{"name":"username","title":lang.username,"breakpoints":"xs sm"},
{"name":"used_by_domains","title":lang.in_use_by,"style":{"width":"110px"}, "type": "text","breakpoints":"xs sm"},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"280px","width":"280px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/relayhost/all',
jsonp: false,
error: function () {
console.log('Cannot draw forwarding hosts table');
},
success: function (data) {
return process_table_data(data, 'relayhoststable');
}
}),
"empty": lang.empty,
"paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
"sorting": {"enabled": true}
});
}
function process_table_data(data, table) {
if (table == 'relayhoststable') {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
'<a href="#" data-toggle="modal" id="miau" data-target="#testRelayhostModal" data-relayhost-id="' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-stats"></span> Test</a>' +
- '<a href="/edit.php?relayhost=' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-rlshost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="rlyhosts" name="multi_select" value="' + item.id + '" />';
});
} else if (table == 'forwardinghoststable') {
$.each(data, function (i, item) {
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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
if (item.keep_spam == "yes") {
item.keep_spam = lang.no;
}
else {
item.keep_spam = lang.yes;
}
item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
});
} else if (table == 'domainadminstable') {
$.each(data, function (i, item) {
item.selected_domains = escapeHtml(item.selected_domains.toString().replace(/,/g, " "));
item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?domainadmin=' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>' +
'</div>';
});
}
return data
};
// Initial table drawings
draw_domain_admins();
draw_fwd_hosts();
draw_relayhosts();
// Relayhost
$('#testRelayhostModal').on('show.bs.modal', function (e) {
$('#test_relayhost_result').text("-");
button = $(e.relatedTarget)
if (button != null) {
$('#relayhost_id').val(button.data('relayhost-id'));
}
})
$('#test_relayhost').on('click', function (e) {
e.preventDefault();
prev = $('#test_relayhost').text();
$(this).prop("disabled",true);
$(this).html('<span class="glyphicon glyphicon-refresh glyphicon-spin"></span> ');
$.ajax({
type: 'GET',
url: 'inc/ajax/relay_check.php',
dataType: 'text',
data: $('#test_relayhost_form').serialize(),
complete: function (data) {
$('#test_relayhost_result').html(data.responseText);
$('#test_relayhost').prop("disabled",false);
$('#test_relayhost').text(prev);
}
});
})
// DKIM private key modal
$('#showDKIMprivKey').on('show.bs.modal', function (e) {
$('#priv_key_pre').text("-");
p_related = $(e.relatedTarget)
if (p_related != null) {
var decoded_key = Base64.decode((p_related.data('priv-key')));
$('#priv_key_pre').text(decoded_key);
}
})
// App links
function add_table_row(table_id) {
var row = $('<tr />');
cols = '<td><input class="input-sm form-control" data-id="app_links" type="text" name="app" required></td>';
cols += '<td><input class="input-sm form-control" data-id="app_links" type="text" name="href" required></td>';
cols += '<td><a href="#" role="button" class="btn btn-xs btn-default" type="button">Remove row</a></td>';
row.append(cols);
table_id.append(row);
}
$('#app_link_table').on('click', 'tr a', function (e) {
e.preventDefault();
$(this).parents('tr').remove();
});
$('#add_app_link_row').click(function() {
add_table_row($('#app_link_table'));
});
});
$(window).load(function(){
initial_width = $("#sidebar-admin").width();
$("#scrollbox").css("width", initial_width);
if (sessionStorage.scrollTop > 70) {
$('#scrollbox').addClass('scrollboxFixed');
}
$(window).bind('scroll', function() {
if ($(window).scrollTop() > 70) {
$('#scrollbox').addClass('scrollboxFixed');
} else {
$('#scrollbox').removeClass('scrollboxFixed');
}
});
});
function resizeScrollbox() {
on_resize_width = $("#sidebar-admin").width();
$("#scrollbox").removeAttr("style");
$("#scrollbox").css("width", on_resize_width);
}
$(window).on('resize', resizeScrollbox);
$('a[data-toggle="tab"]').on('shown.bs.tab', resizeScrollbox);
diff --git a/data/web/js/mailbox.js b/data/web/js/mailbox.js
index 836ec872..8894e995 100644
--- a/data/web/js/mailbox.js
+++ b/data/web/js/mailbox.js
@@ -1,896 +1,965 @@
$(document).ready(function() {
acl_data = JSON.parse(acl);
FooTable.domainFilter = FooTable.Filtering.extend({
construct: function(instance){
this._super(instance);
var domain_list = [];
$.ajax({
dataType: 'json',
url: '/api/v1/get/domain/all',
jsonp: false,
error: function () {
domain_list.push('Cannot read domain list');
},
success: function (data) {
$.each(data, function (i, item) {
domain_list.push(item.domain_name);
});
}
});
this.domains = domain_list;
this.def = 'All Domains';
this.$domain = null;
},
$create: function(){
this._super();
var self = this,
$form_grp = $('<div/>', {'class': 'form-group'})
.append($('<label/>', {'class': 'sr-only', text: 'Domain'}))
.prependTo(self.$form);
self.$domain = $('<select/>', { 'class': 'form-control' })
.on('change', {self: self}, self._onDomainDropdownChanged)
.append($('<option/>', {text: self.def}))
.appendTo($form_grp);
$.each(self.domains, function(i, domain){
self.$domain.append($('<option/>').text(domain));
});
},
_onDomainDropdownChanged: function(e){
var self = e.data.self,
selected = $(this).val();
if (selected !== self.def){
self.addFilter('domain', selected, ['domain']);
} else {
self.removeFilter('domain');
}
self.filter();
},
draw: function(){
this._super();
var domain = this.find('domain');
if (domain instanceof FooTable.Filter){
this.$domain.val(domain.query.val());
} else {
this.$domain.val(this.def);
}
$(this.$domain).closest("select").selectpicker();
}
});
// Auto-fill domain quota when adding new domain
auto_fill_quota = function(domain) {
$.get("/api/v1/get/domain/" + domain, function(data){
var result = $.parseJSON(JSON.stringify(data));
max_new_mailbox_quota = ( result.max_new_mailbox_quota / 1048576);
if (max_new_mailbox_quota != '0') {
$("#quotaBadge").html('max. ' + max_new_mailbox_quota + ' MiB');
$('#addInputQuota').attr({"disabled": false, "value": "", "type": "number", "max": max_new_mailbox_quota});
$('#addInputQuota').val(max_new_mailbox_quota);
}
else {
$("#quotaBadge").html('max. ' + max_new_mailbox_quota + ' MiB');
$('#addInputQuota').attr({"disabled": true, "value": "", "type": "text", "value": "n/a"});
$('#addInputQuota').val(max_new_mailbox_quota);
}
});
}
$('#addSelectDomain').on('change', function() {
auto_fill_quota($('#addSelectDomain').val());
});
auto_fill_quota($('#addSelectDomain').val());
$(".generate_password").click(function( event ) {
event.preventDefault();
$('[data-hibp]').trigger('input');
var random_passwd = Math.random().toString(36).slice(-8)
$(this).closest("form").find("input[name='password']").prop('type', 'text');
$(this).closest("form").find("input[name='password2']").prop('type', 'text');
$(this).closest("form").find("input[name='password']").val(random_passwd);
$(this).closest("form").find("input[name='password2']").val(random_passwd);
});
$(".goto_checkbox").click(function( event ) {
$("form[data-id='add_alias'] .goto_checkbox").not(this).prop('checked', false);
if ($("form[data-id='add_alias'] .goto_checkbox:checked").length > 0) {
$('#textarea_alias_goto').prop('disabled', true);
}
else {
$("#textarea_alias_goto").removeAttr('disabled');
}
});
$('#addAliasModal').on('show.bs.modal', function(e) {
if ($("form[data-id='add_alias'] .goto_checkbox:checked").length > 0) {
$('#textarea_alias_goto').prop('disabled', true);
}
else {
$("#textarea_alias_goto").removeAttr('disabled');
}
});
// Log modal
$('#syncjobLogModal').on('show.bs.modal', function(e) {
var syncjob_id = $(e.relatedTarget).data('syncjob-id');
$.ajax({
url: '/inc/ajax/syncjob_logs.php',
data: { id: syncjob_id },
dataType: 'text',
success: function(data){
$(e.currentTarget).find('#logText').text(data);
},
error: function(xhr, status, error) {
$(e.currentTarget).find('#logText').text(xhr.responseText);
}
});
});
// Log modal
$('#dnsInfoModal').on('show.bs.modal', function(e) {
var domain = $(e.relatedTarget).data('domain');
$('.dns-modal-body').html('<center><span style="font-size:18pt;margin:50px" class="glyphicon glyphicon-refresh glyphicon-spin"></span></center>');
$.ajax({
url: '/inc/ajax/dns_diagnostics.php',
data: { domain: domain },
dataType: 'text',
success: function(data){
$('.dns-modal-body').html(data);
},
error: function(xhr, status, error) {
$('.dns-modal-body').html(xhr.responseText);
}
});
});
// Sieve data modal
$('#sieveDataModal').on('show.bs.modal', function(e) {
var sieveScript = $(e.relatedTarget).data('sieve-script');
$(e.currentTarget).find('#sieveDataText').html('<pre style="font-size:14px;line-height:1.1">' + sieveScript + '</pre>');
});
// Set line numbers for textarea
$("#script_data").numberedtextarea({allowTabChar: true});
// Disable submit button on script change
$('#script_data').on('keyup', function() {
$('#add_filter_btns > #add_item').attr({"disabled": true});
$('#validation_msg').html('-');
});
// Validate script data
$("#validate_sieve").click(function( event ) {
event.preventDefault();
var script = $('#script_data').val();
$.ajax({
dataType: 'jsonp',
url: "/inc/ajax/sieve_validation.php",
type: "get",
data: { script: script },
complete: function(data) {
var response = (data.responseText);
response_obj = JSON.parse(response);
if (response_obj.type == "success") {
$('#add_filter_btns > #add_item').attr({"disabled": false});
}
mailcow_alert_box(response_obj.msg, response_obj.type);
},
});
});
// $(document).on('DOMNodeInserted', '#prefilter_table', function () {
// $("#active-script").closest('td').css('background-color','#b0f0a0');
// $("#inactive-script").closest('td').css('background-color','#b0f0a0');
// });
});
jQuery(function($){
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
var entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
return entityMap[s];
});
}
if (localStorage.getItem("current_page") === null) {
var current_page = {};
} else {
var current_page = JSON.parse(localStorage.getItem('current_page'));
}
// http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
function validateEmail(email) {
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
// Calculation human readable file sizes
function humanFileSize(bytes) {
if(Math.abs(bytes) < 1024) {
return bytes + ' B';
}
var units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
var u = -1;
do {
bytes /= 1024;
++u;
} while(Math.abs(bytes) >= 1024 && u < units.length - 1);
return bytes.toFixed(1)+' '+units[u];
}
function unix_time_format(tm) {
var date = new Date(tm ? tm * 1000 : 0);
return date.toLocaleString();
}
$(".refresh_table").on('click', function(e) {
e.preventDefault();
var table_name = $(this).data('table');
$('#' + table_name).find("tr.footable-empty").remove();
draw_table = $(this).data('draw');
eval(draw_table + '()');
});
function table_mailbox_ready(ft, name) {
if(is_dual) {
$('.login_as').data("toggle", "tooltip")
.attr("disabled", true)
.removeAttr("href")
.attr("title", "Dual login cannot be used twice")
.tooltip();
}
heading = ft.$el.parents('.tab-pane').find('.panel-heading')
var ft_paging = ft.use(FooTable.Paging)
$(heading).children('.table-lines').text(function(){
return ft_paging.totalRows;
})
if (current_page[name]) {
ft_paging.goto(parseInt(current_page[name]))
}
}
function paging_mailbox_after(ft, name) {
var ft_paging = ft.use(FooTable.Paging)
current_page[name] = ft_paging.current;
localStorage.setItem('current_page', JSON.stringify(current_page));
}
function draw_domain_table() {
ft_domain_table = FooTable.init('#domain_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"domain_name","title":lang.domain,"style":{"width":"250px"}},
{"name":"aliases","title":lang.aliases,"breakpoints":"xs sm"},
{"name":"mailboxes","title":lang.mailboxes},
{"name":"quota","style":{"whiteSpace":"nowrap"},"title":lang.domain_quota,"formatter": function(value){
res = value.split("/");
return humanFileSize(res[0]) + " / " + humanFileSize(res[1]);
},
"sortValue": function(value){
res = value.split("/");
return Number(res[0]);
},
},
{"name":"max_quota_for_mbox","title":lang.mailbox_quota,"breakpoints":"xs sm","style":{"width":"125px"}},
{"name":"rl","title":"RL","breakpoints":"xs sm md","style":{"maxWidth":"100px","width":"100px"}},
{"name":"backupmx","filterable": false,"style":{"maxWidth":"120px","width":"120px"},"title":lang.backup_mx,"breakpoints":"xs sm md"},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"240px","width":"240px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
],
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/domain/all',
jsonp: false,
error: function (data) {
console.log('Cannot draw domain table');
},
success: function (data) {
$.each(data, function (i, item) {
item.aliases = item.aliases_in_domain + " / " + item.max_num_aliases_for_domain;
item.mailboxes = item.mboxes_in_domain + " / " + item.max_num_mboxes_for_domain;
item.quota = item.quota_used_in_domain + "/" + item.max_quota_for_domain;
if (!item.rl) {
item.rl = '∞';
} else {
item.rl = $.map(item.rl, function(e){
return e;
}).join('/1');
}
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
item.chkbox = '<input type="checkbox" data-id="domain" name="multi_select" value="' + encodeURIComponent(item.domain_name) + '" />';
item.action = '<div class="btn-group">';
if (role == "admin") {
- item.action += '<a href="/edit.php?domain=' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>';
}
else {
- item.action += '<a href="/edit.php?domain=' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>';
+ item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>';
}
item.action += '<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><span class="glyphicon glyphicon-question-sign"></span> DNS</a></div>';
});
}
}),
"empty": lang.empty,
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
"placeholder": lang.filter_table
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'domain_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'domain_table');
}
}
});
}
function draw_mailbox_table() {
ft_mailbox_table = FooTable.init('#mailbox_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"username","style":{"word-break":"break-all","min-width":"120px"},"title":lang.username},
{"name":"name","title":lang.fname,"style":{"word-break":"break-all","min-width":"120px"},"breakpoints":"xs sm"},
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
{"name":"quota","style":{"whiteSpace":"nowrap"},"title":lang.domain_quota,"formatter": function(value){
res = value.split("/");
return humanFileSize(res[0]) + " / " + humanFileSize(res[1]);
},
"sortValue": function(value){
res = value.split("/");
return Number(res[0]);
},
},
{"name":"spam_aliases","filterable": false,"title":lang.spam_aliases,"breakpoints":"xs sm md"},
+ {"name":"tls_enforce_in","filterable": false,"title":lang.tls_enforce_in,"breakpoints":"all"},
+ {"name":"tls_enforce_out","filterable": false,"title":lang.tls_enforce_out,"breakpoints":"all"},
{"name":"in_use","filterable": false,"type":"html","title":lang.in_use,"sortValue": function(value){
return Number($(value).find(".progress-bar").attr('aria-valuenow'));
},
},
{"name":"messages","filterable": false,"title":lang.msg_num,"breakpoints":"xs sm md"},
{"name":"rl","title":"RL","breakpoints":"xs sm md","style":{"width":"125px"}},
{"name":"active","filterable": false,"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"min-width":"250px","text-align":"right"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/mailbox/all',
jsonp: false,
error: function () {
console.log('Cannot draw mailbox table');
},
success: function (data) {
$.each(data, function (i, item) {
item.quota = item.quota_used + "/" + item.quota;
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
if (!item.rl) {
item.rl = '∞';
} else {
item.rl = $.map(item.rl, function(e){
return e;
}).join('/1');
}
item.chkbox = '<input type="checkbox" data-id="mailbox" name="multi_select" value="' + encodeURIComponent(item.username) + '" />';
+ item.tls_enforce_in = '<span class="text-' + (item.attributes.tls_enforce_in == 1 ? 'success' : 'danger') + ' glyphicon glyphicon-lock"></span>';
+ item.tls_enforce_out = '<span class="text-' + (item.attributes.tls_enforce_out == 1 ? 'success' : 'danger') + ' glyphicon glyphicon-lock"></span>';
if (acl_data.login_as === 1) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?mailbox=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>' +
'</div>';
}
else {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?mailbox=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
}
item.in_use = '<div class="progress">' +
'<div class="progress-bar progress-bar-' + item.percent_class + ' role="progressbar" aria-valuenow="' + item.percent_in_use + '" aria-valuemin="0" aria-valuemax="100" ' +
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>';
item.username = escapeHtml(item.username);
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
+ //"container": "#tab-mailboxes.panel",
"placeholder": lang.filter_table
},
"components": {
"filtering": FooTable.domainFilter
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'mailbox_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'mailbox_table');
}
}
});
}
function draw_resource_table() {
ft_resource_table = FooTable.init('#resource_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"description","title":lang.description,"style":{"width":"250px"}},
{"name":"kind","title":lang.kind},
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
{"name":"multiple_bookings","filterable": false,"style":{"maxWidth":"150px","width":"140px"},"title":lang.multiple_bookings,"breakpoints":"xs sm"},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/resource/all',
jsonp: false,
error: function () {
console.log('Cannot draw resource table');
},
success: function (data) {
$.each(data, function (i, item) {
if (item.multiple_bookings == '0') {
item.multiple_bookings = '<span id="active-script" class="label label-success">' + lang.booking_0_short + '</span>';
} else if (item.multiple_bookings == '-1') {
item.multiple_bookings = '<span id="active-script" class="label label-warning">' + lang.booking_lt0_short + '</span>';
} else {
item.multiple_bookings = '<span id="active-script" class="label label-danger">' + lang.booking_custom_short + ' (' + item.multiple_bookings + ')</span>';
}
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?resource=' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
item.name = escapeHtml(item.name);
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
"placeholder": lang.filter_table
},
"components": {
"filtering": FooTable.domainFilter
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'resource_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'resource_table');
}
}
});
}
function draw_bcc_table() {
ft_bcc_table = FooTable.init('#bcc_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
{"name":"type","title":lang.bcc_type},
{"name":"local_dest","title":lang.bcc_local_dest},
{"name":"bcc_dest","title":lang.bcc_destinations},
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/bcc/all',
jsonp: false,
error: function () {
console.log('Cannot draw bcc table');
},
success: function (data) {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?bcc=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/bcc/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="bcc" name="multi_select" value="' + item.id + '" />';
item.local_dest = escapeHtml(item.local_dest);
item.bcc_dest = escapeHtml(item.bcc_dest);
if (item.type == 'sender') {
item.type = '<span id="active-script" class="label label-success">Sender</span>';
} else {
item.type = '<span id="inactive-script" class="label label-warning">Recipient</span>';
}
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
"placeholder": lang.filter_table
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'bcc_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'bcc_table');
}
}
});
}
function draw_recipient_map_table() {
ft_recipient_map_table = FooTable.init('#recipient_map_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
{"name":"recipient_map_old","title":lang.recipient_map_old},
{"name":"recipient_map_new","title":lang.recipient_map_new},
{"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":(role == "admin" ? lang.action : ""),"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/recipient_map/all',
jsonp: false,
error: function () {
console.log('Cannot draw recipient map table');
},
success: function (data) {
if (role == "admin") {
$.each(data, function (i, item) {
item.recipient_map_old = escapeHtml(item.recipient_map_old);
item.recipient_map_new = escapeHtml(item.recipient_map_new);
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?recipient_map=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/recipient_map/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
});
}
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
"placeholder": lang.filter_table
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'recipient_map_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'recipient_map_table');
}
}
});
}
+ function draw_tls_policy_table() {
+ ft_tls_policy_table = FooTable.init('#tls_policy_table', {
+ "columns": [
+ {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
+ {"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
+ {"name":"dest","title":lang.tls_map_dest},
+ {"name":"policy","title":lang.tls_map_policy},
+ {"name":"parameters","title":lang.tls_map_parameters},
+ {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
+ {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":(role == "admin" ? lang.action : ""),"breakpoints":"xs sm"}
+ ],
+ "empty": lang.empty,
+ "rows": $.ajax({
+ dataType: 'json',
+ url: '/api/v1/get/tls-policy-map/all',
+ jsonp: false,
+ error: function () {
+ console.log('Cannot draw tls policy map table');
+ },
+ success: function (data) {
+ if (role == "admin") {
+ $.each(data, function (i, item) {
+ item.dest = escapeHtml(item.dest);
+ item.policy = '<b>' + escapeHtml(item.policy) + '</b>';
+ if (item.parameters == '') {
+ item.parameters = '<code>-</code>';
+ } else {
+ item.parameters = '<code>' + escapeHtml(item.parameters) + '</code>';
+ }
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
+ '</div>';
+ item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
+ });
+ }
+ }
+ }),
+ "paging": {
+ "enabled": true,
+ "limit": 5,
+ "size": pagination_size
+ },
+ "filtering": {
+ "enabled": true,
+ "delay": 100,
+ "position": "left",
+ "connectors": false,
+ "placeholder": lang.filter_table
+ },
+ "sorting": {
+ "enabled": true
+ },
+ "on": {
+ "ready.ft.table": function(e, ft){
+ table_mailbox_ready(ft, 'tls_policy_table');
+ },
+ "after.ft.paging": function(e, ft){
+ paging_mailbox_after(ft, 'tls_policy_table');
+ }
+ }
+ });
+ }
function draw_alias_table() {
ft_alias_table = FooTable.init('#alias_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
{"sorted": true,"name":"address","title":lang.alias,"style":{"width":"250px"}},
{"name":"goto","title":lang.target_address},
{"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
{"name":"active","filterable": false,"style":{"maxWidth":"50px","width":"70px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/alias/all',
jsonp: false,
error: function () {
console.log('Cannot draw alias table');
},
success: function (data) {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?alias=' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.goto = escapeHtml(item.goto.replace(/,/g, " "));
if (item.is_catch_all == 1) {
item.address = '<div class="label label-default">Catch-All</div> ' + escapeHtml(item.address);
}
else {
item.address = escapeHtml(item.address);
}
if (item.goto == "null@localhost") {
item.goto = '⤷ <span style="font-size:12px" class="glyphicon glyphicon-trash" aria-hidden="true"></span>';
}
else if (item.goto == "spam@localhost") {
item.goto = '<span class="label label-danger">Learn as spam</span>';
}
else if (item.goto == "ham@localhost") {
item.goto = '<span class="label label-success">Learn as ham</span>';
}
if (item.in_primary_domain !== "") {
item.domain = "↳ " + item.domain + " (" + item.in_primary_domain + ")";
}
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
"placeholder": lang.filter_table
},
"components": {
"filtering": FooTable.domainFilter
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'alias_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'alias_table');
}
}
});
}
function draw_aliasdomain_table() {
ft_aliasdomain_table = FooTable.init('#aliasdomain_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"alias_domain","title":lang.alias,"style":{"width":"250px"}},
{"name":"target_domain","title":lang.target_domain},
{"name":"active","filterable": false,"style":{"maxWidth":"50px","width":"70px"},"title":lang.active},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/alias-domain/all',
jsonp: false,
error: function () {
console.log('Cannot draw alias domain table');
},
success: function (data) {
$.each(data, function (i, item) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?aliasdomain=' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'<a href="#dnsInfoModal" class="btn btn-xs btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><span class="glyphicon glyphicon-question-sign"></span> DNS</a></div>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="alias-domain" name="multi_select" value="' + encodeURIComponent(item.alias_domain) + '" />';
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
"placeholder": lang.filter_table
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'aliasdomain_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'aliasdomain_table');
}
}
});
}
function draw_sync_job_table() {
ft_syncjob_table = FooTable.init('#sync_job_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
{"name":"user2","title":lang.owner},
{"name":"server_w_port","title":"Server","breakpoints":"xs","style":{"word-break":"break-all"}},
{"name":"exclude","title":lang.excludes,"breakpoints":"all"},
{"name":"mins_interval","title":lang.mins_interval,"breakpoints":"all"},
{"name":"last_run","title":lang.last_run,"breakpoints":"sm"},
{"name":"log","title":"Log"},
{"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active},
{"name":"is_running","filterable": false,"style":{"maxWidth":"120px","width":"100px"},"title":lang.status},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/syncjobs/all/no_log',
jsonp: false,
error: function () {
console.log('Cannot draw sync job table');
},
success: function (data) {
$.each(data, function (i, item) {
item.log = '<a href="#syncjobLogModal" data-toggle="modal" data-syncjob-id="' + encodeURIComponent(item.id) + '">Open logs</a>'
item.user2 = escapeHtml(item.user2);
if (!item.exclude > 0) {
item.exclude = '-';
} else {
item.exclude = '<code>' + item.exclude + '</code>';
}
item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1;
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?syncjob=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
if (item.is_running == 1) {
item.is_running = '<span id="active-script" class="label label-success">' + lang.running + '</span>';
} else {
item.is_running = '<span id="inactive-script" class="label label-warning">' + lang.waiting + '</span>';
}
if (!item.last_run > 0) {
item.last_run = lang.waiting;
}
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
"placeholder": lang.filter_table
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'sync_job_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'sync_job_table');
}
}
});
}
function draw_filter_table() {
ft_filter_table = FooTable.init('#filter_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
{"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
{"name":"active","style":{"maxWidth":"80px","width":"80px"},"title":lang.active},
{"name":"filter_type","style":{"maxWidth":"80px","width":"80px"},"title":"Type"},
{"sorted": true,"name":"username","title":lang.owner,"style":{"maxWidth":"550px","width":"350px"}},
{"name":"script_desc","title":lang.description,"breakpoints":"xs"},
{"name":"script_data","title":"Script","breakpoints":"all"},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/filters/all',
jsonp: false,
error: function () {
console.log('Cannot draw filter table');
},
success: function (data) {
$.each(data, function (i, item) {
if (item.active_int == 1) {
item.active = '<span id="active-script" class="label label-success">' + lang.active + '</span>';
} else {
item.active = '<span id="inactive-script" class="label label-warning">' + lang.inactive + '</span>';
}
item.script_data = '<pre style="margin:0px">' + escapeHtml(item.script_data) + '</pre>'
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">' +
- '<a href="/edit.php?filter=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/filter/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="filter_item" name="multi_select" value="' + item.id + '" />'
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"filtering": {
"enabled": true,
"delay": 100,
"position": "left",
"connectors": false,
"placeholder": lang.filter_table
},
"sorting": {
"enabled": true
},
"on": {
"ready.ft.table": function(e, ft){
table_mailbox_ready(ft, 'filter_table');
},
"after.ft.paging": function(e, ft){
paging_mailbox_after(ft, 'filter_table');
}
}
});
};
draw_domain_table();
draw_mailbox_table();
draw_resource_table();
draw_alias_table();
draw_aliasdomain_table();
draw_sync_job_table();
draw_filter_table();
draw_bcc_table();
draw_recipient_map_table();
+ draw_tls_policy_table();
});
diff --git a/data/web/js/user.js b/data/web/js/user.js
index 5649d6c6..2c960e82 100644
--- a/data/web/js/user.js
+++ b/data/web/js/user.js
@@ -1,262 +1,262 @@
$(document).ready(function() {
$('#syncjobLogModal').on('show.bs.modal', function(e) {
var syncjob_id = $(e.relatedTarget).data('syncjob-id');
$.ajax({
url: '/inc/ajax/syncjob_logs.php',
data: { id: syncjob_id },
dataType: 'text',
success: function(data){
$(e.currentTarget).find('#logText').text(data);
},
error: function(xhr, status, error) {
$(e.currentTarget).find('#logText').text(xhr.responseText);
}
});
});
});
jQuery(function($){
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
var entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
return entityMap[s];
});
}
// http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
function validateEmail(email) {
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
function unix_time_format(tm) {
var date = new Date(tm ? tm * 1000 : 0);
return date.toLocaleString();
}
acl_data = JSON.parse(acl);
var last_login = $('.last_login_date').data('time');
$('.last_login_date').text(unix_time_format(last_login));
function draw_tla_table() {
ft_tla_table = FooTable.init('#tla_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"address","title":lang.alias},
{"name":"validity","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.alias_valid_until,"style":{"width":"170px"}},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/time_limited_aliases',
jsonp: false,
error: function () {
console.log('Cannot draw tla table');
},
success: function (data) {
$.each(data, function (i, item) {
if (acl_data.spam_alias === 1) {
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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
item.address = escapeHtml(item.address);
}
else {
item.chkbox = '<input type="checkbox" disabled />';
item.action = '<span>-</span>';
}
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"sorting": {
"enabled": true
}
});
}
function draw_sync_job_table() {
ft_syncjob_table = FooTable.init('#sync_job_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
{"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
{"name":"server_w_port","title":"Server"},
{"name":"enc1","title":lang.encryption,"breakpoints":"xs sm"},
{"name":"user1","title":lang.username},
{"name":"exclude","title":lang.excludes,"breakpoints":"all"},
{"name":"mins_interval","title":lang.interval + " (min)","breakpoints":"all"},
{"name":"last_run","title":lang.last_run,"breakpoints":"all"},
{"name":"log","title":"Log"},
{"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active},
{"name":"is_running","filterable": false,"style":{"maxWidth":"120px","width":"100px"},"title":lang.status},
{"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/syncjobs/' + encodeURIComponent(mailcow_cc_username) + '/no_log',
jsonp: false,
error: function () {
console.log('Cannot draw sync job table');
},
success: function (data) {
$.each(data, function (i, item) {
item.user1 = escapeHtml(item.user1);
item.log = '<a href="#syncjobLogModal" data-toggle="modal" data-syncjob-id="' + item.id + '">Open logs</a>'
if (!item.exclude > 0) {
item.exclude = '-';
} else {
item.exclude = '<code>' + escapeHtml(item.exclude) + '</code>';
}
item.server_w_port = escapeHtml(item.user1 + '@' + item.host1 + ':' + item.port1);
if (acl_data.syncjobs === 1) {
item.action = '<div class="btn-group">' +
- '<a href="/edit.php?syncjob=' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + lang.edit + '</a>' +
+ '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> ' + 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"><span class="glyphicon glyphicon-trash"></span> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
}
else {
item.action = '<span>-</span>';
item.chkbox = '<input type="checkbox" disabled />';
}
if (item.is_running == 1) {
item.is_running = '<span id="active-script" class="label label-success">' + lang.running + '</span>';
} else {
item.is_running = '<span id="inactive-script" class="label label-warning">' + lang.waiting + '</span>';
}
if (!item.last_run > 0) {
item.last_run = lang.waiting;
}
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"sorting": {
"enabled": true
}
});
}
function draw_wl_policy_mailbox_table() {
ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_mailbox_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
{"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
{"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
{"name":"object","title":"Scope"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/policy_wl_mailbox',
jsonp: false,
error: function () {
console.log('Cannot draw mailbox policy wl table');
},
success: function (data) {
$.each(data, function (i, item) {
if (validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_wl_mailbox" name="multi_select" value="' + item.prefid + '" />';
}
else {
item.chkbox = '<input type="checkbox" disabled title="' + lang.spamfilter_table_domain_policy + '" />';
}
if (acl_data.spam_policy === 0) {
item.chkbox = '<input type="checkbox" disabled />';
}
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"sorting": {
"enabled": true
}
});
}
function draw_bl_policy_mailbox_table() {
ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_mailbox_table', {
"columns": [
{"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
{"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
{"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
{"name":"object","title":"Scope"}
],
"empty": lang.empty,
"rows": $.ajax({
dataType: 'json',
url: '/api/v1/get/policy_bl_mailbox',
jsonp: false,
error: function () {
console.log('Cannot draw mailbox policy bl table');
},
success: function (data) {
$.each(data, function (i, item) {
if (validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_bl_mailbox" name="multi_select" value="' + item.prefid + '" />';
}
else {
item.chkbox = '<input type="checkbox" disabled tooltip="' + lang.spamfilter_table_domain_policy + '" />';
}
if (acl_data.spam_policy === 0) {
item.chkbox = '<input type="checkbox" disabled />';
}
});
}
}),
"paging": {
"enabled": true,
"limit": 5,
"size": pagination_size
},
"sorting": {
"enabled": true
}
});
}
draw_sync_job_table();
draw_tla_table();
draw_wl_policy_mailbox_table();
draw_bl_policy_mailbox_table();
// Sieve data modal
$('#userFilterModal').on('show.bs.modal', function(e) {
$('#user_sieve_filter').text(lang.loading);
$.ajax({
dataType: 'json',
url: '/api/v1/get/active-user-sieve/' + encodeURIComponent(mailcow_cc_username),
jsonp: false,
error: function () {
console.log('Cannot get active sieve script');
},
complete: function (data) {
if (data.responseText == '{}') {
$('#user_sieve_filter').text(lang.no_active_filter);
} else {
$('#user_sieve_filter').text(JSON.parse(data.responseText));
}
}
})
});
$('#userFilterModal').on('hidden.bs.modal', function () {
$('#user_sieve_filter').text(lang.loading);
});
});
\ No newline at end of file
diff --git a/data/web/json_api.php b/data/web/json_api.php
index adeb162e..d1f6a979 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -1,1081 +1,1115 @@
<?php
/*
edit/alias => POST data:
{
address: {a, b, c}, (where a, b, c represent alias addresses)
active: 1 (0 or 1)
}
delete/alias => POST data:
{
address: {a, b, c}, (where a, b, c represent alias addresses)
}
*/
header('Content-Type: application/json');
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
error_reporting(0);
function api_log($_data) {
global $redis;
$data_var = array();
foreach ($_data as $data => &$value) {
if ($data == 'csrf_token') {
continue;
}
if ($value = json_decode($value, true)) {
unset($value["csrf_token"]);
foreach ($value as $key => &$val) {
if(preg_match("/pass/i", $key)) {
$val = '*';
}
}
$value = json_encode($value);
}
$data_var[] = $data . "='" . $value . "'";
}
try {
$log_line = array(
'time' => time(),
'uri' => $_SERVER['REQUEST_URI'],
'method' => $_SERVER['REQUEST_METHOD'],
'remote' => get_remote_ip(),
'data' => implode(', ', $data_var)
);
$redis->lPush('API_LOG', json_encode($log_line));
}
catch (RedisException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'msg' => 'Redis: '.$e
);
return false;
}
}
api_log($_POST);
if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_username'])) {
if (isset($_GET['query'])) {
$query = explode('/', $_GET['query']);
$action = (isset($query[0])) ? $query[0] : null;
$category = (isset($query[1])) ? $query[1] : null;
$object = (isset($query[2])) ? $query[2] : null;
$extra = (isset($query[3])) ? $query[3] : null;
$request_incomplete = json_encode(array(
'type' => 'error',
'msg' => 'Cannot find attributes in post data'
));
switch ($action) {
case "add":
function process_add_return($return) {
$generic_failure = json_encode(array(
'type' => 'error',
'msg' => 'Cannot add item'
));
$generic_success = json_encode(array(
'type' => 'success',
'msg' => 'Task completed'
));
if ($return === false) {
echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
}
else {
echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
}
}
if (!isset($_POST['attr'])) {
echo $request_incomplete;
exit;
}
else {
$attr = (array)json_decode($_POST['attr'], true);
unset($attr['csrf_token']);
}
switch ($category) {
case "time_limited_alias":
process_add_return(mailbox('add', 'time_limited_alias', $attr));
break;
case "relayhost":
process_add_return(relayhost('add', $attr));
break;
case "rsetting":
process_add_return(rsettings('add', $attr));
break;
case "mailbox":
process_add_return(mailbox('add', 'mailbox', $attr));
break;
case "domain":
process_add_return(mailbox('add', 'domain', $attr));
break;
case "resource":
process_add_return(mailbox('add', 'resource', $attr));
break;
case "alias":
process_add_return(mailbox('add', 'alias', $attr));
break;
case "filter":
process_add_return(mailbox('add', 'filter', $attr));
break;
case "domain-policy":
process_add_return(policy('add', 'domain', $attr));
break;
case "mailbox-policy":
process_add_return(policy('add', 'mailbox', $attr));
break;
case "alias-domain":
process_add_return(mailbox('add', 'alias_domain', $attr));
break;
case "fwdhost":
process_add_return(fwdhost('add', $attr));
break;
case "dkim":
process_add_return(dkim('add', $attr));
break;
case "dkim_duplicate":
process_add_return(dkim('duplicate', $attr));
break;
case "dkim_import":
process_add_return(dkim('import', $attr));
break;
case "domain-admin":
process_add_return(domain_admin('add', $attr));
break;
case "syncjob":
process_add_return(mailbox('add', 'syncjob', $attr));
break;
case "bcc":
process_add_return(bcc('add', $attr));
break;
case "recipient_map":
process_add_return(recipient_map('add', $attr));
break;
+ case "tls-policy-map":
+ process_add_return(tls_policy_maps('add', $attr));
+ break;
}
break;
case "get":
function process_get_return($data) {
echo (!isset($data) || empty($data)) ? '{}' : json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
switch ($category) {
case "rspamd":
switch ($object) {
case "actions":
$curl = curl_init();
curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, '/var/lib/rspamd/rspamd.sock');
curl_setopt($curl, CURLOPT_URL,"http://rspamd/stat");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($curl);
if ($data) {
$return = array();
$stats_array = json_decode($data, true)['actions'];
$stats_array['soft reject'] = $stats_array['soft reject'] + $stats_array['greylist'];
unset($stats_array['greylist']);
foreach ($stats_array as $action => $count) {
$return[] = array($action, $count);
}
echo json_encode($return, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
elseif (!isset($data) || empty($data)) {
echo '{}';
}
break;
}
break;
case "domain":
switch ($object) {
case "all":
$domains = mailbox('get', 'domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
if ($details = mailbox('get', 'domain_details', $domain)) {
$data[] = $details;
}
else {
continue;
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$data = mailbox('get', 'domain_details', $object);
process_get_return($data);
break;
}
break;
case "rl-domain":
switch ($object) {
case "all":
$domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
if (!empty($domains)) {
foreach ($domains as $domain) {
if ($details = ratelimit('get', 'domain', $domain)) {
$details['domain'] = $domain;
$data[] = $details;
}
else {
continue;
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$data = ratelimit('get', 'domain', $object);
process_get_return($data);
break;
}
break;
case "rl-mbox":
switch ($object) {
case "all":
$domains = mailbox('get', 'domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
$mailboxes = mailbox('get', 'mailboxes', $domain);
if (!empty($mailboxes)) {
foreach ($mailboxes as $mailbox) {
if ($details = ratelimit('get', 'mailbox', $mailbox)) {
$details['mailbox'] = $mailbox;
$data[] = $details;
}
else {
continue;
}
}
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$data = ratelimit('get', 'mailbox', $object);
process_get_return($data);
break;
}
break;
case "relayhost":
switch ($object) {
case "all":
$relayhosts = relayhost('get');
if (!empty($relayhosts)) {
foreach ($relayhosts as $relayhost) {
if ($details = relayhost('details', $relayhost['id'])) {
$data[] = $details;
}
else {
continue;
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$data = relayhost('details', $object);
process_get_return($data);
break;
}
break;
case "rsetting":
switch ($object) {
case "all":
$rsettings = rsettings('get');
if (!empty($rsettings)) {
foreach ($rsettings as $rsetting) {
if ($details = rsettings('details', $rsetting['id'])) {
$data[] = $details;
}
else {
continue;
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$data = rsetting('details', $object);
process_get_return($data);
break;
}
break;
case "oauth2-client":
switch ($object) {
case "all":
$clients = oauth2('get', 'clients');
if (!empty($clients)) {
foreach ($clients as $client) {
if ($details = oauth2('details', 'client', $client)) {
$data[] = $details;
}
else {
continue;
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$data = oauth2('details', 'client', $object);
process_get_return($data);
break;
}
break;
case "logs":
switch ($object) {
case "dovecot":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('dovecot-mailcow', $extra);
}
else {
$logs = get_logs('dovecot-mailcow');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "netfilter":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('netfilter-mailcow', $extra);
}
else {
$logs = get_logs('netfilter-mailcow');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "postfix":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('postfix-mailcow', $extra);
}
else {
$logs = get_logs('postfix-mailcow');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "autodiscover":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('autodiscover-mailcow', $extra);
}
else {
$logs = get_logs('autodiscover-mailcow');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "sogo":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('sogo-mailcow', $extra);
}
else {
$logs = get_logs('sogo-mailcow');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "ui":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('mailcow-ui', $extra);
}
else {
$logs = get_logs('mailcow-ui');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "watchdog":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('watchdog-mailcow', $extra);
}
else {
$logs = get_logs('watchdog-mailcow');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "acme":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('acme-mailcow', $extra);
}
else {
$logs = get_logs('acme-mailcow');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "api":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('api-mailcow', $extra);
}
else {
$logs = get_logs('api-mailcow');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
case "rspamd-history":
// 0 is first record, so empty is fine
if (isset($extra)) {
$extra = preg_replace('/[^\d\-]/i', '', $extra);
$logs = get_logs('rspamd-history', $extra);
}
else {
$logs = get_logs('rspamd-history');
}
echo (isset($logs) && !empty($logs)) ? json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) : '{}';
break;
}
break;
case "mailbox":
switch ($object) {
case "all":
$domains = mailbox('get', 'domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
$mailboxes = mailbox('get', 'mailboxes', $domain);
if (!empty($mailboxes)) {
foreach ($mailboxes as $mailbox) {
if ($details = mailbox('get', 'mailbox_details', $mailbox)) {
$data[] = $details;
}
else {
continue;
}
}
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$data = mailbox('get', 'mailbox_details', $object);
process_get_return($data);
break;
}
break;
case "syncjobs":
switch ($object) {
case "all":
$domains = mailbox('get', 'domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
$mailboxes = mailbox('get', 'mailboxes', $domain);
if (!empty($mailboxes)) {
foreach ($mailboxes as $mailbox) {
$syncjobs = mailbox('get', 'syncjobs', $mailbox);
if (!empty($syncjobs)) {
foreach ($syncjobs as $syncjob) {
if (isset($extra)) {
$details = mailbox('get', 'syncjob_details', $syncjob, explode(',', $extra));
}
else {
$details = mailbox('get', 'syncjob_details', $syncjob);
}
if ($details) {
$data[] = $details;
}
else {
continue;
}
}
}
}
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$syncjobs = mailbox('get', 'syncjobs', $object);
if (!empty($syncjobs)) {
foreach ($syncjobs as $syncjob) {
if (isset($extra)) {
$details = mailbox('get', 'syncjob_details', $syncjob, explode(',', $extra));
}
else {
$details = mailbox('get', 'syncjob_details', $syncjob);
}
if ($details) {
$data[] = $details;
}
else {
continue;
}
}
}
process_get_return($data);
break;
}
break;
case "active-user-sieve":
if (isset($object)) {
$sieve_filter = mailbox('get', 'active_user_sieve', $object);
if (!empty($sieve_filter)) {
$data[] = $sieve_filter;
}
}
process_get_return($data);
break;
case "filters":
switch ($object) {
case "all":
$domains = mailbox('get', 'domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
$mailboxes = mailbox('get', 'mailboxes', $domain);
if (!empty($mailboxes)) {
foreach ($mailboxes as $mailbox) {
$filters = mailbox('get', 'filters', $mailbox);
if (!empty($filters)) {
foreach ($filters as $filter) {
if ($details = mailbox('get', 'filter_details', $filter)) {
$data[] = $details;
}
else {
continue;
}
}
}
}
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$filters = mailbox('get', 'filters', $object);
if (!empty($filters)) {
foreach ($filters as $filter) {
if ($details = mailbox('get', 'filter_details', $filter)) {
$data[] = $details;
}
else {
continue;
}
}
}
process_get_return($data);
break;
}
break;
case "bcc":
switch ($object) {
case "all":
$bcc_items = bcc('get');
if (!empty($bcc_items)) {
foreach ($bcc_items as $bcc_item) {
if ($details = bcc('details', $bcc_item)) {
$data[] = $details;
}
else {
continue;
}
}
}
process_get_return($data);
break;
default:
$data = bcc('details', $object);
if (!empty($data)) {
$data[] = $details;
}
process_get_return($data);
break;
}
break;
case "recipient_map":
switch ($object) {
case "all":
$recipient_map_items = recipient_map('get');
if (!empty($recipient_map_items)) {
foreach ($recipient_map_items as $recipient_map_item) {
if ($details = recipient_map('details', $recipient_map_item)) {
$data[] = $details;
}
else {
continue;
}
}
}
process_get_return($data);
break;
default:
$data = recipient_map('details', $object);
if (!empty($data)) {
$data[] = $details;
}
process_get_return($data);
break;
}
break;
+ case "tls-policy-map":
+ switch ($object) {
+ case "all":
+ $tls_policy_maps_items = tls_policy_maps('get');
+ if (!empty($tls_policy_maps_items)) {
+ foreach ($tls_policy_maps_items as $tls_policy_maps_item) {
+ if ($details = tls_policy_maps('details', $tls_policy_maps_item)) {
+ $data[] = $details;
+ }
+ else {
+ continue;
+ }
+ }
+ }
+ process_get_return($data);
+ break;
+ default:
+ $data = tls_policy_maps('details', $object);
+ if (!empty($data)) {
+ $data[] = $details;
+ }
+ process_get_return($data);
+ break;
+ }
+ break;
case "policy_wl_mailbox":
switch ($object) {
default:
$data = policy('get', 'mailbox', $object)['whitelist'];
process_get_return($data);
break;
}
break;
case "policy_bl_mailbox":
switch ($object) {
default:
$data = policy('get', 'mailbox', $object)['blacklist'];
process_get_return($data);
break;
}
break;
case "policy_wl_domain":
switch ($object) {
default:
$data = policy('get', 'domain', $object)['whitelist'];
process_get_return($data);
break;
}
break;
case "policy_bl_domain":
switch ($object) {
default:
$data = policy('get', 'domain', $object)['blacklist'];
process_get_return($data);
break;
}
break;
case "time_limited_aliases":
switch ($object) {
default:
$data = mailbox('get', 'time_limited_aliases', $object);
process_get_return($data);
break;
}
break;
case "resource":
switch ($object) {
case "all":
$domains = mailbox('get', 'domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
$resources = mailbox('get', 'resources', $domain);
if (!empty($resources)) {
foreach ($resources as $resource) {
if ($details = mailbox('get', 'resource_details', $resource)) {
$data[] = $details;
}
else {
continue;
}
}
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
$data = mailbox('get', 'resource_details', $object);
process_get_return($data);
break;
}
break;
case "fwdhost":
switch ($object) {
case "all":
process_get_return(fwdhost('get'));
break;
default:
process_get_return(fwdhost('details', $object));
break;
}
break;
case "quarantine":
// "all" will not print details
switch ($object) {
case "all":
process_get_return(quarantine('get'));
break;
default:
process_get_return(quarantine('details', $object));
break;
}
break;
case "alias-domain":
switch ($object) {
case "all":
$alias_domains = mailbox('get', 'alias_domains');
if (!empty($alias_domains)) {
foreach ($alias_domains as $alias_domain) {
if ($details = mailbox('get', 'alias_domain_details', $alias_domain)) {
$data[] = $details;
}
else {
continue;
}
}
}
process_get_return($data);
break;
default:
process_get_return(mailbox('get', 'alias_domain_details', $object));
break;
}
break;
case "alias":
switch ($object) {
case "all":
$domains = array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains'));
if (!empty($domains)) {
foreach ($domains as $domain) {
$aliases = mailbox('get', 'aliases', $domain);
if (!empty($aliases)) {
foreach ($aliases as $alias) {
if ($details = mailbox('get', 'alias_details', $alias)) {
$data[] = $details;
}
else {
continue;
}
}
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
process_get_return(mailbox('get', 'alias_details', $object));
break;
}
break;
case "domain-admin":
switch ($object) {
case "all":
$domain_admins = domain_admin('get');
if (!empty($domain_admins)) {
foreach ($domain_admins as $domain_admin) {
if ($details = domain_admin('details', $domain_admin)) {
$data[] = $details;
}
else {
continue;
}
}
process_get_return($data);
}
else {
echo '{}';
}
break;
default:
process_get_return(domain_admin('details', $object));
break;
}
break;
case "u2f-registration":
header('Content-Type: application/javascript');
if (($_SESSION["mailcow_cc_role"] == "admin" || $_SESSION["mailcow_cc_role"] == "domainadmin") && $_SESSION["mailcow_cc_username"] == $object) {
list($req, $sigs) = $u2f->getRegisterData(get_u2f_registrations($object));
$_SESSION['regReq'] = json_encode($req);
$_SESSION['regSigs'] = json_encode($sigs);
echo 'var req = ' . json_encode($req) . ';';
echo 'var registeredKeys = ' . json_encode($sigs) . ';';
echo 'var appId = req.appId;';
echo 'var registerRequests = [{version: req.version, challenge: req.challenge}];';
}
else {
return;
}
break;
case "u2f-authentication":
header('Content-Type: application/javascript');
if (isset($_SESSION['pending_mailcow_cc_username']) && $_SESSION['pending_mailcow_cc_username'] == $object) {
$auth_data = $u2f->getAuthenticateData(get_u2f_registrations($object));
$challenge = $auth_data[0]->challenge;
$appId = $auth_data[0]->appId;
foreach ($auth_data as $each) {
$key = array(); // Empty array
$key['version'] = $each->version;
$key['keyHandle'] = $each->keyHandle;
$registeredKey[] = $key;
}
$_SESSION['authReq'] = json_encode($auth_data);
echo 'var appId = "' . $appId . '";';
echo 'var challenge = ' . json_encode($challenge) . ';';
echo 'var registeredKeys = ' . json_encode($registeredKey) . ';';
}
else {
return;
}
break;
default:
echo '{}';
break;
}
break;
case "delete":
function process_delete_return($return) {
$generic_failure = json_encode(array(
'type' => 'error',
'msg' => 'Cannot delete item'
));
$generic_success = json_encode(array(
'type' => 'success',
'msg' => 'Task completed'
));
if ($return === false) {
echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
}
else {
echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
}
}
if (!isset($_POST['items'])) {
echo $request_incomplete;
exit;
}
else {
$items = (array)json_decode($_POST['items'], true);
}
switch ($category) {
case "alias":
process_delete_return(mailbox('delete', 'alias', array('id' => $items)));
break;
case "relayhost":
process_delete_return(relayhost('delete', array('id' => $items)));
break;
case "rsetting":
process_delete_return(rsettings('delete', array('id' => $items)));
break;
case "syncjob":
process_delete_return(mailbox('delete', 'syncjob', array('id' => $items)));
break;
case "filter":
process_delete_return(mailbox('delete', 'filter', array('id' => $items)));
break;
case "qitem":
process_delete_return(quarantine('delete', array('id' => $items)));
break;
case "bcc":
process_delete_return(bcc('delete', array('id' => $items)));
break;
case "recipient_map":
process_delete_return(recipient_map('delete', array('id' => $items)));
break;
+ case "tls-policy-map":
+ process_delete_return(tls_policy_maps('delete', array('id' => $items)));
+ break;
case "fwdhost":
process_delete_return(fwdhost('delete', array('forwardinghost' => $items)));
break;
case "dkim":
process_delete_return(dkim('delete', array('domains' => $items)));
break;
case "domain":
file_put_contents('/tmp/dssaa', $items);
process_delete_return(mailbox('delete', 'domain', array('domain' => $items)));
break;
case "alias-domain":
process_delete_return(mailbox('delete', 'alias_domain', array('alias_domain' => $items)));
break;
case "mailbox":
process_delete_return(mailbox('delete', 'mailbox', array('username' => $items)));
break;
case "resource":
process_delete_return(mailbox('delete', 'resource', array('name' => $items)));
break;
case "mailbox-policy":
process_delete_return(policy('delete', 'mailbox', array('prefid' => $items)));
break;
case "domain-policy":
process_delete_return(policy('delete', 'domain', array('prefid' => $items)));
break;
case "time_limited_alias":
process_delete_return(mailbox('delete', 'time_limited_alias', array('address' => $items)));
break;
case "eas_cache":
process_delete_return(mailbox('delete', 'eas_cache', array('username' => $items)));
break;
case "domain-admin":
process_delete_return(domain_admin('delete', array('username' => $items)));
break;
}
break;
case "edit":
function process_edit_return($return) {
$generic_failure = json_encode(array(
'type' => 'error',
'msg' => 'Cannot edit item'
));
$generic_success = json_encode(array(
'type' => 'success',
'msg' => 'Task completed'
));
if ($return === false) {
echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_failure;
}
else {
echo isset($_SESSION['return']) ? json_encode($_SESSION['return']) : $generic_success;
}
}
if (!isset($_POST['attr'])) {
echo $request_incomplete;
exit;
}
else {
$attr = (array)json_decode($_POST['attr'], true);
unset($attr['csrf_token']);
$items = isset($_POST['items']) ? (array)json_decode($_POST['items'], true) : null;
}
switch ($category) {
case "bcc":
process_edit_return(bcc('edit', array_merge(array('id' => $items), $attr)));
break;
case "oauth2-client":
process_edit_return(oauth2('edit', 'client', array_merge(array('id' => $items), $attr)));
break;
case "recipient_map":
process_edit_return(recipient_map('edit', array_merge(array('id' => $items), $attr)));
break;
+ case "tls-policy-map":
+ process_edit_return(tls_policy_maps('edit', array_merge(array('id' => $items), $attr)));
+ break;
case "alias":
process_edit_return(mailbox('edit', 'alias', array_merge(array('id' => $items), $attr)));
break;
case "app_links":
process_edit_return(customize('edit', 'app_links', $attr));
break;
case "relayhost":
process_edit_return(relayhost('edit', array_merge(array('id' => $items), $attr)));
break;
case "rsetting":
process_edit_return(rsettings('edit', array_merge(array('id' => $items), $attr)));
break;
case "delimiter_action":
process_edit_return(mailbox('edit', 'delimiter_action', array_merge(array('username' => $items), $attr)));
break;
case "tls_policy":
process_edit_return(mailbox('edit', 'tls_policy', array_merge(array('username' => $items), $attr)));
break;
case "qitem":
process_edit_return(quarantine('edit', array_merge(array('id' => $items), $attr)));
break;
case "quarantine":
process_edit_return(quarantine('edit', $attr));
break;
case "time_limited_alias":
process_edit_return(mailbox('edit', 'time_limited_alias', array_merge(array('address' => $items), $attr)));
break;
case "mailbox":
process_edit_return(mailbox('edit', 'mailbox', array_merge(array('username' => $items), $attr)));
break;
case "syncjob":
process_edit_return(mailbox('edit', 'syncjob', array_merge(array('id' => $items), $attr)));
break;
case "filter":
process_edit_return(mailbox('edit', 'filter', array_merge(array('id' => $items), $attr)));
break;
case "resource":
process_edit_return(mailbox('edit', 'resource', array_merge(array('name' => $items), $attr)));
break;
case "domain":
process_edit_return(mailbox('edit', 'domain', array_merge(array('domain' => $items), $attr)));
break;
case "rl-domain":
process_edit_return(ratelimit('edit', 'domain', array_merge(array('object' => $items), $attr)));
break;
case "rl-mbox":
process_edit_return(ratelimit('edit', 'mailbox', array_merge(array('object' => $items), $attr)));
break;
case "user-acl":
process_edit_return(acl('edit', 'user', array_merge(array('username' => $items), $attr)));
break;
case "da-acl":
process_edit_return(acl('edit', 'domainadmin', array_merge(array('username' => $items), $attr)));
break;
case "alias-domain":
process_edit_return(mailbox('edit', 'alias_domain', array_merge(array('alias_domain' => $items), $attr)));
break;
case "spam-score":
process_edit_return(mailbox('edit', 'spam_score', array_merge(array('username' => $items), $attr)));
break;
case "domain-admin":
process_edit_return(domain_admin('edit', array_merge(array('username' => $items), $attr)));
break;
case "fwdhost":
process_edit_return(fwdhost('edit', array_merge(array('fwdhost' => $items), $attr)));
break;
case "fail2ban":
process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr)));
break;
case "ui_texts":
process_edit_return(customize('edit', 'ui_texts', $attr));
break;
case "self":
if ($_SESSION['mailcow_cc_role'] == "domainadmin") {
process_edit_return(domain_admin('edit', $attr));
}
elseif ($_SESSION['mailcow_cc_role'] == "user") {
process_edit_return(edit_user_account($attr));
}
elseif ($_SESSION['mailcow_cc_role'] == "admin") {
process_edit_return(edit_admin_account($attr));
}
break;
}
break;
}
}
}
diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php
index 4cb2e789..9392f346 100644
--- a/data/web/lang/lang.de.php
+++ b/data/web/lang/lang.de.php
@@ -1,674 +1,689 @@
<?php
/*
* German language file
*/
$lang['footer']['loading'] = 'Einen Moment bitte...';
$lang['header']['restart_sogo'] = 'SOGo neustarten';
$lang['header']['restart_netfilter'] = 'Netfilter neustarten';
$lang['footer']['restart_container'] = 'Container neustarten';
$lang['footer']['restart_now'] = 'Jetzt neustarten';
$lang['footer']['restarting_container'] = 'Container wird neugestartet, bitte warten...';
$lang['footer']['restart_container_info'] = '<b>Wichtig:</b> Der Neustart eines Containers kann eine Weile in Anspruch nehmen.';
$lang['footer']['confirm_delete'] = 'Löschen bestätigen';
$lang['footer']['delete_these_items'] = 'Sind Sie sicher, dass die Änderungen an Elementen mit folgender ID durchgeführt werden sollen?';
$lang['footer']['delete_now'] = 'Jetzt löschen';
$lang['footer']['cancel'] = 'Abbrechen';
$lang['footer']['hibp_nok'] = 'Übereinstimmung gefunden! Dieses Passwort ist potentiell gefährlich!';
$lang['footer']['hibp_ok'] = 'Keine Übereinstimmung gefunden.';
$lang['danger']['mysql_error'] = "MySQL Fehler: %s";
$lang['danger']['redis_error'] = "Redis Fehler: %s";
$lang['danger']['unknown_tfa_method'] = "Unbekannte TFA Methode";
$lang['danger']['totp_verification_failed'] = "TOTP Verifizierung fehlgeschlagen";
$lang['success']['verified_totp_login'] = "TOTP Anmeldung verifiziert";
$lang['danger']['u2f_verification_failed'] = "U2F Verifizierung fehlgeschlagen: %s";
$lang['success']['verified_u2f_login'] = "U2F Anmeldung verifiziert";
$lang['success']['verified_yotp_login'] = "Yubico OTP Anmeldung verifiziert";
$lang['danger']['yotp_verification_failed'] = "Yubico OTP Verifizierung fehlgeschlagen: %s";
$lang['danger']['ip_list_empty'] = "Liste erlaubter IPs darf nicht leer sein";
$lang['danger']['rspamd_ui_pw_length'] = "Rspamd UI Passwort muss mindestens 6 Zeichen lang sein";
$lang['success']['rspamd_ui_pw_set'] = "Rspamd UI Passwort wurde gesetzt";
$lang['danger']['unknown'] = "Ein unbekannter Fehler trat auf";
$lang['danger']['malformed_username'] = "Benutzername hat falsches Format";
$lang['info']['awaiting_tfa_confirmation'] = "Warte auf TFA Verifizierung";
$lang['success']['logged_in_as'] = "Eingeloggt als %s";
$lang['danger']['login_failed'] = "Anmeldung fehlgeschlagen";
$lang['danger']['set_acl_failed'] = "ACL konnte nicht gesetzt werden";
$lang['danger']['no_user_defined'] = "Kein Benutzer definiert";
$lang['danger']['script_empty'] = "Script darf nicht leer sein";
$lang['danger']['sieve_error'] = "Sieve Parser: %s";
$lang['danger']['value_missing'] = "Bitte alle Felder ausfüllen";
$lang['danger']['filter_type'] = "Falscher Filtertyp";
$lang['danger']['domain_cannot_match_hostname'] = "Domain darf nicht dem Hostnamen entsprechen";
$lang['warning']['domain_added_sogo_failed'] = "Domain wurde hinzugefügt; SOGo konnte nicht neugestartet werden";
$lang['danger']['rl_timeframe'] = "Ratelimit Zeitraum ist inkorrekt";
$lang['success']['rl_saved'] = "Ratelimit für Objekt %s wurde gesetzt";
$lang['success']['acl_saved'] = "ACL für Objekt %s wurde gesetzt";
$lang['success']['deleted_syncjobs'] = "Syncjobs gelöscht: %s";
$lang['success']['deleted_syncjob'] = "Syncjobs ID %s gelöscht";
$lang['success']['delete_filters'] = "Filter gelöscht: %s";
$lang['success']['delete_filter'] = "Filter ID %s wurde gelöscht";
$lang['danger']['invalid_bcc_map_type'] = "Ungültiger BCC Map-Typ";
$lang['danger']['bcc_empty'] = "BCC Ziel darf nicht leer sein";
$lang['danger']['bcc_must_be_email'] = "BCC Map %s ist keine gültige E-Mail-Adresse";
$lang['danger']['bcc_exists'] = "Ein BCC Map Eintrag %s existiert bereits als Typ %s";
$lang['success']['bcc_saved'] = "BCC Map Eintrag wurde gespeichert";
$lang['success']['bcc_edited'] = "BCC Map Eintrag %s wurde editiert";
$lang['success']['bcc_deleted'] = "BCC Map Einträge gelöscht: %s";
$lang['danger']['private_key_error'] = "Schlüsselfehler: %s";
$lang['danger']['map_content_empty'] = "Inhalt darf nicht leer sein";
$lang['success']['settings_map_added'] = "Regel wurde gespeichert";
$lang['danger']['settings_map_invalid'] = "Regel ID %s ist ungültig";
$lang['danger']['settings_map_removed'] = "Regeln wurden entfernt: %s";
$lang['danger']['invalid_host'] = "Ungültiger Host: %s";
$lang['danger']['relayhost_invalid'] = "Relayhost %s ist ungültig";
$lang['success']['saved_settings'] = "Regel wurde gespeichert";
$lang['danger']['dkim_domain_or_sel_invalid'] = 'DKIM-Domain oder Selektor nicht korrekt: %s';
$lang['success']['dkim_removed'] = 'DKIM-Key wurde entfernt';
$lang['success']['dkim_added'] = 'DKIM-Key wurde hinzugefügt';
$lang['success']['dkim_duplicated'] = "DKIM-Key der Domain %s wurde auf Domain %s kopiert";
$lang['danger']['access_denied'] = 'Zugriff verweigert oder unvollständige/ungültige Daten';
$lang['danger']['domain_invalid'] = 'Domainname %s ist ungültig';
$lang['danger']['mailbox_quota_exceeds_domain_quota'] = 'Maximale Größe für Mailboxen überschreitet das Domain Speicherlimit';
$lang['danger']['object_is_not_numeric'] = 'Wert %s ist nicht numerisch';
$lang['success']['domain_added'] = 'Domain %s wurde angelegt';
$lang['success']['items_deleted'] = "Objekt(e) %s wurde(n) erfolgreich entfernt";
$lang['success']['item_deleted'] = "Objekt %s wurde entfernt";
$lang['danger']['alias_empty'] = 'Alias-Adresse darf nicht leer sein';
$lang['danger']['goto_empty'] = 'Ziel-Adresse darf nicht leer sein';
$lang['danger']['policy_list_from_exists'] = 'Ein Eintrag mit diesem Wert existiert bereits';
$lang['danger']['policy_list_from_invalid'] = 'Eintrag hat ungültiges Format';
$lang['danger']['alias_invalid'] = 'Alias-Adresse %s ist ungültig';
$lang['danger']['goto_invalid'] = 'Ziel-Adresse %s ist ungültig';
$lang['danger']['last_key'] = 'Letzter Key kann nicht gelöscht werden';
$lang['danger']['alias_domain_invalid'] = 'Alias-Domain %s ist ungültig';
$lang['danger']['target_domain_invalid'] = 'Ziel-Domain %s ist ungültig';
$lang['danger']['object_exists'] = 'Objekt %s existiert bereits';
$lang['danger']['domain_exists'] = 'Domain %s existiert bereits';
$lang['danger']['alias_goto_identical'] = 'Alias- und Ziel-Adresse dürfen nicht identisch sein';
$lang['danger']['aliasd_targetd_identical'] = 'Alias-Domain darf nicht gleich Ziel-Domain sein: %s';
$lang['danger']['maxquota_empty'] = 'Max. Speicherplatz pro Mailbox darf nicht 0 sein.';
$lang['success']['alias_added'] = 'Alias-Adresse %s wurden angelegt';
$lang['success']['alias_modified'] = 'Änderungen an Alias %s wurden gespeichert';
$lang['success']['aliasd_modified'] = 'Änderungen an Alias-Domain %s wurden gespeichert';
$lang['success']['mailbox_modified'] = 'Änderungen an Mailbox %s wurden gespeichert';
$lang['success']['resource_modified'] = "Änderungen an Ressource %s wurden gespeichert";
$lang['success']['object_modified'] = "Änderungen an Objekt %s wurden gespeichert";
$lang['success']['f2b_modified'] = "Änderungen an Fail2ban Parametern wurden gespeichert";
$lang['danger']['targetd_not_found'] = 'Ziel-Domain %s nicht gefunden';
$lang['success']['aliasd_added'] = 'Alias-Domain %s wurde angelegt';
$lang['success']['aliasd_modified'] = 'Änderungen an Alias-Domain %s wurden gespeichert';
$lang['success']['domain_modified'] = 'Änderungen an Domain %s wurden gespeichert';
$lang['success']['domain_admin_modified'] = 'Änderungen an Domain-Administrator %s wurden gespeichert';
$lang['success']['domain_admin_added'] = 'Domain-Administrator %s wurde angelegt';
$lang['success']['admin_modified'] = 'Änderungen am Administrator wurden gespeichert';
$lang['danger']['username_invalid'] = 'Benutzername %s kann nicht verwendet werden';
$lang['danger']['password_mismatch'] = 'Passwort-Wiederholung stimmt nicht überein';
$lang['danger']['password_complexity'] = 'Passwort entspricht nicht den Richtlinien';
$lang['danger']['password_empty'] = 'Passwort darf nicht leer sein';
$lang['danger']['login_failed'] = 'Anmeldung fehlgeschlagen';
$lang['danger']['mailbox_invalid'] = 'Mailboxname ist ungültig';
$lang['danger']['resource_invalid'] = 'Ressourcenname %s ist ungültig';
$lang['danger']['description_invalid'] = 'Ressourcenbeschreibung für %s ist ungültig';
$lang['danger']['is_alias'] = '%s lautet bereits eine Alias-Adresse';
$lang['danger']['is_alias_or_mailbox'] = "Eine Mailbox, ein Alias oder eine sich aus einer Alias-Domain ergebende Adresse mit dem Namen %s ist bereits vorhanden";
$lang['danger']['is_spam_alias'] = '%s lautet bereits eine Spam-Alias-Adresse';
$lang['danger']['quota_not_0_not_numeric'] = 'Speicherplatz muss numerisch und >= 0 sein';
$lang['danger']['domain_not_found'] = 'Domain %s nicht gefunden';
$lang['danger']['max_mailbox_exceeded'] = 'Anzahl an Mailboxen überschritten (%d von %d)';
$lang['danger']['max_alias_exceeded'] = 'Anzahl an Alias-Adressen überschritten';
$lang['danger']['mailbox_quota_exceeded'] = 'Speicherplatz überschreitet das Limit (max. %d MiB)';
$lang['danger']['mailbox_quota_left_exceeded'] = 'Nicht genügend Speicherplatz vorhanden (Speicherplatz anwendbar: %d MiB)';
$lang['success']['mailbox_added'] = 'Mailbox %s wurde angelegt';
$lang['success']['resource_added'] = 'Ressource %s wurde angelegt';
$lang['success']['domain_removed'] = 'Domain %s wurde entfernt';
$lang['success']['alias_removed'] = 'Alias-Adresse %s wurde entfernt';
$lang['success']['alias_domain_removed'] = 'Alias-Domain %s wurde entfernt';
$lang['success']['domain_admin_removed'] = 'Domain-Administrator %s wurde entfernt';
$lang['success']['mailbox_removed'] = 'Mailbox %s wurde entfernt';
$lang['success']['eas_reset'] = "ActiveSync Gerät des Benutzers %s wurden zurückgesetzt";
$lang['success']['resource_removed'] = 'Ressource %s wurde entfernt';
$lang['danger']['max_quota_in_use'] = 'Mailbox Speicherplatzlimit muss größer oder gleich %d MiB sein';
$lang['danger']['domain_quota_m_in_use'] = 'Domain Speicherplatzlimit muss größer oder gleich %d MiB sein';
$lang['danger']['mailboxes_in_use'] = 'Maximale Anzahl an Mailboxen muss größer oder gleich %d sein';
$lang['danger']['aliases_in_use'] = 'Maximale Anzahl an Aliassen muss größer oder gleich %d sein';
$lang['danger']['sender_acl_invalid'] = 'Sender ACL %s ist ungültig';
$lang['danger']['domain_not_empty'] = 'Kann nur leere Domains entfernen';
$lang['danger']['validity_missing'] = 'Bitte geben Sie eine Gültigkeitsdauer an';
$lang['user']['loading'] = "Lade...";
$lang['user']['force_pw_update'] = 'Das Passwort für diesen Benutzer <b>muss</b> geändert werden, damit die Zugriffssperre auf die Groupwarekomponenten wieder freigeschaltet wird.';
$lang['user']['active_sieve'] = "Aktiver Filter";
$lang['user']['show_sieve_filters'] = "Zeige aktiven Filter des Benutzers";
$lang['user']['no_active_filter'] = "Kein aktiver Filter vorhanden";
$lang['user']['messages'] = "Nachrichten";
$lang['user']['in_use'] = "Verwendet";
$lang['user']['user_change_fn'] = '';
$lang['user']['user_settings'] = 'Benutzereinstellungen';
$lang['user']['mailbox_details'] = 'Mailbox-Details';
$lang['user']['change_password'] = 'Passwort ändern';
$lang['user']['client_configuration'] = 'Konfigurationsanleitungen für E-Mail-Programme und Smartphones anzeigen';
$lang['user']['new_password'] = 'Neues Passwort';
$lang['user']['save_changes'] = 'Änderungen speichern';
$lang['user']['password_now'] = 'Aktuelles Passwort (Änderungen bestätigen)';
$lang['user']['new_password_repeat'] = 'Neues Passwort (Wiederholung)';
$lang['user']['new_password_description'] = 'Mindestanforderung: 6 Zeichen lang, Buchstaben und Zahlen.';
$lang['user']['spam_aliases'] = 'Temporäre E-Mail Aliasse';
$lang['user']['alias'] = 'Alias';
$lang['user']['shared_aliases'] = 'Geteilte Alias-Adressen';
$lang['user']['shared_aliases_desc'] = 'Geteilte Alias-Adressen werden nicht bei benutzerdefinierten Einstellungen wie die des Spam-Filters oder der Verschlüsselungsrichtlinie berücksichtigt. Entsprechende Spam-Filter können lediglich von einem Administrator vorgenommen werden.';
$lang['user']['direct_aliases'] = 'Direkte Alias-Adressen';
$lang['user']['direct_aliases_desc'] = 'Nur direkte Alias-Adressen werden für benutzerdefinierte Einstellungen berücksichtigt.';
$lang['user']['is_catch_all'] = 'Ist Catch-All Adresse für Domain(s)';
$lang['user']['aliases_also_send_as'] = 'Darf außerdem versenden als Benutzer';
$lang['user']['aliases_send_as_all'] = 'Absender für folgende Domains und zugehörige Alias-Domains nicht prüfen';
$lang['user']['alias_create_random'] = 'Zufälligen Alias generieren';
$lang['user']['alias_extend_all'] = 'Gültigkeit +1h';
$lang['user']['alias_valid_until'] = 'Gültig bis';
$lang['user']['alias_remove_all'] = 'Alle entfernen';
$lang['user']['alias_time_left'] = 'Zeit verbleibend';
$lang['user']['alias_full_date'] = 'd.m.Y, H:i:s T';
$lang['user']['alias_select_validity'] = 'Bitte Gültigkeit auswählen';
$lang['user']['sync_jobs'] = 'Sync Jobs';
$lang['user']['hour'] = 'Stunde';
$lang['user']['hours'] = 'Stunden';
$lang['user']['day'] = 'Tag';
$lang['user']['week'] = 'Woche';
$lang['user']['weeks'] = 'Wochen';
$lang['user']['spamfilter'] = 'Spamfilter';
$lang['admin']['spamfilter'] = 'Spamfilter';
$lang['user']['spamfilter_wl'] = 'Whitelist';
$lang['user']['spamfilter_wl_desc'] = 'Für E-Mail-Adressen, die vom Spamfilter <b>nicht</b> erfasst werden sollen. Die Verwendung von Wildcards ist gestattet. Ein Filter funktioniert lediglich für direkte nicht-"Catch All" Alias-Adressen (Alias-Adressen mit lediglich einer Mailbox als Ziel-Adresse) sowie die Mailbox-Adresse selbst.';
$lang['user']['spamfilter_bl'] = 'Blacklist';
$lang['user']['spamfilter_bl_desc'] = 'Für E-Mail-Adressen, die vom Spamfilter <b>immer</b> als Spam erfasst und abgelehnt werden. Die Verwendung von Wildcards ist gestattet. Ein Filter funktioniert lediglich für direkte nicht-"Catch All" Alias-Adressen (Alias-Adressen mit lediglich einer Mailbox als Ziel-Adresse) sowie die Mailbox-Adresse selbst.';
$lang['user']['spamfilter_table_rule'] = 'Regel';
$lang['user']['spamfilter_table_action'] = 'Aktion';
$lang['user']['spamfilter_table_empty'] = 'Keine Einträge vorhanden';
$lang['user']['spamfilter_table_remove'] = 'entfernen';
$lang['user']['spamfilter_table_add'] = 'Eintrag hinzufügen';
$lang['user']['spamfilter_behavior'] = 'Bewertung';
$lang['user']['spamfilter_default_score'] = 'Spam-Score:';
$lang['user']['spamfilter_green'] = 'Grün: Die Nachricht ist kein Spam';
$lang['user']['spamfilter_yellow'] = 'Gelb: Die Nachricht ist vielleicht Spam, wird als Spam markiert und in den Junk-Ordner verschoben';
$lang['user']['spamfilter_red'] = 'Rot: Die Nachricht ist eindeutig Spam und wird vom Server abgelehnt';
$lang['user']['spamfilter_default_score'] = 'Standardwert:';
$lang['user']['spamfilter_hint'] = 'Der erste Wert beschreibt den "low spam score", der zweite Wert den "high spam score".';
$lang['user']['spamfilter_table_domain_policy'] = "n.v. (Domainrichtlinie)";
$lang['user']['waiting'] = "Warte auf Ausführung";
$lang['user']['status'] = "Status";
$lang['user']['running'] = "Wird ausgeführt";
$lang['user']['tls_policy_warning'] = '<strong>Vorsicht:</strong> Entscheiden Sie sich unverschlüsselte Verbindungen abzulehnen, kann dies dazu führen, dass Kontakte Sie nicht mehr erreichen.<br>Nachrichten, die die Richtlinie nicht erfüllen, werden durch einen Hard-Fail im Mailsystem abgewiesen.<br>Diese Einstellung ist aktiv für die primäre Mailbox, für alle Alias-Adressen, die dieser Mailbox <b>direkt zugeordnet</b> sind (lediglich eine einzige Ziel-Adresse) und der Adressen, die sich aus Alias-Domains ergeben. Ausgeschlossen sind temporäre Aliasse ("Spam-Alias-Adressen"), Catch-All Alias-Adressen sowie Alias-Adressen mit mehreren Zielen.';
$lang['user']['tls_policy'] = 'Verschlüsselungsrichtlinie';
$lang['user']['tls_enforce_in'] = 'TLS eingehend erzwingen';
$lang['user']['tls_enforce_out'] = 'TLS ausgehend erzwingen';
$lang['user']['no_record'] = 'Kein Eintrag';
$lang['user']['tag_handling'] = 'Umgang mit getaggten E-Mails steuern';
$lang['user']['tag_in_subfolder'] = 'In Unterordner';
$lang['user']['tag_in_subject'] = 'In Betreff';
$lang['user']['tag_in_none'] = 'Nichts tun';
$lang['user']['tag_help_explain'] = 'Als Unterordner: Es wird ein Ordner mit dem Namen des Tags unterhalb der Inbox erstellt ("INBOX/Facebook").<br>
In Betreff: Der Name des Tags wird dem Betreff angefügt, etwa "[Facebook] Meine Neuigkeiten".';
$lang['user']['tag_help_example'] = 'Beispiel für eine getaggte E-Mail-Adresse: ich<b>+Facebook</b>@example.org';
$lang['user']['eas_reset'] = 'ActiveSync Geräte-Cache zurücksetzen';
$lang['user']['eas_reset_now'] = 'Jetzt zurücksetzen';
$lang['user']['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!';
$lang['user']['encryption'] = 'Verschlüsselung';
$lang['user']['username'] = 'Benutzername';
$lang['user']['last_run'] = 'Letzte Ausführung';
$lang['user']['excludes'] = 'Ausschlüsse';
$lang['user']['interval'] = 'Intervall';
$lang['user']['active'] = 'Aktiv';
$lang['user']['action'] = 'Aktion';
$lang['user']['edit'] = 'Bearbeiten';
$lang['user']['remove'] = 'Entfernen';
$lang['user']['create_syncjob'] = 'Neuen Sync-Job erstellen';
$lang['start']['mailcow_apps_detail'] = 'Verwenden Sie mailcow Apps, um E-Mails abzurufen, Kalender- und Kontakte zu verwalten und vieles mehr.';
$lang['start']['mailcow_panel_detail'] = '<b>Domain-Administratoren</b> erstellen, verändern oder löschen Mailboxen, verwalten die Domäne und sehen sonstige Einstellungen ein.<br>
Als <b>Mailbox-Benutzer</b> erstellen Sie hier zeitlich limitierte Aliasse, ändern das Verhalten des Spamfilters, setzen ein neues Passwort und vieles mehr.';
$lang['start']['imap_smtp_server_auth_info'] = 'Bitte verwenden Sie Ihre vollständige E-Mail-Adresse sowie das PLAIN-Authentifizierungsverfahren.<br>
Ihre Anmeldedaten werden durch die obligatorische Verschlüsselung entgegen des Begriffes "PLAIN" nicht unverschlüsselt übertragen.';
$lang['start']['help'] = 'Hilfe ein-/ausblenden';
$lang['header']['mailcow_settings'] = 'Konfiguration';
$lang['header']['administration'] = 'Administration';
$lang['header']['mailboxes'] = 'Mailboxen';
$lang['header']['user_settings'] = 'Benutzereinstellungen';
+$lang['mailbox']['tls_policy_maps'] = 'TLS-Richtlinien';
+$lang['mailbox']['tls_policy_maps_long'] = 'Ausgehende TLS-Richtlinien';
+$lang['mailbox']['tls_policy_maps_info'] = 'Nachstehende Richtlinien erzwingen TLS-Transportregeln unabhängig von TLS-Richtlinieneinstellungen eines Benutzers.<br>
+ Für weitere Informationen zur Syntax sollte <a href="http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps" target="_blank">die "smtp_tls_policy_maps" Dokumentation</a> konsultiert werden.';
+$lang['mailbox']['tls_enforce_in'] = 'Enforce TLS incoming';
+$lang['mailbox']['tls_enforce_out'] = 'Enforce TLS outgoing';
+$lang['mailbox']['tls_map_dest'] = 'Ziel';
+$lang['mailbox']['tls_map_dest_info'] = 'Beispiele: example.org, .example.org, mail@example.org, [mail.example.org]:25';
+$lang['mailbox']['tls_map_policy'] = 'Richtlinie';
+$lang['mailbox']['tls_map_parameters'] = 'Parameter';
+$lang['mailbox']['tls_map_parameters_info'] = 'Leer oder Parameter, Beispiele: protocols=!SSLv2 ciphers=medium exclude=3DES';
$lang['mailbox']['booking_0'] = 'Immer als verfügbar anzeigen';
$lang['mailbox']['booking_lt0'] = 'Unbegrenzt, jedoch anzeigen, wenn gebucht';
$lang['mailbox']['booking_custom'] = 'Benutzerdefiniertes Limit';
$lang['mailbox']['booking_0_short'] = 'Immer verfügbar';
$lang['mailbox']['booking_lt0_short'] = 'Weiches Limit';
$lang['mailbox']['booking_custom_short'] = 'Hartes Limit';
$lang['mailbox']['domain'] = 'Domain';
$lang['mailbox']['spam_aliases'] = 'Temp. Alias';
$lang['mailbox']['alias'] = 'Alias';
$lang['mailbox']['aliases'] = 'Aliasse';
$lang['mailbox']['multiple_bookings'] = 'Mehrfachbuchen';
$lang['mailbox']['kind'] = 'Art';
$lang['mailbox']['description'] = 'Beschreibung';
$lang['mailbox']['resources'] = 'Ressourcen';
$lang['mailbox']['domains'] = 'Domains';
$lang['admin']['domain_s'] = 'Domain(s)';
$lang['mailbox']['mailboxes'] = 'Mailboxen';
$lang['mailbox']['mailbox_quota'] = 'Max. Größe einer Mailbox';
$lang['mailbox']['domain_quota'] = 'Gesamtspeicher';
$lang['mailbox']['active'] = 'Aktiv';
$lang['mailbox']['action'] = 'Aktion';
$lang['mailbox']['backup_mx'] = 'Backup MX';
$lang['mailbox']['domain_aliases'] = 'Domain-Aliasse';
$lang['mailbox']['target_domain'] = 'Ziel-Domain';
$lang['mailbox']['target_address'] = 'Ziel-Adresse';
$lang['mailbox']['username'] = 'Benutzername';
$lang['mailbox']['fname'] = 'Name';
$lang['mailbox']['filter_table'] = 'Filtern';
$lang['mailbox']['yes'] = '&#10004;';
$lang['mailbox']['no'] = '&#10008;';
$lang['mailbox']['in_use'] = 'Prozentualer Gebrauch';
$lang['mailbox']['msg_num'] = 'Anzahl Nachrichten';
$lang['mailbox']['remove'] = 'Entfernen';
$lang['mailbox']['edit'] = 'Bearbeiten';
$lang['mailbox']['no_record'] = 'Kein Eintrag für Objekt %s';
$lang['mailbox']['no_record_single'] = 'Kein Eintrag';
$lang['mailbox']['add_domain'] = 'Domain hinzufügen';
$lang['mailbox']['add_domain_alias'] = 'Domain-Alias hinzufügen';
$lang['mailbox']['add_mailbox'] = 'Mailbox hinzufügen';
$lang['mailbox']['add_resource'] = 'Ressource hinzufügen';
$lang['mailbox']['add_alias'] = 'Alias hinzufügen';
$lang['mailbox']['empty'] = 'Keine Einträge vorhanden';
$lang['mailbox']['toggle_all'] = 'Alle';
$lang['mailbox']['quick_actions'] = 'Aktionen';
$lang['mailbox']['activate'] = 'Aktivieren';
$lang['mailbox']['deactivate'] = 'Deaktivieren';
$lang['mailbox']['owner'] = 'Besitzer';
$lang['mailbox']['mins_interval'] = 'Intervall (min)';
$lang['mailbox']['last_run'] = 'Letzte Ausführung';
$lang['mailbox']['last_run_reset'] = 'Als nächstes ausführen';
$lang['mailbox']['sieve_info'] = 'Es können mehrere Filter pro Benutzer existieren, aber nur ein Filter eines Typs (Pre-/Postfilter) kann gleichzeitig aktiv sein.<br>
Die Ausführung erfolgt in nachstehender Reihenfolge. Ein fehlgeschlagenes Script sowie der Befehl "keep;" stoppen die weitere Verarbeitung <b>nicht</b>.<br>
Prefilter → User scripts → Postfilter → <a href="https://github.com/mailcow/mailcow-dockerized/blob/master/data/conf/dovecot/sieve_after" target="_blank">global sieve postfilter</a>';
$lang['info']['no_action'] = 'Keine Aktion anwendbar';
$lang['edit']['syncjob'] = 'Sync-Job bearbeiten';
$lang['edit']['save'] = 'Änderungen speichern';
$lang['edit']['username'] = 'Benutzername';
$lang['edit']['hostname'] = 'Servername';
$lang['edit']['encryption'] = 'Verschlüsselung';
$lang['edit']['maxage'] = 'Maximales Alter in Tagen einer Nachricht, die kopiert werden soll</br ><small>(0 = alle Nachrichten kopieren)</small>';
$lang['edit']['subfolder2'] = 'Ziel-Ordner<br><small>(leer = kein Unterordner)</small>';
$lang['edit']['mins_interval'] = 'Intervall (min)';
$lang['edit']['maxbytespersecond'] = 'Max. Übertragungsrate in Bytes/s (0 für unlimitiert)';
$lang['edit']['automap'] = 'Ordner automatisch mappen ("Sent items", "Sent" => "Sent" etc.)';
$lang['edit']['skipcrossduplicates'] = 'Duplikate auch über Ordner hinweg überspringen ("first come, first serve")';
$lang['add']['automap'] = 'Ordner automatisch mappen ("Sent items", "Sent" => "Sent" etc.)';
$lang['add']['skipcrossduplicates'] = 'Duplikate auch über Ordner hinweg überspringen ("first come, first serve")';
$lang['edit']['exclude'] = 'Elemente ausschließen (Regex)';
$lang['edit']['max_mailboxes'] = 'Max. Mailboxanzahl:';
$lang['edit']['title'] = 'Objekt bearbeiten';
$lang['edit']['target_address'] = 'Ziel-Adresse(n) <small>(getrennt durch Komma)</small>:';
$lang['edit']['active'] = 'Aktiv';
$lang['edit']['force_pw_update'] = 'Erzwinge Passwortänderung bei nächstem Login';
$lang['edit']['force_pw_update_info'] = 'Dem Benutzer wird lediglich der Zugang zur mailcow UI ermöglicht.';
$lang['edit']['target_domain'] = 'Ziel-Domain:';
$lang['edit']['password'] = 'Passwort:';
$lang['edit']['password_repeat'] = 'Passwort (Wiederholung):';
$lang['edit']['domain_admin'] = 'Domain-Administrator bearbeiten';
$lang['edit']['domain'] = 'Domain bearbeiten';
$lang['edit']['edit_alias_domain'] = 'Alias-Domain bearbeiten';
$lang['edit']['domains'] = 'Domains';
$lang['edit']['alias'] = 'Alias bearbeiten';
$lang['edit']['mailbox'] = 'Mailbox bearbeiten';
$lang['edit']['description'] = 'Beschreibung:';
$lang['edit']['max_aliases'] = 'Max. Aliasse:';
$lang['edit']['max_quota'] = 'Max. Größe per Mailbox (MiB):';
$lang['edit']['domain_quota'] = 'Domain Speicherplatz gesamt (MiB):';
$lang['edit']['backup_mx_options'] = 'Backup MX Optionen:';
$lang['edit']['relay_domain'] = 'Relay Domain';
$lang['edit']['relay_all'] = 'Alle Empfänger-Adressen relayen';
$lang['edit']['relay_all_info'] = '<small>Wenn Sie <b>nicht</b> alle Empfänger-Adressen relayen möchten, müssen Sie eine ("blinde") Mailbox für jede Adresse, die relayt werden soll, erstellen.</small>';
$lang['edit']['full_name'] = 'Voller Name';
$lang['edit']['quota_mb'] = 'Speicherplatz (MiB)';
$lang['edit']['sender_acl'] = 'Darf Nachrichten versenden als';
$lang['edit']['sender_acl_disabled'] = '↳ <span class="label label-danger">Absenderprüfung deaktiviert</span>';
$lang['user']['sender_acl_disabled'] = '<span class="label label-danger">Absenderprüfung deaktiviert</span>';
$lang['edit']['previous'] = 'Vorherige Seite';
$lang['edit']['unchanged_if_empty'] = 'Unverändert, wenn leer';
$lang['edit']['dont_check_sender_acl'] = 'Absender für Domain %s u. Alias-Dom. nicht prüfen';
$lang['edit']['multiple_bookings'] = 'Mehrfaches Buchen';
$lang['edit']['kind'] = 'Art';
$lang['edit']['resource'] = 'Ressource';
$lang['acl']['spam_alias'] = 'Temporäre E-Mail Aliasse';
$lang['acl']['tls_policy'] = 'Verschlüsselungsrichtlinie';
$lang['acl']['spam_score'] = 'Spam Bewertung';
$lang['acl']['spam_policy'] = 'Blacklist/Whitelist';
$lang['acl']['delimiter_action'] = 'Delimiter Aktionen (tags)';
$lang['acl']['syncjobs'] = 'Sync Jobs';
$lang['acl']['eas_reset'] = 'EAS-Cache zurücksetzen';
$lang['acl']['quarantine'] = 'Quarantäne';
$lang['acl']['login_as'] = 'Einloggen als Mailbox-Benutzer';
$lang['acl']['bcc_maps'] = 'BCC Maps';
$lang['acl']['filters'] = 'Filter';
$lang['acl']['ratelimit'] = 'Rate limit';
$lang['acl']['recipient_maps'] = 'Empfängerumschreibungen';
$lang['acl']['prohibited'] = 'Untersagt durch Richtlinie';
$lang['add']['generate'] = 'generieren';
$lang['add']['syncjob_hint'] = 'Passwörter werden unverschlüsselt abgelegt!';
$lang['add']['hostname'] = 'Servername';
$lang['add']['port'] = 'Port';
$lang['add']['username'] = 'Benutzername';
$lang['add']['enc_method'] = 'Verschlüsselung';
$lang['add']['mins_interval'] = 'Abrufintervall (Minuten)';
$lang['add']['exclude'] = 'Elemente ausschließen (Regex)';
$lang['add']['delete2duplicates'] = 'Lösche Duplikate im Ziel';
$lang['add']['delete1'] = 'Lösche Nachricht nach Übertragung vom Quell-Server';
$lang['add']['delete2'] = 'Lösche Nachrichten von Ziel-Server, die nicht auf Quell-Server vorhanden sind';
$lang['add']['custom_params'] = 'Eigene Parameter';
$lang['add']['subscribeall'] = 'Alle synchronisierten Ordner abonnieren';
$lang['add']['timeout1'] = 'Timeout für Verbindung zum Remote-Host';
$lang['add']['timeout2'] = 'Timeout für Verbindung zum lokalen Host';
$lang['edit']['delete2duplicates'] = 'Lösche Duplikate im Ziel';
$lang['edit']['delete1'] = 'Lösche Nachricht nach Übertragung vom Quell-Server';
$lang['edit']['delete2'] = 'Lösche Nachrichten von Ziel-Server, die nicht auf Quell-Server vorhanden sind';
$lang['add']['domain_matches_hostname'] = 'Domain %s darf nicht dem Hostnamen entsprechen';
$lang['add']['domain'] = 'Domain';
$lang['add']['active'] = 'Aktiv';
$lang['add']['multiple_bookings'] = 'Mehrfaches Buchen möglich';
$lang['add']['description'] = 'Beschreibung';
$lang['add']['max_aliases'] = 'Max. mögliche Aliasse';
$lang['add']['max_mailboxes'] = 'Max. mögliche Mailboxen';
$lang['add']['mailbox_quota_m'] = 'Max. Speicherplatz pro Mailbox (MiB)';
$lang['add']['domain_quota_m'] = 'Domain Speicherplatz gesamt (MiB)';
$lang['add']['backup_mx_options'] = 'Backup MX Optionen';
$lang['add']['relay_all'] = 'Alle Empfänger-Adressen relayen';
$lang['add']['relay_domain'] = 'Relay Domain';
$lang['add']['relay_all_info'] = '<small>Wenn Sie <b>nicht</b> alle Empfänger-Adressen relayen möchten, müssen Sie eine Mailbox für jede Adresse, die relayt werden soll, erstellen.</small>';
$lang['add']['alias_address'] = 'Alias-Adresse(n)';
$lang['add']['alias_address_info'] = '<small>Vollständige E-Mail-Adresse(n) oder @example.com, um alle Nachrichten einer Domain weiterzuleiten. Getrennt durch Komma. <b>Nur eigene Domains</b>.</small>';
$lang['add']['alias_domain_info'] = '<small>Nur gültige Domains. Getrennt durch Komma.</small>';
$lang['add']['target_address'] = 'Ziel-Adresse(n)';
$lang['add']['target_address_info'] = '<small>Vollständige E-Mail-Adresse(n). Getrennt durch Komma.</small>';
$lang['add']['alias_domain'] = 'Alias-Domain';
$lang['add']['select'] = 'Bitte auswählen';
$lang['add']['target_domain'] = 'Ziel-Domain';
$lang['add']['kind'] = 'Art';
$lang['add']['mailbox_username'] = 'Benutzername (linker Teil der E-Mail-Adresse)';
$lang['add']['full_name'] = 'Vor- und Zuname';
$lang['add']['quota_mb'] = 'Speicherplatz (MiB)';
$lang['add']['select_domain'] = 'Bitte zuerst eine Domain auswählen';
$lang['add']['password'] = 'Passwort';
$lang['add']['password_repeat'] = 'Passwort (Wiederholung)';
$lang['add']['restart_sogo_hint'] = 'Der SOGo Container muss nach dem Hinzufügen einer neuen Domain neugestartet werden!';
$lang['add']['goto_null'] = 'Nachrichten sofort verwerfen';
$lang['add']['goto_ham'] = 'Nachrichten als <span class="text-success"><b>Ham</b></span> lernen';
$lang['add']['goto_spam'] = 'Nachrichten als <span class="text-danger"><b>Spam</b></span> lernen';
$lang['add']['validation_success'] = 'Erfolgreich validiert';
$lang['add']['activate_filter_warn'] = 'Alle anderen Filter diesen Typs werden deaktiviert, falls dieses Script aktiv markiert wird.';
$lang['add']['validate'] = 'Validieren';
$lang['mailbox']['add_filter'] = 'Filter erstellen';
$lang['add']['sieve_desc'] = 'Kurze Beschreibung';
$lang['edit']['sieve_desc'] = 'Kurze Beschreibung';
$lang['add']['sieve_type'] = 'Filtertyp';
$lang['edit']['sieve_type'] = 'Filtertyp';
$lang['mailbox']['set_prefilter'] = 'Als Prefilter markieren';
$lang['mailbox']['set_postfilter'] = 'Als Postfilter markieren';
$lang['mailbox']['filters'] = 'Filter';
$lang['mailbox']['sync_jobs'] = 'Synchronisationen';
$lang['mailbox']['inactive'] = 'Inaktiv';
$lang['edit']['validate_save'] = 'Validieren und speichern';
$lang['login']['username'] = 'Benutzername';
$lang['login']['password'] = 'Passwort';
$lang['login']['login'] = 'Anmelden';
$lang['login']['delayed'] = 'Login wurde zur Sicherheit um %s Sekunde/n verzögert.';
$lang['tfa']['tfa'] = "Zwei-Faktor-Authentifizierung";
$lang['tfa']['set_tfa'] = "Konfiguriere Zwei-Faktor-Authentifizierungsmethode";
$lang['tfa']['yubi_otp'] = "Yubico OTP Authentifizierung";
$lang['tfa']['key_id'] = "Ein Name für diesen YubiKey";
$lang['tfa']['key_id_totp'] = "Ein eindeutiger Name";
$lang['tfa']['api_register'] = 'mailcow verwendet die Yubico Cloud API. Ein API-Key für den Yubico Stick kann <a href="https://upgrade.yubico.com/getapikey/" target="_blank">hier</a> bezogen werden.';
$lang['tfa']['u2f'] = "U2F Authentifizierung";
$lang['tfa']['totp'] = "TOTP Authentifizierung";
$lang['tfa']['none'] = "Deaktiviert";
$lang['tfa']['delete_tfa'] = "Deaktiviere 2FA";
$lang['tfa']['disable_tfa'] = "Deaktiviere 2FA bis zur nächsten erfolgreichen Anmeldung";
$lang['tfa']['confirm'] = "Bestätigen";
$lang['tfa']['totp'] = "Time-based OTP (Google Authenticator etc.)";
$lang['tfa']['select'] = "Bitte auswählen";
$lang['tfa']['waiting_usb_auth'] = "<i>Warte auf USB-Gerät...</i><br><br>Bitte jetzt den vorgesehenen Taster des U2F USB-Gerätes berühren.";
$lang['tfa']['waiting_usb_register'] = "<i>Warte auf USB-Gerät...</i><br><br>Bitte zuerst das obere Passwortfeld ausfüllen und erst dann den vorgesehenen Taster des U2F USB-Gerätes berühren.";
$lang['tfa']['scan_qr_code'] = "Bitte scannen Sie jetzt den angezeigten QR-Code:.";
$lang['tfa']['enter_qr_code'] = "Falls Sie den angezeigten QR-Code nicht scannen können, verwenden Sie bitte nachstehenden Sicherheitsschlüssel";
$lang['tfa']['confirm_totp_token'] = "Bitte bestätigen Sie die Änderung durch Eingabe eines generierten Tokens";
$lang['admin']['rspamd-com_settings'] = '<a href="https://rspamd.com/doc/configuration/settings.html#settings-structure" target="_blank">Rspamd docs</a>
- Ein Name wird automatisch generiert. Beispielinhalte zur Einsicht stehen nachstehend bereit.';
$lang['admin']['no_new_rows'] = 'Keine weiteren Zeilen vorhanden';
$lang['admin']['additional_rows'] = ' zusätzliche Zeilen geladen'; // parses to 'n additional rows were added'
$lang['admin']['private_key'] = 'Private Key';
$lang['admin']['import'] = 'Importieren';
$lang['admin']['duplicate'] = 'Duplizieren';
$lang['admin']['import_private_key'] = 'Private Key importieren';
$lang['admin']['duplicate_dkim'] = 'DKIM duplizieren';
$lang['admin']['f2b_parameters'] = 'Fail2ban Parameter';
$lang['admin']['f2b_ban_time'] = 'Banzeit (s)';
$lang['admin']['f2b_max_attempts'] = 'Max. Versuche';
$lang['admin']['f2b_retry_window'] = 'Wiederholungen im Zeitraum von (s)';
$lang['admin']['f2b_netban_ipv4'] = 'Netzbereich für IPv4 Bans (8-32)';
$lang['admin']['f2b_netban_ipv6'] = 'Netzbereich für IPv6 Bans (8-128)';
$lang['admin']['f2b_whitelist'] = 'Whitelist für Netzwerke und Hosts';
$lang['admin']['r_inactive'] = 'Inaktive Restriktionen';
$lang['admin']['r_active'] = 'Aktive Restriktionen';
$lang['admin']['r_info'] = 'Ausgegraute/deaktivierte Elemente sind mailcow nicht bekannt und können nicht in die Liste inaktiver Elemente verschoben werden. Unbekannte Restriktionen werden trotzdem in Reihenfolge der Erscheinung gesetzt.<br>Sie können ein Element in der Datei <code>inc/vars.local.inc.php</code> als bekannt hinzufügen, um es zu bewegen.';
$lang['admin']['save'] = 'Änderungen speichern';
$lang['admin']['dkim_add_key'] = 'ARC/DKIM-Key hinzufügen';
$lang['admin']['dkim_keys'] = 'ARC/DKIM-Keys';
$lang['admin']['dkim_key_valid'] = 'Key gültig';
$lang['admin']['dkim_key_unused'] = 'Key ohne Zuweisung';
$lang['admin']['dkim_key_missing'] = 'Key fehlt';
$lang['admin']['dkim_from'] = 'Von';
$lang['admin']['dkim_to'] = 'Nach';
$lang['admin']['dkim_from_title'] = 'Quellobjekt für Duplizierung';
$lang['admin']['dkim_to_title'] = 'Ziel-Objekt(e) werden überschrieben';
$lang['admin']['dkim_domains_wo_keys'] = "Domains mit fehlenden Keys auswählen";
$lang['admin']['add'] = 'Hinzufügen';
$lang['add']['add_domain_restart'] = 'Domain hinzufügen und SOGo neustarten';
$lang['add']['add_domain_only'] = 'Nur Domain hinzufügen';
$lang['admin']['configuration'] = 'Konfiguration';
$lang['admin']['password'] = 'Passwort';
$lang['admin']['password_repeat'] = 'Passwort (Wiederholung)';
$lang['admin']['active'] = 'Aktiv';
$lang['admin']['inactive'] = 'Inaktiv';
$lang['admin']['action'] = 'Aktion';
$lang['admin']['add_domain_admin'] = 'Domain-Administrator hinzufügen';
$lang['admin']['add_settings_rule'] = 'Rspamd Regel hinzufügen';
$lang['admin']['rsetting_desc'] = 'Kurze Beschreibung';
$lang['admin']['rsetting_content'] = 'Regelinhalt';
$lang['admin']['rsetting_none'] = 'Keine Regel hinterlegt';
$lang['admin']['rsetting_no_selection'] = 'Bitte eine Regel auswählen';
$lang['admin']['rsettings_preset_1'] = 'Alles außer DKIM and Ratelimits für authentifizierte Benutzer deaktivieren"';
$lang['admin']['rsettings_preset_2'] = 'Spam an Postmaster-Addressen nicht blockieren';
$lang['admin']['rsettings_insert_preset'] = 'Beispiel "%s" laden';
$lang['admin']['rsetting_add_rule'] = 'Regel hinzufügen';
$lang['admin']['admin_domains'] = 'Domain-Zuweisungen';
$lang['admin']['domain_admins'] = 'Domain-Administratoren';
$lang['admin']['username'] = 'Benutzername';
$lang['admin']['edit'] = 'Bearbeiten';
$lang['admin']['remove'] = 'Entfernen';
$lang['admin']['save'] = 'Änderungen speichern';
$lang['admin']['admin'] = 'Administrator';
$lang['admin']['admin_details'] = 'Administrator bearbeiten';
$lang['admin']['unchanged_if_empty'] = 'Unverändert, wenn leer';
$lang['admin']['yes'] = '&#10004;';
$lang['admin']['no'] = '&#10008;';
$lang['admin']['access'] = 'Zugang';
$lang['admin']['no_record'] = 'Kein Eintrag';
$lang['admin']['filter_table'] = 'Tabelle Filtern';
$lang['admin']['empty'] = 'Keine Einträge vorhanden';
$lang['admin']['time'] = 'Zeit';
$lang['admin']['priority'] = 'Gewichtung';
$lang['admin']['refresh'] = 'Neu laden';
$lang['admin']['to_top'] = 'Nach oben';
$lang['admin']['in_use_by'] = 'Verwendet von';
$lang['admin']['message'] = 'Nachricht';
$lang['admin']['forwarding_hosts'] = 'Weiterleitungs-Hosts';
$lang['admin']['forwarding_hosts_hint'] = 'Eingehende Nachrichten werden von den hier gelisteten Hosts bedingungslos akzeptiert. Diese Hosts werden dann nicht mit DNSBLs abgeglichen oder Greylisting unterworfen. Von ihnen empfangener Spam wird nie abgelehnt, optional kann er aber in den Spam-Ordner einsortiert werden. Die übliche Verwendung für diese Funktion ist, um Mailserver anzugeben, auf denen eine Weiterleitung zu Ihrem mailcow-Server eingerichtet wurde.';
$lang['admin']['forwarding_hosts_add_hint'] = 'Sie können entweder IPv4/IPv6-Adressen, Netzwerke in CIDR-Notation, Hostnamen (die zu IP-Adressen aufgelöst werden), oder Domainnamen (die zu IP-Adressen aufgelöst werden, indem ihr SPF-Record abgefragt wird oder, in dessen Abwesenheit, ihre MX-Records) angeben.';
$lang['admin']['relayhosts_hint'] = 'Erstellen Sie Relayhosts, um diese im Einstellungsdialog einer Domain auszuwählen.';
$lang['admin']['add_relayhost_add_hint'] = 'Bitte beachten Sie, dass Relayhost Anmeldedaten im Klartext gespeichert werden.';
$lang['admin']['host'] = 'Host';
$lang['admin']['source'] = 'Quelle';
$lang['admin']['add_forwarding_host'] = 'Weiterleitungs-Host hinzufügen';
$lang['admin']['add_relayhost'] = 'Relayhost hinzufügen';
$lang['admin']['api_allow_from'] = "IP-Adressen für Zugriff";
$lang['admin']['api_key'] = "API-Key";
$lang['admin']['activate_api'] = "API aktivieren";
$lang['admin']['regen_api_key'] = "API-Key regenerieren";
$lang['admin']['ban_list_info'] = "Übersicht ausgesperrter Netzwerke: <b>Netzwerk (verbleibende Banzeit) - [Aktionen]</b>.<br />IPs, die zum Unban eingereiht werden, verlassen die Liste aktiver Bans nach wenigen Sekunden.<br />Rote Labels sind Indikatoren für aktive Blacklisteinträge.";
$lang['admin']['unban_pending'] = "ausstehend";
$lang['admin']['queue_unban'] = "Unban einreihen";
$lang['admin']['no_active_bans'] = "Keine aktiven Bans";
$lang['admin']['quarantine'] = "Quarantäne";
$lang['admin']['quarantine_retention_size'] = "Rückhaltungen pro Mailbox<br />0 bedeutet <b>inaktiv</b>!";
$lang['admin']['quarantine_max_size'] = "Maximale Größe in MiB (größere Elemente werden verworfen)<br />0 bedeutet <b>nicht</b> unlimitert!";
$lang['admin']['quarantine_exclude_domains'] = "Domains und Alias-Domains ausschließen:";
$lang['success']['forwarding_host_removed'] = "Weiterleitungs-Host %s wurde entfernt";
$lang['success']['forwarding_host_added'] = "Weiterleitungs-Host %s wurde hinzugefügt";
$lang['success']['relayhost_removed'] = "Relayhost %s wurde entfernt";
$lang['success']['relayhost_added'] = "Relayhost %s wurde hinzugefügt";
$lang['diagnostics']['dns_records'] = 'DNS-Einträge';
$lang['diagnostics']['dns_records_24hours'] = 'Bitte beachten Sie, dass es bis zu 24 Stunden dauern kann, bis Änderungen an Ihren DNS-Einträgen als aktueller Status auf dieser Seite dargestellt werden. Diese Seite ist nur als Hilfsmittel gedacht, um die korrekten Werte für DNS-Einträge zu anzuzeigen und zu überprüfen, ob die Daten im DNS hinterlegt sind.';
$lang['diagnostics']['dns_records_name'] = 'Name';
$lang['diagnostics']['dns_records_type'] = 'Typ';
$lang['diagnostics']['dns_records_data'] = 'Korrekte Daten';
$lang['diagnostics']['dns_records_status'] = 'Aktueller Status';
$lang['diagnostics']['optional'] = 'Dieser Eintrag ist optional.';
$lang['diagnostics']['cname_from_a'] = 'Wert abgeleitet von A/AAAA Eintrag. Wird unterstützt, sofern der Eintrag auf die korrekte Ressource zeigt.';
$lang['admin']['relay_from'] = "Absenderadresse";
$lang['admin']['relay_run'] = "Test durchführen";
$lang['mailbox']['waiting'] = "Wartend";
$lang['mailbox']['status'] = "Status";
$lang['mailbox']['running'] = "In Ausführung";
$lang['admin']['ui_texts'] = "UI Label und Texte";
$lang['admin']['help_text'] = "Hilfstext unter Login-Maske (HTML zulässig)";
$lang['admin']['title_name'] = '"mailcow UI" Webseiten Titel';
$lang['admin']['main_name'] = '"mailcow UI" Name';
$lang['admin']['apps_name'] = '"mailcow Apps" Name';
$lang['admin']['customize'] = "UI Anpassung";
$lang['admin']['change_logo'] = "Logo ändern";
$lang['admin']['logo_info'] = "Die hochgeladene Grafik wird für die Navigationsleiste auf eine Höhe von 40px skaliert. Für die Darstellung auf der Login-Maske beträgt die skalierte Breite maximal 250px. Eine frei skalierbare Grafik (etwa SVG) wird empfohlen.";
$lang['admin']['upload'] = "Hochladen";
$lang['admin']['app_links'] = "App Links";
$lang['admin']['app_name'] = "App Name";
$lang['admin']['link'] = "Link";
$lang['admin']['remove_row'] = "Entfernen";
$lang['admin']['add_row'] = "Reihe hinzufügen";
$lang['admin']['reset_default'] = "Zurücksetzen auf Standard";
$lang['admin']['merged_vars_hint'] = 'Ausgegraute Reihen wurden aus der Datei <code>vars.(local.)inc.php</code> gelesen und können hier nicht verändert werden.';
$lang['edit']['spam_score'] = "Einen benutzerdefiniterten Spam-Score festlegen";
$lang['edit']['spam_policy'] = "Hinzufügen und Entfernen von Einträgen in White- und Blacklists";
$lang['edit']['spam_alias'] = "Anpassen temporärer Alias-Adressen";
$lang['danger']['img_tmp_missing'] = "Grafik konnte nicht validiert werden: Erstellung temporärer Datei fehlgeschlagen";
$lang['danger']['img_invalid'] = "Grafik konnte nicht validiert werden";
$lang['danger']['invalid_mime_type'] = "Grafik konnte nicht validiert werden: Ungültiger MIME-Type";
$lang['success']['upload_success'] = "Datei wurde erfolgreich hochgeladen";
$lang['success']['app_links'] = "Änderungen an App Links wurden gespeichert";
$lang['success']['ui_texts'] = "Änderungen an UI-Texten";
$lang['success']['reset_main_logo'] = "Standardgrafik wurde wiederhergestellt";
$lang['success']['items_released'] = "Ausgewählte Objekte wurden an Mailbox versendet";
$lang['danger']['imagick_exception'] = "Fataler Bildverarbeitungsfehler";
$lang['quarantine']['learn_spam_delete'] = "Als Spam lernen und löschen";
$lang['quarantine']['quarantine'] = "Quarantäne";
$lang['quarantine']['qinfo'] = 'Das Quarantänesystem speichert abgelehnte Nachrichten in der Datenbank. Dem Sender wird <em>nicht</em> signalisiert, dass seine E-Mail zugestellt wurde.
<br>"' . $lang['quarantine']['learn_spam_delete'] . '" lernt Nachrichten nach bayesscher Statistik als Spam und erstellt Fuzzy Hashes ausgehend von der jeweiligen Nachricht, um ähnliche Inhalte zukünftig zu unterbinden.
<br>Der Prozess des Lernens kann abhängig vom System zeitintensiv sein.';
$lang['quarantine']['release'] = "Freigeben";
$lang['quarantine']['empty'] = 'Keine Einträge';
$lang['quarantine']['toggle_all'] = 'Alle auswählen';
$lang['quarantine']['quick_actions'] = 'Aktionen';
$lang['quarantine']['remove'] = 'Entfernen';
$lang['quarantine']['received'] = "Empfangen";
$lang['quarantine']['action'] = "Aktion";
$lang['quarantine']['rcpt'] = "Empfänger";
$lang['quarantine']['qid'] = "Rspamd QID";
$lang['quarantine']['sender'] = "Sender";
$lang['quarantine']['show_item'] = "Details";
$lang['quarantine']['check_hash'] = "Checksumme auf VirusTotal suchen";
$lang['quarantine']['qitem'] = "Quarantäneeintrag";
$lang['quarantine']['subj'] = "Betreff";
$lang['quarantine']['text_plain_content'] = "Inhalt (text/plain)";
$lang['quarantine']['text_from_html_content'] = "Inhalt (html, konvertiert)";
$lang['quarantine']['atts'] = "Anhänge";
$lang['warning']['fuzzy_learn_error'] = "Fuzzy Lernfehler: %s";
$lang['danger']['spam_learn_error'] = "Spam Lernfehler: %s";
$lang['success']['qlearn_spam'] = "Nachricht ID %s wurde als Spam gelernt und gelöscht";
$lang['header']['quarantine'] = "Quarantäne";
$lang['header']['debug'] = "Debugging";
$lang['debug']['log_info'] = '<p>mailcow <b>in-memory Logs</b> werden in Redis Listen gespeichert, die maximale Anzahl der Einträge pro Anwendung richtet sich nach LOG_LINES (%d).
<br>In-memory Logs sind vergänglich und nicht zur ständigen Aufbewahrung bestimmt. Alle Anwendungen, die in-memory protokollieren, schreiben ebenso in den Docker Daemon.
<br>Das in-memory Protokoll versteht sich als schnelle Übersicht zum Debugging eines Containers, für komplexere Protokolle sollte der Docker Daemon konsultiert werden.</p>
<p><b>Externe Logs</b> werden via API externer Applikationen bezogen.</p>
<p><b>Statische Logs</b> sind weitesgehend Aktivitätsprotokolle, die nicht in den Docker Daemon geschrieben werden, jedoch permanent verfügbar sein müssen (ausgeschloßen API Logs).</p>';
$lang['debug']['in_memory_logs'] = 'In-memory Logs';
$lang['debug']['external_logs'] = 'Externe Logs';
$lang['debug']['static_logs'] = 'Statische Logs';
$lang['quarantine']['release_body'] = "Die ursprüngliche Nachricht wurde als EML-Datei im Anhang hinterlegt.";
$lang['danger']['release_send_failed'] = "Die Nachricht konnte nicht versendet werden: %s";
$lang['quarantine']['release_subject'] = "Potentiell schädliche Nachricht aus Quarantäne: %s";
$lang['mailbox']['bcc_map'] = "BCC Map";
$lang['mailbox']['bcc_map_type'] = "BCC Typ";
$lang['mailbox']['bcc_type'] = "BCC Typ";
$lang['mailbox']['bcc_sender_map'] = "Senderabhängig";
$lang['mailbox']['bcc_rcpt_map'] = "Empfängerabhängig";
$lang['mailbox']['bcc_local_dest'] = "Lokales Ziel";
$lang['mailbox']['bcc_destinations'] = "BCC Ziel";
$lang['mailbox']['bcc_destination'] = "BCC Ziel";
$lang['edit']['bcc_dest_format'] = 'BCC-Ziel muss eine gültige E-Mail-Adresse sein.';
$lang['mailbox']['bcc'] = "BCC";
$lang['mailbox']['bcc_maps'] = "BCC-Maps";
$lang['mailbox']['bcc_to_sender'] = "Map senderabhängig verwenden";
$lang['mailbox']['bcc_to_rcpt'] = "Map empfängerabhängig verwenden";
$lang['mailbox']['add_bcc_entry'] = "BCC-Eintrag hinzufügen";
$lang['mailbox']['bcc_info'] = "Eine empfängerabhängige Map wird verwendet, wenn die BCC-Map Eintragung auf den Eingang einer E-Mail auf das lokale Ziel reagieren soll. Senderabhängige Maps verfahren nach dem gleichen Prinzip.<br/>
Das lokale Ziel wird bei Fehlzustellungen an ein BCC-Ziel nicht informiert.";
$lang['mailbox']['address_rewriting'] = 'Adressumschreibung';
$lang['mailbox']['recipient_maps'] = 'Empfängerumschreibungen';
$lang['mailbox']['recipient_map'] = 'Empfängerumschreibung';
$lang['mailbox']['recipient_map_info'] = 'Empfängerumschreibung ersetzen den Empfänger einer E-Mail vor dem Versand.';
$lang['mailbox']['recipient_map_old_info'] = 'Der originale Empfänger muss eine E-Mail-Adresse oder ein Domainname sein.';
$lang['mailbox']['recipient_map_new_info'] = 'Der neue Empfänger muss eine E-Mail-Adresse sein.';
$lang['mailbox']['recipient_map_old'] = 'Original Empfänger';
$lang['mailbox']['recipient_map_new'] = 'Neuer Empfänger';
$lang['mailbox']['add_recipient_map_entry'] = 'Empfängerumschreibung hinzufügen';
-$lang['danger']['invalid_recipient_map_new'] = 'Neuer Empfänger %s ist ungültig';
-$lang['danger']['invalid_recipient_map_old'] = 'Originaler Empfänger %s ist ungültig';
-$lang['danger']['recipient_map_entry_exists'] = 'Eine Empfängerumschreibung für %s existiert bereits';
-$lang['success']['recipient_map_entry_saved'] = 'Empfängerumschreibung für Objekt %s wurde gespeichert';
-$lang['success']['recipient_map_entry_deleted'] = 'Empfängerumschreibung für Objekt %s wurde gelöscht';
-
+$lang['danger']['invalid_recipient_map_new'] = 'Neuer Empfänger "%s" ist ungültig';
+$lang['danger']['invalid_recipient_map_old'] = 'Originaler Empfänger "%s" ist ungültig';
+$lang['danger']['recipient_map_entry_exists'] = 'Eine Empfängerumschreibung für Objekt "%s" existiert bereits';
+$lang['success']['recipient_map_entry_saved'] = 'Empfängerumschreibung für Objekt "%s" wurde gespeichert';
+$lang['success']['recipient_map_entry_deleted'] = 'Empfängerumschreibung mit der ID %s wurde gelöscht';
+$lang['danger']['tls_policy_map_entry_exists'] = 'Eine TLS-Richtlinie "%s" existiert bereits';
+$lang['success']['tls_policy_map_entry_saved'] = 'TLS-Richtlinieneintrag "%s" wurde gespeichert';
+$lang['success']['tls_policy_map_entry_deleted'] = 'TLS-Richtlinie mit der ID %s wurde gelöscht';
+$lang['mailbox']['add_tls_policy_map'] = "TLS-Richtlinieneintrag hinzufügen";
+$lang['danger']['tls_policy_map_parameter_invalid'] = "Parameter ist ungültig";
diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php
index 9e5dc9ec..195bceb2 100644
--- a/data/web/lang/lang.en.php
+++ b/data/web/lang/lang.en.php
@@ -1,693 +1,709 @@
<?php
/*
* English language file
*/
$lang['footer']['loading'] = "Please wait...";
$lang['header']['restart_sogo'] = 'Restart SOGo';
$lang['header']['restart_netfilter'] = 'Restart netfilter';
$lang['footer']['restart_container'] = 'Restart container';
$lang['footer']['restart_now'] = 'Restart now';
$lang['footer']['restarting_container'] = 'Restarting container, this may take a while...';
$lang['footer']['restart_container_info'] = '<b>Important:</b> A graceful restart may take a while to complete, please wait for it to finish.';
$lang['footer']['confirm_delete'] = 'Confirm deletion';
$lang['footer']['delete_these_items'] = 'Please confirm your changes to the following object id:';
$lang['footer']['delete_now'] = 'Delete now';
$lang['footer']['cancel'] = 'Cancel';
$lang['footer']['hibp_nok'] = 'Matched! This is a potentially dangerous password!';
$lang['footer']['hibp_ok'] = 'No match found.';
$lang['danger']['mysql_error'] = "MySQL error: %s";
$lang['danger']['redis_error'] = "Redis error: %s";
$lang['danger']['unknown_tfa_method'] = "Unknown TFA method";
$lang['danger']['totp_verification_failed'] = "TOTP verification failed";
$lang['success']['verified_totp_login'] = "Verified TOTP login";
$lang['danger']['u2f_verification_failed'] = "U2F verification failed: %s";
$lang['success']['verified_u2f_login'] = "Verified U2F login";
$lang['success']['verified_yotp_login'] = "Verified Yubico OTP login";
$lang['danger']['yotp_verification_failed'] = "Yubico OTP verification failed: %s";
$lang['danger']['ip_list_empty'] = "List of allowed IPs cannot be empty";
$lang['danger']['rspamd_ui_pw_length'] = "Rspamd UI password should be at least 6 chars long";
$lang['success']['rspamd_ui_pw_set'] = "Rspamd UI password successfully set";
$lang['danger']['unknown'] = "An unknown error occured";
$lang['danger']['malformed_username'] = "Malformed username";
$lang['info']['awaiting_tfa_confirmation'] = "Awaiting TFA confirmation";
$lang['success']['logged_in_as'] = "Logged in as %s";
$lang['danger']['login_failed'] = "Login failed";
$lang['danger']['set_acl_failed'] = "Failed to set ACL";
$lang['danger']['no_user_defined'] = "No user defined";
$lang['danger']['script_empty'] = "Script cannot be empty";
$lang['danger']['sieve_error'] = "Sieve parser error: %s";
$lang['danger']['value_missing'] = "Please provide all values";
$lang['danger']['filter_type'] = "Wrong filter type";
$lang['danger']['domain_cannot_match_hostname'] = "Domain cannot match hostname";
$lang['warning']['domain_added_sogo_failed'] = "Added domain but failed to restart SOGo, please check your server logs.";
$lang['danger']['rl_timeframe'] = "Rate limit time frame is incorrect";
$lang['success']['rl_saved'] = "Rate limit for object %s saved";
$lang['success']['acl_saved'] = "ACL for object %s saved";
$lang['success']['deleted_syncjobs'] = "Deleted syncjobs: %s";
$lang['success']['deleted_syncjob'] = "Deleted syncjob ID %s";
$lang['success']['delete_filters'] = "Deleted filters: %s";
$lang['success']['delete_filter'] = "Deleted filters ID %s";
$lang['danger']['invalid_bcc_map_type'] = "Invalid BCC map type";
$lang['danger']['bcc_empty'] = "BCC destination cannot be empty";
$lang['danger']['bcc_must_be_email'] = "BCC map %s is not a valid email address";
$lang['danger']['bcc_exists'] = "A BCC map %s exists for type %s";
$lang['success']['bcc_saved'] = "BCC map entry saved";
$lang['success']['bcc_edited'] = "BCC map entry %s edited";
$lang['success']['bcc_deleted'] = "BCC map entries deleted: %s";
$lang['danger']['private_key_error'] = "Private key error: %s";
$lang['danger']['map_content_empty'] = "Map content cannot be empty";
$lang['success']['settings_map_added'] = "Added settings map entry";
$lang['danger']['settings_map_invalid'] = "Settings map ID %s invalid";
$lang['danger']['settings_map_removed'] = "Removed settings map deleted: %s";
$lang['danger']['invalid_host'] = "Invalid host specified: %s";
$lang['danger']['relayhost_invalid'] = "Relayhost %s is invalid";
$lang['success']['saved_settings'] = "Saved settings";
$lang['success']['db_init_complete'] = "Database initialization completed";
$lang['warning']['session_ua'] = "Form token invalid: User-Agent validation error";
$lang['warning']['session_token'] = "Form token invalid: Token mismatch";
$lang['danger']['dkim_domain_or_sel_invalid'] = "DKIM domain or selector invalid: %s";
$lang['success']['dkim_removed'] = "DKIM key %s has been removed";
$lang['success']['dkim_added'] = "DKIM key %s has been saved";
$lang['success']['dkim_duplicated'] = "DKIM key for domain %s has been copied to %s";
$lang['danger']['access_denied'] = "Access denied or invalid form data";
$lang['danger']['domain_invalid'] = "Domain name %s is invalid";
$lang['danger']['mailbox_quota_exceeds_domain_quota'] = "Max. quota exceeds domain quota limit";
$lang['danger']['object_is_not_numeric'] = "Value %s is not numeric";
$lang['success']['domain_added'] = "Added domain %s";
$lang['success']['items_deleted'] = "Item %s successfully deleted";
$lang['success']['item_deleted'] = "Item %s successfully deleted";
$lang['danger']['alias_empty'] = "Alias address must not be empty";
$lang['danger']['last_key'] = 'Last key cannot be deleted';
$lang['danger']['goto_empty'] = "Goto address must not be empty";
$lang['danger']['policy_list_from_exists'] = "A record with given name exists";
$lang['danger']['policy_list_from_invalid'] = "Record has invalid format";
$lang['danger']['alias_invalid'] = "Alias address %s is invalid";
$lang['danger']['goto_invalid'] = "Goto address %s is invalid";
$lang['danger']['alias_domain_invalid'] = "Alias domain %s is invalid";
$lang['danger']['target_domain_invalid'] = "Target domain %s is invalid";
$lang['danger']['object_exists'] = "Object %s already exists";
$lang['danger']['domain_exists'] = "Domain %s already exists";
$lang['danger']['alias_goto_identical'] = "Alias and goto address must not be identical";
$lang['danger']['aliasd_targetd_identical'] = "Alias domain must not be equal to target domain: %s";
$lang['danger']['maxquota_empty'] = 'Max. quota per mailbox must not be 0.';
$lang['success']['alias_added'] = "Alias address %s has been added";
$lang['success']['alias_modified'] = "Changes to alias address %s have been saved";
$lang['success']['mailbox_modified'] = "Changes to mailbox %s have been saved";
$lang['success']['resource_modified'] = "Changes to mailbox %s have been saved";
$lang['success']['object_modified'] = "Changes to object %s have been saved";
$lang['success']['f2b_modified'] = "Changes to Fail2ban parameters have been saved";
$lang['danger']['targetd_not_found'] = "Target domain %s not found";
$lang['success']['aliasd_added'] = "Added alias domain %s";
$lang['success']['aliasd_modified'] = "Changes to alias domain %s have been saved";
$lang['success']['domain_modified'] = "Changes to domain %s have been saved";
$lang['success']['domain_admin_modified'] = "Changes to domain administrator %s have been saved";
$lang['success']['domain_admin_added'] = "Domain administrator %s has been added";
$lang['success']['admin_modified'] = "Changes to administrator have been saved";
$lang['danger']['username_invalid'] = "Username %s cannot be used";
$lang['danger']['password_mismatch'] = "Confirmation password does not match";
$lang['danger']['password_complexity'] = "Password does not meet the policy";
$lang['danger']['password_empty'] = "Password must not be empty";
$lang['danger']['login_failed'] = "Login failed";
$lang['danger']['mailbox_invalid'] = "Mailbox name is invalid";
$lang['danger']['description_invalid'] = 'Resource description for %s is invalid';
$lang['danger']['resource_invalid'] = "Resource name %s is invalid";
$lang['danger']['is_alias'] = "%s is already known as an alias address";
$lang['danger']['is_alias_or_mailbox'] = "%s is already known as an alias, a mailbox or an alias address expanded from an alias domain.";
$lang['danger']['is_spam_alias'] = "%s is already known as a spam alias address";
$lang['danger']['quota_not_0_not_numeric'] = "Quota must be numeric and >= 0";
$lang['danger']['domain_not_found'] = 'Domain %s not found';
$lang['danger']['max_mailbox_exceeded'] = "Max. mailboxes exceeded (%d of %d)";
$lang['danger']['max_alias_exceeded'] = 'Max. aliases exceeded';
$lang['danger']['mailbox_quota_exceeded'] = "Quota exceeds the domain limit (max. %d MiB)";
$lang['danger']['mailbox_quota_left_exceeded'] = "Not enough space left (space left: %d MiB)";
$lang['success']['mailbox_added'] = "Mailbox %s has been added";
$lang['success']['resource_added'] = "Resource %s has been added";
$lang['success']['domain_removed'] = "Domain %s has been removed";
$lang['success']['alias_removed'] = "Alias %s has been removed";
$lang['success']['alias_domain_removed'] = "Alias domain %s has been removed";
$lang['success']['domain_admin_removed'] = "Domain administrator %s has been removed";
$lang['success']['mailbox_removed'] = "Mailbox %s has been removed";
$lang['success']['eas_reset'] = "ActiveSync devices for user %s were reset";
$lang['success']['resource_removed'] = "Resource %s has been removed";
$lang['danger']['max_quota_in_use'] = "Mailbox quota must be greater or equal to %d MiB";
$lang['danger']['domain_quota_m_in_use'] = "Domain quota must be greater or equal to %s MiB";
$lang['danger']['mailboxes_in_use'] = "Max. mailboxes must be greater or equal to %d";
$lang['danger']['aliases_in_use'] = "Max. aliases must be greater or equal to %d";
$lang['danger']['sender_acl_invalid'] = "Sender ACL value %s is invalid";
$lang['danger']['domain_not_empty'] = "Cannot remove non-empty domain";
$lang['danger']['validity_missing'] = 'Please assign a period of validity';
$lang['user']['loading'] = "Loading...";
$lang['user']['force_pw_update'] = 'You <b>must</b> set a new password to be able to access groupware related services.';
$lang['user']['active_sieve'] = "Active filter";
$lang['user']['show_sieve_filters'] = "Show active user sieve filter";
$lang['user']['no_active_filter'] = "No active filter available";
$lang['user']['messages'] = "messages"; // "123 messages"
$lang['user']['in_use'] = "Used";
$lang['user']['user_change_fn'] = "";
$lang['user']['user_settings'] = 'User settings';
$lang['user']['mailbox_details'] = 'Mailbox details';
$lang['user']['change_password'] = 'Change password';
$lang['user']['client_configuration'] = 'Show configuration guides for email clients and smartphones';
$lang['user']['new_password'] = 'New password';
$lang['user']['save_changes'] = 'Save changes';
$lang['user']['password_now'] = 'Current password (confirm changes)';
$lang['user']['new_password_repeat'] = 'Confirmation password (repeat)';
$lang['user']['new_password_description'] = 'Requirement: 6 characters long, letters and numbers.';
$lang['user']['spam_aliases'] = 'Temporary email aliases';
$lang['user']['alias'] = 'Alias';
$lang['user']['shared_aliases'] = 'Shared alias addresses';
$lang['user']['shared_aliases_desc'] = 'Shared aliases are not affected by user specific settings such as the spam filter or encryption policy. Corresponding spam filters can only be made by an administrator as a domain-wide policy..';
$lang['user']['direct_aliases'] = 'Direct alias addresses';
$lang['user']['direct_aliases_desc'] = 'Direct alias addresses are affected by spam filter and TLS policy settings.';
$lang['user']['is_catch_all'] = 'Catch-all for domain/s';
$lang['user']['aliases_also_send_as'] = 'Also allowed to send as user';
$lang['user']['aliases_send_as_all'] = 'Do not check sender access for the following domain(s) and its alias domains';
$lang['user']['alias_create_random'] = 'Generate random alias';
$lang['user']['alias_extend_all'] = 'Extend aliases by 1 hour';
$lang['user']['alias_valid_until'] = 'Valid until';
$lang['user']['alias_remove_all'] = 'Remove all aliases';
$lang['user']['alias_time_left'] = 'Time left';
$lang['user']['alias_full_date'] = 'd.m.Y, H:i:s T';
$lang['user']['alias_select_validity'] = 'Period of validity';
$lang['user']['sync_jobs'] = 'Sync jobs';
$lang['user']['hour'] = 'Hour';
$lang['user']['hours'] = 'Hours';
$lang['user']['day'] = 'Day';
$lang['user']['week'] = 'Week';
$lang['user']['weeks'] = 'Weeks';
$lang['user']['spamfilter'] = 'Spam filter';
$lang['admin']['spamfilter'] = 'Spam filter';
$lang['user']['spamfilter_wl'] = 'Whitelist';
$lang['user']['spamfilter_wl_desc'] = 'Whitelisted email addresses to <b>never</b> classify as spam. Wildcards may be used. A filter is only applied to direct aliases (aliases with a single target mailbox) excluding catch-all aliases and a mailbox itself.';
$lang['user']['spamfilter_bl'] = 'Blacklist';
$lang['user']['spamfilter_bl_desc'] = 'Blacklisted email addresses to <b>always</b> classify as spam and reject. Wildcards may be used. A filter is only applied to direct aliases (aliases with a single target mailbox) excluding catch-all aliases and a mailbox itself.';
$lang['user']['spamfilter_behavior'] = 'Rating';
$lang['user']['spamfilter_table_rule'] = 'Rule';
$lang['user']['spamfilter_table_action'] = 'Action';
$lang['user']['spamfilter_table_empty'] = 'No data to display';
$lang['user']['spamfilter_table_remove'] = 'remove';
$lang['user']['spamfilter_table_add'] = 'Add item';
$lang['user']['spamfilter_green'] = 'Green: this message is not spam';
$lang['user']['spamfilter_yellow'] = 'Yellow: this message may be spam, will be tagged as spam and moved to your junk folder';
$lang['user']['spamfilter_red'] = 'Red: This message is spam and will be rejected by the server';
$lang['user']['spamfilter_default_score'] = 'Default values:';
$lang['user']['spamfilter_hint'] = 'The first value describes the "low spam score", the second represents the "high spam score".';
$lang['user']['spamfilter_table_domain_policy'] = "n/a (domain policy)";
$lang['user']['waiting'] = "Waiting";
$lang['user']['status'] = "Status";
$lang['user']['running'] = "Running";
$lang['user']['tls_policy_warning'] = '<strong>Warning:</strong> If you decide to enforce encrypted mail transfer, you may lose emails.<br>Messages to not satisfy the policy will be bounced with a hard fail by the mail system.<br>This option applies to your primary email address (login name), all addresses derived from alias domains as well as alias addresses <b>with only this single mailbox</b> as target.';
$lang['user']['tls_policy'] = 'Encryption policy';
$lang['user']['tls_enforce_in'] = 'Enforce TLS incoming';
$lang['user']['tls_enforce_out'] = 'Enforce TLS outgoing';
$lang['user']['no_record'] = 'No record';
$lang['user']['tag_handling'] = 'Set handling for tagged mail';
$lang['user']['tag_in_subfolder'] = 'In subfolder';
$lang['user']['tag_in_subject'] = 'In subject';
$lang['user']['tag_in_none'] = 'Do nothing';
$lang['user']['tag_help_explain'] = 'In subfolder: a new subfolder named after the tag will be created below INBOX ("INBOX/Facebook").<br>
In subject: the tags name will be prepended to the mails subject, example: "[Facebook] My News".';
$lang['user']['tag_help_example'] = 'Example for a tagged email address: me<b>+Facebook</b>@example.org';
$lang['user']['eas_reset'] = 'Reset ActiveSync device cache';
$lang['user']['eas_reset_now'] = 'Reset now';
$lang['user']['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!';
$lang['user']['encryption'] = 'Encryption';
$lang['user']['username'] = 'Username';
$lang['user']['last_run'] = 'Last run';
$lang['user']['excludes'] = 'Excludes';
$lang['user']['interval'] = 'Interval';
$lang['user']['active'] = 'Active';
$lang['user']['action'] = 'Action';
$lang['user']['edit'] = 'Edit';
$lang['user']['remove'] = 'Remove';
$lang['user']['create_syncjob'] = 'Create new sync job';
$lang['start']['mailcow_apps_detail'] = 'Use a mailcow app to access your mails, calendar, contacts and more.';
$lang['start']['mailcow_panel_detail'] = '<b>Domain administrators</b> create, modify or delete mailboxes and aliases, change domains and read further information about their assigned domains.<br>
<b>Mailbox users</b> are able to create time-limited aliases (spam aliases), change their password and spam filter settings.';
$lang['start']['imap_smtp_server_auth_info'] = 'Please use your full email address and the PLAIN authentication mechanism.<br>
Your login data will be encrypted by the server-side mandatory encryption.';
$lang['start']['help'] = 'Show/Hide help panel';
$lang['header']['mailcow_settings'] = 'Configuration';
$lang['header']['administration'] = 'Administration';
$lang['header']['mailboxes'] = 'Mailboxes';
$lang['header']['user_settings'] = 'User settings';
+$lang['mailbox']['tls_policy_maps'] = 'TLS policy maps';
+$lang['mailbox']['tls_policy_maps_long'] = 'Outgoing TLS policy map overrides';
+$lang['mailbox']['tls_policy_maps_info'] = 'This policy map overrides outgoing TLS transport rules independently of a users TLS policy settings.<br>
+ Please check <a href="http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps" target="_blank">the "smtp_tls_policy_maps" docs</a> for further information.';
+$lang['mailbox']['tls_enforce_in'] = 'Enforce TLS incoming';
+$lang['mailbox']['tls_enforce_out'] = 'Enforce TLS outgoing';
+$lang['mailbox']['tls_map_dest'] = 'Destination';
+$lang['mailbox']['tls_map_dest_info'] = 'Examples: example.org, .example.org, mail@example.org, [mail.example.org]:25';
+$lang['mailbox']['tls_map_policy'] = 'Policy';
+$lang['mailbox']['tls_map_parameters'] = 'Parameters';
+$lang['mailbox']['tls_map_parameters_info'] = 'Empty or parameters, for example: protocols=!SSLv2 ciphers=medium exclude=3DES';
$lang['mailbox']['booking_0'] = 'Always show as free';
$lang['mailbox']['booking_lt0'] = 'Unlimited, but show as busy when booked';
$lang['mailbox']['booking_custom'] = 'Hard-limit to a custom amount of bookings';
$lang['mailbox']['booking_0_short'] = 'Always free';
$lang['mailbox']['booking_lt0_short'] = 'Soft limit';
$lang['mailbox']['booking_custom_short'] = 'Hard limit';
$lang['mailbox']['domain'] = 'Domain';
$lang['mailbox']['spam_aliases'] = 'Temp. alias';
$lang['mailbox']['multiple_bookings'] = 'Multiple bookings';
$lang['mailbox']['kind'] = 'Kind';
$lang['mailbox']['description'] = 'Description';
$lang['mailbox']['alias'] = 'Alias';
$lang['mailbox']['aliases'] = 'Aliases';
$lang['mailbox']['domains'] = 'Domains';
$lang['admin']['domain_s'] = 'Domain/s';
$lang['mailbox']['mailboxes'] = 'Mailboxes';
$lang['mailbox']['resources'] = 'Resources';
$lang['mailbox']['mailbox_quota'] = 'Max. size of a mailbox';
$lang['mailbox']['domain_quota'] = 'Quota';
$lang['mailbox']['active'] = 'Active';
$lang['mailbox']['action'] = 'Action';
$lang['mailbox']['backup_mx'] = 'Backup MX';
$lang['mailbox']['domain_aliases'] = 'Domain aliases';
$lang['mailbox']['target_domain'] = 'Target domain';
$lang['mailbox']['target_address'] = 'Goto address';
$lang['mailbox']['username'] = 'Username';
$lang['mailbox']['fname'] = 'Full name';
$lang['mailbox']['filter_table'] = 'Filter table';
$lang['mailbox']['yes'] = '&#10004;';
$lang['mailbox']['no'] = '&#10008;';
$lang['mailbox']['in_use'] = 'In use (%)';
$lang['mailbox']['msg_num'] = 'Message #';
$lang['mailbox']['remove'] = 'Remove';
$lang['mailbox']['edit'] = 'Edit';
$lang['mailbox']['no_record'] = 'No record for object %s';
$lang['mailbox']['no_record_single'] = 'No record';
$lang['mailbox']['add_domain'] = 'Add domain';
$lang['mailbox']['add_domain_alias'] = 'Add domain alias';
$lang['mailbox']['add_mailbox'] = 'Add mailbox';
$lang['mailbox']['add_resource'] = 'Add resource';
$lang['mailbox']['add_alias'] = 'Add alias';
$lang['mailbox']['add_domain_record_first'] = 'Please add a domain first';
$lang['mailbox']['empty'] = 'No results';
$lang['mailbox']['toggle_all'] = 'Toggle all';
$lang['mailbox']['quick_actions'] = 'Actions';
$lang['mailbox']['activate'] = 'Activate';
$lang['mailbox']['deactivate'] = 'Deactivate';
$lang['mailbox']['owner'] = 'Owner';
$lang['mailbox']['mins_interval'] = 'Interval (min)';
$lang['mailbox']['last_run'] = 'Last run';
$lang['mailbox']['excludes'] = 'Excludes';
$lang['mailbox']['last_run_reset'] = 'Schedule next';
$lang['mailbox']['sieve_info'] = 'You can store multiple filters per user, but only one prefilter and one postfilter can be active at the same time.<br>
Each filter will be processed in the described order. Neither a failed script nor an issued "keep;" will stop processing of further scripts.<br>
Prefilter → User scripts → Postfilter → <a href="https://github.com/mailcow/mailcow-dockerized/blob/master/data/conf/dovecot/sieve_after" target="_blank">global sieve postfilter</a>';
$lang['info']['no_action'] = 'No action applicable';
$lang['edit']['syncjob'] = 'Edit sync job';
$lang['edit']['client_id'] = 'Client ID';
$lang['edit']['client_secret'] = 'Client secret';
$lang['edit']['scope'] = 'Scope';
$lang['edit']['grant_types'] = 'Grant types';
$lang['edit']['redirect_uri'] = 'Redirect/Callback URL';
$lang['edit']['hostname'] = 'Hostname';
$lang['edit']['encryption'] = 'Encryption';
$lang['edit']['maxage'] = 'Maximum age of messages in days that will be polled from remote<br><small>(0 = ignore age)</small>';
$lang['edit']['maxbytespersecond'] = 'Max. bytes per second <br><small>(0 = unlimited)</small>';
$lang['edit']['automap'] = 'Try to automap folders ("Sent items", "Sent" => "Sent" etc.)';
$lang['edit']['skipcrossduplicates'] = 'Skip duplicate messages across folders (first come, first serve)';
$lang['add']['automap'] = 'Try to automap folders ("Sent items", "Sent" => "Sent" etc.)';
$lang['add']['skipcrossduplicates'] = 'Skip duplicate messages across folders (first come, first serve)';
$lang['edit']['subfolder2'] = 'Sync into subfolder on destination<br><small>(empty = do not use subfolder)</small>';
$lang['edit']['mins_interval'] = 'Interval (min)';
$lang['edit']['exclude'] = 'Exclude objects (regex)';
$lang['edit']['save'] = 'Save changes';
$lang['edit']['username'] = 'Username';
$lang['edit']['max_mailboxes'] = 'Max. possible mailboxes';
$lang['edit']['title'] = 'Edit object';
$lang['edit']['target_address'] = 'Goto address/es <small>(comma-separated)</small>';
$lang['edit']['active'] = 'Active';
$lang['edit']['force_pw_update'] = 'Force password update at next login';
$lang['edit']['force_pw_update_info'] = 'This user will only be able to login to mailcow UI.';
$lang['edit']['target_domain'] = 'Target domain';
$lang['edit']['password'] = 'Password';
$lang['edit']['password_repeat'] = 'Confirmation password (repeat)';
$lang['edit']['domain_admin'] = 'Edit domain administrator';
$lang['edit']['domain'] = 'Edit domain';
$lang['edit']['edit_alias_domain'] = 'Edit Alias domain';
$lang['edit']['domains'] = 'Domains';
$lang['edit']['alias'] = 'Edit alias';
$lang['edit']['mailbox'] = 'Edit mailbox';
$lang['edit']['description'] = 'Description';
$lang['edit']['max_aliases'] = 'Max. aliases';
$lang['edit']['max_quota'] = 'Max. quota per mailbox (MiB)';
$lang['edit']['domain_quota'] = 'Domain quota';
$lang['edit']['backup_mx_options'] = 'Backup MX options';
$lang['edit']['relay_domain'] = 'Relay domain';
$lang['edit']['relay_all'] = 'Relay all recipients';
$lang['edit']['relay_all_info'] = '<small>If you choose <b>not</b> to relay all recipients, you will need to add a ("blind") mailbox for every single recipient that should be relayed.</small>';
$lang['edit']['full_name'] = 'Full name';
$lang['edit']['quota_mb'] = 'Quota (MiB)';
$lang['edit']['sender_acl'] = 'Allow to send as';
$lang['edit']['sender_acl_disabled'] = '↳ <span class="label label-danger">Sender check is disabled</span>';
$lang['user']['sender_acl_disabled'] = '<span class="label label-danger">Sender check is disabled</span>';
$lang['edit']['previous'] = 'Previous page';
$lang['edit']['unchanged_if_empty'] = 'If unchanged leave blank';
$lang['edit']['dont_check_sender_acl'] = "Disable sender check for domain %s (+ alias domains)";
$lang['edit']['multiple_bookings'] = 'Multiple bookings';
$lang['edit']['kind'] = 'Kind';
$lang['edit']['resource'] = 'Resource';
$lang['acl']['spam_alias'] = 'Temporary aliases';
$lang['acl']['tls_policy'] = 'TLS policy';
$lang['acl']['spam_score'] = 'Spam score';
$lang['acl']['spam_policy'] = 'Blacklist/Whitelist';
$lang['acl']['delimiter_action'] = 'Delimiter action';
$lang['acl']['syncjobs'] = 'Sync jobs';
$lang['acl']['eas_reset'] = 'Reset EAS devices';
$lang['acl']['quarantine'] = 'Quarantine';
$lang['acl']['login_as'] = 'Login as mailbox user';
$lang['acl']['bcc_maps'] = 'BCC maps';
$lang['acl']['filters'] = 'Filters';
$lang['acl']['ratelimit'] = 'Rate limit';
$lang['acl']['recipient_maps'] = 'Recipient maps';
$lang['acl']['prohibited'] = 'Prohibited by ACL';
$lang['add']['generate'] = 'generate';
$lang['add']['syncjob'] = 'Add sync job';
$lang['add']['syncjob_hint'] = 'Be aware that passwords need to be saved plain-text!';
$lang['add']['hostname'] = 'Hostname';
$lang['add']['port'] = 'Port';
$lang['add']['username'] = 'Username';
$lang['add']['enc_method'] = 'Encryption method';
$lang['add']['mins_interval'] = 'Polling interval (minutes)';
$lang['add']['exclude'] = 'Exclude objects (regex)';
$lang['add']['delete2duplicates'] = 'Delete duplicates on destination';
$lang['add']['delete1'] = 'Delete from source when completed';
$lang['add']['delete2'] = 'Delete messages on destination that are not on source';
$lang['add']['custom_params'] = 'Custom parameters';
$lang['add']['subscribeall'] = 'Subscribe all folders';
$lang['add']['timeout1'] = 'Timeout for connection to remote host';
$lang['add']['timeout2'] = 'Timeout for connection to local host';
$lang['edit']['delete2duplicates'] = 'Delete duplicates on destination';
$lang['edit']['delete1'] = 'Delete from source when completed';
$lang['edit']['delete2'] = 'Delete messages on destination that are not on source';
$lang['add']['domain_matches_hostname'] = 'Domain %s matches hostname';
$lang['add']['domain'] = 'Domain';
$lang['add']['active'] = 'Active';
$lang['add']['multiple_bookings'] = 'Multiple bookings';
$lang['add']['description'] = 'Description';
$lang['add']['max_aliases'] = 'Max. possible aliases';
$lang['add']['max_mailboxes'] = 'Max. possible mailboxes';
$lang['add']['mailbox_quota_m'] = 'Max. quota per mailbox (MiB)';
$lang['add']['domain_quota_m'] = 'Total domain quota (MiB)';
$lang['add']['backup_mx_options'] = 'Backup MX options';
$lang['add']['relay_all'] = 'Relay all recipients';
$lang['add']['relay_domain'] = 'Relay this domain';
$lang['add']['relay_all_info'] = '<small>If you choose <b>not</b> to relay all recipients, you will need to add a ("blind") mailbox for every single recipient that should be relayed.</small>';
$lang['add']['alias_address'] = 'Alias address/es';
$lang['add']['alias_address_info'] = '<small>Full email address/es or @example.com, to catch all messages for a domain (comma-separated). <b>mailcow domains only</b>.</small>';
$lang['add']['alias_domain_info'] = '<small>Valid domain names only (comma-separated).</small>';
$lang['add']['target_address'] = 'Goto addresses';
$lang['add']['target_address_info'] = '<small>Full email address/es (comma-separated).</small>';
$lang['add']['alias_domain'] = 'Alias domain';
$lang['add']['select'] = 'Please select...';
$lang['add']['target_domain'] = 'Target domain';
$lang['add']['kind'] = 'Kind';
$lang['add']['mailbox_username'] = 'Username (left part of an email address)';
$lang['add']['full_name'] = 'Full name';
$lang['add']['quota_mb'] = 'Quota (MiB)';
$lang['add']['select_domain'] = 'Please select a domain first';
$lang['add']['password'] = 'Password';
$lang['add']['password_repeat'] = 'Confirmation password (repeat)';
$lang['add']['restart_sogo_hint'] = 'You will need to restart the SOGo service container after adding a new domain!';
$lang['add']['goto_null'] = 'Silently discard mail';
$lang['add']['goto_ham'] = 'Learn as <span class="text-success"><b>ham</b></span>';
$lang['add']['goto_spam'] = 'Learn as <span class="text-danger"><b>spam</b></span>';
$lang['add']['validation_success'] = 'Validated successfully';
$lang['add']['activate_filter_warn'] = 'All other filters will be deactivated, when active is checked.';
$lang['add']['validate'] = 'Validate';
$lang['mailbox']['add_filter'] = 'Add filter';
$lang['add']['sieve_desc'] = 'Short description';
$lang['edit']['sieve_desc'] = 'Short description';
$lang['add']['sieve_type'] = 'Filter type';
$lang['edit']['sieve_type'] = 'Filter type';
$lang['mailbox']['set_prefilter'] = 'Mark as prefilter';
$lang['mailbox']['set_postfilter'] = 'Mark as postfilter';
$lang['mailbox']['filters'] = 'Filters';
$lang['mailbox']['sync_jobs'] = 'Sync jobs';
$lang['mailbox']['inactive'] = 'Inactive';
$lang['edit']['validate_save'] = 'Validate and save';
$lang['login']['username'] = 'Username';
$lang['login']['password'] = 'Password';
$lang['login']['login'] = 'Login';
$lang['login']['delayed'] = 'Login was delayed by %s seconds.';
$lang['tfa']['tfa'] = "Two-factor authentication";
$lang['tfa']['set_tfa'] = "Set two-factor authentication method";
$lang['tfa']['yubi_otp'] = "Yubico OTP authentication";
$lang['tfa']['key_id'] = "An identifier for your YubiKey";
$lang['tfa']['key_id_totp'] = "An identifier for your key";
$lang['tfa']['api_register'] = 'mailcow uses the Yubico Cloud API. Please get an API key for your key <a href="https://upgrade.yubico.com/getapikey/" target="_blank">here</a>';
$lang['tfa']['u2f'] = "U2F authentication";
$lang['tfa']['none'] = "Deactivate";
$lang['tfa']['delete_tfa'] = "Disable TFA";
$lang['tfa']['disable_tfa'] = "Disable TFA until next successful login";
$lang['tfa']['confirm'] = "Confirm";
$lang['tfa']['totp'] = "Time-based OTP (Google Authenticator etc.)";
$lang['tfa']['select'] = "Please select";
$lang['tfa']['waiting_usb_auth'] = "<i>Waiting for USB device...</i><br><br>Please tap the button on your U2F USB device now.";
$lang['tfa']['waiting_usb_register'] = "<i>Waiting for USB device...</i><br><br>Please enter your password above and confirm your U2F registration by tapping the button on your U2F USB device.";
$lang['tfa']['scan_qr_code'] = "Please scan the following code with your authenticator app or enter the code manually.";
$lang['tfa']['enter_qr_code'] = "Your TOTP code if your device cannot scan QR codes";
$lang['tfa']['confirm_totp_token'] = "Please confirm your changes by entering the generated token";
$lang['admin']['rspamd-com_settings'] = '<a href="https://rspamd.com/doc/configuration/settings.html#settings-structure" target="_blank">Rspamd docs</a>
- A setting name will be auto-generated, please see the example presets below.';
$lang['admin']['no_new_rows'] = 'No further rows available';
$lang['admin']['additional_rows'] = ' additional rows were added'; // parses to 'n additional rows were added'
$lang['admin']['private_key'] = 'Private key';
$lang['admin']['import'] = 'Import';
$lang['admin']['duplicate'] = 'Duplicate';
$lang['admin']['import_private_key'] = 'Import private key';
$lang['admin']['duplicate_dkim'] = 'Duplicate DKIM record';
$lang['admin']['dkim_from'] = 'From';
$lang['admin']['dkim_to'] = 'To';
$lang['admin']['dkim_from_title'] = 'Source domain to copy data from';
$lang['admin']['dkim_to_title'] = 'Target domain/s - will be overwritten';
$lang['admin']['f2b_parameters'] = 'Fail2ban parameters';
$lang['admin']['f2b_ban_time'] = 'Ban time (s)';
$lang['admin']['f2b_max_attempts'] = 'Max. attempts';
$lang['admin']['f2b_retry_window'] = 'Retry window (s) for max. attempts';
$lang['admin']['f2b_netban_ipv4'] = 'IPv4 subnet size to apply ban on (8-32)';
$lang['admin']['f2b_netban_ipv6'] = 'IPv6 subnet size to apply ban on (8-128)';
$lang['admin']['f2b_whitelist'] = 'Whitelisted networks/hosts';
$lang['admin']['f2b_blacklist'] = 'Blacklisted networks/hosts';
$lang['admin']['f2b_list_info'] = 'A blacklisted host or network will always outweigh a whitelist entity. Blacklist records are created at boot-time of the container. Whitelist records are read each time a ban is about to be applied.';
$lang['admin']['search_domain_da'] = 'Search domains';
$lang['admin']['r_inactive'] = 'Inactive restrictions';
$lang['admin']['r_active'] = 'Active restrictions';
$lang['admin']['r_info'] = 'Greyed out/disabled elements on the list of active restrictions are not known as valid restrictions to mailcow and cannot be moved. Unknown restrictions will be set in order of appearance anyway. <br>You can add new elements in <code>inc/vars.local.inc.php</code> to be able to toggle them.';
$lang['admin']['dkim_key_length'] = 'DKIM key length (bits)';
$lang['admin']['dkim_key_valid'] = 'Key valid';
$lang['admin']['dkim_key_unused'] = 'Key unused';
$lang['admin']['dkim_key_missing'] = 'Key missing';
$lang['admin']['dkim_add_key'] = 'Add ARC/DKIM key';
$lang['admin']['dkim_keys'] = 'ARC/DKIM keys';
$lang['admin']['dkim_domains_wo_keys'] = "Select domains with missing keys";
$lang['admin']['add'] = 'Add';
$lang['add']['add_domain_restart'] = 'Add domain and restart SOGo';
$lang['add']['add_domain_only'] = 'Add domain only';
$lang['admin']['configuration'] = 'Configuration';
$lang['admin']['password'] = 'Password';
$lang['admin']['password_repeat'] = 'Confirmation password (repeat)';
$lang['admin']['active'] = 'Active';
$lang['admin']['inactive'] = 'Inactive';
$lang['admin']['action'] = 'Action';
$lang['admin']['add_domain_admin'] = 'Add domain administrator';
$lang['admin']['add_settings_rule'] = 'Add settings rule';
$lang['admin']['rsetting_desc'] = 'Short description';
$lang['admin']['rsetting_content'] = 'Rule content';
$lang['admin']['rsetting_none'] = 'No rule available';
$lang['admin']['rsetting_no_selection'] = 'Please select a rule';
$lang['admin']['rsettings_preset_1'] = 'Disable all but DKIM and rate limit for authenticated users';
$lang['admin']['rsettings_preset_2'] = 'Postmasters want spam';
$lang['admin']['rsettings_insert_preset'] = 'Insert example preset "%s"';
$lang['admin']['rsetting_add_rule'] = 'Add rule';
$lang['admin']['admin_domains'] = 'Domain assignments';
$lang['admin']['domain_admins'] = 'Domain administrators';
$lang['admin']['username'] = 'Username';
$lang['admin']['edit'] = 'Edit';
$lang['admin']['remove'] = 'Remove';
$lang['admin']['save'] = 'Save changes';
$lang['admin']['admin'] = 'Administrator';
$lang['admin']['admin_details'] = 'Edit administrator details';
$lang['admin']['unchanged_if_empty'] = 'If unchanged leave blank';
$lang['admin']['yes'] = '&#10004;';
$lang['admin']['no'] = '&#10008;';
$lang['admin']['access'] = 'Access';
$lang['admin']['no_record'] = 'No record';
$lang['admin']['filter_table'] = 'Filter table';
$lang['admin']['empty'] = 'No results';
$lang['admin']['time'] = 'Time';
$lang['admin']['priority'] = 'Priority';
$lang['admin']['message'] = 'Message';
$lang['admin']['refresh'] = 'Refresh';
$lang['admin']['to_top'] = 'Back to top';
$lang['admin']['in_use_by'] = 'In use by';
$lang['admin']['forwarding_hosts'] = 'Forwarding Hosts';
$lang['admin']['forwarding_hosts_hint'] = 'Incoming messages are unconditionally accepted from any hosts listed here. These hosts are then not checked against DNSBLs or subjected to greylisting. Spam received from them is never rejected, but optionally it can be filed into the Junk folder. The most common use for this is to specify mail servers on which you have set up a rule that forwards incoming emails to your mailcow server.';
$lang['admin']['forwarding_hosts_add_hint'] = 'You can either specify IPv4/IPv6 addresses, networks in CIDR notation, host names (which will be resolved to IP addresses), or domain names (which will be resolved to IP addresses by querying SPF records or, in their absence, MX records).';
$lang['admin']['relayhosts_hint'] = 'Define relayhosts here to be able to select them in a domains configuration dialog.';
$lang['admin']['add_relayhost_add_hint'] = 'Please be aware that relayhost authentication data will be stored as plain text.';
$lang['admin']['host'] = 'Host';
$lang['admin']['source'] = 'Source';
$lang['admin']['add_forwarding_host'] = 'Add Forwarding Host';
$lang['admin']['add_relayhost'] = 'Add Relayhost';
$lang['success']['forwarding_host_removed'] = "Forwarding host %s has been removed";
$lang['success']['forwarding_host_added'] = "Forwarding host %s has been added";
$lang['success']['relayhost_removed'] = "Relayhost %s has been removed";
$lang['success']['relayhost_added'] = "Relayhost %s has been added";
$lang['diagnostics']['dns_records'] = 'DNS Records';
$lang['diagnostics']['dns_records_24hours'] = 'Please note that changes made to DNS may take up to 24 hours to correctly have their current state reflected on this page. It is intended as a way for you to easily see how to configure your DNS records and to check whether all your records are correctly stored in DNS.';
$lang['diagnostics']['dns_records_name'] = 'Name';
$lang['diagnostics']['dns_records_type'] = 'Type';
$lang['diagnostics']['dns_records_data'] = 'Correct Data';
$lang['diagnostics']['dns_records_status'] = 'Current State';
$lang['diagnostics']['optional'] = 'This record is optional.';
$lang['diagnostics']['cname_from_a'] = 'Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.';
$lang['admin']['relay_from'] = '"From:" address';
$lang['admin']['relay_run'] = "Run test";
$lang['admin']['api_allow_from'] = "Allow API access from these IPs";
$lang['admin']['api_key'] = "API key";
$lang['admin']['activate_api'] = "Activate API";
$lang['admin']['regen_api_key'] = "Regenerate API key";
$lang['admin']['ban_list_info'] = "See a list of banned IPs below: <b>network (remaining ban time) - [actions]</b>.<br />IPs queued to be unbanned, will be removed from the active ban list within a few seconds.<br />Red labels indicate active permanent bans by blacklisting.";
$lang['admin']['unban_pending'] = "unban pending";
$lang['admin']['queue_unban'] = "queue unban";
$lang['admin']['no_active_bans'] = "No active bans";
$lang['admin']['quarantine'] = "Quarantine";
$lang['admin']['quarantine_retention_size'] = "Retentions per mailbox<br />0 indicates <b>inactive</b>!";
$lang['admin']['quarantine_max_size'] = "Maximum size in MiB (larger elements are discarded)<br />0 does <b>not</b> indicate unlimited!";
$lang['admin']['quarantine_exclude_domains'] = "Exclude domains and alias-domains:";
$lang['admin']['ui_texts'] = "UI labels and texts";
$lang['admin']['help_text'] = "Override help text below login mask (HTML allowed)";
$lang['admin']['title_name'] = '"mailcow UI" website title';
$lang['admin']['main_name'] = '"mailcow UI" name';
$lang['admin']['apps_name'] = '"mailcow Apps" name';
$lang['admin']['customize'] = "Customize";
$lang['admin']['change_logo'] = "Change logo";
$lang['admin']['logo_info'] = "Your image will be scaled to a height of 40px for the top navigation bar and a max. width of 250px for the start page. A scalable graphic is highly recommended.";
$lang['admin']['upload'] = "Upload";
$lang['admin']['app_links'] = "App links";
$lang['admin']['app_name'] = "App name";
$lang['admin']['link'] = "Link";
$lang['admin']['remove_row'] = "Remove row";
$lang['admin']['add_row'] = "Add row";
$lang['admin']['reset_default'] = "Reset to default";
$lang['admin']['merged_vars_hint'] = 'Greyed out rows were merged from <code>vars.(local.)inc.php</code> and cannot be modified.';
$lang['mailbox']['waiting'] = "Waiting";
$lang['mailbox']['status'] = "Status";
$lang['mailbox']['running'] = "Running";
$lang['edit']['spam_score'] = "Set a custom spam score";
$lang['edit']['spam_policy'] = "Add or remove items to white-/blacklist";
$lang['edit']['spam_alias'] = "Create or change time limited alias addresses";
$lang['danger']['img_tmp_missing'] = "Cannot validate image file: Temporary file not found";
$lang['danger']['img_invalid'] = "Cannot validate image file";
$lang['danger']['invalid_mime_type'] = "Invalid mime type";
$lang['success']['upload_success'] = "File uploaded successfully";
$lang['success']['app_links'] = "Saved changes to app links";
$lang['success']['ui_texts'] = "Saved changes to UI texts";
$lang['success']['reset_main_logo'] = "Reset to default logo";
$lang['success']['items_released'] = "Selected items were released";
$lang['success']['item_released'] = "Item %s released";
$lang['danger']['imagick_exception'] = "Error: Imagick exception while reading image";
$lang['quarantine']['quarantine'] = "Quarantine";
$lang['quarantine']['learn_spam_delete'] = "Learn as spam and delete";
$lang['quarantine']['qinfo'] = 'The quarantine system will save rejected mail to the database, while the sender will <em>not</em> be given the impression of a delivered mail.
<br>"' . $lang['quarantine']['learn_spam_delete'] . '" will learn a message as spam via Bayesian theorem and also calculate fuzzy hashes to deny similar messages in the future.
<br>Please be aware that learning multiple messages can be - depending on your system - time consuming.';
$lang['quarantine']['release'] = "Release";
$lang['quarantine']['empty'] = 'No results';
$lang['quarantine']['toggle_all'] = 'Toggle all';
$lang['quarantine']['quick_actions'] = 'Actions';
$lang['quarantine']['remove'] = 'Remove';
$lang['quarantine']['received'] = "Received";
$lang['quarantine']['action'] = "Action";
$lang['quarantine']['rcpt'] = "Recipient";
$lang['quarantine']['qid'] = "Rspamd QID";
$lang['quarantine']['sender'] = "Sender";
$lang['quarantine']['show_item'] = "Show item";
$lang['quarantine']['check_hash'] = "Search file hash @ VT";
$lang['quarantine']['qitem'] = "Quarantine item";
$lang['quarantine']['subj'] = "Subject";
$lang['quarantine']['text_plain_content'] = "Content (text/plain)";
$lang['quarantine']['text_from_html_content'] = "Content (converted html)";
$lang['quarantine']['atts'] = "Attachments";
$lang['warning']['fuzzy_learn_error'] = "Fuzzy hash learn error: %s";
$lang['danger']['spam_learn_error'] = "Spam learn error: %s";
$lang['success']['qlearn_spam'] = "Message ID %s was learned as spam and deleted";
$lang['header']['quarantine'] = "Quarantine";
$lang['header']['debug'] = "Debug";
$lang['debug']['log_info'] = '<p>mailcow <b>in-memory logs</b> are collected in Redis lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.
<br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.
<br>The in-memory log type should be used for debugging minor issues with containers.</p>
<p><b>External logs</b> are collected via API of the given application.</p>
<p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>';
$lang['debug']['in_memory_logs'] = 'In-memory logs';
$lang['debug']['external_logs'] = 'External logs';
$lang['debug']['static_logs'] = 'Static logs';
$lang['quarantine']['release_body'] = "We have attached your message as eml file to this message.";
$lang['danger']['release_send_failed'] = "Message could not be released: %s";
$lang['quarantine']['release_subject'] = "Potentially damaging quarantine item %s";
$lang['mailbox']['bcc_map'] = "BCC map";
$lang['mailbox']['bcc_map_type'] = "BCC type";
$lang['mailbox']['bcc_type'] = "BCC type";
$lang['mailbox']['bcc_sender_map'] = "Sender map";
$lang['mailbox']['bcc_rcpt_map'] = "Recipient map";
$lang['mailbox']['bcc_local_dest'] = "Local destination";
$lang['mailbox']['bcc_destinations'] = "BCC destination";
$lang['mailbox']['bcc_destination'] = "BCC destination";
$lang['edit']['bcc_dest_format'] = 'BCC destination must be a single valid email address.';
$lang['mailbox']['bcc'] = "BCC";
$lang['mailbox']['bcc_maps'] = "BCC maps";
$lang['mailbox']['bcc_to_sender'] = "Switch to sender map type";
$lang['mailbox']['bcc_to_rcpt'] = "Switch to recipient map type";
$lang['mailbox']['add_bcc_entry'] = "Add BCC map";
+$lang['mailbox']['add_tls_policy_map'] = "Add TLS policy map";
$lang['mailbox']['bcc_info'] = "BCC maps are used to silently forward copies of all messages to another address. A recipient map type entry is used, when the local destination acts as recipient of a mail. Sender maps conform to the same principle.<br/>
The local destination will not be informed about a failed delivery.";
$lang['mailbox']['address_rewriting'] = 'Address rewriting';
$lang['mailbox']['recipient_maps'] = 'Recipient maps';
$lang['mailbox']['recipient_map'] = 'Recipient map';
$lang['mailbox']['recipient_map_info'] = 'Recipient maps are used to replace the destination address on a message before it is delivered.';
$lang['mailbox']['recipient_map_old_info'] = 'A recipient maps original destination must be valid email addresses or a domain name.';
$lang['mailbox']['recipient_map_new_info'] = 'Recipient map destination must be a valid email address.';
$lang['mailbox']['recipient_map_old'] = 'Original recipient';
$lang['mailbox']['recipient_map_new'] = 'New recipient';
$lang['danger']['invalid_recipient_map_new'] = 'Invalid new recipient specified: %s';
$lang['danger']['invalid_recipient_map_old'] = 'Invalid original recipient specified: %s';
-$lang['danger']['recipient_map_entry_exists'] = 'A Recipient map entry for %s exists';
-$lang['success']['recipient_map_entry_saved'] = 'Recipient map entry for %s has been saved';
-$lang['success']['recipient_map_entry_deleted'] = 'Recipient map entry for %s has been deleted';
+$lang['danger']['recipient_map_entry_exists'] = 'A Recipient map entry "%s" exists';
+$lang['success']['recipient_map_entry_saved'] = 'Recipient map entry "%s" has been saved';
+$lang['success']['recipient_map_entry_deleted'] = 'Recipient map ID %s has been deleted';
+$lang['danger']['tls_policy_map_entry_exists'] = 'A TLS policy map entry "%s" exists';
+$lang['success']['tls_policy_map_entry_saved'] = 'TLS policy map entry "%s" has been saved';
+$lang['success']['tls_policy_map_entry_deleted'] = 'TLS policy map ID %s has been deleted';
$lang['mailbox']['add_recipient_map_entry'] = 'Add recipient map';
+$lang['danger']['tls_policy_map_parameter_invalid'] = "Policy parameter is invalid";
$lang['oauth2']['scope_ask_permission'] = 'An application asked for the following permissions';
$lang['oauth2']['profile'] = 'Profile';
$lang['oauth2']['profile_desc'] = 'View personal information: username, full name, created, modified, active';
$lang['oauth2']['permit'] = 'Authorize application';
$lang['oauth2']['authorize_app'] = 'Authorize application';
$lang['oauth2']['deny'] = 'Deny';
$lang['oauth2']['access_denied'] = 'Please login as mailbox owner to grant access via OAuth2.';
diff --git a/data/web/mailbox.php b/data/web/mailbox.php
index 70d8dbb6..fd21d26d 100644
--- a/data/web/mailbox.php
+++ b/data/web/mailbox.php
@@ -1,318 +1,347 @@
<?php
require_once "inc/prerequisites.inc.php";
if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
require_once "inc/header.inc.php";
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
?>
<div class="container">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#tab-domains" aria-controls="tab-domains" role="tab" data-toggle="tab"><?=$lang['mailbox']['domains'];?></a></li>
<li role="presentation"><a href="#tab-mailboxes" aria-controls="tab-mailboxes" role="tab" data-toggle="tab"><?=$lang['mailbox']['mailboxes'];?></a></li>
<li role="presentation"><a href="#tab-resources" aria-controls="tab-resources" role="tab" data-toggle="tab"><?=$lang['mailbox']['resources'];?></a></li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['aliases'];?>
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li role="presentation"><a href="#tab-mbox-aliases" aria-controls="tab-mbox-aliases" role="tab" data-toggle="tab"><?=$lang['mailbox']['aliases'];?></a></li>
<li role="presentation"><a href="#tab-domain-aliases" aria-controls="tab-domain-aliases" role="tab" data-toggle="tab"><?=$lang['mailbox']['domain_aliases'];?></a></li>
</ul>
</li>
<li role="presentation"><a href="#tab-syncjobs" aria-controls="tab-syncjobs" role="tab" data-toggle="tab"><?=$lang['mailbox']['sync_jobs'];?></a></li>
<li role="presentation"><a href="#tab-filters" aria-controls="tab-filters" role="tab" data-toggle="tab"><?=$lang['mailbox']['filters'];?></a></li>
<li role="presentation"><a href="#tab-bcc" aria-controls="tab-filters" role="tab" data-toggle="tab"><?=$lang['mailbox']['address_rewriting'];?></a></li>
+ <li role="presentation"><a href="#tab-tls-policy" aria-controls="tab-tls-policy" role="tab" data-toggle="tab"><?=$lang['mailbox']['tls_policy_maps'];?></a></li>
</ul>
<div class="row">
<div class="col-md-12">
<div class="tab-content" style="padding-top:20px">
<div role="tabpanel" class="tab-pane active" id="tab-domains">
<div class="panel panel-default">
<div class="panel-heading">
<?=$lang['mailbox']['domains'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_domain_table" data-table="domain_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<div class="table-responsive">
<table id="domain_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="domain" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<? if($_SESSION['mailcow_cc_role'] == "admin"): ?>
<li><a data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="domain" data-api-url='edit/domain' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="domain" data-api-url='delete/domain' href="#"><?=$lang['mailbox']['remove'];?></a></li>
<? endif; ?>
</ul>
<? if($_SESSION['mailcow_cc_role'] == "admin"): ?>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addDomainModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_domain'];?></a>
<? endif; ?>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tab-mailboxes">
<div class="panel panel-default">
<div class="panel-heading">
<?=$lang['mailbox']['mailboxes'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_mailbox_table" data-table="mailbox_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<div class="table-responsive">
<table id="mailbox_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="mailbox" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="mailbox" data-api-url='edit/mailbox' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="mailbox" data-api-url='delete/mailbox' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addMailboxModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_mailbox'];?></a>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tab-resources">
<div class="panel panel-default">
<div class="panel-heading">
<?=$lang['mailbox']['resources'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_resource_table" data-table="resource_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<div class="table-responsive">
<table id="resource_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="resource" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="resource" data-api-url='edit/resource' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="resource" data-api-url='delete/resource' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addResourceModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_resource'];?></a>
</div>
</div>
<hr>
<div class="panel-body help-block">
<p><span class="label label-success"><?=$lang['mailbox']['booking_0_short'];?></span> - <?=$lang['mailbox']['booking_0'];?></p>
<p><span class="label label-warning"><?=$lang['mailbox']['booking_lt0_short'];?></span> - <?=$lang['mailbox']['booking_lt0'];?></p>
<p><span class="label label-danger"><?=$lang['mailbox']['booking_custom_short'];?></span> - <?=$lang['mailbox']['booking_custom'];?></p>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tab-domain-aliases">
<div class="panel panel-default">
<div class="panel-heading">
<?=$lang['mailbox']['domain_aliases'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_aliasdomain_table" data-table="aliasdomain_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<div class="table-responsive">
<table id="aliasdomain_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="alias-domain" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="alias-domain" data-api-url='edit/alias-domain' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="alias-domain" data-api-url='delete/alias-domain' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addAliasDomainModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_domain_alias'];?></a>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tab-mbox-aliases">
<div class="panel panel-default">
<div class="panel-heading">
<?=$lang['mailbox']['aliases'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_alias_table" data-table="alias_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<div class="table-responsive">
<table id="alias_table" class="table table-striped"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="alias" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="alias" data-api-url='edit/alias' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="alias" data-api-url='delete/alias' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addAliasModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_alias'];?></a>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tab-syncjobs">
<div class="panel panel-default">
<div class="panel-heading">
<?=$lang['mailbox']['sync_jobs'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_sync_job_table" data-table="sync_job_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<div class="table-responsive">
<table class="table table-striped" id="sync_job_table"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['syncjobs'];?>">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="syncjob" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"last_run":""}' href="#"><?=$lang['mailbox']['last_run_reset'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-text="<?=$lang['user']['eas_reset'];?>?" data-id="syncjob" data-api-url='delete/syncjob' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModalAdmin"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['create_syncjob'];?></a>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tab-filters">
<div class="panel panel-default">
<div class="panel-heading">
<?=$lang['mailbox']['filters'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_filter_table" data-table="filter_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<p style="margin:10px" class="help-block"><?=$lang['mailbox']['sieve_info'];?></p>
<div class="table-responsive">
<table class="table table-striped" id="filter_table"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['filters'];?>">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="filter_item" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"filter_type":"prefilter"}' href="#"><?=$lang['mailbox']['set_prefilter'];?></a></li>
<li><a data-action="edit_selected" data-id="filter_item" data-api-url='edit/filter' data-api-attr='{"filter_type":"postfilter"}' href="#"><?=$lang['mailbox']['set_postfilter'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-text="<?=$lang['user']['eas_reset'];?>?" data-id="filter_item" data-api-url='delete/filter' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addFilterModalAdmin"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_filter'];?></a>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tab-bcc">
<div class="panel panel-default">
<div class="panel-heading">
<?=$lang['mailbox']['bcc_maps'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_bcc_table" data-table="bcc_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<p style="margin:10px" class="help-block"><?=$lang['mailbox']['bcc_info'];?></p>
<div class="table-responsive">
<table class="table table-striped" id="bcc_table"></table>
</div>
<div class="mass-actions-mailbox">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['bcc_maps'];?>">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="bcc" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"sender"}' href="#"><?=$lang['mailbox']['bcc_to_sender'];?></a></li>
<li><a data-action="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"rcpt"}' href="#"><?=$lang['mailbox']['bcc_to_rcpt'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="bcc" data-api-url='delete/bcc' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addBCCModalAdmin"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_bcc_entry'];?></a>
</div>
</div>
</div>
<div class="panel panel-default <?=($_SESSION['mailcow_cc_role'] == "admin") ?: 'hidden';?>">
<div class="panel-heading">
<?=$lang['mailbox']['recipient_maps'];?> <span class="badge badge-info table-lines"></span>
<div class="btn-group pull-right">
<button class="btn btn-xs btn-default refresh_table" data-draw="draw_recipient_map_table" data-table="recipient_map_table"><?=$lang['admin']['refresh'];?></button>
</div>
</div>
<p style="margin:10px" class="help-block"><?=$lang['mailbox']['recipient_map_info'];?></p>
<div class="table-responsive">
<table class="table table-striped" id="recipient_map_table"></table>
</div>
<div class="mass-actions-mailbox" style="display: <?php echo $display; ?>">
<div class="btn-group">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="recipient_map" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="recipient_map" data-api-url='edit/recipient_map' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="recipient_map" data-api-url='delete/recipient_map' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addRecipientMapModalAdmin"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_recipient_map_entry'];?></a>
</div>
</div>
</div>
</div>
+
+ <div role="tabpanel" class="tab-pane <?=($_SESSION['mailcow_cc_role'] == "admin") ?: 'hidden';?>" id="tab-tls-policy">
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <?=$lang['mailbox']['tls_policy_maps_long'];?> <span class="badge badge-info table-lines"></span>
+ <div class="btn-group pull-right">
+ <button class="btn btn-xs btn-default refresh_table" data-draw="draw_tls_policy_table" data-table="tls_policy_table"><?=$lang['admin']['refresh'];?></button>
+ </div>
+ </div>
+ <p style="margin:10px" class="help-block"><?=$lang['mailbox']['tls_policy_maps_info'];?></p>
+ <div class="table-responsive">
+ <table class="table table-striped" id="tls_policy_table"></table>
+ </div>
+ <div class="mass-actions-mailbox">
+ <div class="btn-group">
+ <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="tls-policy-map" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
+ <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+ <ul class="dropdown-menu">
+ <li><a data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
+ <li><a data-action="edit_selected" data-id="tls-policy-map" data-api-url='edit/tls-policy-map' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
+ <li role="separator" class="divider"></li>
+ <li><a data-action="delete_selected" data-id="tls-policy-map" data-api-url='delete/tls-policy-map' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+ </ul>
+ <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addTLSPolicyMapAdmin"><span class="glyphicon glyphicon-plus"></span> <?=$lang['mailbox']['add_tls_policy_map'];?></a>
+ </div>
+ </div>
+ </div>
+ </div>
</div> <!-- /tab-content -->
</div> <!-- /col-md-12 -->
</div> <!-- /row -->
</div> <!-- /container -->
<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/mailbox.php';
?>
<script type='text/javascript'>
<?php
$lang_mailbox = json_encode($lang['mailbox']);
echo "var lang = ". $lang_mailbox . ";\n";
echo "var acl = '". json_encode($_SESSION['acl']) . "';\n";
echo "var csrf_token = '". $_SESSION['CSRF']['TOKEN'] . "';\n";
$role = ($_SESSION['mailcow_cc_role'] == "admin") ? 'admin' : 'domainadmin';
$is_dual = (!empty($_SESSION["dual-login"]["username"])) ? 'true' : 'false';
echo "var role = '". $role . "';\n";
echo "var is_dual = " . $is_dual . ";\n";
echo "var pagination_size = '". $PAGINATION_SIZE . "';\n";
?>
</script>
<script src="js/footable.min.js"></script>
<script src="js/mailbox.js"></script>
<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/footer.inc.php';
} else {
header('Location: /');
exit();
}
?>
diff --git a/data/web/modals/mailbox.php b/data/web/modals/mailbox.php
index fe99bc6d..107df71a 100644
--- a/data/web/modals/mailbox.php
+++ b/data/web/modals/mailbox.php
@@ -1,738 +1,794 @@
<?php
if (!isset($_SESSION['mailcow_cc_role'])) {
header('Location: /');
exit();
}
?>
<!-- add mailbox modal -->
<div class="modal fade" id="addMailboxModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><?=$lang['mailbox']['add_mailbox'];?></h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" data-id="add_mailbox" role="form">
<div class="form-group">
<label class="control-label col-sm-2" for="local_part"><?=$lang['add']['mailbox_username'];?></label>
<div class="col-sm-10">
<input type="text" pattern="[A-Za-z0-9\.!#$%&'*+/=?^_`{|}~-]+" autocorrect="off" autocapitalize="none" class="form-control" name="local_part" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domain"><?=$lang['add']['domain'];?>:</label>
<div class="col-sm-10">
<select class="full-width-select" data-live-search="true" id="addSelectDomain" name="domain" required>
<?php
foreach (mailbox('get', 'domains') as $domain) {
echo "<option>".htmlspecialchars($domain)."</option>";
}
?>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="name"><?=$lang['add']['full_name'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="addInputQuota"><?=$lang['add']['quota_mb'];?>
<br /><span id="quotaBadge" class="badge">max. - MiB</span>
</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="quota" min="1" max="" id="addInputQuota" disabled value="<?=$lang['add']['select_domain'];?>" required>
<small class="help-block">min. 1</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password"><?=$lang['add']['password'];?> (<a href="#" class="generate_password"><?=$lang['add']['generate'];?></a>)</label>
<div class="col-sm-10">
<input type="password" data-hibp="true" class="form-control" name="password" placeholder="" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password2"><?=$lang['add']['password_repeat'];?></label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password2" placeholder="" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-default" data-action="add_item" data-id="add_mailbox" data-api-url='add/mailbox' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add mailbox modal -->
<!-- add domain modal -->
<div class="modal fade" id="addDomainModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><?=$lang['mailbox']['add_domain'];?></h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" data-id="add_domain" role="form">
<div class="form-group">
<label class="control-label col-sm-2" for="domain"><?=$lang['add']['domain'];?>:</label>
<div class="col-sm-10">
<input type="text" autocorrect="off" autocapitalize="none" class="form-control" name="domain" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="aliases"><?=$lang['add']['max_aliases'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="aliases" value="400" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mailboxes"><?=$lang['add']['max_mailboxes'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mailboxes" value="10" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxquota"><?=$lang['add']['mailbox_quota_m'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxquota" value="3072" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="quota"><?=$lang['add']['domain_quota_m'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="quota" value="10240" required>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-2" for="quota">Ratelimit</label>
<div class="col-sm-7">
<input name="rl_value" type="number" value="<?=(!empty($rl['value'])) ? $rl['value'] : null;?>" class="form-control" placeholder="disabled">
</div>
<div class="col-sm-3">
<select name="rl_frame" class="form-control">
<option value="s" <?=(isset($rl['frame']) && $rl['frame'] == 's') ? 'selected' : null;?>>msgs / second</option>
<option value="m" <?=(isset($rl['frame']) && $rl['frame'] == 'm') ? 'selected' : null;?>>msgs / minute</option>
<option value="h" <?=(isset($rl['frame']) && $rl['frame'] == 'h') ? 'selected' : null;?>>msgs / hour</option>
</select>
</div>
</div>
<hr>
<div class="form-group">
<label class="control-label col-sm-2"><?=$lang['add']['backup_mx_options'];?></label>
<div class="col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="backupmx"> <?=$lang['add']['relay_domain'];?></label>
<br />
<label><input type="checkbox" value="1" name="relay_all_recipients"> <?=$lang['add']['relay_all'];?></label>
<p><?=$lang['add']['relay_all_info'];?></p>
</div>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#"><?=$lang['add']['add_domain_only'];?></button>
<button class="btn btn-default" data-action="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{"restart_sogo":"1"}' href="#"><?=$lang['add']['add_domain_restart'];?></button>
</div>
</div>
<p><span class="glyphicon glyphicon-exclamation-sign text-danger"></span> <?=$lang['add']['restart_sogo_hint'];?></p>
</form>
</div>
</div>
</div>
</div><!-- add domain modal -->
<!-- add resource modal -->
<div class="modal fade" id="addResourceModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><?=$lang['mailbox']['add_resource'];?></h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_resource">
<div class="form-group">
<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="description" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domain"><?=$lang['add']['domain'];?>:</label>
<div class="col-sm-10">
<select data-live-search="true" name="domain" title="<?=$lang['add']['select'];?>" required>
<?php
foreach (mailbox('get', 'domains') as $domain) {
echo "<option>".htmlspecialchars($domain)."</option>";
}
?>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="domain"><?=$lang['add']['kind'];?>:</label>
<div class="col-sm-10">
<select name="kind" title="<?=$lang['add']['select'];?>" required>
<option value="location">Location</option>
<option value="group">Group</option>
<option value="thing">Thing</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="multiple_bookings_select"><?=$lang['add']['multiple_bookings'];?>:</label>
<div class="col-sm-10">
<select name="multiple_bookings_select" id="multiple_bookings_select" title="<?=$lang['add']['select'];?>" required>
<option value="0"><?=$lang['mailbox']['booking_0'];?></option>
<option value="-1" selected><?=$lang['mailbox']['booking_lt0'];?></option>
<option value="custom"><?=$lang['mailbox']['booking_custom'];?></option>
</select>
<div style="display:none" id="multiple_bookings_custom_div">
<hr>
<input type="number" class="form-control" name="multiple_bookings_custom" id="multiple_bookings_custom">
</div>
<input type="hidden" name="multiple_bookings" id="multiple_bookings">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-default" data-action="add_item" data-id="add_resource" data-api-url='add/resource' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add resource modal -->
<!-- add alias modal -->
<div class="modal fade" id="addAliasModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><?=$lang['mailbox']['add_alias'];?></h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_alias">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="address"><?=$lang['add']['alias_address'];?></label>
<div class="col-sm-10">
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="5" name="address" id="address" required></textarea>
<p><?=$lang['add']['alias_address_info'];?></p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="goto"><?=$lang['add']['target_address'];?></label>
<div class="col-sm-10">
<textarea id="textarea_alias_goto" autocorrect="off" autocapitalize="none" class="form-control" rows="5" id="goto" name="goto" required></textarea>
<p><?=$lang['add']['target_address_info'];?></p>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_null"> <?=$lang['add']['goto_null'];?></label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_spam"> <?=$lang['add']['goto_spam'];?></label>
</div>
<div class="checkbox">
<label><input class="goto_checkbox" type="checkbox" value="1" name="goto_ham"> <?=$lang['add']['goto_ham'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-default" data-action="add_item" data-id="add_alias" data-api-url='add/alias' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add alias modal -->
<!-- add domain alias modal -->
<div class="modal fade" id="addAliasDomainModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><?=$lang['mailbox']['add_domain_alias'];?></h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_alias_domain">
<input type="hidden" value="0" name="active">
<div class="form-group">
<label class="control-label col-sm-2" for="alias_domain"><?=$lang['add']['alias_domain'];?></label>
<div class="col-sm-10">
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="5" name="alias_domain" id="alias_domain" required></textarea>
<p><?=$lang['add']['alias_domain_info'];?></p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="target_domain"><?=$lang['add']['target_domain'];?></label>
<div class="col-sm-10">
<select data-live-search="true" name="target_domain" title="<?=$lang['add']['select'];?>" required>
<?php
foreach (mailbox('get', 'domains') as $domain) {
echo "<option>".htmlspecialchars($domain)."</option>";
}
?>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-default" data-action="add_item" data-id="add_alias_domain" data-api-url='add/alias-domain' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add domain alias modal -->
<!-- add sync job modal -->
<div class="modal fade" id="addSyncJobModalAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><?=$lang['add']['syncjob'];?></h3>
</div>
<div class="modal-body">
<p class="help-block"><?=$lang['add']['syncjob_hint'];?></p>
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_syncjob">
<div class="form-group">
<label class="control-label col-sm-2" for="username"><?=$lang['add']['username'];?>:</label>
<div class="col-sm-10">
<select data-live-search="true" name="username" required>
<?php
$domains = mailbox('get', 'domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
$mailboxes = mailbox('get', 'mailboxes', $domain);
foreach ($mailboxes as $mailbox) {
echo "<option>".htmlspecialchars($mailbox)."</option>";
}
}
}
?>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="host1"><?=$lang['add']['hostname'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="host1" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="port1"><?=$lang['add']['port'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="port1" min="1" max="65535" value="143" required>
<small class="help-block">1-65535</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="user1"><?=$lang['add']['username'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="user1" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="password1"><?=$lang['add']['password'];?></label>
<div class="col-sm-10">
<input type="password" class="form-control" name="password1" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="enc1"><?=$lang['add']['enc_method'];?></label>
<div class="col-sm-10">
<select name="enc1" title="<?=$lang['add']['select'];?>" required>
<option selected>TLS</option>
<option>SSL</option>
<option>PLAIN</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="mins_interval"><?=$lang['add']['mins_interval'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="mins_interval" min="1" max="3600" value="20" required>
<small class="help-block">1-3600</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="subfolder2"><?=$lang['edit']['subfolder2'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="subfolder2" value="External">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxage"><?=$lang['edit']['maxage'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxage" min="0" max="32000" value="0">
<small class="help-block">0-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="maxbytespersecond"><?=$lang['edit']['maxbytespersecond'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="maxbytespersecond" min="0" max="125000000" value="0">
<small class="help-block">0-125000000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout1"><?=$lang['edit']['timeout1'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout1" min="1" max="32000" value="600">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="timeout2"><?=$lang['edit']['timeout2'];?></label>
<div class="col-sm-10">
<input type="number" class="form-control" name="timeout2" min="1" max="32000" value="600">
<small class="help-block">1-32000</small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="exclude"><?=$lang['add']['exclude'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="exclude" value="(?i)spam|(?i)junk">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="custom_params"><?=$lang['add']['custom_params'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="custom_params" placeholder="--delete2folders --otheroption">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2duplicates" checked> <?=$lang['add']['delete2duplicates'];?> (--delete2duplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete1"> <?=$lang['add']['delete1'];?> (--delete1)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="delete2"> <?=$lang['add']['delete2'];?> (--delete2)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="automap" checked> <?=$lang['add']['automap'];?> (--automap)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="skipcrossduplicates"> <?=$lang['add']['skipcrossduplicates'];?> (--skipcrossduplicates)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="subscribeall" checked> <?=$lang['add']['subscribeall'];?> (--subscribeall)</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-default" data-action="add_item" data-id="add_syncjob" data-api-url='add/syncjob' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add sync job modal -->
<!-- add add_filter modal -->
<div class="modal fade" id="addFilterModalAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title">Filter</h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_filter">
<div class="form-group">
<label class="control-label col-sm-2" for="username"><?=$lang['add']['username'];?>:</label>
<div class="col-sm-10">
<select data-live-search="true" name="username" required>
<?php
$domains = mailbox('get', 'domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
$mailboxes = mailbox('get', 'mailboxes', $domain);
foreach ($mailboxes as $mailbox) {
echo "<option>".htmlspecialchars($mailbox)."</option>";
}
}
}
?>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="filter_type"><?=$lang['add']['sieve_type'];?>:</label>
<div class="col-sm-10">
<select id="addFilterType" name="filter_type" required>
<option value="prefilter">Prefilter</option>
<option value="postfilter">Postfilter</option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="script_desc"><?=$lang['add']['sieve_desc'];?>:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="script_desc" required maxlength="255">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="script_data">Script:</label>
<div class="col-sm-10">
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control" rows="20" id="script_data" name="script_data" required></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<p class="help-block"><?=$lang['add']['activate_filter_warn'];?></p>
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10" id="add_filter_btns">
<button class="btn btn-default" id="validate_sieve" href="#"><?=$lang['add']['validate'];?></button>
<button class="btn btn-success" data-action="add_item" data-id="add_filter" data-api-url='add/filter' data-api-attr='{}' href="#" disabled><?=$lang['admin']['add'];?></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add add_filter modal -->
<!-- add add_bcc modal -->
<div class="modal fade" id="addBCCModalAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><?=$lang['mailbox']['bcc_maps'];?></h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_bcc">
<div class="form-group">
<label class="control-label col-sm-2" for="local_dest"><?=$lang['mailbox']['bcc_local_dest'];?>:</label>
<div class="col-sm-10">
<select data-live-search="true" name="local_dest" required>
<?php
$domains = mailbox('get', 'domains');
$alias_domains = mailbox('get', 'alias_domains');
if (!empty($domains)) {
foreach ($domains as $domain) {
echo "<option>".htmlspecialchars($domain)."</option>";
}
}
if (!empty($alias_domains)) {
foreach ($alias_domains as $alias_domain) {
echo "<option>".htmlspecialchars($alias_domain)."</option>";
}
}
if (!empty($domains)) {
foreach ($domains as $domain) {
$mailboxes = mailbox('get', 'mailboxes', $domain);
foreach ($mailboxes as $mailbox) {
echo "<option>".htmlspecialchars($mailbox)."</option>";
}
}
}
?>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="type"><?=$lang['mailbox']['bcc_map_type'];?>:</label>
<div class="col-sm-10">
<select name="type" required>
<option value="sender"><?=$lang['mailbox']['bcc_sender_map'];?></option>
<option value="rcpt"><?=$lang['mailbox']['bcc_rcpt_map'];?></option>
</select>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="bcc_dest"><?=$lang['mailbox']['bcc_destination'];?>:</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="bcc_dest">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="add_item" data-id="add_bcc" data-api-url='add/bcc' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add add_bcc modal -->
<!-- add add_recipient_map modal -->
<div class="modal fade" id="addRecipientMapModalAdmin" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
<h3 class="modal-title"><?=$lang['mailbox']['recipient_maps'];?></h3>
</div>
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_recipient_map">
<div class="form-group">
<label class="control-label col-sm-2" for="recipient_map_old"><?=$lang['mailbox']['recipient_map_old'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="recipient_map_old">
<small><?=$lang['mailbox']['recipient_map_old_info'];?></small>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="recipient_map_new"><?=$lang['mailbox']['recipient_map_new'];?></label>
<div class="col-sm-10">
<input type="text" class="form-control" name="recipient_map_new">
<small><?=$lang['mailbox']['recipient_map_new_info'];?></small>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-success" data-action="add_item" data-id="add_recipient_map" data-api-url='add/recipient_map' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div><!-- add add_recipient_map modal -->
+<!-- add add_tls_policy_map modal -->
+<div class="modal fade" id="addTLSPolicyMapAdmin" tabindex="-1" role="dialog" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
+ <h3 class="modal-title"><?=$lang['mailbox']['tls_policy_maps'];?></h3>
+ </div>
+ <div class="modal-body">
+ <form class="form-horizontal" data-cached-form="true" role="form" data-id="add_tls_policy_map">
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="dest"><?=$lang['mailbox']['tls_map_dest'];?></label>
+ <div class="col-sm-10">
+ <input type="text" class="form-control" name="dest">
+ <small><?=$lang['mailbox']['tls_map_dest_info'];?></small>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="policy"><?=$lang['mailbox']['tls_map_policy'];?>:</label>
+ <div class="col-sm-10">
+ <select class="full-width-select" name="policy" required>
+ <option value="none">none</option>
+ <option value="may">may</option>
+ <option value="encrypt">encrypt</option>
+ <option value="dane">dane</option>
+ <option value="dane-only">dane-only</option>
+ <option value="fingerprint">fingerprint</option>
+ <option value="verify">verify</option>
+ <option value="secure">secure</option>
+ </select>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="control-label col-sm-2" for="parameters"><?=$lang['mailbox']['tls_map_parameters'];?></label>
+ <div class="col-sm-10">
+ <input type="text" class="form-control" name="parameters">
+ <small><?=$lang['mailbox']['tls_map_parameters_info'];?></small>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <div class="checkbox">
+ <label><input type="checkbox" value="1" name="active" checked> <?=$lang['add']['active'];?></label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button class="btn btn-success" data-action="add_item" data-id="add_tls_policy_map" data-api-url='add/tls-policy-map' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></button>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+</div><!-- add add_tls_policy_map modal -->
<!-- log modal -->
<div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header"><h4 class="modal-title">Log</h4></div>
<div class="modal-body">
<textarea class="form-control" rows="20" id="logText" spellcheck="false"></textarea>
</div>
</div>
</div>
</div><!-- log modal -->
<!-- DNS info modal -->
<div class="modal fade" id="dnsInfoModal" tabindex="-1" role="dialog" aria-labelledby="dnsInfoModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header"><h4 class="modal-title"><?=$lang['diagnostics']['dns_records'];?></h4></div>
<div class="modal-body">
<p><?=$lang['diagnostics']['dns_records_24hours'];?></p>
<div class="dns-modal-body"></div>
</div>
</div>
</div>
</div><!-- DNS info modal -->
<script>
$('#addResourceModal').on('shown.bs.modal', function() {
$("#multiple_bookings").val($("#multiple_bookings_select").val());
if ($("#multiple_bookings").val() == "custom") {
$("#multiple_bookings_custom_div").show();
$("#multiple_bookings").val($("#multiple_bookings_custom").val());
}
})
$("#multiple_bookings_select").change(function() {
$("#multiple_bookings").val($("#multiple_bookings_select").val());
if ($("#multiple_bookings").val() == "custom") {
$("#multiple_bookings_custom_div").show();
}
else {
$("#multiple_bookings_custom_div").hide();
}
});
$("#multiple_bookings_custom").bind ("change keypress keyup blur", function () {
$("#multiple_bookings").val($("#multiple_bookings_custom").val());
});
</script>
diff --git a/data/web/user.php b/data/web/user.php
index 329a99c2..ebefadeb 100644
--- a/data/web/user.php
+++ b/data/web/user.php
@@ -1,419 +1,419 @@
<?php
require_once("inc/prerequisites.inc.php");
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'domainadmin') {
/*
/ DOMAIN ADMIN
*/
require_once("inc/header.inc.php");
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$tfa_data = get_tfa();
$username = $_SESSION['mailcow_cc_username'];
?>
<div class="container">
<h3><?=$lang['user']['user_settings'];?></h3>
<div class="panel panel-default">
<div class="panel-heading"><?=$lang['user']['user_settings'];?></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-offset-3 col-sm-9">
<p><a href="#pwChangeModal" data-toggle="modal">[<?=$lang['user']['change_password'];?>]</a></p>
<p><small>
<?php
if ($_SESSION['mailcow_cc_last_login']['remote']):
?>
<span style="margin-right:10px" class="glyphicon glyphicon-log-in"></span> <span data-time="<?=$_SESSION['mailcow_cc_last_login']['time'];?>" class="last_login_date"></span> (<?=$_SESSION['mailcow_cc_last_login']['remote'];?>)
<?php
else: echo "Last login: -"; endif;
?>
</small></p>
<p>
</div>
</div>
<hr>
<div class="row">
<div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['tfa'];?></div>
<div class="col-sm-9 col-xs-7">
<p id="tfa_pretty"><?=$tfa_data['pretty'];?></p>
<div id="tfa_additional">
<?php if (!empty($tfa_data['additional'])):
foreach ($tfa_data['additional'] as $key_info): ?>
<form style="display:inline;" method="post">
<input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>" />
<div class="label label-default">🔑 <?=$key_info['key_id'];?> <a href="#" style="font-weight:bold;color:white" onClick="$(this).closest('form').submit()">[<?=strtolower($lang['admin']['remove']);?>]</a></div>
</form>
<?php endforeach;
endif;?>
</div>
<br />
</div>
</div>
<div class="row">
<div class="col-sm-3 col-xs-5 text-right"><?=$lang['tfa']['set_tfa'];?></div>
<div class="col-sm-9 col-xs-7">
<select id="selectTFA" class="selectpicker" title="<?=$lang['tfa']['select'];?>">
<option value="yubi_otp"><?=$lang['tfa']['yubi_otp'];?></option>
<option value="u2f"><?=$lang['tfa']['u2f'];?></option>
<option value="totp"><?=$lang['tfa']['totp'];?></option>
<option value="none"><?=$lang['tfa']['none'];?></option>
</select>
</div>
</div>
</div>
</div>
<?php
}
elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user') {
/*
/ USER
*/
require_once("inc/header.inc.php");
$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
$username = $_SESSION['mailcow_cc_username'];
$mailboxdata = mailbox('get', 'mailbox_details', $username);
$clientconfigstr = "host=" . urlencode($mailcow_hostname) . "&email=" . urlencode($username) . "&name=" . urlencode($mailboxdata['name']) . "&port=" . urlencode($autodiscover_config['caldav']['port']);
if ($autodiscover_config['useEASforOutlook'] == 'yes')
$clientconfigstr .= "&outlookEAS=1";
if (file_exists('thunderbird-plugins/version.csv')) {
$fh = fopen('thunderbird-plugins/version.csv', 'r');
if ($fh) {
while (($row = fgetcsv($fh, 1000, ';')) !== FALSE) {
if ($row[0] == 'sogo-integrator@inverse.ca') {
$clientconfigstr .= "&integrator=" . urlencode($row[1]);
}
}
fclose($fh);
}
}
?>
<div class="container">
<h3><?=$lang['user']['user_settings'];?></h3>
<div class="panel panel-default">
<div class="panel-heading"><?=$lang['user']['mailbox_details'];?></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-offset-3 col-sm-9">
<?php if ($mailboxdata['attributes']['force_pw_update'] == "1"): ?>
<div class="alert alert-danger"><?=$lang['user']['force_pw_update'];?></div>
<?php endif; ?>
<p><a href="#pwChangeModal" data-toggle="modal">[<?=$lang['user']['change_password'];?>]</a></p>
<p><a target="_blank" href="https://mailcow.github.io/mailcow-dockerized-docs/client/#<?=$clientconfigstr;?>">[<?=$lang['user']['client_configuration'];?>]</a></p>
<p><a href="#userFilterModal" data-toggle="modal">[<?=$lang['user']['show_sieve_filters'];?>]</a></p>
<p><small>
<?php
if ($_SESSION['mailcow_cc_last_login']['remote']):
?>
<span style="margin-right:10px" class="glyphicon glyphicon-log-in"></span> <span data-time="<?=$_SESSION['mailcow_cc_last_login']['time'];?>" class="last_login_date"></span> (<?=$_SESSION['mailcow_cc_last_login']['remote'];?>)
<?php
else: echo "Last login: -"; endif;
?>
</small></p>
</div>
</div>
<hr>
<?php // Get user information about aliases
$user_get_alias_details = user_get_alias_details($username);
?>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['direct_aliases'];?>:
<p class="small"><?=$lang['user']['direct_aliases_desc'];?></p>
</div>
<div class="col-md-9 col-xs-7">
<p><?=$user_get_alias_details['direct_aliases'];?></p>
</div>
</div>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['shared_aliases'];?>:
<p class="small"><?=$lang['user']['shared_aliases_desc'];?></p>
</div>
<div class="col-md-9 col-xs-7">
<p><?=$user_get_alias_details['shared_aliases'];?></p>
</div>
</div>
<hr>
<div class="row">
<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">
<p><?=($user_get_alias_details['aliases_also_send_as'] == '*') ? $lang['user']['sender_acl_disabled'] : $user_get_alias_details['aliases_also_send_as'];?></p>
</div>
</div>
<div class="row">
<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">
<p><?=$user_get_alias_details['aliases_send_as_all'];?></p>
</div>
</div>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['is_catch_all'];?>:</div>
<div class="col-md-9 col-xs-7">
<p><?=$user_get_alias_details['is_catch_all'];?></p>
</div>
</div>
<hr>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['in_use'];?>:</div>
<div class="col-md-5 col-xs-7">
<div class="progress">
<div class="progress-bar progress-bar-<?=$mailboxdata['percent_class'];?>" role="progressbar" aria-valuenow="<?=$mailboxdata['percent_in_use'];?>" aria-valuemin="0" aria-valuemax="100" style="min-width:2em;width: <?=$mailboxdata['percent_in_use'];?>%;">
<?=$mailboxdata['percent_in_use'];?>%
</div>
</div>
<p><?=formatBytes($mailboxdata['quota_used'], 2);?> / <?=formatBytes($mailboxdata['quota'], 2);?>, <?=$mailboxdata['messages'];?> <?=$lang['user']['messages'];?></p>
</div>
</div>
<hr>
<?php
// Show tagging options
$get_tagging_options = mailbox('get', 'delimiter_action', $username);
?>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['tag_handling'];?>:</div>
<div class="col-md-9 col-xs-7">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['delimiter_action'];?>">
<button type="button" class="btn btn-sm btn-default <?=($get_tagging_options == "subfolder") ? 'active' : null; ?>"
data-action="edit_selected"
data-item="<?= htmlentities($username); ?>"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"subfolder"}'><?=$lang['user']['tag_in_subfolder'];?></button>
<button type="button" class="btn btn-sm btn-default <?=($get_tagging_options == "subject") ? 'active' : null; ?>"
data-action="edit_selected"
data-item="<?= htmlentities($username); ?>"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"subject"}'><?=$lang['user']['tag_in_subject'];?></button>
<button type="button" class="btn btn-sm btn-default <?=($get_tagging_options == "none") ? 'active' : null; ?>"
data-action="edit_selected"
data-item="<?= htmlentities($username); ?>"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"none"}'><?=$lang['user']['tag_in_none'];?></button>
</div>
<p class="help-block"><?=$lang['user']['tag_help_explain'];?></p>
<p class="help-block"><?=$lang['user']['tag_help_example'];?></p>
</div>
</div>
<?php
// Show TLS policy options
$get_tls_policy = mailbox('get', 'tls_policy', $username);
?>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['tls_policy'];?>:</div>
<div class="col-md-9 col-xs-7">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['tls_policy'];?>">
<button type="button" class="btn btn-sm btn-default <?=($get_tls_policy['tls_enforce_in'] == "1") ? "active" : null;?>"
data-action="edit_selected"
data-item="<?= htmlentities($username); ?>"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_in":<?=($get_tls_policy['tls_enforce_in'] == "1") ? "0" : "1";?>}'><?=$lang['user']['tls_enforce_in'];?></button>
<button type="button" class="btn btn-sm btn-default <?=($get_tls_policy['tls_enforce_out'] == "1") ? "active" : null;?>"
data-action="edit_selected"
data-item="<?= htmlentities($username); ?>"
data-id="tls_policy"
data-api-url='edit/tls_policy'
data-api-attr='{"tls_enforce_out":<?=($get_tls_policy['tls_enforce_out'] == "1") ? "0" : "1";?>}'><?=$lang['user']['tls_enforce_out'];?></button>
</div>
<p class="help-block"><?=$lang['user']['tls_policy_warning'];?></p>
</div>
</div>
<div class="row">
<div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['eas_reset'];?>:</div>
<div class="col-md-9 col-xs-7">
<button class="btn btn-xs btn-default" data-acl="<?=$_SESSION['acl']['eas_reset'];?>" data-action="delete_selected" data-text="<?=$lang['user']['eas_reset'];?>?" data-item="<?= htmlentities($username); ?>" data-id="eas_cache" data-api-url='delete/eas_cache' href="#"><?=$lang['user']['eas_reset_now'];?></button>
<p class="help-block"><?=$lang['user']['eas_reset_help'];?></p>
</div>
</div>
</div>
</div>
<!-- Nav tabs -->
<ul class="nav nav-pills nav-justified" role="tablist">
<li role="presentation" class="active"><a href="#SpamAliases" aria-controls="SpamAliases" role="tab" data-toggle="tab"><?=$lang['user']['spam_aliases'];?></a></li>
<li role="presentation"><a href="#Spamfilter" aria-controls="Spamfilter" role="tab" data-toggle="tab"><?=$lang['user']['spamfilter'];?></a></li>
<li role="presentation"><a href="#Syncjobs" aria-controls="Syncjobs" role="tab" data-toggle="tab"><?=$lang['user']['sync_jobs'];?></a></li>
</ul>
<hr>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="SpamAliases">
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="table-responsive">
<table class="table table-striped" id="tla_table"></table>
</div>
</div>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_alias'];?>">
<div class="btn-group">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="tla" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-time"></span> + 1h</a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-id="tla" data-api-url='delete/time_limited_alias' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
</div>
<div class="btn-group">
<a class="btn btn-sm btn-success dropdown-toggle" data-toggle="dropdown" href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['alias_create_random'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"1"}' href="#">1 <?=$lang['user']['hour'];?></a></li>
<li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"6"}' href="#">6 <?=$lang['user']['hours'];?></a></li>
<li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"24"}' href="#">1 <?=$lang['user']['day'];?></a></li>
<li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"168"}' href="#">1 <?=$lang['user']['week'];?></a></li>
<li><a data-action="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"672"}' href="#">4 <?=$lang['user']['weeks'];?></a></li>
</ul>
</div>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="Spamfilter">
<h4><?=$lang['user']['spamfilter_behavior'];?></h4>
<form class="form-horizontal" role="form" data-id="spam_score" method="post">
<div class="form-group">
<div class="col-lg-6 col-sm-12">
<input data-acl="<?=$_SESSION['acl']['spam_score'];?>" name="spam_score" id="spam_score" type="text" style="width: 100%;"
data-provide="slider"
data-slider-min="1"
data-slider-max="2000"
data-slider-scale='logarithmic'
data-slider-step="0.5"
data-slider-range="true"
data-slider-tooltip='always'
data-slider-id="slider1"
data-slider-value="[<?=mailbox('get', 'spam_score', $username);?>]"
data-slider-step="1" />
<br /><br />
<ul>
<li><?=$lang['user']['spamfilter_green'];?></li>
<li><?=$lang['user']['spamfilter_yellow'];?></li>
<li><?=$lang['user']['spamfilter_red'];?></li>
</ul>
<p><i><?=$lang['user']['spamfilter_default_score'];?> 5:15</i></p>
<p><?=$lang['user']['spamfilter_hint'];?></p>
</div>
</div>
<div class="form-group">
<div class="col-sm-10">
<button data-acl="<?=$_SESSION['acl']['spam_score'];?>" type="button" class="btn btn-sm btn-success" data-action="edit_selected"
data-item="<?= htmlentities($username); ?>"
data-id="spam_score"
data-api-url='edit/spam-score'
data-api-attr='{}'><?=$lang['user']['save_changes'];?></button>
</div>
</div>
</form>
<hr>
<div class="row">
<div class="col-sm-6">
<h4><?=$lang['user']['spamfilter_wl'];?></h4>
<p><?=$lang['user']['spamfilter_wl_desc'];?></p>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="wl_policy_mailbox_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_wl_mailbox" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-danger" data-action="delete_selected" data-id="policy_wl_mailbox" data-api-url='delete/mailbox-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</div>
</div>
<form class="form-inline" data-id="add_wl_policy_mailbox">
<div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
<input type="text" class="form-control" name="object_from" id="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-default" data-action="add_item" data-id="add_wl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username":<?= json_encode($username); ?>,"object_list":"wl"}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['spamfilter_table_add'];?></button>
</span>
</div>
</form>
</div>
<div class="col-sm-6">
<h4><?=$lang['user']['spamfilter_bl'];?></h4>
<p><?=$lang['user']['spamfilter_bl_desc'];?></p>
<div class="table-responsive">
<table class="table table-striped table-condensed" id="bl_policy_mailbox_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_bl_mailbox" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-danger" data-action="delete_selected" data-id="policy_bl_mailbox" data-api-url='delete/mailbox-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</div>
</div>
<form class="form-inline" data-id="add_bl_policy_mailbox">
<div class="input-group" data-acl="<?=$_SESSION['acl']['spam_policy'];?>">
<input type="text" class="form-control" name="object_from" id="object_from" placeholder="*@example.org" required>
<span class="input-group-btn">
<button class="btn btn-default" data-action="add_item" data-id="add_bl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username":<?= json_encode($username); ?>,"object_list":"bl"}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['spamfilter_table_add'];?></button>
</span>
</div>
</form>
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="Syncjobs">
<div class="table-responsive">
<table class="table table-striped" id="sync_job_table"></table>
</div>
<div class="mass-actions-user">
<div class="btn-group" data-acl="<?=$_SESSION['acl']['syncjobs'];?>">
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="syncjob" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
<a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
<li><a data-action="edit_selected" data-id="syncjob" data-api-url='edit/syncjob' data-api-attr='{"active":"0"}' href="#"><?=$lang['mailbox']['deactivate'];?></a></li>
<li role="separator" class="divider"></li>
<li><a data-action="delete_selected" data-text="<?=$lang['user']['eas_reset'];?>?" data-id="syncjob" data-api-url='delete/syncjob' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
<a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModal"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['create_syncjob'];?></a>
</div>
</div>
</div>
</div>
</div><!-- /container -->
<div style="margin-bottom:200px;"></div>
<?php
}
-if (isset($_SESSION['mailcow_cc_role'])) {
+if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] != 'admin') {
require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/user.php';
?>
<script type='text/javascript'>
<?php
$lang_user = json_encode($lang['user']);
echo "var lang = ". $lang_user . ";\n";
echo "var acl = '". json_encode($_SESSION['acl']) . "';\n";
echo "var csrf_token = '". $_SESSION['CSRF']['TOKEN'] . "';\n";
echo "var mailcow_cc_username = '". $_SESSION['mailcow_cc_username'] . "';\n";
echo "var pagination_size = '". $PAGINATION_SIZE . "';\n";
?>
</script>
<script src="js/footable.min.js"></script>
<script src="js/user.js"></script>
<?php
require_once("inc/footer.inc.php");
}
else {
header('Location: /');
exit();
}
?>

File Metadata

Mime Type
text/x-diff
Expires
9月 9 Tue, 5:41 AM (7 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5313
默认替代文本
(449 KB)

Event Timeline