public
nobgit
read
NobMail
Based on mailcow: dockerized
Languages
Repository composition by tracked source files.
PHP
49%
JavaScript
35%
HTML
9%
CSS
4%
Shell
2%
Python
1%
Lua
0%
Perl
0%
Ruby
0%
SCSS
0%
Create file
Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git
Commit
Web UI improvements
ce6bf18c
data/web/add.php | 403 ------------------
data/web/admin.php | 32 +-
data/web/css/mailbox.css | 3 +
data/web/css/user.css | 3 +
data/web/edit.php | 24 +-
data/web/inc/footer.inc.php | 2 +-
data/web/inc/functions.dkim.inc.php | 151 +++++++
data/web/inc/functions.fwdhost.inc.php | 171 ++++++++
data/web/inc/functions.inc.php | 305 --------------
data/web/inc/functions.mailbox.inc.php | 12 +-
data/web/inc/functions.policy.inc.php | 8 +-
data/web/inc/prerequisites.inc.php | 4 +-
data/web/inc/triggers.inc.php | 40 --
data/web/inc/vars.inc.php | 8 +-
data/web/js/add.js | 4 +-
data/web/js/admin.js | 4 -
data/web/js/api.js | 84 ++--
data/web/js/mailbox.js | 24 ++
data/web/json_api.php | 469 +++++++++++++++++++--
data/web/lang/lang.en.php | 6 +-
data/web/mailbox.php | 27 +-
data/web/{inc/tfa_modals.php => modals/footer.php} | 0
data/web/modals/mailbox.php | 303 +++++++++++++
data/web/modals/user.php | 106 +++++
data/web/user.php | 19 +-
25 files changed, 1318 insertions(+), 894 deletions(-)
delete mode 100644 data/web/add.php
create mode 100644 data/web/inc/functions.dkim.inc.php
create mode 100644 data/web/inc/functions.fwdhost.inc.php
rename data/web/{inc/tfa_modals.php => modals/footer.php} (100%)
create mode 100644 data/web/modals/mailbox.php
create mode 100644 data/web/modals/user.php
Diff
diff --git a/data/web/add.php b/data/web/add.php
deleted file mode 100644
index b81a4e55..00000000
--- a/data/web/add.php
+++ /dev/null
@@ -1,403 +0,0 @@
-<?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['add']['title'];?></h3>
- </div>
- <div class="panel-body">
-<?php
-if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
- if (isset($_GET['domain']) && $_SESSION['mailcow_cc_role'] == "admin") {
-?>
- <h4><?=$lang['add']['domain'];?></h4>
- <form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
- <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="domain"><?=$lang['add']['domain'];?>:</label>
- <div class="col-sm-10">
- <input type="text" autocorrect="off" autocapitalize="none" class="form-control" name="domain" id="domain">
- </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" id="description">
- </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" id="aliases" value="400">
- </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" id="mailboxes" value="10">
- </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" id="maxquota" value="3072">
- </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" id="quota" value="10240">
- </div>
- </div>
- <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>
- <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 type="submit" name="mailbox_add_domain" class="btn btn-success"><?=$lang['add']['save'];?></button>
- </div>
- </div>
- <p><span class="glyphicon glyphicon-exclamation-sign text-danger"></span> <?=$lang['add']['restart_sogo_hint'];?></p>
- </form>
-<?php
- }
- elseif (isset($_GET['alias'])) {
-?>
- <h4><?=$lang['add']['alias'];?></h4>
- <p><?=$lang['add']['alias_spf_fail'];?></p>
- <form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
- <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"></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 autocorrect="off" autocapitalize="none" class="form-control" rows="5" id="goto" name="goto"></textarea>
- <p><?=$lang['add']['target_address_info'];?></p>
- </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 type="submit" name="mailbox_add_alias" class="btn btn-success "><?=$lang['add']['save'];?></button>
- </div>
- </div>
- </form>
- <?php
- }
- elseif (isset($_GET['aliasdomain'])) {
- ?>
- <h4><?=$lang['add']['alias_domain'];?></h4>
- <form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
- <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"></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 name="target_domain" id="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 type="submit" name="mailbox_add_alias_domain" class="btn btn-success "><?=$lang['add']['save'];?></button>
- </div>
- </div>
- </form>
- <?php
- }
- elseif (isset($_GET['mailbox'])) {
- ?>
- <h4><?=$lang['add']['mailbox'];?></h4>
- <form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
- <input type="hidden" value="0" name="active">
- <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" id="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 id="addSelectDomain" name="domain" id="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" id="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>
- </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" class="form-control" name="password" id="password" placeholder="">
- </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" id="password2" placeholder="">
- </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 type="submit" name="mailbox_add_mailbox" class="btn btn-success "><?=$lang['add']['save'];?></button>
- </div>
- </div>
- </form>
- <?php
- }
- elseif (isset($_GET['resource'])) {
- ?>
- <h4><?=$lang['add']['resource'];?></h4>
- <form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
- <input type="hidden" value="0" name="active">
- <input type="hidden" value="0" name="multiple_bookings">
- <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" id="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 name="domain" id="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" id="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">
- <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">
- <div class="checkbox">
- <label><input type="checkbox" value="1" name="multiple_bookings" checked> <?=$lang['add']['multiple_bookings'];?></label>
- </div>
- </div>
- </div>
- <div class="form-group">
- <div class="col-sm-offset-2 col-sm-10">
- <button type="submit" name="mailbox_add_resource" class="btn btn-success "><?=$lang['add']['save'];?></button>
- </div>
- </div>
- </form>
- <?php
- }
- else {
- ?>
- <div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
- <?php
- }
-}
-elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "user")) {
- if (isset($_GET['syncjob'])) {
-?>
- <h4><?=$lang['add']['syncjob'];?></h4>
- <p><?=$lang['add']['syncjob_hint'];?></p>
- <form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
- <input type="hidden" value="0" name="active">
- <input type="hidden" value="0" name="delete1">
- <input type="hidden" value="0" name="delete2duplicates">
- <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" id="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" id="port1" min="1" max="65535" value="143" required>
- </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" id="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="text" class="form-control" name="password1" id="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" id="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="10" max="3600" value="20" required>
- </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="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" id="maxage" min="0" max="32000" value="0">
- </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" id="exclude" value="(?i)spam|(?i)junk">
- </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'];?></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'];?></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 type="submit" name="add_syncjob" class="btn btn-success "><?=$lang['add']['save'];?></button>
- </div>
- </div>
- </form>
- <?php
- }
-}
-
-else {
-?>
- <div class="alert alert-danger" role="alert"><?=$lang['danger']['access_denied'];?></div>
-<?php
-}
-?>
- </div>
- </div>
- </div>
- </div>
-<a href="<?=$_SESSION['return_to'];?>">← <?=$lang['add']['previous'];?></a>
-</div> <!-- /container -->
-<script src="js/add.js"></script>
-<?php
-require_once("inc/footer.inc.php");
-?>
diff --git a/data/web/admin.php b/data/web/admin.php
index 64ad77ec..674d7f29 100644
--- a/data/web/admin.php
+++ b/data/web/admin.php
@@ -176,7 +176,7 @@ $tfa_data = get_tfa();
</div>
<?php
foreach(mailbox('get', 'domains') as $domain) {
- if (!empty($dkim = dkim_get_key_details($domain))) {
+ if (!empty($dkim = dkim('details', $domain))) {
?>
<div class="row">
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" /></div>
@@ -204,8 +204,8 @@ $tfa_data = get_tfa();
</div>
<?php
}
- foreach(mailbox('get', 'alias_domains') as $alias_domain) {
- if (!empty($dkim = dkim_get_key_details($alias_domain))) {
+ foreach(mailbox('get', 'alias_domains', $domain) as $alias_domain) {
+ if (!empty($dkim = dkim('details', $alias_domain))) {
?>
<div class="row">
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" /></div>
@@ -235,8 +235,8 @@ $tfa_data = get_tfa();
}
}
}
- foreach(dkim_get_blind_keys() as $blind) {
- if (!empty($dkim = dkim_get_key_details($blind))) {
+ foreach(dkim('blind') as $blind) {
+ if (!empty($dkim = dkim('details', $blind))) {
?>
<div class="row">
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>" /></div>
@@ -257,7 +257,7 @@ $tfa_data = get_tfa();
?>
<legend style="margin-top:40px"><?=$lang['admin']['dkim_add_key'];?></legend>
- <form class="form-inline" role="form" method="post">
+ <form class="form-inline" data-id="dkim" role="form" method="post">
<div class="form-group">
<label for="domain">Domain</label>
<input class="form-control" id="domain" name="domain" placeholder="example.org" required>
@@ -272,7 +272,7 @@ $tfa_data = get_tfa();
<option data-subtext="bits">2048</option>
</select>
</div>
- <button type="submit" name="dkim_add_key" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
+ <button class="btn btn-default" id="add_item" data-id="dkim" data-api-url='add/dkim' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
</form>
</div>
</div>
@@ -281,18 +281,24 @@ $tfa_data = get_tfa();
<div class="panel-heading"><?=$lang['admin']['forwarding_hosts'];?></div>
<div class="panel-body">
<p style="margin-bottom:40px"><?=$lang['admin']['forwarding_hosts_hint'];?></p>
+ <div class="table-responsive">
+ <table class="table table-striped table-condensed" id="forwardinghoststable"></table>
+ </div>
<div class="mass-actions-admin">
<div class="btn-group btn-group-sm">
<button type="button" id="toggle_multi_select_all" data-id="fwdhosts" class="btn btn-default"><?=$lang['mailbox']['toggle_all'];?></button>
- <button type="button" id="delete_selected" name="delete_selected" data-id="fwdhosts" data-api-url="delete/fwdhost" class="btn btn-danger"><?=$lang['admin']['remove'];?></button>
+ <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="fwdhosts" data-api-url='edit/fwdhost' data-api-attr='{"keep_spam":"0"}' href="#">Enable spam filter</a></li>
+ <li><a id="edit_selected" data-id="fwdhosts" data-api-url='edit/fwdhost' data-api-attr='{"keep_spam":"1"}' href="#">Disable spam filter</a></li>
+ <li role="separator" class="divider"></li>
+ <li><a id="delete_selected" data-id="fwdhosts" data-api-url='delete/fwdhost' href="#"><?=$lang['admin']['remove'];?></a></li>
+ </ul>
</div>
</div>
- <div class="table-responsive">
- <table class="table table-striped" id="forwardinghoststable"></table>
- </div>
<legend><?=$lang['admin']['add_forwarding_host'];?></legend>
<p class="help-block"><?=$lang['admin']['forwarding_hosts_add_hint'];?></p>
- <form class="form-inline" role="form" method="post">
+ <form class="form-inline" data-id="fwdhost" role="form" method="post">
<div class="form-group">
<label for="hostname"><?=$lang['admin']['host'];?></label>
<input class="form-control" id="hostname" name="hostname" placeholder="example.org" required>
@@ -303,7 +309,7 @@ $tfa_data = get_tfa();
<option value="0"><?=$lang['admin']['inactive'];?></option>
</select>
</div>
- <button type="submit" name="add_forwarding_host" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
+ <button class="btn btn-default" id="add_item" data-id="fwdhost" data-api-url='add/fwdhost' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
</form>
</div>
</div>
diff --git a/data/web/css/mailbox.css b/data/web/css/mailbox.css
index 79e88255..63e688dc 100644
--- a/data/web/css/mailbox.css
+++ b/data/web/css/mailbox.css
@@ -27,3 +27,6 @@ table.footable>tbody>tr.footable-empty>td {
user-select: none;
padding:10px 0 10px 10px;
}
+.inputMissingAttr {
+ border-color: #FF4136;
+}
\ No newline at end of file
diff --git a/data/web/css/user.css b/data/web/css/user.css
index 605a1010..2222b624 100644
--- a/data/web/css/user.css
+++ b/data/web/css/user.css
@@ -22,3 +22,6 @@ table.footable>tbody>tr.footable-empty>td {
user-select: none;
padding:10px 0 10px 0;
}
+.inputMissingAttr {
+ border-color: #FF4136;
+}
diff --git a/data/web/edit.php b/data/web/edit.php
index d9121401..d4f6ce19 100644
--- a/data/web/edit.php
+++ b/data/web/edit.php
@@ -208,12 +208,12 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
</div>
</form>
<?php
- if (!empty($dkim = dkim_get_key_details($domain))) {
+ if (!empty($dkim = dkim('details', $domain))) {
?>
<hr>
<div class="row">
<div class="col-xs-2">
- <p>Domain: <strong><?=htmlspecialchars($result['domain_name']);?></strong> (dkim._domainkey)</p>
+ <p>Domain: <strong><?=htmlspecialchars($result['domain_name']);?></strong> (<?=$dkim['dkim_selector'];?>._domainkey)</p>
</div>
<div class="col-xs-10">
<pre><?=$dkim['dkim_txt'];?></pre>
@@ -233,17 +233,15 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
<div class="mass-actions-user">
<div class="btn-group">
<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" id="delete_selected" data-id="policy_wl_domain" data-api-url='delete/policy_mailbox' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+ <a class="btn btn-sm btn-danger" id="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" method="post">
+ <form class="form-inline" data-id="add_wl_policy_domain">
<div class="input-group">
<input type="text" class="form-control" name="object_from" id="object_from" placeholder="*@example.org" required>
- <input type="hidden" name="domain" value="<?= $domain ;?>">
- <input type="hidden" name="object_list" value="wl">
<span class="input-group-btn">
- <button type="submit" id="add_policy_list_item" name="add_policy_list_item" class="btn btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
+ <button class="btn btn-default" id="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>
@@ -257,17 +255,15 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
<div class="mass-actions-user">
<div class="btn-group">
<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" id="delete_selected" data-id="policy_bl_domain" data-api-url='delete/policy_mailbox' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+ <a class="btn btn-sm btn-danger" id="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" method="post">
+ <form class="form-inline" data-id="add_bl_policy_domain">
<div class="input-group">
<input type="text" class="form-control" name="object_from" id="object_from" placeholder="*@example.org" required>
- <input type="hidden" name="domain" value="<?= $domain ;?>">
- <input type="hidden" name="object_list" value="bl">
<span class="input-group-btn">
- <button type="submit" id="add_policy_list_item" name="add_policy_list_item" class="btn btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
+ <button class="btn btn-default" id="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>
@@ -312,12 +308,12 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
</div>
</form>
<?php
- if (!empty($dkim = dkim_get_key_details($alias_domain))) {
+ 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._domainkey)</p>
+ <p>Domain: <strong><?=htmlspecialchars($result['alias_domain']);?></strong> (<?=$dkim['dkim_selector'];?>._domainkey)</p>
</div>
<div class="col-xs-10">
<pre><?=$dkim['dkim_txt'];?></pre>
diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php
index d364a4df..336a9c4f 100644
--- a/data/web/inc/footer.inc.php
+++ b/data/web/inc/footer.inc.php
@@ -1,5 +1,5 @@
<?php
-include 'inc/tfa_modals.php';
+include 'modals/footer.php';
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'admin'):
?>
diff --git a/data/web/inc/functions.dkim.inc.php b/data/web/inc/functions.dkim.inc.php
new file mode 100644
index 00000000..16fb4da1
--- /dev/null
+++ b/data/web/inc/functions.dkim.inc.php
@@ -0,0 +1,151 @@
+<?php
+
+function dkim($_action, $_data = null) {
+ global $redis;
+ global $lang;
+ switch ($_action) {
+ case 'add':
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ $key_length = intval($_data['key_size']);
+ $dkim_selector = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : 'dkim';
+ $domain = $_data['domain'];
+ if (!is_valid_domain_name($domain) || !is_numeric($key_length)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
+ );
+ return false;
+ }
+ if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
+ );
+ return false;
+ }
+ if (!ctype_alnum($dkim_selector)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
+ );
+ return false;
+ }
+ $config = array(
+ "digest_alg" => "sha256",
+ "private_key_bits" => $key_length,
+ "private_key_type" => OPENSSL_KEYTYPE_RSA,
+ );
+ if ($keypair_ressource = openssl_pkey_new($config)) {
+ $key_details = openssl_pkey_get_details($keypair_ressource);
+ $pubKey = implode(array_slice(
+ array_filter(
+ explode(PHP_EOL, $key_details['key'])
+ ), 1, -1)
+ );
+ // Save public key and selector to redis
+ try {
+ $redis->hSet('DKIM_PUB_KEYS', $domain, $pubKey);
+ $redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ // Export private key and save private key to redis
+ openssl_pkey_export($keypair_ressource, $privKey);
+ if (isset($privKey) && !empty($privKey)) {
+ try {
+ $redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, trim($privKey));
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => sprintf($lang['success']['dkim_added'])
+ );
+ return true;
+ }
+ else {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
+ );
+ return false;
+ }
+ break;
+ case 'details':
+ if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+ return false;
+ }
+ $dkimdata = array();
+ if ($redis_dkim_key_data = $redis->hGet('DKIM_PUB_KEYS', $_data)) {
+ $dkimdata['pubkey'] = $redis_dkim_key_data;
+ $dkimdata['length'] = (strlen($dkimdata['pubkey']) < 391) ? 1024 : 2048;
+ $dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data;
+ $dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data);
+ }
+ return $dkimdata;
+ break;
+ case 'blind':
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ return false;
+ }
+ $blinddkim = array();
+ foreach ($redis->hKeys('DKIM_PUB_KEYS') as $redis_dkim_domain) {
+ $blinddkim[] = $redis_dkim_domain;
+ }
+ return array_diff($blinddkim, array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')));
+ break;
+ case 'delete':
+ $domains = (array)$_data['domains'];
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ foreach ($domains as $domain) {
+ if (!is_valid_domain_name($domain)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
+ );
+ return false;
+ }
+ try {
+ $selector = $redis->hGet('DKIM_SELECTORS', $domain);
+ $redis->hDel('DKIM_PUB_KEYS', $domain);
+ $redis->hDel('DKIM_PRIV_KEYS', $selector . '.' . $domain);
+ $redis->hDel('DKIM_SELECTORS', $domain);
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => sprintf($lang['success']['dkim_removed'], htmlspecialchars(implode(', ', $domains)))
+ );
+ break;
+ }
+}
\ No newline at end of file
diff --git a/data/web/inc/functions.fwdhost.inc.php b/data/web/inc/functions.fwdhost.inc.php
new file mode 100644
index 00000000..6f3e8022
--- /dev/null
+++ b/data/web/inc/functions.fwdhost.inc.php
@@ -0,0 +1,171 @@
+<?php
+
+function fwdhost($_action, $_data = null) {
+ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/spf.inc.php';
+ global $redis;
+ global $lang;
+ switch ($_action) {
+ case 'add':
+ global $lang;
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ $source = $_data['hostname'];
+ $host = trim($_data['hostname']);
+ $filter_spam = (isset($_data['filter_spam']) && $_data['filter_spam'] == 1) ? 1 : 0;
+ if (preg_match('/^[0-9a-fA-F:\/]+$/', $host)) { // IPv6 address
+ $hosts = array($host);
+ }
+ elseif (preg_match('/^[0-9\.\/]+$/', $host)) { // IPv4 address
+ $hosts = array($host);
+ }
+ else {
+ $hosts = get_outgoing_hosts_best_guess($host);
+ }
+ if (empty($hosts)) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Invalid host specified: '. htmlspecialchars($host)
+ );
+ return false;
+ }
+ foreach ($hosts as $host) {
+ try {
+ $redis->hSet('WHITELISTED_FWD_HOST', $host, $source);
+ if ($filter_spam == 0) {
+ $redis->hSet('KEEP_SPAM', $host, 1);
+ }
+ elseif ($redis->hGet('KEEP_SPAM', $host)) {
+ $redis->hDel('KEEP_SPAM', $host);
+ }
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => sprintf($lang['success']['forwarding_host_added'], htmlspecialchars(implode(', ', $hosts)))
+ );
+ break;
+ case 'edit':
+ global $lang;
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ $fwdhosts = (array)$_data['fwdhost'];
+ foreach ($fwdhosts as $fwdhost) {
+ $is_now = fwdhost('details', $fwdhost);
+ if (!empty($is_now)) {
+ $keep_spam = (isset($_data['keep_spam'])) ? $_data['keep_spam'] : $is_now['keep_spam'];
+ }
+ else {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => sprintf($lang['danger']['access_denied'])
+ );
+ return false;
+ }
+ try {
+ if ($keep_spam == 1) {
+ $redis->hSet('KEEP_SPAM', $fwdhost, 1);
+ }
+ else {
+ $redis->hDel('KEEP_SPAM', $fwdhost);
+ }
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars(implode(', ', $fwdhosts)))
+ );
+ break;
+ case 'delete':
+ $hosts = (array)$_data['forwardinghost'];
+ foreach ($hosts as $host) {
+ try {
+ $redis->hDel('WHITELISTED_FWD_HOST', $host);
+ $redis->hDel('KEEP_SPAM', $host);
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => sprintf($lang['success']['forwarding_host_removed'], htmlspecialchars(implode(', ', $hosts)))
+ );
+ break;
+ case 'get':
+ if ($_SESSION['mailcow_cc_role'] != "admin") {
+ return false;
+ }
+ $fwdhostsdata = array();
+ try {
+ $fwd_hosts = $redis->hGetAll('WHITELISTED_FWD_HOST');
+ if (!empty($fwd_hosts)) {
+ foreach ($fwd_hosts as $fwd_host => $source) {
+ $keep_spam = ($redis->hGet('KEEP_SPAM', $fwd_host)) ? "yes" : "no";
+ $fwdhostsdata[] = array(
+ 'host' => $fwd_host,
+ 'source' => $source,
+ 'keep_spam' => $keep_spam
+ );
+ }
+ }
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ return $fwdhostsdata;
+ break;
+ case 'details':
+ $fwdhostdetails = array();
+ if (!isset($_data) || empty($_data)) {
+ return false;
+ }
+ try {
+ if ($source = $redis->hGet('WHITELISTED_FWD_HOST', $_data)) {
+ $fwdhostdetails['host'] = $_data;
+ $fwdhostdetails['source'] = $source;
+ $fwdhostdetails['keep_spam'] = ($redis->hGet('KEEP_SPAM', $_data)) ? "yes" : "no";
+ }
+ }
+ catch (RedisException $e) {
+ $_SESSION['return'] = array(
+ 'type' => 'danger',
+ 'msg' => 'Redis: '.$e
+ );
+ return false;
+ }
+ return $fwdhostdetails;
+ break;
+ }
+}
\ No newline at end of file
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index f6fe886a..9ddfb726 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -1310,317 +1310,12 @@ function get_admin_details() {
}
return $data;
}
-function dkim_add_key($postarray) {
- global $lang;
- global $pdo;
- global $redis;
- if ($_SESSION['mailcow_cc_role'] != "admin") {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['access_denied'])
- );
- return false;
- }
- // if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
- // $_SESSION['return'] = array(
- // 'type' => 'danger',
- // 'msg' => sprintf($lang['danger']['access_denied'])
- // );
- // return false;
- // }
- $key_length = intval($postarray['key_size']);
- $dkim_selector = (isset($postarray['dkim_selector'])) ? $postarray['dkim_selector'] : 'dkim';
- $domain = $postarray['domain'];
- if (!is_valid_domain_name($domain) || !is_numeric($key_length)) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
- );
- return false;
- }
-
- if (!empty(glob($GLOBALS['MC_DKIM_TXTS'] . '/' . $domain . '.dkim')) ||
- $redis->hGet('DKIM_PUB_KEYS', $domain)) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
- );
- return false;
- }
-
- if (!ctype_alnum($dkim_selector)) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
- );
- return false;
- }
-
- $config = array(
- "digest_alg" => "sha256",
- "private_key_bits" => $key_length,
- "private_key_type" => OPENSSL_KEYTYPE_RSA,
- );
- if ($keypair_ressource = openssl_pkey_new($config)) {
- $key_details = openssl_pkey_get_details($keypair_ressource);
- $pubKey = implode(array_slice(
- array_filter(
- explode(PHP_EOL, $key_details['key'])
- ), 1, -1)
- );
- // Save public key and selector to redis
- try {
- $redis->hSet('DKIM_PUB_KEYS', $domain, $pubKey);
- $redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
- }
- catch (RedisException $e) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => 'Redis: '.$e
- );
- return false;
- }
- // Export private key and save private key to redis
- openssl_pkey_export($keypair_ressource, $privKey);
- if (isset($privKey) && !empty($privKey)) {
- try {
- $redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, trim($privKey));
- }
- catch (RedisException $e) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => 'Redis: '.$e
- );
- return false;
- }
- }
- $_SESSION['return'] = array(
- 'type' => 'success',
- 'msg' => sprintf($lang['success']['dkim_added'])
- );
- return true;
- }
- else {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
- );
- return false;
- }
-}
-function dkim_get_key_details($domain) {
- global $redis;
- if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
- return false;
- }
- $data = array();
- if ($redis_dkim_key_data = $redis->hGet('DKIM_PUB_KEYS', $domain)) {
- $data['pubkey'] = $redis_dkim_key_data;
- $data['length'] = (strlen($data['pubkey']) < 391) ? 1024 : 2048;
- $data['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data;
- $data['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $domain);
- }
- return $data;
-}
-function dkim_get_blind_keys() {
- global $redis;
- global $lang;
- if ($_SESSION['mailcow_cc_role'] != "admin") {
- return false;
- }
- $domains = array();
- foreach ($redis->hKeys('DKIM_PUB_KEYS') as $redis_dkim_domain) {
- $domains[] = $redis_dkim_domain;
- }
- return array_diff($domains, array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')));
-}
-function dkim_delete_key($postarray) {
- global $redis;
- global $lang;
- if (!is_array($postarray['domains'])) {
- $domains = array();
- $domains[] = $postarray['domains'];
- }
- else {
- $domains = $postarray['domains'];
- }
- if ($_SESSION['mailcow_cc_role'] != "admin") {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['access_denied'])
- );
- return false;
- }
- foreach ($domains as $domain) {
- if (!is_valid_domain_name($domain)) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
- );
- return false;
- }
- try {
- $selector = $redis->hGet('DKIM_SELECTORS', $domain);
- $redis->hDel('DKIM_PUB_KEYS', $domain);
- $redis->hDel('DKIM_PRIV_KEYS', $selector . '.' . $domain);
- $redis->hDel('DKIM_SELECTORS', $domain);
- }
- catch (RedisException $e) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => 'Redis: '.$e
- );
- return false;
- }
- }
- $_SESSION['return'] = array(
- 'type' => 'success',
- 'msg' => sprintf($lang['success']['dkim_removed'], htmlspecialchars(implode(', ', $domains)))
- );
- return true;
-}
function get_u2f_registrations($username) {
global $pdo;
$sel = $pdo->prepare("SELECT * FROM `tfa` WHERE `authmech` = 'u2f' AND `username` = ? AND `active` = '1'");
$sel->execute(array($username));
return $sel->fetchAll(PDO::FETCH_OBJ);
}
-function get_forwarding_hosts() {
- global $redis;
- $data = array();
- try {
- $fwd_hosts = $redis->hGetAll('WHITELISTED_FWD_HOST');
- if (!empty($fwd_hosts)) {
- foreach ($fwd_hosts as $fwd_host => $source) {
- $data[] = $fwd_host;
- }
- }
- }
- catch (RedisException $e) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => 'Redis: '.$e
- );
- return false;
- }
- return $data;
-}
-function get_forwarding_host_details($host) {
- global $redis;
- $data = array();
- if (!isset($host) || empty($host)) {
- return false;
- }
- try {
- if ($source = $redis->hGet('WHITELISTED_FWD_HOST', $host)) {
- $data['host'] = $host;
- $data['source'] = $source;
- $data['keep_spam'] = ($redis->hGet('KEEP_SPAM', $host)) ? "yes" : "no";
- }
- }
- catch (RedisException $e) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => 'Redis: '.$e
- );
- return false;
- }
- return $data;
-}
-function add_forwarding_host($postarray) {
- require_once 'spf.inc.php';
- global $redis;
- global $lang;
- if ($_SESSION['mailcow_cc_role'] != "admin") {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['access_denied'])
- );
- return false;
- }
- $source = $postarray['hostname'];
- $host = trim($postarray['hostname']);
- $filter_spam = $postarray['filter_spam'];
- if (isset($postarray['filter_spam']) && $postarray['filter_spam'] == 1) {
- $filter_spam = 1;
- }
- else {
- $filter_spam = 0;
- }
- if (preg_match('/^[0-9a-fA-F:\/]+$/', $host)) { // IPv6 address
- $hosts = array($host);
- }
- elseif (preg_match('/^[0-9\.\/]+$/', $host)) { // IPv4 address
- $hosts = array($host);
- }
- else {
- $hosts = get_outgoing_hosts_best_guess($host);
- }
- if (empty($hosts)) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => 'Invalid host specified: '. htmlspecialchars($host)
- );
- return false;
- }
- foreach ($hosts as $host) {
- try {
- $redis->hSet('WHITELISTED_FWD_HOST', $host, $source);
- if ($filter_spam == 0) {
- $redis->hSet('KEEP_SPAM', $host, 1);
- }
- elseif ($redis->hGet('KEEP_SPAM', $host)) {
- $redis->hDel('KEEP_SPAM', $host);
- }
- }
- catch (RedisException $e) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => 'Redis: '.$e
- );
- return false;
- }
- }
- $_SESSION['return'] = array(
- 'type' => 'success',
- 'msg' => sprintf($lang['success']['forwarding_host_added'], htmlspecialchars(implode(', ', $hosts)))
- );
-}
-function delete_forwarding_host($postarray) {
- global $redis;
- global $lang;
- if ($_SESSION['mailcow_cc_role'] != "admin") {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => sprintf($lang['danger']['access_denied'])
- );
- return false;
- }
- if (!is_array($postarray['forwardinghost'])) {
- $hosts = array();
- $hosts[] = $postarray['forwardinghost'];
- }
- else {
- $hosts = $postarray['forwardinghost'];
- }
- foreach ($hosts as $host) {
- try {
- $redis->hDel('WHITELISTED_FWD_HOST', $host);
- $redis->hDel('KEEP_SPAM', $host);
- }
- catch (RedisException $e) {
- $_SESSION['return'] = array(
- 'type' => 'danger',
- 'msg' => 'Redis: '.$e
- );
- return false;
- }
- }
- $_SESSION['return'] = array(
- 'type' => 'success',
- 'msg' => sprintf($lang['success']['forwarding_host_removed'], htmlspecialchars(implode(', ', $hosts)))
- );
-}
function get_logs($container, $lines = 100) {
global $lang;
global $redis;
diff --git a/data/web/inc/functions.mailbox.inc.php b/data/web/inc/functions.mailbox.inc.php
index 53a93c53..900fa560 100644
--- a/data/web/inc/functions.mailbox.inc.php
+++ b/data/web/inc/functions.mailbox.inc.php
@@ -648,7 +648,7 @@ function mailbox($_action, $_type, $_data = null) {
if ($num_results == 0) {
$_SESSION['return'] = array(
'type' => 'danger',
- 'msg' => sprintf($lang['danger']['domain_not_found'], $domain)
+ 'msg' => sprintf($lang['danger']['domain_not_found'], htmlspecialchars($domain))
);
return false;
}
@@ -832,7 +832,7 @@ function mailbox($_action, $_type, $_data = null) {
if ($num_results == 0) {
$_SESSION['return'] = array(
'type' => 'danger',
- 'msg' => sprintf($lang['danger']['domain_not_found'], $domain)
+ 'msg' => sprintf($lang['danger']['domain_not_found'], htmlspecialchars($domain))
);
return false;
}
@@ -875,13 +875,7 @@ function mailbox($_action, $_type, $_data = null) {
case 'edit':
switch ($_type) {
case 'alias_domain':
- if (!is_array($_data['alias_domain'])) {
- $alias_domains = array();
- $alias_domains[] = $_data['alias_domain'];
- }
- else {
- $alias_domains = $_data['alias_domain'];
- }
+ $alias_domains = (array)$_data['alias_domain'];
foreach ($alias_domains as $alias_domain) {
$alias_domain = idn_to_ascii(strtolower(trim($alias_domain)));
$is_now = mailbox('get', 'alias_domain_details', $alias_domain);
diff --git a/data/web/inc/functions.policy.inc.php b/data/web/inc/functions.policy.inc.php
index 01ef13ab..3070b5dc 100644
--- a/data/web/inc/functions.policy.inc.php
+++ b/data/web/inc/functions.policy.inc.php
@@ -168,13 +168,7 @@ function policy($_action, $_scope, $_data = null) {
case 'delete':
switch ($_scope) {
case 'domain':
- if (!is_array($_data['prefid'])) {
- $prefids = array();
- $prefids[] = $_data['prefid'];
- }
- else {
- $prefids = $_data['prefid'];
- }
+ (array)$prefids = $_data['prefid'];
foreach ($prefids as $prefid) {
if (!is_numeric($prefid)) {
$_SESSION['return'] = array(
diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php
index 867bc106..f1091d92 100644
--- a/data/web/inc/prerequisites.inc.php
+++ b/data/web/inc/prerequisites.inc.php
@@ -14,7 +14,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/vendor/autoload.php';
// U2F API + T/HOTP API
$u2f = new u2flib_server\U2F('https://' . $_SERVER['HTTP_HOST']);
-$tfa = new RobThree\Auth\TwoFactorAuth('mailcow UI');
+$tfa = new RobThree\Auth\TwoFactorAuth($OTP_LABEL);
// Redis
$redis = new Redis();
@@ -60,6 +60,8 @@ 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.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/init_db.inc.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/triggers.inc.php';
init_db_schema();
diff --git a/data/web/inc/triggers.inc.php b/data/web/inc/triggers.inc.php
index 1fcaf256..4fd207cf 100644
--- a/data/web/inc/triggers.inc.php
+++ b/data/web/inc/triggers.inc.php
@@ -53,33 +53,11 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
}
}
}
-
- if (isset($_POST["edit_admin_account"])) {
- edit_admin_account($_POST);
- }
- if (isset($_POST["dkim_delete_key"])) {
- dkim_delete_key($_POST);
- }
- if (isset($_POST["dkim_add_key"])) {
- dkim_add_key($_POST);
- }
- if (isset($_POST["add_forwarding_host"])) {
- add_forwarding_host($_POST);
- }
- if (isset($_POST["delete_forwarding_host"])) {
- delete_forwarding_host($_POST);
- }
}
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "user") {
if (isset($_POST["edit_user_account"])) {
edit_user_account($_POST);
}
- if (isset($_POST["add_policy_list_item"])) {
- policy('add', 'mailbox', $_POST);
- }
- if (isset($_POST["add_syncjob"])) {
- mailbox('add', 'syncjob', $_POST);
- }
if (isset($_POST["edit_syncjob"])) {
mailbox('edit', 'syncjob', $_POST);
}
@@ -94,24 +72,6 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
if (isset($_POST["unset_tfa_key"])) {
unset_tfa_key($_POST);
}
- if (isset($_POST["add_policy_list_item"])) {
- policy('add', 'domain', $_POST);
- }
- if (isset($_POST["mailbox_add_domain"])) {
- mailbox('add', 'domain', $_POST);
- }
- if (isset($_POST["mailbox_add_alias"])) {
- mailbox('add', 'alias', $_POST);
- }
- if (isset($_POST["mailbox_add_alias_domain"])) {
- mailbox('add', 'alias_domain', $_POST);
- }
- if (isset($_POST["mailbox_add_mailbox"])) {
- mailbox('add', 'mailbox', $_POST);
- }
- if (isset($_POST["mailbox_add_resource"])) {
- mailbox('add', 'resource', $_POST);
- }
if (isset($_POST["mailbox_edit_alias"])) {
mailbox('edit', 'alias', $_POST);
}
diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php
index d5845a46..a29f742c 100644
--- a/data/web/inc/vars.inc.php
+++ b/data/web/inc/vars.inc.php
@@ -1,7 +1,6 @@
<?php
error_reporting(E_ERROR);
//error_reporting(E_ALL);
-header('X-Powered-By: mailcow');
/*
PLEASE USE THE FILE "vars.local.inc.php" TO OVERWRITE SETTINGS AND MAKE THEM PERSISTENT!
@@ -23,10 +22,6 @@ $mailcow_hostname = getenv('MAILCOW_HOSTNAME');
// "form" will stay in the current form, "previous" will redirect to previous page
$FORM_ACTION = 'previous';
-// File locations should not be changed
-$MC_DKIM_TXTS = '/data/dkim/txt';
-$MC_DKIM_KEYS = '/data/dkim/keys';
-
// Change default language, "de", "en", "es", "nl", "pt", "ru"
$DEFAULT_LANG = 'en';
@@ -59,3 +54,6 @@ $PAGINATION_SIZE = 10;
// Session lifetime in seconds
$SESSION_LIFETIME = 3600;
+
+// Label for OTP devices
+$OTP_LABEL = "mailcow UI";
\ No newline at end of file
diff --git a/data/web/js/add.js b/data/web/js/add.js
index f8fc3809..cbc1d3f1 100644
--- a/data/web/js/add.js
+++ b/data/web/js/add.js
@@ -1,5 +1,5 @@
$(document).ready(function() {
-
+ // 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));
@@ -16,10 +16,8 @@ $(document).ready(function() {
}
});
}
-
$('#addSelectDomain').on('change', function() {
auto_fill_quota($('#addSelectDomain').val());
});
-
auto_fill_quota($('#addSelectDomain').val());
});
diff --git a/data/web/js/admin.js b/data/web/js/admin.js
index f99bdac7..501d3b53 100644
--- a/data/web/js/admin.js
+++ b/data/web/js/admin.js
@@ -221,7 +221,6 @@ jQuery(function($){
{"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',
@@ -232,9 +231,6 @@ jQuery(function($){
},
success: function (data) {
$.each(data, function (i, item) {
- item.action = '<div class="btn-group">' +
- '<a href="/delete.php?forwardinghost=' + 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;
}
diff --git a/data/web/js/api.js b/data/web/js/api.js
index f1f760be..ef926476 100644
--- a/data/web/js/api.js
+++ b/data/web/js/api.js
@@ -44,7 +44,6 @@ $(document).ready(function() {
$(document).on('click', '#toggle_multi_select_all', function(e) {
e.preventDefault();
id = $(this).data("id");
- multi_data[id] = [];
var all_checkboxes = $("input[data-id=" + id + "]:enabled");
all_checkboxes.prop("checked", !all_checkboxes.prop("checked")).change();
});
@@ -71,15 +70,18 @@ $(document).ready(function() {
}
if (typeof multi_data[id] == "undefined") return;
api_items = multi_data[id];
-
if (Object.keys(api_items).length !== 0) {
$.ajax({
type: "POST",
dataType: "json",
- data: { "items": JSON.stringify(api_items), "attr": JSON.stringify(api_attr), "csrf_token": csrf_token },
+ data: {
+ "items": JSON.stringify(api_items),
+ "attr": JSON.stringify(api_attr),
+ "csrf_token": csrf_token
+ },
url: '/api/v1/' + api_url,
jsonp: false,
- complete: function (data) {
+ complete: function(data) {
// var reponse = (JSON.parse(data.responseText));
// console.log(reponse.type);
// console.log(reponse.msg);
@@ -98,16 +100,34 @@ $(document).ready(function() {
// If clicked button is in a form with the same data-id as the button,
// we merge all input fields by {"name":"value"} into api-attr
if ($(this).closest("form").data('id') == id) {
- var attr_to_merge = $(this).closest("form").serializeObject();
- var api_attr = $.extend(api_attr, attr_to_merge)
+ var req_empty = false;
+ $(this).closest("form").find('select, textarea, input').each(function() {
+ if ($(this).prop('required')) {
+ if (!$(this).val()) {
+ req_empty = true;
+ $(this).addClass('inputMissingAttr');
+ } else {
+ $(this).removeClass('inputMissingAttr');
+ }
+ }
+ });
+ if (!req_empty) {
+ var attr_to_merge = $(this).closest("form").serializeObject();
+ var api_attr = $.extend(api_attr, attr_to_merge)
+ } else {
+ return false;
+ }
}
$.ajax({
type: "POST",
dataType: "json",
- data: { "attr": JSON.stringify(api_attr), "csrf_token": csrf_token },
+ data: {
+ "attr": JSON.stringify(api_attr),
+ "csrf_token": csrf_token
+ },
url: '/api/v1/' + api_url,
jsonp: false,
- complete: function (data) {
+ complete: function(data) {
// var reponse = (JSON.parse(data.responseText));
// console.log(reponse.type);
// console.log(reponse.msg);
@@ -115,6 +135,7 @@ $(document).ready(function() {
}
});
});
+
// General API delete actions
$(document).on('click', '#delete_selected', function(e) {
e.preventDefault();
@@ -125,7 +146,7 @@ $(document).ready(function() {
if (typeof multi_data[id] == "undefined") {
multi_data[id] = [];
}
- multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]),1);
+ multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1);
multi_data[id].push($(this).data('item'));
}
if (typeof $(this).data('text') !== 'undefined') {
@@ -135,33 +156,36 @@ $(document).ready(function() {
if (typeof multi_data[id] == "undefined" || multi_data[id] == "") return;
data_array = multi_data[id];
api_url = $(this).data('api-url');
- $(document).on('show.bs.modal','#ConfirmDeleteModal', function () {
+ $(document).on('show.bs.modal', '#ConfirmDeleteModal', function() {
$("#ItemsToDelete").empty();
for (var i in data_array) {
$("#ItemsToDelete").append("<li>" + data_array[i] + "</li>");
}
})
$('#ConfirmDeleteModal').modal({
- backdrop: 'static',
- keyboard: false
- })
- .one('click', '#IsConfirmed', function(e) {
- $.ajax({
- type: "POST",
- dataType: "json",
- cache: false,
- data: { "items": JSON.stringify(data_array), "csrf_token": csrf_token },
- url: '/api/v1/' + api_url,
- jsonp: false,
- complete: function (data) {
- window.location = window.location.href.split("#")[0];
- }
+ backdrop: 'static',
+ keyboard: false
+ })
+ .one('click', '#IsConfirmed', function(e) {
+ $.ajax({
+ type: "POST",
+ dataType: "json",
+ cache: false,
+ data: {
+ "items": JSON.stringify(data_array),
+ "csrf_token": csrf_token
+ },
+ url: '/api/v1/' + api_url,
+ jsonp: false,
+ complete: function(data) {
+ window.location = window.location.href.split("#")[0];
+ }
+ });
+ })
+ .one('click', '#isCanceled', function(e) {
+ // Remove event handler to allow to close modal and restart dialog without multiple submits
+ $('#ConfirmDeleteModal').off();
+ $('#ConfirmDeleteModal').modal('hide');
});
- })
- .one('click', '#isCanceled', function(e) {
- // Remove event handler to allow to close modal and restart dialog without multiple submits
- $('#ConfirmDeleteModal').off();
- $('#ConfirmDeleteModal').modal('hide');
- });
});
});
\ No newline at end of file
diff --git a/data/web/js/mailbox.js b/data/web/js/mailbox.js
index 80d84339..1171d8cb 100644
--- a/data/web/js/mailbox.js
+++ b/data/web/js/mailbox.js
@@ -1,3 +1,27 @@
+$(document).ready(function() {
+ // 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());
+});
+
jQuery(function($){
// Calculation human readable file sizes
function humanFileSize(bytes) {
diff --git a/data/web/json_api.php b/data/web/json_api.php
index 70e42a35..96d6f2e1 100644
--- a/data/web/json_api.php
+++ b/data/web/json_api.php
@@ -60,6 +60,336 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
+ case "mailbox":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (mailbox('add', 'mailbox', $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":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (mailbox('add', 'domain', $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 "resource":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (mailbox('add', 'resource', $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 "alias":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (mailbox('add', 'alias', $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 "syncjob":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (mailbox('add', 'syncjob', $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);
+ if (policy('add', 'domain', $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 "mailbox-policy":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (policy('add', 'mailbox', $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 "alias-domain":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (mailbox('add', 'alias_domain', $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 "fwdhost":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (fwdhost('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 "dkim":
+ if (isset($_POST['attr'])) {
+ $attr = (array)json_decode($_POST['attr'], true);
+ if (dkim('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_admin":
if (isset($_POST['attr'])) {
$attr = (array)json_decode($_POST['attr'], true);
@@ -353,17 +683,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "fwdhost":
switch ($object) {
case "all":
- $fwdhosts = get_forwarding_hosts();
- if (!empty($fwdhosts)) {
- foreach ($fwdhosts as $fwdhost) {
- if ($details = get_forwarding_host_details($fwdhost)) {
- $data[] = $details;
- }
- else {
- continue;
- }
- }
- }
+ $data = fwdhost('get');
if (!isset($data) || empty($data)) {
echo '{}';
}
@@ -372,7 +692,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
}
break;
default:
- $data = get_forwarding_host_details($object);
+ $data = fwdhost('details', $object);
if (!isset($data) || empty($data)) {
echo '{}';
}
@@ -385,34 +705,26 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
case "alias-domain":
switch ($object) {
case "all":
- $domains = mailbox('get', 'domains');
- if (!empty($domains)) {
- foreach ($domains as $domain) {
- $alias_domains = mailbox('get', 'alias_domains', $domain);
- if (!empty($alias_domains)) {
- foreach ($alias_domains as $alias_domain) {
- if ($details = mailbox('get', 'alias_domain_details', $alias_domain)) {
- $data[] = $details;
- }
- else {
- continue;
- }
- }
+ $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;
}
- }
- if (!isset($data) || empty($data)) {
- echo '{}';
- }
- else {
- echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}
}
- else {
+ if (!isset($data) || empty($data)) {
echo '{}';
}
+ else {
+ echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ }
break;
default:
- $data = mailbox('get', 'alias_domains', $object);
+ $data = mailbox('get', 'alias_domain_details', $object);
if (!isset($data) || empty($data)) {
echo '{}';
}
@@ -615,7 +927,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
if (isset($_POST['items'])) {
$items = (array)json_decode($_POST['items'], true);
if (is_array($items)) {
- if (delete_forwarding_host(array('forwardinghost' => $items)) === false) {
+ if (fwdhost('delete', array('forwardinghost' => $items)) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -656,7 +968,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
if (isset($_POST['items'])) {
$items = (array)json_decode($_POST['items'], true);
if (is_array($items)) {
- if (dkim_delete_key(array('domains' => $items)) === false) {
+ if (dkim('delete', array('domains' => $items)) === false) {
if (isset($_SESSION['return'])) {
echo json_encode($_SESSION['return']);
}
@@ -857,7 +1169,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
- case "policy_mailbox":
+ case "mailbox-policy":
if (isset($_POST['items'])) {
$items = (array)json_decode($_POST['items'], true);
if (is_array($items)) {
@@ -898,6 +1210,47 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
+ case "domain-policy":
+ if (isset($_POST['items'])) {
+ $items = (array)json_decode($_POST['items'], true);
+ if (is_array($items)) {
+ if (policy('delete', 'domain', array('prefid' => $items)) === false) {
+ if (isset($_SESSION['return'])) {
+ echo json_encode($_SESSION['return']);
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Task 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 name array in post data'
+ ));
+ }
+ }
+ else {
+ echo json_encode(array(
+ 'type' => 'error',
+ 'msg' => 'Cannot find items in post data'
+ ));
+ }
+ break;
case "time_limited_alias":
if (isset($_POST['items'])) {
$items = (array)json_decode($_POST['items'], true);
@@ -1509,6 +1862,50 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
));
}
break;
+ case "fwdhost":
+ 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('fwdhost' => $items), $attr);
+ if (is_array($postarray['fwdhost'])) {
+ if (fwdhost('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 "admin":
// No items as there is only one admin
if (isset($_POST['attr'])) {
diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php
index 5c2936db..2969f812 100644
--- a/data/web/lang/lang.en.php
+++ b/data/web/lang/lang.en.php
@@ -20,7 +20,7 @@ $lang['danger']['dkim_remove_failed'] = "Cannot remove selected DKIM key";
$lang['danger']['dkim_add_failed'] = "Cannot add given DKIM key";
$lang['danger']['dkim_domain_or_sel_invalid'] = "DKIM domain or selector invalid";
$lang['danger']['dkim_key_length_invalid'] = "DKIM key length invalid";
-$lang['success']['dkim_removed'] = "DKIM key has been removed";
+$lang['success']['dkim_removed'] = "DKIM key %s has been removed";
$lang['success']['dkim_added'] = "DKIM key has been saved";
$lang['danger']['access_denied'] = "Access denied or invalid form data";
$lang['danger']['whitelist_from_invalid'] = "Whitelist entry invalid";
@@ -77,7 +77,7 @@ $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 or a mailbox";
$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']['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)";
@@ -260,7 +260,7 @@ $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'] = 'Quick actions';
+$lang['mailbox']['quick_actions'] = 'Actions';
$lang['mailbox']['activate'] = 'Activate';
$lang['mailbox']['deactivate'] = 'Deactivate';
diff --git a/data/web/mailbox.php b/data/web/mailbox.php
index b10bb414..f7195f6e 100644
--- a/data/web/mailbox.php
+++ b/data/web/mailbox.php
@@ -31,7 +31,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<?php
if ($_SESSION['mailcow_cc_role'] == "admin"):
?>
- <a href="/add.php?domain"><span class="glyphicon glyphicon-plus"></span></a></li>
+ <a href="#" data-toggle="modal" data-target="#addDomainModal" ><span class="glyphicon glyphicon-plus"></span></a>
<?php
endif;
?>
@@ -53,7 +53,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</ul>
</div>
</div>
- <span class="footer-add-item"><a href="/add.php?domain"><?=$lang['mailbox']['add_domain'];?></a></span>
+ <span class="footer-add-item"><a href="#" data-toggle="modal" data-target="#addDomainModal" ><?=$lang['mailbox']['add_domain'];?></a></span>
+
</div>
</div>
@@ -61,7 +62,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<div class="panel panel-default">
<div class="panel-heading">
<div class="pull-right">
- <a href="/add.php?mailbox"><span class="glyphicon glyphicon-plus"></span></a>
+ <a href="#" data-toggle="modal" data-target="#addMailboxModal" ><span class="glyphicon glyphicon-plus"></span></a>
</div>
<h3 class="panel-title"><?=$lang['mailbox']['mailboxes'];?></h3>
</div>
@@ -80,7 +81,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</ul>
</div>
</div>
- <span class="footer-add-item"><a href="/add.php?mailbox"><?=$lang['mailbox']['add_mailbox'];?></a></span>
+ <span class="footer-add-item"><a href="#" data-toggle="modal" data-target="#addMailboxModal" ><?=$lang['mailbox']['add_mailbox'];?></a></span>
</div>
</div>
@@ -88,7 +89,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<div class="panel panel-default">
<div class="panel-heading">
<div class="pull-right">
- <a href="/add.php?resource"><span class="glyphicon glyphicon-plus"></span></a>
+ <a href="#" data-toggle="modal" data-target="#addResourceModal" ><span class="glyphicon glyphicon-plus"></span></a>
</div>
<h3 class="panel-title"><?=$lang['mailbox']['resources'];?></h3>
</div>
@@ -107,7 +108,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</ul>
</div>
</div>
- <span class="footer-add-item"><a href="/add.php?resource"><?=$lang['mailbox']['add_resource'];?></a></span>
+ <span class="footer-add-item"><a href="#" data-toggle="modal" data-target="#addResourceModal" ><?=$lang['mailbox']['add_resource'];?></a></span>
</div>
</div>
@@ -115,7 +116,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
<div class="panel panel-default">
<div class="panel-heading">
<div class="pull-right">
- <a href="/add.php?aliasdomain"><span class="glyphicon glyphicon-plus"></span></a>
+ <a href="#" data-toggle="modal" data-target="#addAliasDomainModal" ><span class="glyphicon glyphicon-plus"></span></a>
</div>
<h3 class="panel-title"><?=$lang['mailbox']['domain_aliases'];?></h3>
</div>
@@ -134,14 +135,16 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</ul>
</div>
</div>
- <span class="footer-add-item"><a href="/add.php?aliasdomain"><?=$lang['mailbox']['add_domain_alias'];?></a></span>
+ <span class="footer-add-item"><a href="#" data-toggle="modal" data-target="#addAliasDomainModal" ><?=$lang['mailbox']['add_domain_alias'];?></a></span>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tab-mbox-aliases">
<div class="panel panel-default">
<div class="panel-heading">
- <a class="pull-right" href="/add.php?alias"><span class="glyphicon glyphicon-plus"></span></a>
+ <div class="pull-right">
+ <a href="#" data-toggle="modal" data-target="#addAliasModal" ><span class="glyphicon glyphicon-plus"></span></a>
+ </div>
<h3 class="panel-title"><?=$lang['mailbox']['aliases'];?></h3>
</div>
<div class="table-responsive">
@@ -159,7 +162,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</ul>
</div>
</div>
- <span class="footer-add-item"><a href="/add.php?alias"><?=$lang['mailbox']['add_alias'];?></a></span>
+ <span class="footer-add-item"><a href="#" data-toggle="modal" data-target="#addAliasModal" ><?=$lang['mailbox']['add_alias'];?></a></span>
</div>
</div>
@@ -167,7 +170,9 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
</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']);
diff --git a/data/web/inc/tfa_modals.php b/data/web/modals/footer.php
similarity index 100%
rename from data/web/inc/tfa_modals.php
rename to data/web/modals/footer.php
diff --git a/data/web/modals/mailbox.php b/data/web/modals/mailbox.php
new file mode 100644
index 00000000..70afeaac
--- /dev/null
+++ b/data/web/modals/mailbox.php
@@ -0,0 +1,303 @@
+<?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-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" id="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 id="addSelectDomain" name="domain" id="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" id="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>
+ </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" class="form-control" name="password" id="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" id="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" id="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-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" id="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" id="description">
+ </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" id="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" id="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" id="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" id="quota" value="10240" required>
+ </div>
+ </div>
+ <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>
+ <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" id="add_item" data-id="add_domain" data-api-url='add/domain' data-api-attr='{}' href="#"><?=$lang['admin']['add'];?></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" 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" id="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 name="domain" id="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" id="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">
+ <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">
+ <div class="checkbox">
+ <label><input type="checkbox" value="1" name="multiple_bookings" checked> <?=$lang['add']['multiple_bookings'];?></label>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button class="btn btn-default" id="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" 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 autocorrect="off" autocapitalize="none" class="form-control" rows="5" id="goto" name="goto" required></textarea>
+ <p><?=$lang['add']['target_address_info'];?></p>
+ </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" id="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" 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 name="target_domain" id="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" id="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 -->
\ No newline at end of file
diff --git a/data/web/modals/user.php b/data/web/modals/user.php
new file mode 100644
index 00000000..74861408
--- /dev/null
+++ b/data/web/modals/user.php
@@ -0,0 +1,106 @@
+<?php
+if (!isset($_SESSION['mailcow_cc_role'])) {
+ header('Location: /');
+ exit();
+}
+?>
+<!-- add sync job modal -->
+<div class="modal fade" id="addSyncJobModal" 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><?=$lang['add']['syncjob_hint'];?></p>
+ <form class="form-horizontal" role="form" data-id="add_syncjob">
+ <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" id="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" id="port1" min="1" max="65535" value="143" required>
+ </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" id="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="text" class="form-control" name="password1" id="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" id="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="10" max="3600" value="20" required>
+ </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="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" id="maxage" min="0" max="32000" value="0">
+ </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" id="exclude" value="(?i)spam|(?i)junk">
+ </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'];?></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'];?></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" id="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 -->
diff --git a/data/web/user.php b/data/web/user.php
index 63ee6858..f1209427 100644
--- a/data/web/user.php
+++ b/data/web/user.php
@@ -272,17 +272,15 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
<div class="mass-actions-user">
<div class="btn-group">
<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" id="delete_selected" data-id="policy_wl_mailbox" data-api-url='delete/policy_mailbox' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+ <a class="btn btn-sm btn-danger" id="delete_selected" data-id="policy_wl_mailbox" data-api-url='delete/mailbox-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
</div>
</div>
- <form class="form-inline" method="post">
+ <form class="form-inline" data-id="add_wl_policy_mailbox">
<div class="input-group">
<input type="text" class="form-control" name="object_from" id="object_from" placeholder="*@example.org" required>
- <input type="hidden" name="username" value="<?= $username ;?>">
- <input type="hidden" name="object_list" value="wl">
<span class="input-group-btn">
- <button type="submit" id="add_policy_list_item" name="add_policy_list_item" class="btn btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
+ <button class="btn btn-default" id="add_item" data-id="add_wl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username":"<?= $username; ?>","object_list":"wl"}' href="#"><?=$lang['user']['spamfilter_table_add'];?></button>
</span>
</div>
</form>
@@ -296,17 +294,17 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
<div class="mass-actions-user">
<div class="btn-group">
<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" id="delete_selected" data-id="policy_bl_mailbox" data-api-url='delete/policy_mailbox' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+ <a class="btn btn-sm btn-danger" id="delete_selected" data-id="policy_bl_mailbox" data-api-url='delete/mailbox-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
</div>
</div>
- <form class="form-inline" method="post">
+ <form class="form-inline" data-id="add_bl_policy_mailbox">
<div class="input-group">
<input type="text" class="form-control" name="object_from" id="object_from" placeholder="*@example.org" required>
<input type="hidden" name="username" value="<?= $username ;?>">
<input type="hidden" name="object_list" value="bl">
<span class="input-group-btn">
- <button type="submit" id="add_policy_list_item" name="add_policy_list_item" class="btn btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
+ <button class="btn btn-default" id="add_item" data-id="add_bl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username":"<?= $username; ?>","object_list":"bl"}' href="#"><?=$lang['user']['spamfilter_table_add'];?></button>
</span>
</div>
</form>
@@ -328,7 +326,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
<li role="separator" class="divider"></li>
<li><a id="delete_selected" data-id="syncjob" data-api-url='delete/syncjob' href="#"><?=$lang['mailbox']['remove'];?></a></li>
</ul>
- <a class="btn btn-sm btn-success" href="/add.php?syncjob"><?=$lang['user']['create_syncjob'];?></a>
+ <a class="btn btn-sm btn-success" href="#" data-toggle="modal" data-target="#addSyncJobModal"><?=$lang['user']['create_syncjob'];?></a>
</div>
</div>
</div>
@@ -391,6 +389,9 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "use
</div>
</div>
</div> <!-- /container -->
+<?php
+require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/user.php';
+?>
<script type='text/javascript'>
<?php
$lang_user = json_encode($lang['user']);