[Postfix, Web] Feature: BCC maps
parent
967108c057
commit
ade4b9e7ae
|
@ -119,6 +119,28 @@ query = SELECT goto FROM alias
|
|||
AND active='1';
|
||||
EOF
|
||||
|
||||
cat <<EOF > /opt/postfix/conf/sql/mysql_recipient_bcc_maps.cf
|
||||
user = ${DBUSER}
|
||||
password = ${DBPASS}
|
||||
hosts = mysql
|
||||
dbname = ${DBNAME}
|
||||
query = SELECT bcc_dest FROM bcc_maps
|
||||
WHERE local_dest='%s'
|
||||
AND type='rcpt'
|
||||
AND active='1';
|
||||
EOF
|
||||
|
||||
cat <<EOF > /opt/postfix/conf/sql/mysql_sender_bcc_maps.cf
|
||||
user = ${DBUSER}
|
||||
password = ${DBPASS}
|
||||
hosts = mysql
|
||||
dbname = ${DBNAME}
|
||||
query = SELECT bcc_dest FROM bcc_maps
|
||||
WHERE local_dest='%s'
|
||||
AND type='sender'
|
||||
AND active='1';
|
||||
EOF
|
||||
|
||||
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_domains_maps.cf
|
||||
user = ${DBUSER}
|
||||
password = ${DBPASS}
|
||||
|
|
|
@ -39,7 +39,27 @@ postscreen_greet_ttl = 2d
|
|||
postscreen_greet_wait = 3s
|
||||
postscreen_non_smtp_command_enable = no
|
||||
postscreen_pipelining_enable = no
|
||||
proxy_read_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_sender_acl.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_sender_dependent_default_transport_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_sasl_passwd_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf, $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $smtpd_sender_login_maps
|
||||
proxy_read_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_sender_acl.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_sender_dependent_default_transport_maps.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_sasl_passwd_maps.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_sender_bcc_maps.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_recipient_bcc_maps.cf,
|
||||
$local_recipient_maps,
|
||||
$mydestination,
|
||||
$virtual_alias_maps,
|
||||
$virtual_alias_domains,
|
||||
$virtual_mailbox_maps,
|
||||
$virtual_mailbox_domains,
|
||||
$relay_recipient_maps,
|
||||
$relay_domains,
|
||||
$canonical_maps,
|
||||
$sender_canonical_maps,
|
||||
$recipient_canonical_maps,
|
||||
$relocated_maps,
|
||||
$transport_maps,
|
||||
$mynetworks,
|
||||
$smtpd_sender_login_maps
|
||||
queue_run_delay = 300s
|
||||
relay_domains = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_relay_domain_maps.cf
|
||||
relay_recipient_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_relay_recipient_maps.cf
|
||||
|
@ -79,10 +99,15 @@ smtpd_tls_mandatory_ciphers = high
|
|||
smtpd_tls_security_level = may
|
||||
tls_ssl_options = NO_COMPRESSION
|
||||
tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
|
||||
virtual_alias_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf, proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_catchall_maps.cf
|
||||
virtual_alias_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_maps.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf,
|
||||
proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_alias_domain_catchall_maps.cf
|
||||
virtual_gid_maps = static:5000
|
||||
virtual_mailbox_base = /var/vmail/
|
||||
virtual_mailbox_domains = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_domains_maps.cf
|
||||
recipient_bcc_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_recipient_bcc_maps.cf
|
||||
sender_bcc_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_sender_bcc_maps.cf
|
||||
virtual_mailbox_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_mailbox_maps.cf
|
||||
virtual_minimum_uid = 104
|
||||
virtual_transport = lmtp:inet:dovecot:24
|
||||
|
|
|
@ -7,7 +7,6 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
$tfa_data = get_tfa();
|
||||
?>
|
||||
<div class="container">
|
||||
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active">
|
||||
<a href="#tab-access" aria-controls="tab-access" role="tab" data-toggle="tab"><?=$lang['admin']['access'];?></a>
|
||||
|
@ -22,7 +21,9 @@ $tfa_data = get_tfa();
|
|||
<li role="presentation"><a href="#tab-postfix-logs" aria-controls="tab-postfix-logs" role="tab" data-toggle="tab">Postfix</a></li>
|
||||
<li role="presentation"><a href="#tab-dovecot-logs" aria-controls="tab-dovecot-logs" role="tab" data-toggle="tab">Dovecot</a></li>
|
||||
<li role="presentation"><a href="#tab-sogo-logs" aria-controls="tab-sogo-logs" role="tab" data-toggle="tab">SOGo</a></li>
|
||||
<?php if (F2B == 1): ?>
|
||||
<li role="presentation"><a href="#tab-fail2ban-logs" aria-controls="tab-fail2ban-logs" role="tab" data-toggle="tab">Fail2ban</a></li>
|
||||
<?php endif; ?>
|
||||
<li role="presentation"><a href="#tab-rspamd-history" aria-controls="tab-rspamd-history" role="tab" data-toggle="tab">Rspamd</a></li>
|
||||
<li role="presentation"><a href="#tab-autodiscover-logs" aria-controls="tab-autodiscover-logs" role="tab" data-toggle="tab">Autodiscover</a></li>
|
||||
</ul>
|
||||
|
@ -127,7 +128,9 @@ $tfa_data = get_tfa();
|
|||
<div id="scrollbox" class="list-group">
|
||||
<a href="#dkim" class="list-group-item"><?=$lang['admin']['dkim_keys'];?></a>
|
||||
<a href="#fwdhosts" class="list-group-item"><?=$lang['admin']['forwarding_hosts'];?></a>
|
||||
<?php if (F2B == 1): ?>
|
||||
<a href="#f2bparams" class="list-group-item"><?=$lang['admin']['f2b_parameters'];?></a>
|
||||
<?php endif; ?>
|
||||
<a href="#relayhosts" class="list-group-item">Relayhosts</a>
|
||||
<a href="#customize" class="list-group-item"><?=$lang['admin']['customize'];?></a>
|
||||
<a href="#top" class="list-group-item" style="border-top:1px dashed #dadada">↸ <?=$lang['admin']['to_top'];?></a>
|
||||
|
@ -307,6 +310,7 @@ $tfa_data = get_tfa();
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (F2B == 1): ?>
|
||||
<span class="anchor" id="f2bparams"></span>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?=$lang['admin']['f2b_parameters'];?></div>
|
||||
|
@ -335,6 +339,7 @@ $tfa_data = get_tfa();
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<span class="anchor" id="relayhosts"></span>
|
||||
<div class="panel panel-default">
|
||||
|
@ -506,6 +511,8 @@ $tfa_data = get_tfa();
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<?php if (F2B == 1): ?>
|
||||
<div role="tabpanel" class="tab-pane" id="tab-fail2ban-logs">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Fail2ban <span class="badge badge-info log-lines"></span>
|
||||
|
@ -522,6 +529,7 @@ $tfa_data = get_tfa();
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="tab-rspamd-history">
|
||||
<div class="panel panel-default">
|
||||
|
|
|
@ -608,6 +608,52 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||
<?php
|
||||
}
|
||||
}
|
||||
elseif (isset($_GET['bcc']) && !empty($_GET["bcc"])) {
|
||||
$bcc = intval($_GET["bcc"]);
|
||||
$result = bcc('details', $bcc);
|
||||
if (!empty($result)) {
|
||||
?>
|
||||
<h4>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">BCC destination</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea id="bcc_dest" class="form-control" autocapitalize="none" autocorrect="off" rows="10" id="bcc_dest" name="bcc_dest" required><?=$result['bcc_dest'];?></textarea>
|
||||
<small>BCC destinations can only be valid email addresses. Separated by whitespace, semicolon, new line or comma.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="type">Type:</label>
|
||||
<div class="col-sm-10">
|
||||
<select id="addFilterType" name="type" id="type" required>
|
||||
<option value="sender" <?=($result['type'] == 'sender') ? 'selected' : null;?>>Sender map</option>
|
||||
<option value="rcpt" <?=($result['type'] == 'rcpt') ? 'selected' : null;?>>Recipient 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" id="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
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin" || $_SESSION['mailcow_cc_role'] == "user") {
|
||||
if (isset($_GET['syncjob']) &&
|
||||
|
@ -722,9 +768,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin" || $_SESSION['mailcow_cc_role'] == "user") {
|
||||
if (isset($_GET['filter']) &&
|
||||
elseif (isset($_GET['filter']) &&
|
||||
is_numeric($_GET['filter'])) {
|
||||
$id = $_GET["filter"];
|
||||
$result = mailbox('get', 'filter_details', $id);
|
||||
|
@ -774,7 +818,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
|||
<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
<?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',
|
||||
'msg' => sprintf($lang['danger']['access_denied'])
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$local_dest = strtolower(trim($_data['local_dest']));
|
||||
$bcc_dest = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['bcc_dest']));
|
||||
$active = intval($_data['active']);
|
||||
$type = $_data['type'];
|
||||
if ($type != 'sender' && $type != 'rcpt') {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'Invalid BCC map type'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (empty($bcc_dest)) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'BCC destination cannot be 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',
|
||||
'msg' => sprintf($lang['danger']['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',
|
||||
'msg' => sprintf($lang['danger']['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;
|
||||
}
|
||||
foreach ($bcc_dest as &$bcc_dest_e) {
|
||||
if (!filter_var($bcc_dest_e, FILTER_VALIDATE_EMAIL)) {
|
||||
$bcc_dest_e = null;;
|
||||
}
|
||||
$bcc_dest_e = strtolower($bcc_dest_e);
|
||||
}
|
||||
$bcc_dest = array_filter($bcc_dest);
|
||||
$bcc_dest = implode(",", $bcc_dest);
|
||||
if (empty($bcc_dest)) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'BCC map destination cannot be empty'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$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));
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($num_results != 0) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'A BCC map entry "' . htmlspecialchars($local_dest_sane) . '" exists for type "' . $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',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'success',
|
||||
'msg' => 'BCC map entry saved'
|
||||
);
|
||||
break;
|
||||
case 'edit':
|
||||
if (!isset($_SESSION['acl']['bcc_maps']) || $_SESSION['acl']['bcc_maps'] != "1" ) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => sprintf($lang['danger']['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',
|
||||
'msg' => sprintf($lang['danger']['access_denied'])
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$bcc_dest = array_map('trim', preg_split( "/( |,|;|\n)/", $bcc_dest));
|
||||
$active = intval($_data['active']);
|
||||
foreach ($bcc_dest as &$bcc_dest_e) {
|
||||
if (!filter_var($bcc_dest_e, FILTER_VALIDATE_EMAIL)) {
|
||||
$bcc_dest_e = null;;
|
||||
}
|
||||
$bcc_dest_e = strtolower($bcc_dest_e);
|
||||
}
|
||||
$bcc_dest = array_filter($bcc_dest);
|
||||
$bcc_dest = implode(",", $bcc_dest);
|
||||
if (empty($bcc_dest)) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'BCC map destination cannot be empty'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
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'];
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (isset($id_now) && $id_now != $id) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'A BCC map entry ' . htmlspecialchars($local_dest) . ' exists for this type'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$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) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'success',
|
||||
'msg' => 'BCC map entry edited'
|
||||
);
|
||||
break;
|
||||
case 'details':
|
||||
$bccdata = array();
|
||||
$id = intval($_data);
|
||||
try {
|
||||
$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);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT `id`, `domain` FROM `bcc_maps`");
|
||||
$all_items = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
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':
|
||||
$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',
|
||||
'msg' => sprintf($lang['danger']['access_denied'])
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `id`= :id");
|
||||
$stmt->execute(array(':id' => $id));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'MySQL: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'success',
|
||||
'msg' => 'Deleted BCC map id/s ' . implode(', ', $ids)
|
||||
);
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
<?php
|
||||
|
||||
function customize($_action, $_item, $_data = null) {
|
||||
global $redis;
|
||||
global $lang;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
if (F2B == 1) {
|
||||
function fail2ban($_action, $_data = null) {
|
||||
global $redis;
|
||||
global $lang;
|
||||
|
@ -96,3 +97,4 @@ function fail2ban($_action, $_data = null) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -722,7 +722,7 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
|||
}
|
||||
$active = intval($_data['active']);
|
||||
$quota_b = ($quota_m * 1048576);
|
||||
$maildir = $domain."/".$local_part."/";
|
||||
$maildir = $domain . "/" . $local_part . "/mail-" . time() . "/";
|
||||
if (!is_valid_domain_name($domain)) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
|
@ -3103,10 +3103,6 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
|||
}
|
||||
foreach ($ids as $id) {
|
||||
if (!is_numeric($id)) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => $id
|
||||
);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
|
@ -3154,10 +3150,6 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
|||
}
|
||||
foreach ($ids as $id) {
|
||||
if (!is_numeric($id)) {
|
||||
$_SESSION['return'] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => $id
|
||||
);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
|
@ -3366,6 +3358,10 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
|||
$stmt->execute(array(
|
||||
':domain' => '%@'.$domain,
|
||||
));
|
||||
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :domain");
|
||||
$stmt->execute(array(
|
||||
':domain' => '%@'.$domain,
|
||||
));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
|
@ -3486,6 +3482,10 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
|||
$stmt->execute(array(
|
||||
':alias_domain' => $alias_domain,
|
||||
));
|
||||
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :alias_domain");
|
||||
$stmt->execute(array(
|
||||
':domain' => '%@'.$alias_domain,
|
||||
));
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$_SESSION['return'] = array(
|
||||
|
@ -3580,6 +3580,10 @@ function mailbox($_action, $_type, $_data = null, $attr = null) {
|
|||
$stmt->execute(array(
|
||||
':username' => $username
|
||||
));
|
||||
$stmt = $pdo->prepare("DELETE FROM `bcc_maps` WHERE `local_dest` = :username");
|
||||
$stmt->execute(array(
|
||||
':username' => $username
|
||||
));
|
||||
$stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias`
|
||||
WHERE `goto` REGEXP :username");
|
||||
$stmt->execute(array(':username' => '(^|,)'.$username.'($|,)'));
|
||||
|
|
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
|||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "14112017_2103";
|
||||
$db_version = "16112017_2259";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
@ -202,6 +202,7 @@ function init_db_schema() {
|
|||
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"filters" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
"bcc_maps" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||
),
|
||||
"keys" => array(
|
||||
"fkey" => array(
|
||||
|
@ -325,6 +326,27 @@ function init_db_schema() {
|
|||
),
|
||||
"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"
|
||||
),
|
||||
"tfa" => array(
|
||||
"cols" => array(
|
||||
"id" => "INT NOT NULL AUTO_INCREMENT",
|
||||
|
|
|
@ -67,6 +67,7 @@ include $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.
|
|||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.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.bcc.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php';
|
||||
|
|
|
@ -118,3 +118,6 @@ $OTP_LABEL = "mailcow UI";
|
|||
|
||||
// Default "to" address in relay test tool
|
||||
$RELAY_TO = "null@hosted.mailcow.de";
|
||||
|
||||
// Internal constants, can be ignored
|
||||
define("F2B", 1);
|
|
@ -314,7 +314,56 @@ jQuery(function($){
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
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":"Type"},
|
||||
{"name":"local_dest","title":"Local destination"},
|
||||
{"name":"bcc_dest","title":"BCC destination/s"},
|
||||
{"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="#" id="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 + '" />';
|
||||
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,
|
||||
"position": "left",
|
||||
"placeholder": lang.filter_table
|
||||
},
|
||||
"sorting": {
|
||||
"enabled": true
|
||||
}
|
||||
});
|
||||
}
|
||||
function draw_alias_table() {
|
||||
ft_alias_table = FooTable.init('#alias_table', {
|
||||
"columns": [
|
||||
|
@ -530,5 +579,6 @@ jQuery(function($){
|
|||
draw_aliasdomain_table();
|
||||
draw_sync_job_table();
|
||||
draw_filter_table();
|
||||
draw_bcc_table();
|
||||
|
||||
});
|
||||
|
|
|
@ -258,6 +258,39 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
|||
));
|
||||
}
|
||||
break;
|
||||
case "bcc":
|
||||
if (isset($_POST['attr'])) {
|
||||
$attr = (array)json_decode($_POST['attr'], true);
|
||||
if (bcc('add', $attr) === false) {
|
||||
if (isset($_SESSION['return'])) {
|
||||
echo json_encode($_SESSION['return']);
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'error',
|
||||
'msg' => 'Cannot add item'
|
||||
));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isset($_SESSION['return'])) {
|
||||
echo json_encode($_SESSION['return']);
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'success',
|
||||
'msg' => 'Task completed'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'error',
|
||||
'msg' => 'Cannot find attributes in post data'
|
||||
));
|
||||
}
|
||||
break;
|
||||
case "domain-policy":
|
||||
if (isset($_POST['attr'])) {
|
||||
$attr = (array)json_decode($_POST['attr'], true);
|
||||
|
@ -1034,6 +1067,42 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$data = bcc('details', $object);
|
||||
if (!empty($data)) {
|
||||
$data[] = $details;
|
||||
}
|
||||
if (!isset($data) || empty($data)) {
|
||||
echo '{}';
|
||||
}
|
||||
else {
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "policy_wl_mailbox":
|
||||
switch ($object) {
|
||||
default:
|
||||
|
@ -1464,6 +1533,47 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
|||
));
|
||||
}
|
||||
break;
|
||||
case "bcc":
|
||||
if (isset($_POST['items'])) {
|
||||
$items = (array)json_decode($_POST['items'], true);
|
||||
if (is_array($items)) {
|
||||
if (bcc('delete', array('id' => $items)) === false) {
|
||||
if (isset($_SESSION['return'])) {
|
||||
echo json_encode($_SESSION['return']);
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'error',
|
||||
'msg' => 'Deletion of items/s failed'
|
||||
));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isset($_SESSION['return'])) {
|
||||
echo json_encode($_SESSION['return']);
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'success',
|
||||
'msg' => 'Task completed'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'error',
|
||||
'msg' => 'Cannot find id array in post data'
|
||||
));
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'error',
|
||||
'msg' => 'Cannot find items in post data'
|
||||
));
|
||||
}
|
||||
break;
|
||||
case "fwdhost":
|
||||
if (isset($_POST['items'])) {
|
||||
$items = (array)json_decode($_POST['items'], true);
|
||||
|
@ -2314,6 +2424,50 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
|||
));
|
||||
}
|
||||
break;
|
||||
case "bcc":
|
||||
if (isset($_POST['items']) && isset($_POST['attr'])) {
|
||||
$items = (array)json_decode($_POST['items'], true);
|
||||
$attr = (array)json_decode($_POST['attr'], true);
|
||||
$postarray = array_merge(array('id' => $items), $attr);
|
||||
if (is_array($postarray['id'])) {
|
||||
if (bcc('edit', $postarray) === false) {
|
||||
if (isset($_SESSION['return'])) {
|
||||
echo json_encode($_SESSION['return']);
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'error',
|
||||
'msg' => 'Edit failed'
|
||||
));
|
||||
}
|
||||
exit();
|
||||
}
|
||||
else {
|
||||
if (isset($_SESSION['return'])) {
|
||||
echo json_encode($_SESSION['return']);
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'success',
|
||||
'msg' => 'Task completed'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'error',
|
||||
'msg' => 'Incomplete post data'
|
||||
));
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo json_encode(array(
|
||||
'type' => 'error',
|
||||
'msg' => 'Incomplete post data'
|
||||
));
|
||||
}
|
||||
break;
|
||||
case "resource":
|
||||
if (isset($_POST['items']) && isset($_POST['attr'])) {
|
||||
$items = (array)json_decode($_POST['items'], true);
|
||||
|
|
|
@ -21,6 +21,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
</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">BCC maps</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="row">
|
||||
|
@ -207,6 +208,34 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div role="tabpanel" class="tab-pane" id="tab-bcc">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">BCC maps</h3>
|
||||
</div>
|
||||
<p style="margin:10px" class="help-block">A recipient map type entry is used, when the local destination acts as recipient of a mail. Sender maps conform to the same principle.
|
||||
The local destination will not be informed about a failed delivery.</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="bcc_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="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 id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"active":"1"}' href="#"><?=$lang['mailbox']['activate'];?></a></li>
|
||||
<li><a id="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 id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"sender"}' href="#">Switch to sender map type</a></li>
|
||||
<li><a id="edit_selected" data-id="bcc" data-api-url='edit/bcc' data-api-attr='{"type":"rcpt"}' href="#">Switch to recipient map type</a></li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li><a id="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> Add BCC map</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- /tab-content -->
|
||||
</div> <!-- /col-md-12 -->
|
||||
</div> <!-- /row -->
|
||||
|
|
|
@ -509,6 +509,77 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
|||
</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">BCC map</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" role="form" data-id="add_bcc">
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="local_dest">Local destination:</label>
|
||||
<div class="col-sm-10">
|
||||
<select id="addSelectLocalDest" name="local_dest" id="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">BCC map type:</label>
|
||||
<div class="col-sm-10">
|
||||
<select id="addFBCCType" name="type" id="type" required>
|
||||
<option value="sender">Sender map</option>
|
||||
<option value="rcpt">Recipient map</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label col-sm-2" for="bcc_dest">BCC destination/s:</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea autocorrect="off" spellcheck="false" autocapitalize="none" class="form-control" rows="20" id="bcc_dest" name="bcc_dest" required></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" 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" id="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 -->
|
||||
<!-- log modal -->
|
||||
<div class="modal fade" id="syncjobLogModal" tabindex="-1" role="dialog" aria-labelledby="syncjobLogModalLabel">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
|
|
|
@ -179,7 +179,7 @@ services:
|
|||
- dovecot
|
||||
|
||||
postfix-mailcow:
|
||||
image: mailcow/postfix:1.7
|
||||
image: mailcow/postfix:1.8
|
||||
build: ./data/Dockerfiles/postfix
|
||||
volumes:
|
||||
- ./data/conf/postfix:/opt/postfix/conf
|
||||
|
|
Loading…
Reference in New Issue