瀏覽代碼

More structural changes

andryyy 8 年之前
父節點
當前提交
fd5a59086b

+ 3 - 0
data/Dockerfiles/rspamd/Dockerfile

@@ -17,6 +17,9 @@ COPY settings.conf /etc/rspamd/modules.d/settings.conf
 COPY antivirus.conf /etc/rspamd/modules.d/antivirus.conf
 COPY dkim_signing.lua /usr/share/rspamd/lua/dkim_signing.lua
 
+RUN apt-get autoremove --purge \
+	&& apt-get clean
+
 CMD /usr/bin/rspamd -f -u _rspamd -g _rspamd
 
 RUN rm -rf /tmp/* /var/tmp/*

+ 3 - 3
data/web/add.php

@@ -139,7 +139,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 						<div class="col-sm-10">
 							<select name="target_domain" id="target_domain" title="<?=$lang['add']['select'];?>" required>
 							<?php
-              foreach (mailbox_get_domains() as $domain) {
+              foreach (mailbox('get', 'domains') as $domain) {
 								echo "<option>".htmlspecialchars($domain)."</option>";
 							}
 							?>
@@ -177,7 +177,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 						<div class="col-sm-10">
 							<select id="addSelectDomain" name="domain" id="domain" required>
 							<?php
-              foreach (mailbox_get_domains() as $domain) {
+              foreach (mailbox('get', 'domains') as $domain) {
 								echo "<option>".htmlspecialchars($domain)."</option>";
 							}
 							?>
@@ -242,7 +242,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 						<div class="col-sm-10">
 							<select name="domain" id="domain" title="<?=$lang['add']['select'];?>" required>
 							<?php
-              foreach (mailbox_get_domains() as $domain) {
+              foreach (mailbox('get', 'domains') as $domain) {
 								echo "<option>".htmlspecialchars($domain)."</option>";
 							}
 							?>

+ 43 - 12
data/web/admin.php

@@ -15,8 +15,15 @@ $tfa_data = get_tfa();
     <li role="presentation">
       <a href="#tab-config" aria-controls="tab-config" role="tab" data-toggle="tab"><?=$lang['admin']['configuration'];?></a>
     </li>
-    <li role="presentation">
-      <a href="#tab-logs" aria-controls="tab-logs" role="tab" data-toggle="tab"><?=$lang['admin']['logs'];?></a>
+    <li class="dropdown">
+    <a class="dropdown-toggle" data-toggle="dropdown" href="#">Logs
+    <span class="caret"></span></a>
+    <ul class="dropdown-menu">
+    <li role="presentation"><a href="#tab-postfix-logs" aria-controls="tab-postfix-logs" role="tab" data-toggle="tab">Postfix</a></li>
+    <li role="presentation"><a href="#tab-dovecot-logs" aria-controls="tab-dovecot-logs" role="tab" data-toggle="tab">Dovecot</a></li>
+    <li role="presentation"><a href="#tab-sogo-logs" aria-controls="tab-sogo-logs" role="tab" data-toggle="tab">SOGo</a></li>
+    <li role="presentation"><a href="#tab-rspamd-history" aria-controls="tab-rspamd-history" role="tab" data-toggle="tab">Rspamd</a></li>
+    </ul>
     </li>
   </ul>
 
@@ -113,7 +120,7 @@ $tfa_data = get_tfa();
               <div class="col-sm-10">
                 <select title="<?=$lang['admin']['search_domain_da'];?>" style="width:100%" name="domain[]" size="5" multiple>
                 <?php
-                foreach (mailbox_get_domains() as $domain) {
+                foreach (mailbox('get', 'domains') as $domain) {
                   echo "<option>".htmlspecialchars($domain)."</option>";
                 }
                 ?>
@@ -163,7 +170,7 @@ $tfa_data = get_tfa();
           </div>
         </div>
         <?php
-        foreach(mailbox_get_domains() as $domain) {
+        foreach(mailbox('get', 'domains') as $domain) {
             if (!empty($dkim = dkim_get_key_details($domain))) {
           ?>
             <div class="row">
@@ -192,7 +199,7 @@ $tfa_data = get_tfa();
           </div>
           <?php
           }
-          foreach(mailbox_get_alias_domains($domain) as $alias_domain) {
+          foreach(mailbox('get', 'alias_domains') as $alias_domain) {
             if (!empty($dkim = dkim_get_key_details($alias_domain))) {
             ?>
               <div class="row">
@@ -297,37 +304,43 @@ $tfa_data = get_tfa();
     </div>
   </div>
 
-  <div role="tabpanel" class="tab-pane" id="tab-logs">
+  <div role="tabpanel" class="tab-pane" id="tab-postfix-logs">
     <div class="panel panel-default">
-      <div class="panel-heading">Dovecot
+      <div class="panel-heading">Postfix
         <div class="btn-group pull-right">
           <a class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['admin']['action'];?> <span class="caret"></span></a>
           <ul class="dropdown-menu">
-            <li><a href="#" id="refresh_dovecot_log"><?=$lang['admin']['refresh'];?></a></li>
+            <li><a href="#" id="refresh_postfix_log"><?=$lang['admin']['refresh'];?></a></li>
           </ul>
         </div>
       </div>
       <div class="panel-body">
         <div class="table-responsive">
-          <table class="table table-striped" id="dovecot_log"></table>
+          <table class="table table-striped" id="postfix_log"></table>
         </div>
       </div>
     </div>
+  </div>
+
+  <div role="tabpanel" class="tab-pane" id="tab-dovecot-logs">
     <div class="panel panel-default">
-      <div class="panel-heading">Postfix
+      <div class="panel-heading">Dovecot
         <div class="btn-group pull-right">
           <a class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['admin']['action'];?> <span class="caret"></span></a>
           <ul class="dropdown-menu">
-            <li><a href="#" id="refresh_postfix_log"><?=$lang['admin']['refresh'];?></a></li>
+            <li><a href="#" id="refresh_dovecot_log"><?=$lang['admin']['refresh'];?></a></li>
           </ul>
         </div>
       </div>
       <div class="panel-body">
         <div class="table-responsive">
-          <table class="table table-striped" id="postfix_log"></table>
+          <table class="table table-striped" id="dovecot_log"></table>
         </div>
       </div>
     </div>
+  </div>
+
+  <div role="tabpanel" class="tab-pane" id="tab-sogo-logs">
     <div class="panel panel-default">
       <div class="panel-heading">SOGo
         <div class="btn-group pull-right">
@@ -345,6 +358,24 @@ $tfa_data = get_tfa();
     </div>
   </div>
 
+  <div role="tabpanel" class="tab-pane" id="tab-rspamd-history">
+    <div class="panel panel-default">
+      <div class="panel-heading">Rspamd history
+        <div class="btn-group pull-right">
+          <a class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['admin']['action'];?> <span class="caret"></span></a>
+          <ul class="dropdown-menu">
+            <li><a href="#" id="refresh_rspamd_history"><?=$lang['admin']['refresh'];?></a></li>
+          </ul>
+        </div>
+      </div>
+      <div class="panel-body">
+        <div class="table-responsive">
+          <table class="table table-striped" id="rspamd_history"></table>
+        </div>
+      </div>
+    </div>
+  </div>
+
   </div>
 </div> <!-- /container -->
 <script type='text/javascript'>

+ 24 - 0
data/web/css/edit.css

@@ -0,0 +1,24 @@
+table.footable>tbody>tr.footable-empty>td {
+  font-size:15px !important;
+  font-style:italic;
+}
+.pagination a {
+  text-decoration: none !important;
+}
+.panel panel-default {
+  overflow: visible !important;
+}
+.table-responsive {
+  overflow: visible !important;
+}
+.footer-add-item {
+  display:block;
+  text-align: center;
+  font-style: italic;
+  padding: 10px;
+  background: #F5F5F5;
+}
+.mass-actions-user {
+  user-select: none;
+  padding:10px 0 10px 0;
+}

+ 63 - 117
data/web/edit.php

@@ -20,7 +20,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		if (isset($_GET["alias"]) &&
 			!empty($_GET["alias"])) {
 				$alias = $_GET["alias"];
-        $result = mailbox_get_alias_details($alias);
+        $result = mailbox('get', 'alias_details', $alias);
 				if (!empty($result)) {
 				?>
 					<h4><?=$lang['edit']['alias'];?></h4>
@@ -138,7 +138,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		is_valid_domain_name($_GET["domain"]) &&
 		!empty($_GET["domain"])) {
 			$domain = $_GET["domain"];
-      $result = mailbox_get_domain_details($domain);
+      $result = mailbox('get', 'domain_details', $domain);
 			if (!empty($result)) {
 			?>
 				<h4><?=$lang['edit']['domain'];?></h4>
@@ -225,119 +225,54 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		<hr>
 		<div class="row">
 			<div class="col-sm-6">
-				<h4><span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span> <?=$lang['user']['spamfilter_wl'];?></h4>
-				<p><?=$lang['user']['spamfilter_wl_desc'];?></p>
-				<div class="row">
-					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_rule'];?></b></div>
-					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
-				</div>
-				<?php
-        $get_policy_list = get_policy_list($domain);
-				if (empty($get_policy_list['whitelist'])):
-				?>
-					<div class="row">
-						<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
-					</div>
-				<?php
-				else:
-          foreach($get_policy_list['whitelist'] as $wl):
-          ?>
-          <div class="row striped">
-            <form class="form-inline" method="post">
-            <div class="col-xs-6"><code><?=$wl['value'];?></code></div>
-            <div class="col-xs-6">
-              <?php
-              if ($wl['object'] == $domain):
-              ?>
-							<input type="hidden" name="delete_prefid" value="<?=$wl['prefid'];?>">
-							<input type="hidden" name="delete_policy_list_item">
-							<input type="hidden" name="domain" value="<?=$domain;?>">
-                <a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
-              <?php
-              else:
-              ?>
-                <span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
-              <?php
-              endif;
-              ?>
-            </div>
-            </form>
+				<h4><?=$lang['user']['spamfilter_wl'];?></h4>
+        <p><?=$lang['user']['spamfilter_wl_desc'];?></p>
+        <div class="table-responsive">
+          <table class="table table-striped table-condensed" id="wl_policy_domain_table"></table>
+        </div>
+        <div class="mass-actions-user">
+          <div class="btn-group">
+            <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>
+            </ul>
           </div>
-          <?php
-          endforeach;
-        endif;
-				?>
-				<hr style="margin:5px 0px 7px 0px">
-				<div class="row">
-					<form class="form-inline" method="post">
-					<div class="col-xs-6">
-						<input type="text" class="form-control input-sm" name="object_from" id="object_from" placeholder="*@example.org" required>
-						<input type="hidden" name="object_list" value="wl">
-						<input type="hidden" name="domain" value="<?=$domain;?>">
-					</div>
-					<div class="col-xs-6">
-						<button type="submit" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
-					</div>
-					</form>
-				</div>
-			</div>
+        </div>
+        <form class="form-inline" method="post">
+          <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>
+            </span>
+          </div>
+        </form>
+      </div>
 			<div class="col-sm-6">
-				<h4><span class="glyphicon glyphicon-thumbs-down" aria-hidden="true"></span> <?=$lang['user']['spamfilter_bl'];?></h4>
-				<p><?=$lang['user']['spamfilter_bl_desc'];?></p>
-				<div class="row">
-					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_rule'];?></b></div>
-					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
-				</div>
-				<?php
-				if (empty($get_policy_list['blacklist'])):
-				?>
-					<div class="row">
-						<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
-					</div>
-				<?php
-				else:
-          foreach($get_policy_list['blacklist'] as $bl):
-          ?>
-          <div class="row striped">
-            <form class="form-inline" method="post">
-            <div class="col-xs-6"><code><?=$bl['value'];?></code></div>
-            <div class="col-xs-6">
-							<input type="hidden" name="delete_prefid" value="<?=$bl['prefid'];?>">
-              <?php
-              if ($bl['object'] == $domain):
-              ?>
-								<input type="hidden" name="delete_policy_list_item">
-								<input type="hidden" name="domain" value="<?=$domain;?>">
-                <a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
-              <?php
-              else:
-              ?>
-                <span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
-              <?php
-              endif;
-              ?>
-            </div>
-            </form>
+				<h4><?=$lang['user']['spamfilter_bl'];?></h4>
+        <p><?=$lang['user']['spamfilter_bl_desc'];?></p>
+        <div class="table-responsive">
+          <table class="table table-striped table-condensed" id="bl_policy_domain_table"></table>
+        </div>
+        <div class="mass-actions-user">
+          <div class="btn-group">
+            <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>
+            </ul>
           </div>
-          <?php
-          endforeach;
-        endif;
-				?>
-				<hr style="margin:5px 0px 7px 0px">
-				<div class="row">
-					<form class="form-inline" method="post">
-					<div class="col-xs-6">
-						<input type="text" class="form-control input-sm" name="object_from" id="object_from" placeholder="*@example.org" required>
-						<input type="hidden" name="object_list" value="bl">
-						<input type="hidden" name="domain" value="<?=$domain;?>">
-					</div>
-					<div class="col-xs-6">
-						<button type="submit" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
-					</div>
-					</form>
-				</div>
-			</div>
-		</div>
+        </div>
+        <form class="form-inline" method="post">
+          <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>
+            </span>
+          </div>
+        </form>
+      </div>
+    </div>
         <?php
 			}
 			else {
@@ -350,7 +285,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		is_valid_domain_name($_GET["aliasdomain"]) &&
 		!empty($_GET["aliasdomain"])) {
 			$alias_domain = $_GET["aliasdomain"];
-      $result = mailbox_get_alias_domain_details($alias_domain);
+      $result = mailbox('get', 'alias_domain_details', $alias_domain);
       if (!empty($result)) {
 			?>
 				<h4><?=$lang['edit']['edit_alias_domain'];?></h4>
@@ -399,7 +334,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 	}
 	elseif (isset($_GET['mailbox']) && filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
     $mailbox = $_GET["mailbox"];
-    $result = mailbox_get_mailbox_details($mailbox);
+    $result = mailbox('get', 'mailbox_details', $mailbox);
     if (!empty($result)) {
       ?>
       <h4><?=$lang['edit']['mailbox'];?></h4>
@@ -426,7 +361,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
           <div class="col-sm-10">
             <select data-width="100%" style="width:100%" id="sender_acl" name="sender_acl[]" size="10" multiple>
             <?php
-            $sender_acl_handles = mailbox_get_sender_acl_handles($mailbox);
+            $sender_acl_handles = mailbox('get', 'sender_acl_handles', $mailbox);
 
             foreach ($sender_acl_handles['sender_acl_domains']['ro'] as $domain):
               ?>
@@ -504,7 +439,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
   }
 	elseif (isset($_GET['resource']) && filter_var($_GET["resource"], FILTER_VALIDATE_EMAIL) && !empty($_GET["resource"])) {
 			$resource = $_GET["resource"];
-      $result = mailbox_get_resource_details($resource);
+      $result = mailbox('get', 'resource_details', $resource);
       if (!empty($result)) {
         ?>
 				<h4><?=$lang['edit']['resource'];?></h4>
@@ -566,7 +501,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] ==
 	if (isset($_GET['syncjob']) &&
     is_numeric($_GET['syncjob'])) {
 			$id = $_GET["syncjob"];
-      $result = get_syncjob_details($id);
+      $result = mailbox('get', 'syncjob_details', $id);
       if (!empty($result)) {
 			?>
 				<h4><?=$lang['edit']['syncjob'];?></h4>
@@ -686,6 +621,17 @@ else {
 	</div>
 <a href="<?=$_SESSION['return_to'];?>">&#8592; <?=$lang['edit']['previous'];?></a>
 </div> <!-- /container -->
+<script type='text/javascript'>
+<?php
+$lang_user = json_encode($lang['user']);
+echo "var lang = ". $lang_user . ";\n";
+echo "var table_for_domain = '". ((isset($domain)) ? $domain : null) . "';\n";
+echo "var csrf_token = '". $_SESSION['CSRF']['TOKEN'] . "';\n";
+echo "var pagination_size = '". $PAGINATION_SIZE . "';\n";
+?>
+</script>
+<script src="js/footable.min.js"></script>
+<script src="js/edit.js"></script>
 <?php
 require_once("inc/footer.inc.php");
 ?>

+ 2 - 1
data/web/inc/footer.inc.php

@@ -31,7 +31,7 @@ endif;
       <h4 class="modal-title"><?= $lang['footer']['confirm_delete']; ?></h4>
     </div>
     <div class="modal-body">
-      <p><?= $lang['footer']['delete_these_items']; ?></p>
+      <p id="DeleteText"><?= $lang['footer']['delete_these_items']; ?></p>
       <ul id="ItemsToDelete"></ul>
       <hr>
       <button class="btn btn-sm btn-danger" id="IsConfirmed"><?= $lang['footer']['delete_now']; ?></button>
@@ -48,6 +48,7 @@ endif;
 <script src="/js/bootstrap-select.min.js"></script>
 <script src="/js/notifications.min.js"></script>
 <script src="/js/u2f-api.js"></script>
+<script src="/js/api.js"></script>
 <script>
 // Select language and reopen active URL without POST
 function setLang(sel) {

File diff suppressed because it is too large
+ 428 - 3968
data/web/inc/functions.inc.php


+ 3116 - 0
data/web/inc/functions.mailbox.inc.php

@@ -0,0 +1,3116 @@
+<?php
+function mailbox($_action, $_type, $_data = null) {
+	global $pdo;
+	global $redis;
+	global $lang;
+  switch ($_action) {
+    case 'add':
+      switch ($_type) {
+        case 'time_limited_alias':
+          if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            else {
+              $username = $_data['username'];
+            }
+          }
+          else {
+            $username = $_SESSION['mailcow_cc_username'];
+          }
+          if (!is_numeric($_data["validity"]) || $_data["validity"] > 672) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['validity_missing'])
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `domain` FROM `mailbox` WHERE `username` = :username");
+            $stmt->execute(array(':username' => $_SESSION['mailcow_cc_username']));
+            $domain = $stmt->fetch(PDO::FETCH_ASSOC)['domain'];
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          $validity = strtotime("+".$_data["validity"]." hour"); 
+          $letters = 'abcefghijklmnopqrstuvwxyz1234567890';
+          $random_name = substr(str_shuffle($letters), 0, 24);
+          try {
+            $stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `goto`, `validity`) VALUES
+              (:address, :goto, :validity)");
+            $stmt->execute(array(
+              ':address' => $random_name . '@' . $domain,
+              ':goto' => $username,
+              ':validity' => $validity
+            ));
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($usernames))
+          );
+        break;
+        case 'syncjob':
+          if (isset($_data['username']) && filter_var($_data['username'], FILTER_VALIDATE_EMAIL)) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data['username'])) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            else {
+              $username = $_data['username'];
+            }
+          }
+          else {
+            $username = $_SESSION['mailcow_cc_username'];
+          }
+          $active  = intval($_data['active']);
+          $delete2duplicates = intval($_data['delete2duplicates']);
+          $delete1  = intval($_data['delete1']);
+          $port1            = $_data['port1'];
+          $host1            = $_data['host1'];
+          $password1        = $_data['password1'];
+          $exclude          = $_data['exclude'];
+          $maxage           = $_data['maxage'];
+          $subfolder2       = $_data['subfolder2'];
+          $user1            = $_data['user1'];
+          $mins_interval    = $_data['mins_interval'];
+          $enc1             = $_data['enc1'];
+          if (empty($subfolder2)) {
+            $subfolder2 = "";
+          }
+          if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32767)))) {
+            $maxage = "0";
+          }
+          if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 10, 'max_range' => 3600)))) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          if (!is_valid_domain_name($host1)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          if (@preg_match("/" . $exclude . "/", null) === false) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `user2`, `user1` FROM `imapsync`
+              WHERE `user2` = :user2 AND `user1` = :user1");
+            $stmt->execute(array(':user1' => $user1, ':user2' => $username));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          if ($num_results != 0) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($host1 . ' / ' . $user1))
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("INSERT INTO `imapsync` (`user2`, `exclude`, `delete1`, `maxage`, `subfolder2`, `host1`, `authmech1`, `user1`, `password1`, `mins_interval`, `port1`, `enc1`, `delete2duplicates`, `active`)
+              VALUES (:user2, :exclude, :maxage, :delete1, :subfolder2, :host1, :authmech1, :user1, :password1, :mins_interval, :port1, :enc1, :delete2duplicates, :active)");
+            $stmt->execute(array(
+              ':user2' => $username,
+              ':exclude' => $exclude,
+              ':maxage' => $maxage,
+              ':delete1' => $delete1,
+              ':subfolder2' => $subfolder2,
+              ':host1' => $host1,
+              ':authmech1' => 'PLAIN',
+              ':user1' => $user1,
+              ':password1' => $password1,
+              ':mins_interval' => $mins_interval,
+              ':port1' => $port1,
+              ':enc1' => $enc1,
+              ':delete2duplicates' => $delete2duplicates,
+              ':active' => $active,
+            ));
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], $username)
+          );
+          return true;
+        break;
+        case 'domain':
+          if ($_SESSION['mailcow_cc_role'] != "admin") {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          $domain				= idn_to_ascii(strtolower(trim($_data['domain'])));
+          $description  = $_data['description'];
+          $aliases			= $_data['aliases'];
+          $mailboxes    = $_data['mailboxes'];
+          $maxquota			= $_data['maxquota'];
+          $quota				= $_data['quota'];
+          if ($maxquota > $quota) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['mailbox_quota_exceeds_domain_quota'])
+            );
+            return false;
+          }
+          if ($maxquota == "0" || empty($maxquota)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['maxquota_empty'])
+            );
+            return false;
+          }
+          $active = intval($_data['active']);
+          $relay_all_recipients = intval($_data['relay_all_recipients']);
+          $backupmx = intval($_data['backupmx']);
+          ($relay_all_recipients == 1) ? $backupmx = '1' : null;
+          if (!is_valid_domain_name($domain)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['domain_invalid'])
+            );
+            return false;
+          }
+          foreach (array($quota, $maxquota, $mailboxes, $aliases) as $data) {
+            if (!is_numeric($data)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['object_is_not_numeric'], htmlspecialchars($data))
+              );
+              return false;
+            }
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
+              WHERE `domain` = :domain");
+            $stmt->execute(array(':domain' => $domain));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain`
+              WHERE `alias_domain` = :domain");
+            $stmt->execute(array(':domain' => $domain));
+            $num_results = $num_results + count($stmt->fetchAll(PDO::FETCH_ASSOC));
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          if ($num_results != 0) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['domain_exists'], htmlspecialchars($domain))
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("INSERT INTO `domain` (`domain`, `description`, `aliases`, `mailboxes`, `maxquota`, `quota`, `transport`, `backupmx`, `active`, `relay_all_recipients`)
+              VALUES (:domain, :description, :aliases, :mailboxes, :maxquota, :quota, 'virtual', :backupmx, :active, :relay_all_recipients)");
+            $stmt->execute(array(
+              ':domain' => $domain,
+              ':description' => $description,
+              ':aliases' => $aliases,
+              ':mailboxes' => $mailboxes,
+              ':maxquota' => $maxquota,
+              ':quota' => $quota,
+              ':backupmx' => $backupmx,
+              ':active' => $active,
+              ':relay_all_recipients' => $relay_all_recipients
+            ));
+            try {
+              $redis->hSet('DOMAIN_MAP', $domain, 1);
+            }
+            catch (RedisException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'Redis: '.$e
+              );
+              return false;
+            }
+            $_SESSION['return'] = array(
+              'type' => 'success',
+              'msg' => sprintf($lang['success']['domain_added'], htmlspecialchars($domain))
+            );
+          }
+          catch (PDOException $e) {
+            mailbox('delete', 'domain', array('domain' => $domain));
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+        break;
+        case 'alias':
+          $addresses  = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['address']));
+          $gotos      = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['goto']));
+          $active = intval($_data['active']);
+          if (empty($addresses[0])) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['alias_empty'])
+            );
+            return false;
+          }
+          if (empty($gotos[0])) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['goto_empty'])
+            );
+            return false;
+          }
+          foreach ($addresses as $address) {
+            if (empty($address)) {
+              continue;
+            }
+            $stmt = $pdo->prepare("SELECT `address` FROM `alias`
+              WHERE `address`= :address");
+            $stmt->execute(array(':address' => $address));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['is_alias_or_mailbox'], htmlspecialchars($address))
+              );
+              return false;
+            }
+            $domain       = idn_to_ascii(substr(strstr($address, '@'), 1));
+            $local_part   = strstr($address, '@', true);
+            $address      = $local_part.'@'.$domain;
+            $domaindata = mailbox('get', 'domain_details', $domain);
+            if (is_array($domaindata) && $domaindata['aliases_left'] == "0") {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['max_alias_exceeded'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
+                WHERE `domain`= :domain1 OR `domain` = (SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain2)");
+              $stmt->execute(array(':domain1' => $domain, ':domain2' => $domain));
+              $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+              if ($num_results == 0) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['domain_not_found'], htmlspecialchars($domain))
+                );
+                return false;
+              }
+              $stmt = $pdo->prepare("SELECT `address` FROM `alias`
+                WHERE `address`= :address");
+              $stmt->execute(array(':address' => $address));
+              $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+              if ($num_results != 0) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['is_alias_or_mailbox'], htmlspecialchars($address))
+                );
+                return false;
+              }
+              $stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
+                WHERE `address`= :address");
+              $stmt->execute(array(':address' => $address));
+              $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+              if ($num_results != 0) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($address))
+                );
+                return false;
+              }
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+            if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['alias_invalid'])
+              );
+              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;
+            }
+            foreach ($gotos as &$goto) {
+              if (empty($goto)) {
+                continue;
+              }
+              $goto_domain		= idn_to_ascii(substr(strstr($goto, '@'), 1));
+              $goto_local_part	= strstr($goto, '@', true);
+              $goto				= $goto_local_part.'@'.$goto_domain;
+              $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
+                WHERE `kind` REGEXP 'location|thing|group'
+                  AND `username`= :goto");
+              $stmt->execute(array(':goto' => $goto));
+              $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+              if ($num_results != 0) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['goto_invalid'])
+                );
+                return false;
+              }
+              if (!filter_var($goto, FILTER_VALIDATE_EMAIL) === true) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['goto_invalid'])
+                );
+                return false;
+              }
+              if ($goto == $address) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['alias_goto_identical'])
+                );
+                return false;
+              }
+            }
+            $gotos = array_filter($gotos);
+            $goto = implode(",", $gotos);
+            try {
+              $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
+                VALUES (:address, :goto, :domain, :active)");
+              if (!filter_var($address, FILTER_VALIDATE_EMAIL) === true) {
+                $stmt->execute(array(
+                  ':address' => '@'.$domain,
+                  ':goto' => $goto,
+                  ':domain' => $domain,
+                  ':active' => $active
+                ));
+              }
+              else {
+                $stmt->execute(array(
+                  ':address' => $address,
+                  ':goto' => $goto,
+                  ':domain' => $domain,
+                  ':active' => $active
+                ));
+              }
+              $_SESSION['return'] = array(
+                'type' => 'success',
+                'msg' => sprintf($lang['success']['alias_added'])
+              );
+            }
+            catch (PDOException $e) {
+              mailbox('delete', 'alias', array('address' => $address));
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['alias_added'])
+          );
+        break;
+        case 'alias_domain':
+          $active = intval($_data['active']);
+          $alias_domain     = idn_to_ascii(strtolower(trim($_data['alias_domain'])));
+          $target_domain    = idn_to_ascii(strtolower(trim($_data['target_domain'])));
+          if (!is_valid_domain_name($alias_domain)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['alias_domain_invalid'])
+            );
+            return false;
+          }
+          if (!is_valid_domain_name($target_domain)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['target_domain_invalid'])
+            );
+            return false;
+          }
+          if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          if ($alias_domain == $target_domain) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['aliasd_targetd_identical'])
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
+              WHERE `domain`= :target_domain");
+            $stmt->execute(array(':target_domain' => $target_domain));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results == 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['targetd_not_found'])
+              );
+              return false;
+            }
+            $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain`= :alias_domain
+              UNION
+              SELECT `alias_domain` FROM `alias_domain` WHERE `alias_domain`= :alias_domain_in_domain");
+            $stmt->execute(array(':alias_domain' => $alias_domain, ':alias_domain_in_domain' => $alias_domain));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['aliasd_exists'])
+              );
+              return false;
+            }
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `active`)
+              VALUES (:alias_domain, :target_domain, :active)");
+            $stmt->execute(array(
+              ':alias_domain' => $alias_domain,
+              ':target_domain' => $target_domain,
+              ':active' => $active
+            ));
+            $_SESSION['return'] = array(
+              'type' => 'success',
+              'msg' => sprintf($lang['success']['aliasd_added'], htmlspecialchars($alias_domain))
+            );
+          }
+          catch (PDOException $e) {
+            mailbox('delete', 'alias_domain', array('alias_domain' => $alias_domain));
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+        break;
+        case 'mailbox':
+          $local_part   = strtolower(trim($_data['local_part']));
+          $domain       = idn_to_ascii(strtolower(trim($_data['domain'])));
+          $username     = $local_part . '@' . $domain;
+          if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['mailbox_invalid'])
+            );
+            return false;
+          }
+          if (empty($_data['local_part'])) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['mailbox_invalid'])
+            );
+            return false;
+          }
+          $password     = $_data['password'];
+          $password2    = $_data['password2'];
+          $name         = $_data['name'];
+          $quota_m			= filter_var($_data['quota'], FILTER_SANITIZE_NUMBER_FLOAT);
+          if (empty($name)) {
+            $name = $local_part;
+          }
+          $active = intval($_data['active']);
+          $quota_b		= ($quota_m * 1048576);
+          $maildir		= $domain."/".$local_part."/";
+          if (!is_valid_domain_name($domain)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['domain_invalid'])
+            );
+            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;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `mailboxes`, `maxquota`, `quota` FROM `domain`
+              WHERE `domain` = :domain");
+            $stmt->execute(array(':domain' => $domain));
+            $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
+            $stmt = $pdo->prepare("SELECT 
+              COUNT(*) as count,
+              COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota`
+                FROM `mailbox`
+                  WHERE `kind` NOT REGEXP 'location|thing|group'
+                    AND `domain` = :domain");
+            $stmt->execute(array(':domain' => $domain));
+            $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
+            $stmt = $pdo->prepare("SELECT `local_part` FROM `mailbox` WHERE `local_part` = :local_part and `domain`= :domain");
+            $stmt->execute(array(':local_part' => $local_part, ':domain' => $domain));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($username))
+              );
+              return false;
+            }
+            $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :username");
+            $stmt->execute(array(':username' => $username));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['is_alias'], htmlspecialchars($username))
+              );
+              return false;
+            }
+            $stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :username");
+            $stmt->execute(array(':username' => $username));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($username))
+              );
+              return false;
+            }
+            $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
+            $stmt->execute(array(':domain' => $domain));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results == 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['domain_not_found'], $domain)
+              );
+              return false;
+            }
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          if (!is_numeric($quota_m) || $quota_m == "0") {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['quota_not_0_not_numeric'])
+            );
+            return false;
+          }
+          if (!empty($password) && !empty($password2)) {
+            if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['password_complexity'])
+              );
+              return false;
+            }
+            if ($password != $password2) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['password_mismatch'])
+              );
+              return false;
+            }
+            $password_hashed = hash_password($password);
+          }
+          else {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['password_empty'])
+            );
+            return false;
+          }
+          if ($MailboxData['count'] >= $DomainData['mailboxes']) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['max_mailbox_exceeded'], $MailboxData['count'], $DomainData['mailboxes'])
+            );
+            return false;
+          }
+          if ($quota_m > $DomainData['maxquota']) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['mailbox_quota_exceeded'], $DomainData['maxquota'])
+            );
+            return false;
+          }
+          if (($MailboxData['quota'] + $quota_m) > $DomainData['quota']) {
+            $quota_left_m = ($DomainData['quota'] - $MailboxData['quota']);
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['mailbox_quota_left_exceeded'], $quota_left_m)
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `local_part`, `domain`, `active`) 
+              VALUES (:username, :password_hashed, :name, :maildir, :quota_b, :local_part, :domain, :active)");
+            $stmt->execute(array(
+              ':username' => $username,
+              ':password_hashed' => $password_hashed,
+              ':name' => $name,
+              ':maildir' => $maildir,
+              ':quota_b' => $quota_b,
+              ':local_part' => $local_part,
+              ':domain' => $domain,
+              ':active' => $active
+            ));
+            $stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
+              VALUES (:username, '0', '0')");
+            $stmt->execute(array(':username' => $username));
+            $stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
+              VALUES (:username1, :username2, :domain, :active)");
+            $stmt->execute(array(
+              ':username1' => $username,
+              ':username2' => $username,
+              ':domain' => $domain,
+              ':active' => $active
+            ));
+            $_SESSION['return'] = array(
+              'type' => 'success',
+              'msg' => sprintf($lang['success']['mailbox_added'], htmlspecialchars($username))
+            );
+          }
+          catch (PDOException $e) {
+            mailbox('delete', 'mailbox', array('username' => $username));
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+        break;
+        case 'resource':
+          $domain             = idn_to_ascii(strtolower(trim($_data['domain'])));
+          $description        = $_data['description'];
+          $local_part         = preg_replace('/[^\da-z]/i', '', preg_quote($description, '/'));
+          $name               = $local_part . '@' . $domain;
+          $kind               = $_data['kind'];
+          $active = intval($_data['active']);
+          $multiple_bookings = intval($_data['multiple_bookings']);
+          if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['resource_invalid'])
+            );
+            return false;
+          }
+          if (empty($description)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['description_invalid'])
+            );
+            return false;
+          }
+          
+          if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['resource_invalid'])
+            );
+            return false;
+          }
+          if (!is_valid_domain_name($domain)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['domain_invalid'])
+            );
+            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;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :name");
+            $stmt->execute(array(':name' => $name));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($name))
+              );
+              return false;
+            }
+            $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :name");
+            $stmt->execute(array(':name' => $name));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['is_alias'], htmlspecialchars($name))
+              );
+              return false;
+            }
+            $stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :name");
+            $stmt->execute(array(':name' => $name));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($name))
+              );
+              return false;
+            }
+            $stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
+            $stmt->execute(array(':domain' => $domain));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results == 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['domain_not_found'], $domain)
+              );
+              return false;
+            }
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `local_part`, `domain`, `active`, `multiple_bookings`, `kind`) 
+              VALUES (:name, 'RESOURCE', :description, 'RESOURCE', 0, :local_part, :domain, :active, :multiple_bookings, :kind)");
+            $stmt->execute(array(
+              ':name' => $name,
+              ':description' => $description,
+              ':local_part' => $local_part,
+              ':domain' => $domain,
+              ':active' => $active,
+              ':kind' => $kind,
+              ':multiple_bookings' => $multiple_bookings
+            ));
+            $_SESSION['return'] = array(
+              'type' => 'success',
+              'msg' => sprintf($lang['success']['resource_added'], htmlspecialchars($name))
+            );
+          }
+          catch (PDOException $e) {
+            mailbox('delete', 'resource', array('name' => $name));
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+        break;
+      }
+    break;
+    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'];
+          }
+          foreach ($alias_domains as $alias_domain) {
+            $alias_domain = idn_to_ascii(strtolower(trim($alias_domain)));
+            $is_now = mailbox('get', 'alias_domain_details', $alias_domain);
+            if (!empty($is_now)) {
+              $active         = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int'];
+              $target_domain  = (!empty($_data['target_domain'])) ? idn_to_ascii(strtolower(trim($_data['target_domain']))) : $is_now['target_domain'];
+            }
+            else {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['alias_domain_invalid'])
+              );
+              return false;
+            }
+            if (!is_valid_domain_name($target_domain)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['target_domain_invalid'])
+              );
+              return false;
+            }
+            if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $target_domain)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (empty(mailbox('get', 'domain_details', $target_domain))) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['target_domain_invalid'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("UPDATE `alias_domain` SET
+                `target_domain` = :target_domain,
+                `active` = :active
+                  WHERE `alias_domain` = :alias_domain");
+              $stmt->execute(array(
+                ':alias_domain' => $alias_domain,
+                ':target_domain' => $target_domain,
+                ':active' => $active
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['aliasd_modified'], htmlspecialchars(implode(', ', $alias_domains)))
+          );
+        break;
+        case 'tls_policy':
+          if (!is_array($_data['username'])) {
+            $usernames = array();
+            $usernames[] = $_data['username'];
+          }
+          else {
+            $usernames = $_data['username'];
+          }
+          foreach ($usernames as $username) {
+            if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            $tls_enforce_out = intval($_data['tls_enforce_out']);
+            $tls_enforce_in = intval($_data['tls_enforce_in']);
+            $is_now = mailbox('get', 'tls_policy', $username);
+            if (!empty($is_now)) {
+              $tls_enforce_in = (isset($_data['tls_enforce_in'])) ? $_data['tls_enforce_in'] : $is_now['tls_enforce_in'];
+              $tls_enforce_out = (isset($_data['tls_enforce_out'])) ? $_data['tls_enforce_out'] : $is_now['tls_enforce_out'];
+            }
+            else {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("UPDATE `mailbox` SET `tls_enforce_out` = :tls_out, `tls_enforce_in` = :tls_in WHERE `username` = :username");
+              $stmt->execute(array(
+                ':tls_out' => $tls_enforce_out,
+                ':tls_in' => $tls_enforce_in,
+                ':username' => $username
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames))
+          );
+        break;
+        case 'spam_score':
+          if (!is_array($_data['username'])) {
+            $usernames = array();
+            $usernames[] = $_data['username'];
+          }
+          else {
+            $usernames = $_data['username'];
+          }
+          foreach ($usernames as $username) {
+            $lowspamlevel	= explode(',', $_data['spam_score'])[0];
+            $highspamlevel	= explode(',', $_data['spam_score'])[1];
+            if (!is_numeric($lowspamlevel) || !is_numeric($highspamlevel)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
+                AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
+                VALUES (:username, 'highspamlevel', :highspamlevel)");
+              $stmt->execute(array(
+                ':username' => $username,
+                ':highspamlevel' => $highspamlevel
+              ));
+              $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option`, `value`)
+                VALUES (:username, 'lowspamlevel', :lowspamlevel)");
+              $stmt->execute(array(
+                ':username' => $username,
+                ':lowspamlevel' => $lowspamlevel
+              ));
+            }
+            catch (PDOException $e) {
+              $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
+                AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames))
+          );
+        break;
+        case 'time_limited_alias':
+          if (!is_array($_data['address'])) {
+            $addresses = array();
+            $addresses[] = $_data['address'];
+          }
+          else {
+            $addresses = $_data['address'];
+          }
+          foreach ($addresses as $address) {
+            try {
+              $stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
+              $stmt->execute(array(':address' => $address));
+              $goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = (`validity` + 3600) WHERE 
+                `address` = :address AND
+                `validity` >= :validity");
+              $stmt->execute(array(
+                ':address' => $address,
+                ':validity' => time()
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars(implode(', ', $usernames)))
+          );
+        break;
+        case 'delimiter_action':
+          if (!is_array($_data['username'])) {
+            $usernames = array();
+            $usernames[] = $_data['username'];
+          }
+          else {
+            $usernames = $_data['username'];
+          }
+          foreach ($usernames as $username) {
+            if (!filter_var($username, FILTER_VALIDATE_EMAIL) || !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subject") {
+              try {
+                $redis->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
+              }
+              catch (RedisException $e) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => 'Redis: '.$e
+                );
+                return false;
+              }
+            }
+            else {
+              try {
+                $redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
+              }
+              catch (RedisException $e) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => 'Redis: '.$e
+                );
+                return false;
+              }
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames))
+          );
+        break;
+        case 'syncjob':
+          if (!is_array($_data['id'])) {
+            $ids = array();
+            $ids[] = $_data['id'];
+          }
+          else {
+            $ids = $_data['id'];
+          }
+          foreach ($ids as $id) {
+            $is_now = mailbox('get', 'syncjob_details', $id);
+            if (!empty($is_now)) {
+              $username = $is_now['user2'];
+              $user1 = (!empty($_data['user1'])) ? $_data['user1'] : $is_now['user1'];
+              $active = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int'];
+              $delete2duplicates = (isset($_data['delete2duplicates'])) ? $_data['delete2duplicates'] : $is_now['delete2duplicates'];
+              $delete1 = (isset($_data['delete1'])) ? $_data['delete1'] : $is_now['delete1'];
+              $port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
+              $password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
+              $host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
+              $subfolder2 = (!empty($_data['subfolder2'])) ? $_data['subfolder2'] : $is_now['subfolder2'];
+              $enc1 = (!empty($_data['enc1'])) ? $_data['enc1'] : $is_now['enc1'];
+              $mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
+              $exclude = (!empty($_data['exclude'])) ? $_data['exclude'] : $is_now['exclude'];
+              $maxage = (!empty($_data['maxage'])) ? $_data['maxage'] : $is_now['maxage'];
+            }
+            else {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (empty($subfolder2)) {
+              $subfolder2 = "";
+            }
+            if (!isset($maxage) || !filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 32767)))) {
+              $maxage = "0";
+            }
+            if (!filter_var($port1, FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 65535)))) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (!filter_var($mins_interval, FILTER_VALIDATE_INT, array('options' => array('min_range' => 10, 'max_range' => 3600)))) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (!is_valid_domain_name($host1)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if ($enc1 != "TLS" && $enc1 != "SSL" && $enc1 != "PLAIN") {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (@preg_match("/" . $exclude . "/", null) === false) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("UPDATE `imapsync` SET `delete1` = :delete1, `maxage` = :maxage, `subfolder2` = :subfolder2, `exclude` = :exclude, `host1` = :host1, `user1` = :user1, `password1` = :password1, `mins_interval` = :mins_interval, `port1` = :port1, `enc1` = :enc1, `delete2duplicates` = :delete2duplicates, `active` = :active
+                WHERE `id` = :id");
+              $stmt->execute(array(
+                ':delete1' => $delete1,
+                ':id' => $id,
+                ':exclude' => $exclude,
+                ':maxage' => $maxage,
+                ':subfolder2' => $subfolder2,
+                ':host1' => $host1,
+                ':user1' => $user1,
+                ':password1' => $password1,
+                ':mins_interval' => $mins_interval,
+                ':port1' => $port1,
+                ':enc1' => $enc1,
+                ':delete2duplicates' => $delete2duplicates,
+                ':active' => $active,
+              ));
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], $username)
+          );
+          return true;
+        break;
+        case 'alias':
+          if (!is_array($_data['address'])) {
+            $addresses = array();
+            $addresses[] = $_data['address'];
+          }
+          else {
+            $addresses = $_data['address'];
+          }
+          foreach ($addresses as $address) {
+            $is_now = mailbox('get', 'alias_details', $address);
+            if (!empty($is_now)) {
+              $active = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int'];
+              $goto   = (!empty($_data['goto'])) ? $_data['goto'] : $is_now['goto'];
+            }
+            else {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['alias_invalid'])
+              );
+              return false;
+            }
+            
+            $gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['goto']));
+            foreach ($gotos as &$goto) {
+              if (empty($goto)) {
+                continue;
+              }
+              if (!filter_var($goto, FILTER_VALIDATE_EMAIL)) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' =>sprintf($lang['danger']['goto_invalid'])
+                );
+                return false;
+              }
+              if ($goto == $address) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['alias_goto_identical'])
+                );
+                return false;
+              }
+            }
+            $gotos = array_filter($gotos);
+            $goto = implode(",", $gotos);
+            
+            $domain = idn_to_ascii(substr(strstr($address, '@'), 1));
+            $local_part = strstr($address, '@', true);
+            if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['alias_invalid'])
+              );
+              return false;
+            }
+            try {
+              if (!empty($goto)) {
+                $stmt = $pdo->prepare("UPDATE `alias` SET
+                  `goto` = :goto,
+                  `active`= :active
+                    WHERE `address` = :address");
+                $stmt->execute(array(
+                  ':goto' => $goto,
+                  ':active' => $active,
+                  ':address' => $address
+                ));
+              }
+              else {
+                $stmt = $pdo->prepare("UPDATE `alias` SET
+                  `active`= :active
+                    WHERE `address` = :address");
+                $stmt->execute(array(
+                  ':active' => $active,
+                  ':address' => $address
+                ));
+              }
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['alias_modified'], htmlspecialchars(implode(', ', $addresses)))
+          );
+        break;
+        case 'domain':
+          if (!is_array($_data['domain'])) {
+            $domains = array();
+            $domains[] = $_data['domain'];
+          }
+          else {
+            $domains = $_data['domain'];
+          }
+          foreach ($domains as $domain) {
+            $domain = idn_to_ascii($domain);
+            if (!is_valid_domain_name($domain)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['domain_invalid'])
+              );
+              return false;
+            }
+            if ($_SESSION['mailcow_cc_role'] == "domainadmin" &&
+            hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+              $description  = $_data['description'];
+              $active = intval($_data['active']);
+              try {
+                $stmt = $pdo->prepare("UPDATE `domain` SET 
+                `description` = :description
+                  WHERE `domain` = :domain");
+                $stmt->execute(array(
+                  ':description' => $description,
+                  ':domain' => $domain
+                ));
+                $_SESSION['return'] = array(
+                  'type' => 'success',
+                  'msg' => sprintf($lang['success']['domain_modified'], htmlspecialchars($domain))
+                );
+              }
+              catch (PDOException $e) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => 'MySQL: '.$e
+                );
+                return false;
+              }
+            }
+            elseif ($_SESSION['mailcow_cc_role'] == "admin") {
+              $is_now = mailbox('get', 'domain_details', $domain);
+              if (!empty($is_now)) {
+                $active               = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int'];
+                $backupmx             = (isset($_data['backupmx'])) ? $_data['backupmx'] : $is_now['backupmx_int'];
+                $relay_all_recipients = (isset($_data['relay_all_recipients'])) ? $_data['relay_all_recipients'] : $is_now['relay_all_recipients_int'];
+                $aliases              = (!empty($_data['aliases'])) ? $_data['aliases'] : $is_now['max_num_aliases_for_domain'];
+                $mailboxes            = (!empty($_data['mailboxes'])) ? $_data['mailboxes'] : $is_now['max_num_mboxes_for_domain'];
+                $maxquota             = (!empty($_data['maxquota'])) ? $_data['maxquota'] : ($is_now['max_new_mailbox_quota'] / 1048576);
+                $quota                = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['max_quota_for_domain'] / 1048576);
+                $description          = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
+                ($relay_all_recipients == '1') ? $backupmx = '1' : null;
+              }
+              else {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['domain_invalid'])
+                );
+                return false;
+              }
+              try {
+                // todo: should be using api here
+                $stmt = $pdo->prepare("SELECT 
+                    COUNT(*) AS count,
+                    MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `biggest_mailbox`,
+                    COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota_all`
+                      FROM `mailbox`
+                        WHERE `kind` NOT REGEXP 'location|thing|group'
+                          AND domain = :domain");
+                $stmt->execute(array(':domain' => $domain));
+                $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
+                // todo: should be using api here
+                $stmt = $pdo->prepare("SELECT COUNT(*) AS `count` FROM `alias`
+                    WHERE domain = :domain
+                    AND address NOT IN (
+                      SELECT `username` FROM `mailbox`
+                    )");
+                $stmt->execute(array(':domain' => $domain));
+                $AliasData = $stmt->fetch(PDO::FETCH_ASSOC);
+              }
+              catch(PDOException $e) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => 'MySQL: '.$e
+                );
+                return false;
+              }
+              if ($maxquota > $quota) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['mailbox_quota_exceeds_domain_quota'])
+                );
+                return false;
+              }
+              if ($maxquota == "0" || empty($maxquota)) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['maxquota_empty'])
+                );
+                return false;
+              }
+              if ($MailboxData['biggest_mailbox'] > $maxquota) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['max_quota_in_use'], $MailboxData['biggest_mailbox'])
+                );
+                return false;
+              }
+              if ($MailboxData['quota_all'] > $quota) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['domain_quota_m_in_use'], $MailboxData['quota_all'])
+                );
+                return false;
+              }
+              if ($MailboxData['count'] > $mailboxes) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['mailboxes_in_use'], $MailboxData['count'])
+                );
+                return false;
+              }
+              if ($AliasData['count'] > $aliases) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['aliases_in_use'], $AliasData['count'])
+                );
+                return false;
+              }
+              try {
+                $stmt = $pdo->prepare("UPDATE `domain` SET 
+                `relay_all_recipients` = :relay_all_recipients,
+                `backupmx` = :backupmx,
+                `active` = :active,
+                `quota` = :quota,
+                `maxquota` = :maxquota,
+                `mailboxes` = :mailboxes,
+                `aliases` = :aliases,
+                `description` = :description
+                  WHERE `domain` = :domain");
+                $stmt->execute(array(
+                  ':relay_all_recipients' => $relay_all_recipients,
+                  ':backupmx' => $backupmx,
+                  ':active' => $active,
+                  ':quota' => $quota,
+                  ':maxquota' => $maxquota,
+                  ':mailboxes' => $mailboxes,
+                  ':aliases' => $aliases,
+                  ':description' => $description,
+                  ':domain' => $domain
+                ));
+              }
+              catch (PDOException $e) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => 'MySQL: '.$e
+                );
+                return false;
+              }
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['domain_modified'], htmlspecialchars(implode(', ', $domains)))
+          );
+        break;
+        case 'mailbox':
+          if (!is_array($_data['username'])) {
+            $usernames = array();
+            $usernames[] = $_data['username'];
+          }
+          else {
+            $usernames = $_data['username'];
+          }
+          foreach ($usernames as $username) {
+            if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['username_invalid'])
+              );
+              return false;
+            }
+            $is_now = mailbox('get', 'mailbox_details', $username);
+            if (!empty($is_now)) {
+              $active     = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int'];
+              $name       = (!empty($_data['name'])) ? $_data['name'] : $is_now['name'];
+              $domain     = $is_now['domain'];
+              $quota_m    = (!empty($_data['quota'])) ? $_data['quota'] : ($is_now['quota'] / 1048576);
+              $quota_b    = $quota_m * 1048576;
+              $password   = (!empty($_data['password'])) ? $_data['password'] : null;
+              $password2  = (!empty($_data['password2'])) ? $_data['password2'] : null; 
+            }
+            else {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("SELECT `quota`, `maxquota`
+                FROM `domain`
+                  WHERE `domain` = :domain");
+              $stmt->execute(array(':domain' => $domain));
+              $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+            if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (!is_numeric($quota_m) || $quota_m == "0") {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['quota_not_0_not_numeric'], htmlspecialchars($quota_m))
+              );
+              return false;
+            }
+            if ($quota_m > $DomainData['maxquota']) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['mailbox_quota_exceeded'], $DomainData['maxquota'])
+              );
+              return false;
+            }
+            if (((($is_now['quota_used'] / 1048576) - $quota_m) + $quota_m) > $DomainData['quota']) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['mailbox_quota_left_exceeded'], ($is_now['max_new_quota'] / 1048576))
+              );
+              return false;
+            }
+            if (isset($_data['sender_acl'])) {
+              // Get sender_acl items set by admin
+              $sender_acl_admin = array_merge(
+                mailbox('get', 'sender_acl_handles', $username)['sender_acl_domains']['ro'],
+                mailbox('get', 'sender_acl_handles', $username)['sender_acl_addresses']['ro']
+              );
+              // Get sender_acl items from POST array
+              $sender_acl_domain_admin = ($_data['sender_acl'] == "0") ? array() : $_data['sender_acl'];
+              if (!empty($sender_acl_domain_admin) || !empty($sender_acl_admin)) {
+                // Check items in POST array
+                foreach ($sender_acl_domain_admin as $sender_acl) {
+                  if (!filter_var($sender_acl, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name(ltrim($sender_acl, '@'))) {
+                      $_SESSION['return'] = array(
+                        'type' => 'danger',
+                        'msg' => sprintf($lang['danger']['sender_acl_invalid'])
+                      );
+                      return false;
+                  }
+                  if (is_valid_domain_name(ltrim($sender_acl, '@'))) {
+                    if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], ltrim($sender_acl, '@'))) {
+                      $_SESSION['return'] = array(
+                        'type' => 'danger',
+                        'msg' => sprintf($lang['danger']['sender_acl_invalid'])
+                      );
+                      return false;
+                    }
+                  }
+                  if (filter_var($sender_acl, FILTER_VALIDATE_EMAIL)) {
+                    if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $sender_acl)) {
+                      $_SESSION['return'] = array(
+                        'type' => 'danger',
+                        'msg' => sprintf($lang['danger']['sender_acl_invalid'])
+                      );
+                      return false;
+                    }
+                  }
+                }
+                // Merge both arrays
+                $sender_acl_merged = array_merge($sender_acl_domain_admin, $sender_acl_admin);
+                try {
+                  $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` = :username");
+                  $stmt->execute(array(
+                    ':username' => $username
+                  ));
+                }
+                catch (PDOException $e) {
+                  $_SESSION['return'] = array(
+                    'type' => 'danger',
+                    'msg' => 'MySQL: '.$e
+                  );
+                  return false;
+                }
+                foreach ($sender_acl_merged as $sender_acl) {
+                  $domain = ltrim($sender_acl, '@');
+                  if (is_valid_domain_name($domain)) {
+                    $sender_acl = '@' . $domain;
+                  }
+                  try {
+                    $stmt = $pdo->prepare("INSERT INTO `sender_acl` (`send_as`, `logged_in_as`)
+                      VALUES (:sender_acl, :username)");
+                    $stmt->execute(array(
+                      ':sender_acl' => $sender_acl,
+                      ':username' => $username
+                    ));
+                  }
+                  catch (PDOException $e) {
+                    $_SESSION['return'] = array(
+                      'type' => 'danger',
+                      'msg' => 'MySQL: '.$e
+                    );
+                    return false;
+                  }
+                }
+              }
+              else {
+                try {
+                  $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` = :username");
+                  $stmt->execute(array(
+                    ':username' => $username
+                  ));
+                }
+                catch (PDOException $e) {
+                  $_SESSION['return'] = array(
+                    'type' => 'danger',
+                    'msg' => 'MySQL: '.$e
+                  );
+                  return false;
+                }
+              }
+            }
+            if (!empty($password) && !empty($password2)) {
+              if (!preg_match('/' . $GLOBALS['PASSWD_REGEP'] . '/', $password)) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['password_complexity'])
+                );
+                return false;
+              }
+              if ($password != $password2) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['password_mismatch'])
+                );
+                return false;
+              }
+              $password_hashed = hash_password($password);
+              try {
+                $stmt = $pdo->prepare("UPDATE `alias` SET
+                    `active` = :active
+                      WHERE `address` = :address");
+                $stmt->execute(array(
+                  ':address' => $username,
+                  ':active' => $active
+                ));
+                $stmt = $pdo->prepare("UPDATE `mailbox` SET
+                    `active` = :active,
+                    `password` = :password_hashed,
+                    `name`= :name,
+                    `quota` = :quota_b
+                      WHERE `username` = :username");
+                $stmt->execute(array(
+                  ':password_hashed' => $password_hashed,
+                  ':active' => $active,
+                  ':name' => $name,
+                  ':quota_b' => $quota_b,
+                  ':username' => $username
+                ));
+              }
+              catch (PDOException $e) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => 'MySQL: '.$e
+                );
+                return false;
+              }
+            }
+            try {
+              $stmt = $pdo->prepare("UPDATE `alias` SET
+                  `active` = :active
+                    WHERE `address` = :address");
+              $stmt->execute(array(
+                ':address' => $username,
+                ':active' => $active
+              ));
+              $stmt = $pdo->prepare("UPDATE `mailbox` SET
+                  `active` = :active,
+                  `name`= :name,
+                  `quota` = :quota_b
+                    WHERE `username` = :username");
+              $stmt->execute(array(
+                ':active' => $active,
+                ':name' => $name,
+                ':quota_b' => $quota_b,
+                ':username' => $username
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], implode(', ', $usernames))
+          );
+        break;
+        case 'resource':
+          if (!is_array($_data['name'])) {
+            $names = array();
+            $names[] = $_data['name'];
+          }
+          else {
+            $names = $_data['name'];
+          }
+          foreach ($names as $name) {
+            $is_now = mailbox('get', 'resource_details', $name);
+            if (!empty($is_now)) {
+              $active             = (isset($_data['active'])) ? $_data['active'] : $is_now['active_int'];
+              $multiple_bookings  = (isset($_data['multiple_bookings'])) ? $_data['multiple_bookings'] : $is_now['multiple_bookings_int'];
+              $description        = (!empty($_data['description'])) ? $_data['description'] : $is_now['description'];
+              $kind               = (!empty($_data['kind'])) ? $_data['kind'] : $is_now['kind'];
+            }
+            else {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['resource_invalid'])
+              );
+              return false;
+            }
+            if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['resource_invalid'])
+              );
+              return false;
+            }
+            if (empty($description)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['description_invalid'])
+              );
+              return false;
+            }
+            if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['resource_invalid'])
+              );
+              return false;
+            }
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("UPDATE `mailbox` SET
+                  `active` = :active,
+                  `name`= :description,
+                  `kind`= :kind,
+                  `multiple_bookings`= :multiple_bookings
+                    WHERE `username` = :name");
+              $stmt->execute(array(
+                ':active' => $active,
+                ':description' => $description,
+                ':multiple_bookings' => $multiple_bookings,
+                ':kind' => $kind,
+                ':name' => $name
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['resource_modified'], implode(', ', $names))
+          );
+        break;
+      }
+    break;
+    case 'get':
+      switch ($_type) {
+        case 'sender_acl_handles':
+          if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
+            return false;
+          }
+          $data['sender_acl_domains']['ro']               = array();
+          $data['sender_acl_domains']['rw']               = array();
+          $data['sender_acl_domains']['selectable']       = array();
+          $data['sender_acl_addresses']['ro']             = array();
+          $data['sender_acl_addresses']['rw']             = array();
+          $data['sender_acl_addresses']['selectable']     = array();
+          $data['fixed_sender_aliases']                   = array();
+          try {
+            // Fixed addresses
+            $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` REGEXP :goto AND `address` NOT LIKE '@%'");
+            $stmt->execute(array(':goto' => '(^|,)'.$_data.'($|,)'));
+            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            while ($row = array_shift($rows)) {
+              $data['fixed_sender_aliases'][] = $row['address'];
+            }
+            $stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias_domain_alias` FROM `mailbox`, `alias_domain`
+              WHERE `alias_domain`.`target_domain` = `mailbox`.`domain`
+              AND `mailbox`.`username` = :username");
+            $stmt->execute(array(':username' => $_data));
+            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            while ($row = array_shift($rows)) {
+              if (!empty($row['alias_domain_alias'])) {
+                $data['fixed_sender_aliases'][] = $row['alias_domain_alias'];
+              }
+            }
+            // Return array $data['sender_acl_domains/addresses']['ro'] with read-only objects
+            // Return array $data['sender_acl_domains/addresses']['rw'] with read-write objects (can be deleted)
+            $stmt = $pdo->prepare("SELECT REPLACE(`send_as`, '@', '') AS `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `send_as` LIKE '@%'");
+            $stmt->execute(array(':logged_in_as' => $_data));
+            $domain_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            while ($domain_row = array_shift($domain_rows)) {
+              if (is_valid_domain_name($domain_row['send_as']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
+                $data['sender_acl_domains']['ro'][] = $domain_row['send_as'];
+                continue;
+              }
+              if (is_valid_domain_name($domain_row['send_as']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain_row['send_as'])) {
+                $data['sender_acl_domains']['rw'][] = $domain_row['send_as'];
+                continue;
+              }
+            }
+            $stmt = $pdo->prepare("SELECT `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as AND `send_as` NOT LIKE '@%'");
+            $stmt->execute(array(':logged_in_as' => $_data));
+            $address_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            while ($address_row = array_shift($address_rows)) {
+              if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && !hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
+                $data['sender_acl_addresses']['ro'][] = $address_row['send_as'];
+                continue;
+              }
+              if (filter_var($address_row['send_as'], FILTER_VALIDATE_EMAIL) && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $address_row['send_as'])) {
+                $data['sender_acl_addresses']['rw'][] = $address_row['send_as'];
+                continue;
+              }
+            }
+            $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
+              WHERE `domain` NOT IN (
+                SELECT REPLACE(`send_as`, '@', '') FROM `sender_acl` 
+                  WHERE `logged_in_as` = :logged_in_as
+                    AND `send_as` LIKE '@%')");
+            $stmt->execute(array(
+              ':logged_in_as' => $_data,
+            ));
+            $rows_domain = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            while ($row_domain = array_shift($rows_domain)) {
+              if (is_valid_domain_name($row_domain['domain']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row_domain['domain'])) {
+                $data['sender_acl_domains']['selectable'][] = $row_domain['domain'];
+              }
+            }
+            $stmt = $pdo->prepare("SELECT `address` FROM `alias`
+              WHERE `goto` != :goto
+                AND `address` NOT IN (
+                  SELECT `send_as` FROM `sender_acl` 
+                    WHERE `logged_in_as` = :logged_in_as
+                      AND `send_as` NOT LIKE '@%')");
+            $stmt->execute(array(
+              ':logged_in_as' => $_data,
+              ':goto' => $_data
+            ));
+            $rows_mbox = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            while ($row = array_shift($rows_mbox)) {
+              if (filter_var($row['address'], FILTER_VALIDATE_EMAIL) && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['address'])) {
+                $data['sender_acl_addresses']['selectable'][] = $row['address'];
+              }
+            }
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          return $data;
+        break;
+        case 'mailboxes':
+          $mailboxes = array();
+          if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            return false;
+          }
+          elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            try {
+              $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` != 'ALL' AND `domain` = :domain");
+              $stmt->execute(array(
+                ':domain' => $_data,
+              ));
+              $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+              while($row = array_shift($rows)) {
+                $mailboxes[] = $row['username'];
+              }
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          else {
+            try {
+              $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
+              $stmt->execute(array(
+                ':username' => $_SESSION['mailcow_cc_username'],
+                ':role' => $_SESSION['mailcow_cc_role'],
+              ));
+              $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+              while($row = array_shift($rows)) {
+                $mailboxes[] = $row['username'];
+              }
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          return $mailboxes;
+        break;
+        case 'tls_policy':
+          $policydata = array();
+          if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+              return false;
+            }
+          }
+          else {
+            $_data = $_SESSION['mailcow_cc_username'];
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `tls_enforce_out`, `tls_enforce_in` FROM `mailbox` WHERE `username` = :username");
+            $stmt->execute(array(':username' => $_data));
+            $policydata = $stmt->fetch(PDO::FETCH_ASSOC);
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          return $policydata;
+        break;
+        case 'syncjob_details':
+          $syncjobdetails = array();
+          if (!is_numeric($_data)) {
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT * FROM `imapsync` WHERE id = :id");
+            $stmt->execute(array(':id' => $_data));
+            $syncjobdetails = $stmt->fetch(PDO::FETCH_ASSOC);
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+          }
+          if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $syncjobdetails['user2'])) {
+            return false;
+          }
+          return $syncjobdetails;
+        break;
+        case 'syncjobs':
+          $syncjobdata = array();
+          if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+              return false;
+            }
+          }
+          else {
+            $_data = $_SESSION['mailcow_cc_username'];
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT *,
+              CONCAT(LEFT(`password1`, 3), '...') AS `password1_short`,
+              `active` AS `active_int`,
+              CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`
+                FROM `imapsync`
+                  WHERE `user2` = :username");
+            $stmt->execute(array(':username' => $_data));
+            $syncjobdata = $stmt->fetchAll(PDO::FETCH_ASSOC);
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+          }
+          return $syncjobdata;
+        break;
+        case 'spam_score':
+          $default = "5, 15";
+          $policydata = array();
+          if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+              return false;
+            }
+          }
+          else {
+            $_data = $_SESSION['mailcow_cc_username'];
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `object` = :username AND
+              (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
+            $stmt->execute(array(':username' => $_data));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          if (empty($num_results)) {
+            return $default;
+          }
+          else {
+            try {
+              $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'highspamlevel' AND `object` = :username");
+              $stmt->execute(array(':username' => $_data));
+              $highspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
+
+              $stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `option` = 'lowspamlevel' AND `object` = :username");
+              $stmt->execute(array(':username' => $_data));
+              $lowspamlevel = $stmt->fetch(PDO::FETCH_ASSOC);
+
+              return $lowspamlevel['value'].', '.$highspamlevel['value'];
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+        break;
+        case 'time_limited_aliases':
+          $tladata = array();
+          if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+              return false;
+            }
+          }
+          else {
+            $_data = $_SESSION['mailcow_cc_username'];
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `address`,
+              `goto`,
+              `validity`
+                FROM `spamalias`
+                  WHERE `goto` = :username
+                    AND `validity` >= :unixnow");
+            $stmt->execute(array(':username' => $_data, ':unixnow' => time()));
+            $tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+          }
+          return $tladata;
+        break;
+        case 'delimiter_action':
+          $policydata = array();
+          if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+              return false;
+            }
+          }
+          else {
+            $_data = $_SESSION['mailcow_cc_username'];
+          }
+          try {
+            if ($redis->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
+              return "subject";
+            }
+            else {
+              return "subfolder";
+            }
+          }
+          catch (RedisException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'Redis: '.$e
+            );
+            return false;
+          }
+        break;
+        case 'resources':
+          $resources = array();
+          if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            return false;
+          }
+          elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            try {
+              $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` != 'ALL' AND `domain` = :domain");
+              $stmt->execute(array(
+                ':domain' => $_data,
+              ));
+              $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+              while($row = array_shift($rows)) {
+                $resources[] = $row['username'];
+              }
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          else {
+            try {
+              $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
+              $stmt->execute(array(
+                ':username' => $_SESSION['mailcow_cc_username'],
+                ':role' => $_SESSION['mailcow_cc_role'],
+              ));
+              $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+              while($row = array_shift($rows)) {
+                $resources[] = $row['username'];
+              }
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          return $resources;
+        break;
+        case 'alias_domains':
+          $aliasdomains = array();
+          if (isset($_data) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            return false;
+          }
+          elseif (isset($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            try {
+              $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain");
+              $stmt->execute(array(
+                ':domain' => $_data,
+              ));
+              $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+              while($row = array_shift($rows)) {
+                $aliasdomains[] = $row['alias_domain'];
+              }
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          else {
+            try {
+              $stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
+              $stmt->execute(array(
+                ':username' => $_SESSION['mailcow_cc_username'],
+                ':role' => $_SESSION['mailcow_cc_role'],
+              ));
+              $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+              while($row = array_shift($rows)) {
+                $aliasdomains[] = $row['alias_domain'];
+              }
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          return $aliasdomains;
+        break;
+        case 'aliases':
+          $aliases = array();
+          if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `address` != `goto` AND `domain` = :domain");
+            $stmt->execute(array(
+              ':domain' => $_data,
+            ));
+            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            while($row = array_shift($rows)) {
+              $aliases[] = $row['address'];
+            }
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          return $aliases;
+        break;
+        case 'alias_details':
+          $aliasdata = array();
+          try {
+            $stmt = $pdo->prepare("SELECT
+              `domain`,
+              `goto`,
+              `address`,
+              `active` as `active_int`,
+              CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
+              `created`,
+              `modified`
+                FROM `alias`
+                    WHERE `address` = :address AND `address` != `goto`");
+            $stmt->execute(array(
+              ':address' => $_data,
+            ));
+            $row = $stmt->fetch(PDO::FETCH_ASSOC);
+            $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
+            $stmt->execute(array(
+              ':domain' => $row['domain'],
+            ));
+            $row_alias_domain = $stmt->fetch(PDO::FETCH_ASSOC);
+            if (isset($row_alias_domain['target_domain']) && !empty($row_alias_domain['target_domain'])) {
+              $aliasdata['in_primary_domain'] = $row_alias_domain['target_domain'];
+            }
+            else {
+              $aliasdata['in_primary_domain'] = "";
+            }
+            $aliasdata['domain'] = $row['domain'];
+            $aliasdata['goto'] = $row['goto'];
+            $aliasdata['address'] = $row['address'];
+            (!filter_var($aliasdata['address'], FILTER_VALIDATE_EMAIL)) ? $aliasdata['is_catch_all'] = 1 : $aliasdata['is_catch_all'] = 0;
+            $aliasdata['active'] = $row['active'];
+            $aliasdata['active_int'] = $row['active_int'];
+            $aliasdata['created'] = $row['created'];
+            $aliasdata['modified'] = $row['modified'];
+            if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdata['domain'])) {
+              return false;
+            }
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          return $aliasdata;
+        break;
+        case 'alias_domain_details':
+          $aliasdomaindata = array();
+          try {
+            $stmt = $pdo->prepare("SELECT
+              `alias_domain`,
+              `target_domain`,
+              `active` AS `active_int`,
+              CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
+              `created`,
+              `modified`
+                FROM `alias_domain`
+                    WHERE `alias_domain` = :aliasdomain");
+            $stmt->execute(array(
+              ':aliasdomain' => $_data,
+            ));
+            $row = $stmt->fetch(PDO::FETCH_ASSOC);
+            $aliasdomaindata['alias_domain'] = $row['alias_domain'];
+            $aliasdomaindata['target_domain'] = $row['target_domain'];
+            $aliasdomaindata['active'] = $row['active'];
+            $aliasdomaindata['active_int'] = $row['active_int'];
+            $aliasdomaindata['created'] = $row['created'];
+            $aliasdomaindata['modified'] = $row['modified'];
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdomaindata['target_domain'])) {
+            return false;
+          }
+          return $aliasdomaindata;
+        break;
+        case 'domains':
+          $domains = array();
+          if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
+              WHERE (`domain` IN (
+                SELECT `domain` from `domain_admins`
+                  WHERE (`active`='1' AND `username` = :username))
+                )
+                OR ('admin'= :role)
+                AND `domain` != 'ALL'");
+            $stmt->execute(array(
+              ':username' => $_SESSION['mailcow_cc_username'],
+              ':role' => $_SESSION['mailcow_cc_role'],
+            ));
+            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            while($row = array_shift($rows)) {
+              $domains[] = $row['domain'];
+            }
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          return $domains;
+        break;
+        case 'domain_details':
+          $domaindata = array();
+          $_data = idn_to_ascii(strtolower(trim($_data)));
+          if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` =  :domain");
+            $stmt->execute(array(
+              ':domain' => $_data
+            ));
+            $row = $stmt->fetch(PDO::FETCH_ASSOC);
+            if (!empty($row)) { 
+              $_data = $row['target_domain'];
+            }
+            $stmt = $pdo->prepare("SELECT 
+                `domain`,
+                `description`,
+                `aliases`,
+                `mailboxes`, 
+                `maxquota`,
+                `quota`,
+                `relay_all_recipients` as `relay_all_recipients_int`,
+                `backupmx` as `backupmx_int`,
+                `active` as `active_int`,
+                CASE `relay_all_recipients` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `relay_all_recipients`,
+                CASE `backupmx` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `backupmx`,
+                CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`
+                  FROM `domain` WHERE `domain`= :domain");
+            $stmt->execute(array(
+              ':domain' => $_data
+            ));
+            $row = $stmt->fetch(PDO::FETCH_ASSOC);
+            if (empty($row)) { 
+              return false;
+            }
+            $stmt = $pdo->prepare("SELECT COUNT(*) AS `count`,
+              COALESCE(SUM(`quota`), 0) AS `in_use`
+                FROM `mailbox`
+                  WHERE `kind` NOT REGEXP 'location|thing|group'
+                    AND `domain` = :domain");
+            $stmt->execute(array(':domain' => $row['domain']));
+            $MailboxDataDomain	= $stmt->fetch(PDO::FETCH_ASSOC);
+            $domaindata['max_new_mailbox_quota']	= ($row['quota'] * 1048576) - $MailboxDataDomain['in_use'];
+            if ($domaindata['max_new_mailbox_quota'] > ($row['maxquota'] * 1048576)) {
+              $domaindata['max_new_mailbox_quota'] = ($row['maxquota'] * 1048576);
+            }
+            $domaindata['quota_used_in_domain'] = $MailboxDataDomain['in_use'];
+            $domaindata['mboxes_in_domain'] = $MailboxDataDomain['count'];
+            $domaindata['mboxes_left'] = $row['mailboxes']	- $MailboxDataDomain['count'];
+            $domaindata['domain_name'] = $row['domain'];
+            $domaindata['description'] = $row['description'];
+            $domaindata['max_num_aliases_for_domain'] = $row['aliases'];
+            $domaindata['max_num_mboxes_for_domain'] = $row['mailboxes'];
+            $domaindata['max_quota_for_mbox'] = $row['maxquota'] * 1048576;
+            $domaindata['max_quota_for_domain'] = $row['quota'] * 1048576;
+            $domaindata['backupmx'] = $row['backupmx'];
+            $domaindata['backupmx_int'] = $row['backupmx_int'];
+            $domaindata['active'] = $row['active'];
+            $domaindata['active_int'] = $row['active_int'];
+            $domaindata['relay_all_recipients'] = $row['relay_all_recipients'];
+            $domaindata['relay_all_recipients_int'] = $row['relay_all_recipients_int'];
+            $stmt = $pdo->prepare("SELECT COUNT(*) AS `alias_count` FROM `alias`
+              WHERE (`domain`= :domain OR `domain` IN (SELECT `alias_domain` FROM `alias_domain` WHERE `target_domain` = :domain2))
+                AND `address` NOT IN (
+                  SELECT `username` FROM `mailbox`
+                )");
+            $stmt->execute(array(
+              ':domain' => $_data,
+              ':domain2' => $_data
+            ));
+            $AliasDataDomain = $stmt->fetch(PDO::FETCH_ASSOC);
+            (isset($AliasDataDomain['alias_count'])) ? $domaindata['aliases_in_domain'] = $AliasDataDomain['alias_count'] : $domaindata['aliases_in_domain'] = "0";
+            $domaindata['aliases_left'] = $row['aliases']	- $AliasDataDomain['alias_count'];
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          return $domaindata;
+        break;
+        case 'mailbox_details':
+          if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            return false;
+          }
+          $mailboxdata = array();
+          try {
+            $stmt = $pdo->prepare("SELECT
+                `domain`.`backupmx`,
+                `mailbox`.`username`,
+                `mailbox`.`name`,
+                `mailbox`.`active` AS `active_int`,
+                CASE `mailbox`.`active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
+                `mailbox`.`domain`,
+                `mailbox`.`quota`,
+                `quota2`.`bytes`,
+                `quota2`.`messages`
+                  FROM `mailbox`, `quota2`, `domain`
+                    WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group' AND `mailbox`.`username` = `quota2`.`username` AND `domain`.`domain` = `mailbox`.`domain` AND `mailbox`.`username` = :mailbox");
+            $stmt->execute(array(
+              ':mailbox' => $_data,
+            ));
+            $row = $stmt->fetch(PDO::FETCH_ASSOC);
+            $stmt = $pdo->prepare("SELECT `maxquota`, `quota` FROM  `domain` WHERE `domain` = :domain");
+            $stmt->execute(array(':domain' => $row['domain']));
+            $DomainQuota  = $stmt->fetch(PDO::FETCH_ASSOC);
+            $stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` = :domain AND `username` != :username");
+            $stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
+            $MailboxUsage	= $stmt->fetch(PDO::FETCH_ASSOC);
+            $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
+            $stmt->execute(array(':address' => $_data, ':unixnow' => time()));
+            $SpamaliasUsage	= $stmt->fetch(PDO::FETCH_ASSOC);
+            $mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
+            if ($mailboxdata['max_new_quota'] > ($DomainQuota['maxquota'] * 1048576)) {
+              $mailboxdata['max_new_quota'] = ($DomainQuota['maxquota'] * 1048576);
+            }
+            $mailboxdata['username'] = $row['username'];
+            $mailboxdata['is_relayed'] = $row['backupmx'];
+            $mailboxdata['name'] = $row['name'];
+            $mailboxdata['active'] = $row['active'];
+            $mailboxdata['active_int'] = $row['active_int'];
+            $mailboxdata['domain'] = $row['domain'];
+            $mailboxdata['quota'] = $row['quota'];
+            $mailboxdata['quota_used'] = intval($row['bytes']);
+            $mailboxdata['percent_in_use'] = round((intval($row['bytes']) / intval($row['quota'])) * 100);
+            $mailboxdata['messages'] = $row['messages'];
+            $mailboxdata['spam_aliases'] = $SpamaliasUsage['sa_count'];
+            if ($mailboxdata['percent_in_use'] >= 90) {
+              $mailboxdata['percent_class'] = "danger";
+            }
+            elseif ($mailboxdata['percent_in_use'] >= 75) {
+              $mailboxdata['percent_class'] = "warning";
+            }
+            else {
+              $mailboxdata['percent_class'] = "success";
+            }
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          return $mailboxdata;
+        break;
+        case 'resource_details':
+          $resourcedata = array();
+          if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT
+                `username`,
+                `name`,
+                `kind`,
+                `multiple_bookings` AS `multiple_bookings_int`,
+                `local_part`,
+                `active` AS `active_int`,
+                CASE `multiple_bookings` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `multiple_bookings`,
+                CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
+                `domain`
+                  FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `username` = :resource");
+            $stmt->execute(array(
+              ':resource' => $_data,
+            ));
+            $row = $stmt->fetch(PDO::FETCH_ASSOC);
+            $resourcedata['name'] = $row['username'];
+            $resourcedata['kind'] = $row['kind'];
+            $resourcedata['multiple_bookings'] = $row['multiple_bookings'];
+            $resourcedata['multiple_bookings_int'] = $row['multiple_bookings_int'];
+            $resourcedata['description'] = $row['name'];
+            $resourcedata['active'] = $row['active'];
+            $resourcedata['active_int'] = $row['active_int'];
+            $resourcedata['domain'] = $row['domain'];
+            $resourcedata['local_part'] = $row['local_part'];
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          if (!isset($resourcedata['domain']) ||
+            (isset($resourcedata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resourcedata['domain']))) {
+            return false;
+          }
+          return $resourcedata;
+        break;
+      }
+    break;
+    case 'delete':
+      switch ($_type) {
+        case 'syncjob':
+          if (!is_array($_data['id'])) {
+            $ids = array();
+            $ids[] = $_data['id'];
+          }
+          else {
+            $ids = $_data['id'];
+          }
+          foreach ($ids as $id) {
+            if (!is_numeric($id)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => $id
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("SELECT `user2` FROM `imapsync` WHERE id = :id");
+              $stmt->execute(array(':id' => $id));
+              $user2 = $stmt->fetch(PDO::FETCH_ASSOC)['user2'];
+              if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $user2)) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['access_denied'])
+                );
+                return false;
+              }
+              $stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `id`= :id");
+              $stmt->execute(array(':id' => $id));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => 'Deleted syncjob id/s ' . implode(', ', $ids)
+          );
+          return true;
+        break;
+        case 'time_limited_alias':
+          if (!is_array($_data['address'])) {
+            $addresses = array();
+            $addresses[] = $_data['address'];
+          }
+          else {
+            $addresses = $_data['address'];
+          }
+          foreach ($addresses as $address) {
+            try {
+              $stmt = $pdo->prepare("SELECT `goto` FROM `spamalias` WHERE `address` = :address");
+              $stmt->execute(array(':address' => $address));
+              $goto = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $goto)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username AND `address` = :item");
+              $stmt->execute(array(
+                ':username' => $goto,
+                ':item' => $address
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }	
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($usernames))
+          );
+        break;
+        case 'eas_cache':
+          if (!is_array($_data['username'])) {
+            $usernames = array();
+            $usernames[] = $_data['username'];
+          }
+          else {
+            $usernames = $_data['username'];
+          }
+          foreach ($usernames as $username) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['eas_reset'], htmlspecialchars(implode(', ', $usernames)))
+          );
+        break;
+        case 'domain':
+          if (!is_array($_data['domain'])) {
+            $domains = array();
+            $domains[] = $_data['domain'];
+          }
+          else {
+            $domains = $_data['domain'];
+          }
+          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']['domain_invalid'])
+              );
+              return false;
+            }
+            $domain	= idn_to_ascii(strtolower(trim($domain)));
+            try {
+              $stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
+                WHERE `domain` = :domain");
+              $stmt->execute(array(':domain' => $domain));
+              $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+            if ($num_results != 0 || !empty($num_results)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['domain_not_empty'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `domain` WHERE `domain` = :domain");
+              $stmt->execute(array(
+                ':domain' => $domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `domain` = :domain");
+              $stmt->execute(array(
+                ':domain' => $domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :domain");
+              $stmt->execute(array(
+                ':domain' => $domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `target_domain` = :domain");
+              $stmt->execute(array(
+                ':domain' => $domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `domain` = :domain");
+              $stmt->execute(array(
+                ':domain' => $domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` LIKE :domain");
+              $stmt->execute(array(
+                ':domain' => '%@'.$domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` = :domain");
+              $stmt->execute(array(
+                ':domain' => '%@'.$domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `address` = :domain");
+              $stmt->execute(array(
+                ':domain' => '%@'.$domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :domain");
+              $stmt->execute(array(
+                ':domain' => '%@'.$domain,
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+            try {
+              $redis->hDel('DOMAIN_MAP', $domain);
+            }
+            catch (RedisException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'Redis: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['domain_removed'], htmlspecialchars(implode(', ', $domains)))
+          );
+          return true;
+        break;
+        case 'alias':
+          if (!is_array($_data['address'])) {
+            $addresses = array();
+            $addresses[] = $_data['address'];
+          }
+          else {
+            $addresses = $_data['address'];
+          }
+          foreach ($addresses as $address) {
+            $local_part		= strstr($address, '@', true);
+            $domain = mailbox('get', 'alias_details', $address)['domain'];
+            try {
+              $stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :address");
+              $stmt->execute(array(':address' => $address));
+              $gotos = $stmt->fetch(PDO::FETCH_ASSOC);
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+            $goto_array = explode(',', $gotos['goto']);
+            if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `address` = :address AND `address` NOT IN (SELECT `username` FROM `mailbox`)");
+              $stmt->execute(array(
+                ':address' => $address
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['alias_removed'], htmlspecialchars(implode(', ', $addresses)))
+          );
+        break;
+        case 'alias_domain':
+          if (!is_array($_data['alias_domain'])) {
+            $alias_domains = array();
+            $alias_domains[] = $_data['alias_domain'];
+          }
+          else {
+            $alias_domains = $_data['alias_domain'];
+          }
+          foreach ($alias_domains as $alias_domain) {
+            if (!is_valid_domain_name($alias_domain)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['domain_invalid'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
+                WHERE `alias_domain`= :alias_domain");
+              $stmt->execute(array(':alias_domain' => $alias_domain));
+              $DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+            if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $DomainData['target_domain'])) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `alias_domain` WHERE `alias_domain` = :alias_domain");
+              $stmt->execute(array(
+                ':alias_domain' => $alias_domain,
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `domain` = :alias_domain");
+              $stmt->execute(array(
+                ':alias_domain' => $alias_domain,
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['alias_domain_removed'], htmlspecialchars(implode(', ', $alias_domains)))
+          );
+        break;
+        case 'mailbox':
+          if (!is_array($_data['username'])) {
+            $usernames = array();
+            $usernames[] = $_data['username'];
+          }
+          else {
+            $usernames = $_data['username'];
+          }
+          foreach ($usernames as $username) {
+            if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `alias` WHERE `goto` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `quota2` WHERE `username` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sender_acl` WHERE `logged_in_as` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `spamalias` WHERE `goto` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `imapsync` WHERE `user2` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $username . "/%' OR `c_uid` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
+              $stmt->execute(array(
+                ':username' => $username
+              ));
+              $stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias`
+                  WHERE `goto` REGEXP :username");
+              $stmt->execute(array(':username' => '(^|,)'.$username.'($|,)'));
+              $GotoData = $stmt->fetchAll(PDO::FETCH_ASSOC);
+              foreach ($GotoData as $gotos) {
+                $goto_exploded = explode(',', $gotos['goto']);
+                if (($key = array_search($username, $goto_exploded)) !== false) {
+                  unset($goto_exploded[$key]);
+                }
+                $gotos_rebuild = implode(',', $goto_exploded);
+                $stmt = $pdo->prepare("UPDATE `alias` SET
+                  `goto` = :goto
+                    WHERE `address` = :address");
+                $stmt->execute(array(
+                  ':goto' => $gotos_rebuild,
+                  ':address' => $gotos['address']
+                ));
+              }
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_removed'], htmlspecialchars(implode(', ', $usernames)))
+          );
+        break;
+        case 'resource':
+          if (!is_array($_data['name'])) {
+            $names = array();
+            $names[] = $_data['name'];
+          }
+          else {
+            $names = $_data['name'];
+          }
+          foreach ($names as $name) {
+            if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :username");
+              $stmt->execute(array(
+                ':username' => $name
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
+              $stmt->execute(array(
+                ':username' => $name
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
+              $stmt->execute(array(
+                ':username' => $name
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $name . "/%' OR `c_uid` = :username");
+              $stmt->execute(array(
+                ':username' => $name
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+              $stmt->execute(array(
+                ':username' => $name
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+              $stmt->execute(array(
+                ':username' => $name
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+              $stmt->execute(array(
+                ':username' => $name
+              ));
+              $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
+              $stmt->execute(array(
+                ':username' => $name
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['resource_removed'], htmlspecialchars(implode(', ', $names)))
+          );
+        break;
+      }
+    break;
+  }
+}

+ 354 - 0
data/web/inc/functions.policy.inc.php

@@ -0,0 +1,354 @@
+<?php
+
+function policy($_action, $_scope, $_data = null) {
+	global $pdo;
+	global $redis;
+	global $lang;
+  switch ($_action) {
+    case 'add':
+      switch ($_scope) {
+        case 'domain':
+          $object = $_data['domain'];
+          if (is_valid_domain_name($object)) {
+            if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            $object = idn_to_ascii(strtolower(trim($object)));
+          }
+          else {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          if ($_data['object_list'] == "bl") {
+            $object_list = "blacklist_from";
+          }
+          elseif ($_data['object_list'] == "wl") {
+            $object_list = "whitelist_from";
+          }
+          $object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($_data['object_from']))), '.'));
+          if (!ctype_alnum(str_replace(array('@', '.', '-', '*'), '', $object_from))) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['policy_list_from_invalid'])
+            );
+            return false;
+          }
+          if ($object_list != "blacklist_from" && $object_list != "whitelist_from") {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `object` FROM `filterconf`
+              WHERE (`option` = 'whitelist_from'  OR `option` = 'blacklist_from')
+                AND `object` = :object
+                AND `value` = :object_from");
+            $stmt->execute(array(':object' => $object, ':object_from' => $object_from));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['policy_list_from_exists'])
+              );
+              return false;
+            }
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option` ,`value`)
+              VALUES (:object, :object_list, :object_from)");
+            $stmt->execute(array(
+              ':object' => $object,
+              ':object_list' => $object_list,
+              ':object_from' => $object_from
+            ));
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['domain_modified'], $object)
+          );
+        break;
+        case 'mailbox':
+          $object = $_data['username'];
+          if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          if ($_data['object_list'] == "bl") {
+            $object_list = "blacklist_from";
+          }
+          elseif ($_data['object_list'] == "wl") {
+            $object_list = "whitelist_from";
+          }
+          $object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($_data['object_from']))), '.'));
+          if (!ctype_alnum(str_replace(array('@', '.', '-', '*'), '', $object_from))) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['policy_list_from_invalid'])
+            );
+            return false;
+          }
+          if ($object_list != "blacklist_from" && $object_list != "whitelist_from") {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => sprintf($lang['danger']['access_denied'])
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("SELECT `object` FROM `filterconf`
+              WHERE (`option` = 'whitelist_from'  OR `option` = 'blacklist_from')
+                AND `object` = :object
+                AND `value` = :object_from");
+            $stmt->execute(array(':object' => $object, ':object_from' => $object_from));
+            $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+            if ($num_results != 0) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['policy_list_from_exists'])
+              );
+              return false;
+            }
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          try {
+            $stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option` ,`value`)
+              VALUES (:object, :object_list, :object_from)");
+            $stmt->execute(array(
+              ':object' => $object,
+              ':object_list' => $object_list,
+              ':object_from' => $object_from
+            ));
+          }
+          catch (PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+            return false;
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['mailbox_modified'], $object)
+          );
+        break;
+      }
+    break;
+    case 'delete':
+      switch ($_scope) {
+        case 'domain':
+          if (!is_array($_data['prefid'])) {
+            $prefids = array();
+            $prefids[] = $_data['prefid'];
+          }
+          else {
+            $prefids = $_data['prefid'];
+          }
+          foreach ($prefids as $prefid) {
+            if (!is_numeric($prefid)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("SELECT `object` FROM `filterconf` WHERE `prefid` = :prefid");
+              $stmt->execute(array(':prefid' => $prefid));
+              $object = $stmt->fetch(PDO::FETCH_ASSOC)['object'];
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+            }
+            if (is_valid_domain_name($object)) {
+              if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
+                $_SESSION['return'] = array(
+                  'type' => 'danger',
+                  'msg' => sprintf($lang['danger']['access_denied'])
+                );
+                return false;
+              }
+              $object = idn_to_ascii(strtolower(trim($object)));
+            }
+            else {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :object AND `prefid` = :prefid");
+              $stmt->execute(array(
+                ':object' => $object,
+                ':prefid' => $prefid
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['items_deleted'], implode(', ', $prefids))
+          );
+        break;
+        case 'mailbox':
+          if (!is_array($_data['prefid'])) {
+            $prefids = array();
+            $prefids[] = $_data['prefid'];
+          }
+          else {
+            $prefids = $_data['prefid'];
+          }
+          foreach ($prefids as $prefid) {
+            if (!is_numeric($prefid)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("SELECT `object` FROM `filterconf` WHERE `prefid` = :prefid");
+              $stmt->execute(array(':prefid' => $prefid));
+              $object = $stmt->fetch(PDO::FETCH_ASSOC)['object'];
+            }
+            catch(PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+            }
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => sprintf($lang['danger']['access_denied'])
+              );
+              return false;
+            }
+            try {
+              $stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :object AND `prefid` = :prefid");
+              $stmt->execute(array(
+                ':object' => $object,
+                ':prefid' => $prefid
+              ));
+            }
+            catch (PDOException $e) {
+              $_SESSION['return'] = array(
+                'type' => 'danger',
+                'msg' => 'MySQL: '.$e
+              );
+              return false;
+            }
+          }
+          $_SESSION['return'] = array(
+            'type' => 'success',
+            'msg' => sprintf($lang['success']['items_deleted'], implode(', ', $prefids))
+          );
+        break;
+      }
+    break;
+    case 'get':
+      switch ($_scope) {
+        case 'domain':
+          if (!is_valid_domain_name($_data)) {
+            return false;
+          }
+          else {
+            if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+              return false;
+            }
+            $_data = idn_to_ascii(strtolower(trim($_data)));
+          }
+          try {
+            // WHITELIST
+            $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND (`object` LIKE :object_mail OR `object` = :object_domain)");
+            $stmt->execute(array(':object_mail' => '%@' . $_data, ':object_domain' => $_data));
+            $rows['whitelist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            // BLACKLIST
+            $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='blacklist_from' AND (`object` LIKE :object_mail OR `object` = :object_domain)");
+            $stmt->execute(array(':object_mail' => '%@' . $_data, ':object_domain' => $_data));
+            $rows['blacklist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+          }
+          return $rows;
+        break;
+        case 'mailbox':
+          if (isset($_data) && filter_var($_data, FILTER_VALIDATE_EMAIL)) {
+            if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
+              return false;
+            }
+          }
+          else {
+            $_data = $_SESSION['mailcow_cc_username'];
+          }
+          $domain = mailbox('get', 'mailbox_details', $_data)['domain'];
+          if (empty($domain)) {
+            return false;
+          }
+          try {
+            // WHITELIST
+            $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND (`object` = :username OR `object` = :domain)");
+            $stmt->execute(array(':username' => $_data, ':domain' => $domain));
+            $rows['whitelist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
+            // BLACKLIST
+            $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='blacklist_from' AND (`object` = :username OR `object` = :domain)");
+            $stmt->execute(array(':username' => $_data, ':domain' => $domain));
+            $rows['blacklist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
+          }
+          catch(PDOException $e) {
+            $_SESSION['return'] = array(
+              'type' => 'danger',
+              'msg' => 'MySQL: '.$e
+            );
+          }
+          return $rows;
+        break;
+      }
+    break;
+  }
+}

+ 1 - 0
data/web/inc/header.inc.php

@@ -22,6 +22,7 @@
 <?= (preg_match("/mailbox.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/mailbox.css">' : null; ?>
 <?= (preg_match("/admin.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/admin.css">' : null; ?>
 <?= (preg_match("/user.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/user.css">' : null; ?>
+<?= (preg_match("/edit.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/edit.css">' : null; ?>
 <link rel="shortcut icon" href="/favicon.png" type="image/png">
 <link rel="icon" href="/favicon.png" type="image/png">
 </head>

+ 6 - 10
data/web/inc/prerequisites.inc.php

@@ -42,28 +42,24 @@ try {
 }
 catch (PDOException $e) {
 ?>
-<center style='font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;'>?? Connection failed, database may be in warm-up state, please try again later.<br /><br />The following error was reported:<br/>  <?=$e->getMessage();?></center>
+<center style='font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;'>Connection failed, database may be in warm-up state, please try again later.<br /><br />The following error was reported:<br/>  <?=$e->getMessage();?></center>
 <?php
 exit;
 }
 
 // Set language
-$_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
-
+if (!isset($_SESSION['mailcow_locale'])) {
+  $_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
+}
 if (isset($_GET['lang']) && in_array($_GET['lang'], $AVAILABLE_LANGUAGES)) {
   $_SESSION['mailcow_locale'] = $_GET['lang'];
 }
-elseif (isset($_COOKIE['language']) && in_array($_COOKIE['language'], $AVAILABLE_LANGUAGES)) {
-  $_SESSION['mailcow_locale'] = $_COOKIE['language'];
-}
-if (isset($_SESSION['mailcow_locale']) && !file_exists($_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.php')) {
-  $_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
-}
-setcookie('language', $_SESSION['mailcow_locale']);
 
 require_once $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.en.php';
 include $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.php';
 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
+require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/init_db.inc.php';
 require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/triggers.inc.php';
 init_db_schema();

+ 20 - 47
data/web/inc/triggers.inc.php

@@ -44,10 +44,7 @@ if (isset($_POST["login_user"]) && isset($_POST["pass_user"])) {
 if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
 	if (isset($_GET["duallogin"])) {
     if (filter_var($_GET["duallogin"], FILTER_VALIDATE_EMAIL)) {
-      $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :duallogin");
-      $stmt->execute(array(':duallogin' => $_GET["duallogin"]));
-      $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
-      if ($num_results != 0) {
+      if (!empty(mailbox('get', 'mailbox_details', $_GET["duallogin"]))) {
         $_SESSION["dual-login"]["username"] = $_SESSION['mailcow_cc_username'];
         $_SESSION["dual-login"]["role"]     = $_SESSION['mailcow_cc_role'];
         $_SESSION['mailcow_cc_username']    = $_GET["duallogin"];
@@ -83,35 +80,14 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "user
 	if (isset($_POST["edit_user_account"])) {
 		edit_user_account($_POST);
 	}
-	if (isset($_POST["mailbox_reset_eas"])) {
-		mailbox_reset_eas($_POST);
-	}
-	if (isset($_POST["edit_spam_score"])) {
-		edit_spam_score($_POST);
-	}
-	if (isset($_POST["edit_delimiter_action"])) {
-		edit_delimiter_action($_POST);
-	}
 	if (isset($_POST["add_policy_list_item"])) {
-		add_policy_list_item($_POST);
-	}
-	if (isset($_POST["delete_policy_list_item"])) {
-		delete_policy_list_item($_POST);
-	}
-	if (isset($_POST["edit_tls_policy"])) {
-		edit_tls_policy($_POST);
+		policy('add', 'mailbox', $_POST);
 	}
 	if (isset($_POST["add_syncjob"])) {
-		add_syncjob($_POST);
+		mailbox('add', 'syncjob', $_POST);
 	}
 	if (isset($_POST["edit_syncjob"])) {
-		edit_syncjob($_POST);
-	}
-	if (isset($_POST["delete_syncjob"])) {
-		delete_syncjob($_POST);
-	}
-	if (isset($_POST["set_time_limited_aliases"])) {
-		set_time_limited_aliases($_POST);
+		mailbox('edit', 'syncjob', $_POST);
 	}
 }
 if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
@@ -125,55 +101,52 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		unset_tfa_key($_POST);
 	}
 	if (isset($_POST["add_policy_list_item"])) {
-		add_policy_list_item($_POST);
-	}
-	if (isset($_POST["delete_policy_list_item"])) {
-		delete_policy_list_item($_POST);
+		policy('add', 'domain', $_POST);
 	}
 	if (isset($_POST["mailbox_add_domain"])) {
-		mailbox_add_domain($_POST);
+		mailbox('add', 'domain', $_POST);
 	}
 	if (isset($_POST["mailbox_add_alias"])) {
-		mailbox_add_alias($_POST);
+		mailbox('add', 'alias', $_POST);
 	}
 	if (isset($_POST["mailbox_add_alias_domain"])) {
-		mailbox_add_alias_domain($_POST);
+		mailbox('add', 'alias_domain', $_POST);
 	}
 	if (isset($_POST["mailbox_add_mailbox"])) {
-		mailbox_add_mailbox($_POST);
+		mailbox('add', 'mailbox', $_POST);
 	}
 	if (isset($_POST["mailbox_add_resource"])) {
-		mailbox_add_resource($_POST);
+		mailbox('add', 'resource', $_POST);
 	}
 	if (isset($_POST["mailbox_edit_alias"])) {
-		mailbox_edit_alias($_POST);
+		mailbox('edit', 'alias', $_POST);
 	}
 	if (isset($_POST["mailbox_edit_domain"])) {
-		mailbox_edit_domain($_POST);
+		mailbox('edit', 'domain', $_POST);
 	}
 	if (isset($_POST["mailbox_edit_mailbox"])) {
-		mailbox_edit_mailbox($_POST);
+		mailbox('edit', 'mailbox', $_POST);
 	}
 	if (isset($_POST["mailbox_edit_alias_domain"])) {
-		mailbox_edit_alias_domain($_POST);
+		mailbox('edit', 'alias_domain', $_POST);
 	}
 	if (isset($_POST["mailbox_edit_resource"])) {
-		mailbox_edit_resource($_POST);
+		mailbox('edit', 'resource', $_POST);
 	}
 	if (isset($_POST["mailbox_delete_domain"])) {
-		mailbox_delete_domain($_POST);
+		mailbox('delete', 'domain', $_POST);
 	}
 	if (isset($_POST["mailbox_delete_alias"])) {
-		mailbox_delete_alias($_POST);
+		mailbox('delete', 'delete_alias', $_POST);
 	}
 	if (isset($_POST["mailbox_delete_alias_domain"])) {
-		mailbox_delete_alias_domain($_POST);
+		mailbox('delete', 'alias_domain', $_POST);
 	}
 	if (isset($_POST["mailbox_delete_mailbox"])) {
-		mailbox_delete_mailbox($_POST);
+		mailbox('delete', 'mailbox', $_POST);
 	}
 	if (isset($_POST["mailbox_delete_resource"])) {
-		mailbox_delete_resource($_POST);
+		mailbox('delete', 'resource', $_POST);
 	}
 }
 ?>

+ 192 - 69
data/web/js/admin.js

@@ -1,76 +1,20 @@
-$(document).ready(function() {
-  // Collect values of input fields with name multi_select with same data-id to js array multi_data[data-id]
-  var multi_data = [];
-  $(document).on('change', 'input[name=multi_select]:checkbox', function() {
-    if ($(this).is(':checked') && $(this).data('id')) {
-      var id = $(this).data('id');
-      if (typeof multi_data[id] == "undefined") {
-        multi_data[id] = [];
-      }
-      multi_data[id].push($(this).val());
-    }
-    else {
-      var id = $(this).data('id');
-      multi_data[id].splice($.inArray($(this).val(), multi_data[id]),1);
-    }
-  });
-  // Select checkbox by click on parent tr
-  $(document).on('click', 'tbody>tr', function(e) {
-    if (e.target.type == "checkbox") {
-      e.stopPropagation();
-    } else {
-      var checkbox = $(this).find(':checkbox');
-      checkbox.trigger('click');
-    }
-  });
-  // Select or deselect all checkboxes with same data-id
-  $(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();
-  });
-  // General API edit function
-  $(document).on('click', '#delete_selected', function(e) {
-    e.preventDefault();
-    var id = $(this).data('id');
-    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 () {
-        $("#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",
-          data: { "items": JSON.stringify(data_array), "csrf_token": csrf_token },
-          url: '/api/v1/' + api_url,
-          jsonp: false,
-          complete: function (data) {
-            location.reload(true);
-          }
-        });
-      })
-      .one('click', '#isCanceled', function(e) {
-        $('#ConfirmDeleteModal').modal('hide');
-      });;
-  });
-
-});
 jQuery(function($){
   function unix_time_format(tm) {
     var date = new Date(tm ? tm * 1000 : 0);
     return date.toLocaleString();
   }
+  function humanFileSize(bytes) {
+    if(Math.abs(bytes) < 1024) {
+        return bytes + ' B';
+    }
+    var units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
+    var u = -1;
+    do {
+        bytes /= 1024;
+        ++u;
+    } while(Math.abs(bytes) >= 1024 && u < units.length - 1);
+    return bytes.toFixed(1)+' '+units[u];
+  }
   $("#refresh_postfix_log").on('click', function(e) {
     e.preventDefault();
     draw_postfix_logs();
@@ -83,6 +27,10 @@ jQuery(function($){
     e.preventDefault();
     draw_sogo_logs();
   });
+  $("#refresh_rspamd_history").on('click', function(e) {
+    e.preventDefault();
+    draw_rspamd_history();
+  });
   function draw_postfix_logs() {
     ft_postfix_logs = FooTable.init('#postfix_log', {
       "columns": [
@@ -307,10 +255,185 @@ jQuery(function($){
       }
     });
   }
-
+  function draw_rspamd_history() {
+    ft_postfix_logs = FooTable.init('#rspamd_history', {
+      "columns": [{
+        "name": "message-id",
+        "title": "ID",
+        "breakpoints": "all",
+        "style": {
+          "minWidth": 130,
+          "overflow": "hidden",
+          "textOverflow": "ellipsis",
+          "wordBreak": "break-all",
+          "whiteSpace": "normal"
+        }
+        }, {
+          "name": "ip",
+          "title": "IP address",
+          "breakpoints": "all",
+          "style": {
+            "minWidth": 88
+          }
+        }, {
+          "name": "sender_mime",
+          "title": "From",
+          "breakpoints": "xs sm md",
+          "style": {
+            "minWidth": 100
+          }
+        }, {
+          "name": "rcpt_mime",
+          "title": "To",
+          "breakpoints": "xs sm md",
+          "style": {
+            "minWidth": 100
+          }
+        }, {
+          "name": "subject",
+          "title": "Subject",
+          "breakpoints": "all",
+          "style": {
+            "word-break": "break-all",
+            "minWidth": 150
+          }
+        }, {
+          "name": "action",
+          "title": "Action",
+          "style": {
+            "minwidth": 82
+          }
+        }, {
+          "name": "score",
+          "title": "Score",
+          "style": {
+            "maxWidth": 110
+          },
+        }, {
+          "name": "symbols",
+          "title": "Symbols",
+          "breakpoints": "all",
+        }, {
+          "name": "size",
+          "title": "Msg size",
+          "breakpoints": "all",
+          "style": {
+            "minwidth": 50,
+          },
+          "formatter": function(value) { return humanFileSize(value); }
+        }, {
+          "name": "scan_time",
+          "title": "Scan time",
+          "breakpoints": "all",
+          "style": {
+            "maxWidth": 72
+          },
+        }, {
+          "sorted": true,
+          "breakpoints": "all",
+          "direction": "DESC",
+          "name": "time",
+          "title": "Time",
+        }, {
+          "name": "user",
+          "title": "Authenticated user",
+          "breakpoints": "xs sm md",
+          "style": {
+            "minWidth": 100
+          }
+        }],
+      "rows": $.ajax({
+        dataType: 'json',
+        url: '/api/v1/get/logs/rspamd-history',
+        jsonp: false,
+        error: function () {
+          console.log('Cannot draw rspamd history table');
+        },
+        success: function (data) {
+          $.each(data, function (i, item) {
+            item.rcpt_mime = item.rcpt_mime.join(",&#8203;");
+            Object.keys(item.symbols).map(function(key) {
+              var sym = item.symbols[key];
+              if (sym.score <= 0) {
+                sym.score_formatted = '(<span class="text-success"><b>' + sym.score + '</b></span>)'
+              }
+              else {
+                sym.score_formatted = '(<span class="text-danger"><b>' + sym.score + '</b></span>)'
+              }
+              var str = '<strong>' + key + '</strong> ' + sym.score_formatted;
+              if (sym.options) {
+                str += ' [' + sym.options.join(",") + "]";
+              }
+              item.symbols[key].str = str;
+            });
+            item.symbols = Object.keys(item.symbols).
+            map(function(key) {
+              return item.symbols[key];
+            }).sort(function(e1, e2) {
+              return Math.abs(e1.score) < Math.abs(e2.score);
+            }).map(function(e) {
+              return e.str;
+            }).join("<br>\n");
+            item.time = {
+              "value": unix_time_format(item.unix_time),
+              "options": {
+                "sortValue": item.unix_time
+              }
+            };
+            var scan_time = item.time_real.toFixed(3) + ' / ' + item.time_virtual.toFixed(3);
+            item.scan_time = {
+              "options": {
+                "sortValue": item.time_real
+              },
+              "value": scan_time
+            };
+            if (item.action === 'clean' || item.action === 'no action') {
+              item.action = "<div class='label label-success'>" + item.action + "</div>";
+            } else if (item.action === 'rewrite subject' || item.action === 'add header' || item.action === 'probable spam') {
+              item.action = "<div class='label label-warning'>" + item.action + "</div>";
+            } else if (item.action === 'spam' || item.action === 'reject') {
+              item.action = "<div class='label label-danger'>" + item.action + "</div>";
+            } else {
+              item.action = "<div class='label label-info'>" + item.action + "</div>";
+            }
+            var score_content;
+            if (item.score < item.required_score) {
+              score_content = "[ <span class='text-success'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
+            } else {
+              score_content = "[ <span class='text-danger'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
+            }
+            item.score = {
+              "options": {
+                "sortValue": item.score
+              },
+              "value": score_content
+            };
+            if (item.user == null) {
+              item.user = "none";
+            }
+          });
+        }
+      }),
+      "empty": lang.empty,
+      "paging": {
+        "enabled": true,
+        "limit": 5,
+        "size": pagination_size
+      },
+      "filtering": {
+        "enabled": true,
+        "position": "left",
+        "placeholder": lang.filter_table
+      },
+      "sorting": {
+        "enabled": true
+      }
+    });
+  }
   draw_postfix_logs();
   draw_dovecot_logs();
   draw_sogo_logs();
   draw_domain_admins();
   draw_fwd_hosts();
+  draw_rspamd_history();
 });

+ 154 - 0
data/web/js/api.js

@@ -0,0 +1,154 @@
+$(document).ready(function() {
+  // Collect values of input fields with name "multi_select" an same data-id to js array multi_data[data-id]
+  var multi_data = [];
+  $(document).on('change', 'input[name=multi_select]:checkbox', function() {
+    if ($(this).is(':checked') && $(this).data('id')) {
+      var id = $(this).data('id');
+      if (typeof multi_data[id] == "undefined") {
+        multi_data[id] = [];
+      }
+      multi_data[id].push($(this).val());
+    }
+    else {
+      var id = $(this).data('id');
+      multi_data[id].splice($.inArray($(this).val(), multi_data[id]),1);
+    }
+  });
+
+  // Select checkbox by click on parent tr
+  $(document).on('click', 'tbody>tr', function(e) {
+    if (e.target.type == "checkbox") {
+      e.stopPropagation();
+    } else {
+      var checkbox = $(this).find(':checkbox');
+      checkbox.trigger('click');
+    }
+  });
+
+  // Select or deselect all checkboxes with same data-id
+  $(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();
+  });
+
+  // General API edit actions
+  $(document).on('click', '#edit_selected', function(e) {
+    e.preventDefault();
+    var id = $(this).data('id');
+    var api_url = $(this).data('api-url');
+    var api_attr = $(this).data('api-attr');
+    // If clicked element #edit_selected 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 = {};
+      $.each($(this).closest("form").serializeArray(), function(i, field) {
+          attr_to_merge[field.name] = field.value;
+      });
+      var api_attr = $.extend(api_attr, attr_to_merge)
+    }
+    // If clicked element #edit_selected has data-item attribute, it is added to "items"
+    if (typeof $(this).data('item') !== 'undefined') {
+      var id = $(this).data('id');
+      if (typeof multi_data[id] == "undefined") {
+        multi_data[id] = [];
+      }
+      multi_data[id].push($(this).data('item'));
+    }
+    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 },
+        url: '/api/v1/' + api_url,
+        jsonp: false,
+        complete: function (data) {
+          // var reponse = (JSON.parse(data.responseText));
+          // console.log(reponse.type);
+          // console.log(reponse.msg);
+          window.location = window.location.href.split("#")[0];
+        }
+      });
+    }
+  });
+
+  // General API add actions
+  $(document).on('click', '#add_item', function(e) {
+    e.preventDefault();
+    var id = $(this).data('id');
+    var api_url = $(this).data('api-url');
+    var api_attr = $(this).data('api-attr');
+    // 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 = {};
+      $.each($(this).closest("form").serializeArray(), function(i, field) {
+          attr_to_merge[field.name] = field.value;
+      });
+      var api_attr = $.extend(api_attr, attr_to_merge)
+    }
+    $.ajax({
+      type: "POST",
+      dataType: "json",
+      data: { "attr": JSON.stringify(api_attr), "csrf_token": csrf_token },
+      url: '/api/v1/' + api_url,
+      jsonp: false,
+      complete: function (data) {
+        // var reponse = (JSON.parse(data.responseText));
+        // console.log(reponse.type);
+        // console.log(reponse.msg);
+        window.location = window.location.href.split("#")[0];
+      }
+    });
+  });
+  // General API delete actions
+  $(document).on('click', '#delete_selected', function(e) {
+    e.preventDefault();
+    var id = $(this).data('id');
+    // If clicked element #delete_selected has data-item attribute, it is added to "items"
+    if (typeof $(this).data('item') !== 'undefined') {
+      var id = $(this).data('id');
+      if (typeof multi_data[id] == "undefined") {
+        multi_data[id] = [];
+      }
+      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') {
+      $("#DeleteText").empty();
+      $("#DeleteText").text($(this).data('text'));
+    }
+    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 () {
+        $("#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",
+          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) {
+        $('#ConfirmDeleteModal').modal('hide');
+      });;
+  });
+});

+ 83 - 0
data/web/js/edit.js

@@ -0,0 +1,83 @@
+jQuery(function($){
+  // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
+  function validateEmail(email) {
+    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+    return re.test(email);
+  }
+  function draw_wl_policy_domain_table() {
+    ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_domain_table', {
+      "columns": [
+        {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+        {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
+        {"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
+        {"name":"object","title":"Scope"}
+      ],
+      "empty": lang.empty,
+      "rows": $.ajax({
+        dataType: 'json',
+        url: '/api/v1/get/policy_wl_domain/' + table_for_domain,
+        jsonp: false,
+        error: function () {
+          console.log('Cannot draw mailbox policy wl table');
+        },
+        success: function (data) {
+          $.each(data, function (i, item) {
+            if (!validateEmail(item.object)) {
+              item.chkbox = '<input type="checkbox" data-id="policy_wl_domain" name="multi_select" value="' + item.prefid + '" />';
+            }
+            else {
+              item.chkbox = '<input type="checkbox" disabled title="' + lang.spamfilter_table_domain_policy + '" />';
+            }
+          });
+        }
+      }),
+      "paging": {
+        "enabled": true,
+        "limit": 5,
+        "size": pagination_size
+      },
+      "sorting": {
+        "enabled": true
+      }
+    });
+  }
+  function draw_bl_policy_domain_table() {
+    ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_domain_table', {
+      "columns": [
+        {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
+        {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
+        {"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
+        {"name":"object","title":"Scope"}
+      ],
+      "empty": lang.empty,
+      "rows": $.ajax({
+        dataType: 'json',
+        url: '/api/v1/get/policy_bl_domain/' + table_for_domain,
+        jsonp: false,
+        error: function () {
+          console.log('Cannot draw mailbox policy bl table');
+        },
+        success: function (data) {
+          $.each(data, function (i, item) {
+            if (!validateEmail(item.object)) {
+              item.chkbox = '<input type="checkbox" data-id="policy_bl_domain" name="multi_select" value="' + item.prefid + '" />';
+            }
+            else {
+              item.chkbox = '<input type="checkbox" disabled tooltip="' + lang.spamfilter_table_domain_policy + '" />';
+            }
+          });
+        }
+      }),
+      "paging": {
+        "enabled": true,
+        "limit": 5,
+        "size": pagination_size
+      },
+      "sorting": {
+        "enabled": true
+      }
+    });
+  }
+  draw_wl_policy_domain_table();
+  draw_bl_policy_domain_table();
+});

+ 0 - 92
data/web/js/mailbox.js

@@ -1,95 +1,3 @@
-$(document).ready(function() {
-  // Collect values of input fields with name multi_select with same data-id to js array multi_data[data-id]
-  var multi_data = [];
-  $(document).on('change', 'input[name=multi_select]:checkbox', function() {
-    if ($(this).is(':checked') && $(this).data('id')) {
-      var id = $(this).data('id');
-      if (typeof multi_data[id] == "undefined") {
-        multi_data[id] = [];
-      }
-      multi_data[id].push($(this).val());
-    }
-    else {
-      var id = $(this).data('id');
-      multi_data[id].splice($.inArray($(this).val(), multi_data[id]),1);
-    }
-  });
-  // Select checkbox by click on parent tr
-  $(document).on('click', 'tbody>tr', function(e) {
-    if (e.target.type == "checkbox") {
-      e.stopPropagation();
-    } else {
-      var checkbox = $(this).find(':checkbox');
-      checkbox.trigger('click');
-    }
-  });
-  // Select or deselect all checkboxes with same data-id
-  $(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();
-  });
-  // General API edit actions
-  $(document).on('click', '#edit_selected', function(e) {
-    e.preventDefault();
-    var id = $(this).data('id');
-    if (typeof multi_data[id] == "undefined") return;
-    data_array = multi_data[id];
-    api_url = $(this).data('api-url');
-    api_attr = $(this).data('api-attr');
-    if (Object.keys(data_array).length !== 0) {
-      $.ajax({
-        type: "POST",
-        dataType: "json",
-        data: { "items": JSON.stringify(data_array), "attr": JSON.stringify(api_attr), "csrf_token": csrf_token },
-        url: '/api/v1/' + api_url,
-        jsonp: false,
-        complete: function (data) {
-          // var reponse = (JSON.parse(data.responseText));
-          // console.log(reponse.type);
-          // console.log(reponse.msg);
-          location.assign(window.location);
-        }
-      });
-    }
-  });
-  // General API delete actions
-  $(document).on('click', '#delete_selected', function(e) {
-    e.preventDefault();
-    var id = $(this).data('id');
-    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 () {
-        $("#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",
-          data: { "items": JSON.stringify(data_array), "csrf_token": csrf_token },
-          url: '/api/v1/' + api_url,
-          jsonp: false,
-          complete: function (data) {
-            location.assign(window.location);
-          }
-        });
-      })
-      .one('click', '#isCanceled', function(e) {
-        $('#ConfirmDeleteModal').modal('hide');
-      });;
-  });
-});
-
 jQuery(function($){
   // Calculation human readable file sizes
   function humanFileSize(bytes) {

+ 123 - 118
data/web/js/user.js

@@ -1,29 +1,4 @@
 $(document).ready(function() {
-	// Show and activate password fields after box was checked
-	// Hidden by default
-	if ( !$("#togglePwNew").is(':checked') ) {
-		$(".passFields").hide();
-	}
-	$('#togglePwNew').click(function() {
-		$("#user_new_pass").attr("disabled", !this.checked);
-		$("#user_new_pass2").attr("disabled", !this.checked);
-		var $this = $(this);
-		if ($this.is(':checked')) {
-			$(".passFields").slideDown();
-		} else {
-			$(".passFields").slideUp();
-		}
-	});
-	// Show generate button after time selection
-	$('#generate_tla').hide(); 
-	$('#validity').change(function(){
-		$('#generate_tla').show(); 
-	});
-
-	// Init Bootstrap Switch
-	$.fn.bootstrapSwitch.defaults.onColor = 'success';
-	$("#tls_out").bootstrapSwitch();
-	$("#tls_in").bootstrapSwitch();
 
   // Log modal
   $('#logModal').on('show.bs.modal', function(e) {
@@ -31,96 +6,8 @@ $(document).ready(function() {
   $(e.currentTarget).find('#logText').html('<pre style="background:none;font-size:11px;line-height:1.1;border:0px">' + logText + '</pre>');
   });
 
-  // Collect values of input fields with name multi_select with same data-id to js array multi_data[data-id]
-  var multi_data = [];
-  $(document).on('change', 'input[name=multi_select]:checkbox', function() {
-    if ($(this).is(':checked') && $(this).data('id')) {
-      var id = $(this).data('id');
-      if (typeof multi_data[id] == "undefined") {
-        multi_data[id] = [];
-      }
-      multi_data[id].push($(this).val());
-    }
-    else {
-      var id = $(this).data('id');
-      multi_data[id].splice($.inArray($(this).val(), multi_data[id]),1);
-    }
-  });
-  // Select checkbox by click on parent tr
-  $(document).on('click', 'tbody>tr', function(e) {
-    if (e.target.type == "checkbox") {
-      e.stopPropagation();
-    } else {
-      var checkbox = $(this).find(':checkbox');
-      checkbox.trigger('click');
-    }
-  });
-  // Select or deselect all checkboxes with same data-id
-  $(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();
-  });
-  // General API edit actions
-  $(document).on('click', '#edit_selected', function(e) {
-    e.preventDefault();
-    var id = $(this).data('id');
-    if (typeof multi_data[id] == "undefined") return;
-    data_array = multi_data[id];
-    api_url = $(this).data('api-url');
-    api_attr = $(this).data('api-attr');
-    if (Object.keys(data_array).length !== 0) {
-      $.ajax({
-        type: "POST",
-        dataType: "json",
-        data: { "items": JSON.stringify(data_array), "attr": JSON.stringify(api_attr), "csrf_token": csrf_token },
-        url: '/api/v1/' + api_url,
-        jsonp: false,
-        complete: function (data) {
-          // var reponse = (JSON.parse(data.responseText));
-          // console.log(reponse.type);
-          // console.log(reponse.msg);
-          location.assign(window.location);
-        }
-      });
-    }
-  });
-  // General API delete actions
-  $(document).on('click', '#delete_selected', function(e) {
-    e.preventDefault();
-    var id = $(this).data('id');
-    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 () {
-        $("#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",
-          data: { "items": JSON.stringify(data_array), "csrf_token": csrf_token },
-          url: '/api/v1/' + api_url,
-          jsonp: false,
-          complete: function (data) {
-            location.reload(true);
-          }
-        });
-      })
-      .one('click', '#isCanceled', function(e) {
-        $('#ConfirmDeleteModal').modal('hide');
-      });;
-  });
 });
+
 jQuery(function($){
   // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
   var entityMap = {
@@ -138,11 +25,52 @@ jQuery(function($){
       return entityMap[s];
     });
   }
+  // http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
+  function validateEmail(email) {
+    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+    return re.test(email);
+  }
+  function unix_time_format(tm) {
+    var date = new Date(tm ? tm * 1000 : 0);
+    return date.toLocaleString();
+  }
+  function draw_tla_table() {
+    ft_tla_table = FooTable.init('#tla_table', {
+      "columns": [
+        {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
+        {"sorted": true,"name":"address","title":lang.alias},
+        {"name":"validity","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.alias_valid_until,"style":{"width":"170px"}},
+      ],
+      "empty": lang.empty,
+      "rows": $.ajax({
+        dataType: 'json',
+        url: '/api/v1/get/time_limited_aliases',
+        jsonp: false,
+        error: function () {
+          console.log('Cannot draw tla table');
+        },
+        success: function (data) {
+          $.each(data, function (i, item) {
+            item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + item.address + '" />';
+          });
+        }
+      }),
+      "paging": {
+        "enabled": true,
+        "limit": 5,
+        "size": pagination_size
+      },
+      "sorting": {
+        "enabled": true
+      }
+    });
+  }
   function draw_sync_job_table() {
-    ft_aliasdomain_table = FooTable.init('#sync_job_table', {
+    ft_syncjob_table = FooTable.init('#sync_job_table', {
       "columns": [
-        {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
-        {"sorted": true,"name":"server_w_port","title":"Server"},
+        {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
+        {"sorted": true,"name":"id","title":"ID"},
+        {"name":"server_w_port","title":"Server"},
         {"name":"enc1","title":lang.encryption},
         {"name":"user1","title":lang.username},
         {"name":"exclude","title":lang.excludes},
@@ -155,7 +83,7 @@ jQuery(function($){
       "empty": lang.empty,
       "rows": $.ajax({
         dataType: 'json',
-        url: '/api/v1/get/syncjob',
+        url: '/api/v1/get/syncjobs',
         jsonp: false,
         error: function () {
           console.log('Cannot draw sync job table');
@@ -182,5 +110,82 @@ jQuery(function($){
       }
     });
   }
+  function draw_wl_policy_mailbox_table() {
+    ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_mailbox_table', {
+      "columns": [
+        {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
+        {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
+        {"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
+        {"name":"object","title":"Scope"}
+      ],
+      "empty": lang.empty,
+      "rows": $.ajax({
+        dataType: 'json',
+        url: '/api/v1/get/policy_wl_mailbox',
+        jsonp: false,
+        error: function () {
+          console.log('Cannot draw mailbox policy wl table');
+        },
+        success: function (data) {
+          $.each(data, function (i, item) {
+            if (validateEmail(item.object)) {
+              item.chkbox = '<input type="checkbox" data-id="policy_wl_mailbox" name="multi_select" value="' + item.prefid + '" />';
+            }
+            else {
+              item.chkbox = '<input type="checkbox" disabled title="' + lang.spamfilter_table_domain_policy + '" />';
+            }
+          });
+        }
+      }),
+      "paging": {
+        "enabled": true,
+        "limit": 5,
+        "size": pagination_size
+      },
+      "sorting": {
+        "enabled": true
+      }
+    });
+  }
+  function draw_bl_policy_mailbox_table() {
+    ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_mailbox_table', {
+      "columns": [
+        {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
+        {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
+        {"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
+        {"name":"object","title":"Scope"}
+      ],
+      "empty": lang.empty,
+      "rows": $.ajax({
+        dataType: 'json',
+        url: '/api/v1/get/policy_bl_mailbox',
+        jsonp: false,
+        error: function () {
+          console.log('Cannot draw mailbox policy bl table');
+        },
+        success: function (data) {
+          $.each(data, function (i, item) {
+            if (validateEmail(item.object)) {
+              item.chkbox = '<input type="checkbox" data-id="policy_bl_mailbox" name="multi_select" value="' + item.prefid + '" />';
+            }
+            else {
+              item.chkbox = '<input type="checkbox" disabled tooltip="' + lang.spamfilter_table_domain_policy + '" />';
+            }
+          });
+        }
+      }),
+      "paging": {
+        "enabled": true,
+        "limit": 5,
+        "size": pagination_size
+      },
+      "sorting": {
+        "enabled": true
+      }
+    });
+  }
   draw_sync_job_table();
+  draw_tla_table();
+  draw_wl_policy_mailbox_table();
+  draw_bl_policy_mailbox_table();
 });

+ 483 - 32
data/web/json_api.php

@@ -25,15 +25,52 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
     $extra =      (isset($query[3])) ? $query[3] : null;
 
     switch ($action) {
+      case "add":
+        switch ($category) {
+          case "time_limited_alias":
+            if (isset($_POST['attr'])) {
+              $attr = (array)json_decode($_POST['attr'], true);
+              if (mailbox('add', 'time_limited_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;
+        }
+      break;
       case "get":
         switch ($category) {
           case "domain":
             switch ($object) {
               case "all":
-                $domains = mailbox_get_domains();
+                $domains = mailbox('get', 'domains');
                 if (!empty($domains)) {
                   foreach ($domains as $domain) {
-                    if ($details = mailbox_get_domain_details($domain)) {
+                    if ($details = mailbox('get', 'domain_details', $domain)) {
                       $data[] = $details;
                     }
                     else {
@@ -53,7 +90,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               break;
 
               default:
-                $data = mailbox_get_domain_details($object);
+                $data = mailbox('get', 'domain_details', $object);
                 if (!isset($data) || empty($data)) {
                   echo '{}';
                 }
@@ -110,18 +147,27 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
                   echo '{}';
                 }
               break;
+              case "rspamd-history":
+                $logs = get_logs('rspamd-history');
+                if (isset($logs) && !empty($logs)) {
+                  echo json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+                }
+                else {
+                  echo '{}';
+                }
+              break;
             }
           break;
           case "mailbox":
             switch ($object) {
               case "all":
-                $domains = mailbox_get_domains();
+                $domains = mailbox('get', 'domains');
                 if (!empty($domains)) {
                   foreach ($domains as $domain) {
-                    $mailboxes = mailbox_get_mailboxes($domain);
+                    $mailboxes = mailbox('get', 'mailboxes', $domain);
                     if (!empty($mailboxes)) {
                       foreach ($mailboxes as $mailbox) {
-                        if ($details = mailbox_get_mailbox_details($mailbox)) {
+                        if ($details = mailbox('get', 'mailbox_details', $mailbox)) {
                           $data[] = $details;
                         }
                         else {
@@ -143,7 +189,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               break;
 
               default:
-                $data = mailbox_get_mailbox_details($object);
+                $data = mailbox('get', 'mailbox_details', $object);
                 if (!isset($data) || empty($data)) {
                   echo '{}';
                 }
@@ -153,10 +199,75 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               break;
             }
           break;
-          case "syncjob":
+          case "syncjobs":
+            switch ($object) {
+              default:
+                $data = mailbox('get', 'syncjobs', $object);
+                if (!isset($data) || empty($data)) {
+                  echo '{}';
+                }
+                else {
+                  echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+                }
+              break;
+            }
+          break;
+          case "policy_wl_mailbox":
+            switch ($object) {
+              default:
+                $data = policy('get', 'mailbox', $object)['whitelist'];
+                if (!isset($data) || empty($data)) {
+                  echo '{}';
+                }
+                else {
+                  echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+                }
+              break;
+            }
+          break;
+          case "policy_bl_mailbox":
+            switch ($object) {
+              default:
+                $data = policy('get', 'mailbox', $object)['blacklist'];
+                if (!isset($data) || empty($data)) {
+                  echo '{}';
+                }
+                else {
+                  echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+                }
+              break;
+            }
+          break;
+          case "policy_wl_domain":
+            switch ($object) {
+              default:
+                $data = policy('get', 'domain', $object)['whitelist'];
+                if (!isset($data) || empty($data)) {
+                  echo '{}';
+                }
+                else {
+                  echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+                }
+              break;
+            }
+          break;
+          case "policy_bl_domain":
             switch ($object) {
               default:
-                $data = get_syncjobs($object);
+                $data = policy('get', 'domain', $object)['blacklist'];
+                if (!isset($data) || empty($data)) {
+                  echo '{}';
+                }
+                else {
+                  echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+                }
+              break;
+            }
+          break;
+          case "time_limited_aliases":
+            switch ($object) {
+              default:
+                $data = mailbox('get', 'time_limited_aliases', $object);
                 if (!isset($data) || empty($data)) {
                   echo '{}';
                 }
@@ -169,13 +280,13 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           case "resource":
             switch ($object) {
               case "all":
-                $domains = mailbox_get_domains();
+                $domains = mailbox('get', 'domains');
                 if (!empty($domains)) {
                   foreach ($domains as $domain) {
-                    $resources = mailbox_get_resources($domain);
+                    $resources = mailbox('get', 'resources', $domain);
                     if (!empty($resources)) {
                       foreach ($resources as $resource) {
-                        if ($details = mailbox_get_resource_details($resource)) {
+                        if ($details = mailbox('get', 'resource_details', $resource)) {
                           $data[] = $details;
                         }
                         else {
@@ -196,7 +307,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
                 }
               break;
               default:
-                $data = mailbox_get_resource_details($object);
+                $data = mailbox('get', 'resource_details', $object);
                 if (!isset($data) || empty($data)) {
                   echo '{}';
                 }
@@ -241,13 +352,13 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           case "alias-domain":
             switch ($object) {
               case "all":
-                $domains = mailbox_get_domains();
+                $domains = mailbox('get', 'domains');
                 if (!empty($domains)) {
                   foreach ($domains as $domain) {
-                    $alias_domains = mailbox_get_alias_domains($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)) {
+                        if ($details = mailbox('get', 'alias_domain_details', $alias_domain)) {
                           $data[] = $details;
                         }
                         else {
@@ -268,7 +379,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
                 }
               break;
               default:
-                $data = mailbox_get_alias_domains($object);
+                $data = mailbox('get', 'alias_domains', $object);
                 if (!isset($data) || empty($data)) {
                   echo '{}';
                 }
@@ -281,13 +392,13 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
           case "alias":
             switch ($object) {
               case "all":
-                $domains = array_merge(mailbox_get_domains(), mailbox_get_alias_domains());
+                $domains = array_merge(mailbox('get', 'domains'),mailbox('get', 'alias_domains'));
                 if (!empty($domains)) {
                   foreach ($domains as $domain) {
-                    $aliases = mailbox_get_aliases($domain);
+                    $aliases = mailbox('get', 'aliases', $domain);
                     if (!empty($aliases)) {
                       foreach ($aliases as $alias) {
-                        if ($details = mailbox_get_alias_details($alias)) {
+                        if ($details = mailbox('get', 'alias_details', $alias)) {
                           $data[] = $details;
                         }
                         else {
@@ -309,7 +420,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               break;
 
               default:
-                $data = mailbox_get_alias_details($object);
+                $data = mailbox('get', 'alias_details', $object);
                 if (!isset($data) || empty($data)) {
                   echo '{}';
                 }
@@ -389,7 +500,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 (mailbox_delete_alias(array('address' => $items)) === false) {
+                if (mailbox('delete', 'alias', array('address' => $items)) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -426,6 +537,47 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               ));
             }
           break;
+          case "syncjob":
+            if (isset($_POST['items'])) {
+              $items = (array)json_decode($_POST['items'], true);
+              if (is_array($items)) {
+                if (mailbox('delete', 'syncjob', array('id' => $items)) === false) {
+                  if (isset($_SESSION['return'])) {
+                    echo json_encode($_SESSION['return']);
+                  }
+                  else {
+                    echo json_encode(array(
+                      'type' => 'error',
+                      'msg' => 'Deletion of items/s failed'
+                    ));
+                  }
+                }
+                else {
+                  if (isset($_SESSION['return'])) {
+                    echo json_encode($_SESSION['return']);
+                  }
+                  else {
+                    echo json_encode(array(
+                      'type' => 'success',
+                      'msg' => 'Task completed'
+                    ));
+                  }
+                }
+              }
+              else {
+                echo json_encode(array(
+                  'type' => 'error',
+                  'msg' => 'Cannot find id array in post data'
+                ));
+              }
+            }
+            else {
+              echo json_encode(array(
+                'type' => 'error',
+                'msg' => 'Cannot find items in post data'
+              ));
+            }
+          break;
           case "fwdhost":
             if (isset($_POST['items'])) {
               $items = (array)json_decode($_POST['items'], true);
@@ -512,7 +664,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 (mailbox_delete_domain(array('domain' => $items)) === false) {
+                if (mailbox('delete', 'domain', array('domain' => $items)) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -553,7 +705,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 (mailbox_delete_alias_domain(array('alias_domain' => $items)) === false) {
+                if (mailbox('delete', 'alias_domain', array('alias_domain' => $items)) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -594,7 +746,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 (mailbox_delete_mailbox(array('username' => $items)) === false) {
+                if (mailbox('delete', 'mailbox', array('username' => $items)) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -635,7 +787,130 @@ 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 (mailbox_delete_resource(array('name' => $items)) === false) {
+                if (mailbox('delete', 'resource', array('name' => $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 "policy_mailbox":
+            if (isset($_POST['items'])) {
+              $items = (array)json_decode($_POST['items'], true);
+              if (is_array($items)) {
+                if (policy('delete', 'mailbox', 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);
+              if (is_array($items)) {
+                if (mailbox('delete', 'time_limited_alias', array('address' => $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 "eas_cache":
+            if (isset($_POST['items'])) {
+              $items = (array)json_decode($_POST['items'], true);
+              if (is_array($items)) {
+                if (mailbox('delete', 'eas_cache', array('username' => $items)) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -682,7 +957,139 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               $attr = (array)json_decode($_POST['attr'], true);
               $postarray = array_merge(array('address' => $items), $attr);
               if (is_array($postarray['address'])) {
-                if (mailbox_edit_alias($postarray) === false) {
+                if (mailbox('edit', 'alias', $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 "delimiter_action":
+            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('username' => $items), $attr);
+              if (is_array($postarray['username'])) {
+                if (mailbox('edit', 'delimiter_action', $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 "tls_policy":
+            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('username' => $items), $attr);
+              if (is_array($postarray['username'])) {
+                if (mailbox('edit', 'tls_policy', $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 "time_limited_alias":
+            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('address' => $items), $attr);
+              if (is_array($postarray['address'])) {
+                if (mailbox('edit', 'time_limited_alias', $postarray) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -726,7 +1133,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               $attr = (array)json_decode($_POST['attr'], true);
               $postarray = array_merge(array('username' => $items), $attr);
               if (is_array($postarray['username'])) {
-                if (mailbox_edit_mailbox($postarray) === false) {
+                if (mailbox('edit', 'mailbox', $postarray) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -770,7 +1177,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               $attr = (array)json_decode($_POST['attr'], true);
               $postarray = array_merge(array('id' => $items), $attr);
               if (is_array($postarray['id'])) {
-                if (edit_syncjob($postarray) === false) {
+                if (mailbox('edit', 'syncjob', $postarray) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -814,7 +1221,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               $attr = (array)json_decode($_POST['attr'], true);
               $postarray = array_merge(array('name' => $items), $attr);
               if (is_array($postarray['name'])) {
-                if (mailbox_edit_resource($postarray) === false) {
+                if (mailbox('edit', 'resource', $postarray) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -858,7 +1265,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               $attr = (array)json_decode($_POST['attr'], true);
               $postarray = array_merge(array('domain' => $items), $attr);
               if (is_array($postarray['domain'])) {
-                if (mailbox_edit_domain($postarray) === false) {
+                if (mailbox('edit', 'domain', $postarray) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }
@@ -902,7 +1309,51 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
               $attr = (array)json_decode($_POST['attr'], true);
               $postarray = array_merge(array('alias_domain' => $items), $attr);
               if (is_array($postarray['alias_domain'])) {
-                if (mailbox_edit_alias_domain($postarray) === false) {
+                if (mailbox('edit', 'alias_domain', $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 "spam_score":
+            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('username' => $items), $attr);
+              if (is_array($postarray['username'])) {
+                if (mailbox('edit', 'spam_score', $postarray) === false) {
                   if (isset($_SESSION['return'])) {
                     echo json_encode($_SESSION['return']);
                   }

+ 2 - 1
data/web/lang/lang.de.php

@@ -10,7 +10,7 @@ $lang['footer']['restart_now'] = 'Jetzt neustarten';
 $lang['footer']['restart_sogo_info'] = 'Einige Änderungen an Domains benötigen einen Neustart SOGos. Hier können Sie SOGo neustarten.<br><br><b>Wichtig:</b> Ein korrekter Neustart SOGos kann eine Weile in Anspruch nehmen, bitte warten Sie, bis der Prozess vollständig beendet wurde.';
 
 $lang['footer']['confirm_delete'] = 'Löschen bestätigen';
-$lang['footer']['delete_these_items'] = 'Sind Sie sicher, dass die folgenden Elemente entfernt werden sollen?';
+$lang['footer']['delete_these_items'] = 'Sind Sie sicher, dass die Änderungen an folgenden Elementen durchgeführt werden sollen?';
 $lang['footer']['delete_now'] = 'Jetzt löschen';
 $lang['footer']['cancel'] = 'Abbrechen';
 
@@ -28,6 +28,7 @@ $lang['danger']['domain_invalid'] = 'Domainname ist ungültig';
 $lang['danger']['mailbox_quota_exceeds_domain_quota'] = 'Maximale Größe für Mailboxen überschreitet das Domain Speicherlimit';
 $lang['danger']['object_is_not_numeric'] = 'Wert %s ist nicht numerisch';
 $lang['success']['domain_added'] = 'Domain %s wurde angelegt';
+$lang['success']['items_deleted'] = "Objekt(e) %s wurde(n) erfolgreich entfernt";
 $lang['danger']['alias_empty'] = 'Alias-Adresse darf nicht leer sein';
 $lang['danger']['goto_empty'] = 'Ziel-Adresse darf nicht leer sein';
 $lang['danger']['policy_list_from_exists'] = 'Ein Eintrag mit diesem Wert existiert bereits';

+ 2 - 1
data/web/lang/lang.en.php

@@ -10,7 +10,7 @@ $lang['footer']['restart_now'] = 'Restart now';
 $lang['footer']['restart_sogo_info'] = 'Some tasks, e.g. adding a domain, require you to restart SOGo to catch changes made in the mailcow UI.<br><br><b>Important:</b> A graceful restart may take a while to complete, please wait for it to finish.';
 
 $lang['footer']['confirm_delete'] = 'Confirm deletion';
-$lang['footer']['delete_these_items'] = 'Are you sure you want to delete the following items?';
+$lang['footer']['delete_these_items'] = 'Please confirm your changes to the following items:';
 $lang['footer']['delete_now'] = 'Delete now';
 $lang['footer']['cancel'] = 'Cancel';
 
@@ -28,6 +28,7 @@ $lang['danger']['domain_invalid'] = "Domain name is invalid";
 $lang['danger']['mailbox_quota_exceeds_domain_quota'] = "Max. quota exceeds domain quota limit";
 $lang['danger']['object_is_not_numeric'] = "Value %s is not numeric";
 $lang['success']['domain_added'] = "Added domain %s";
+$lang['success']['items_deleted'] = "Item %s successfully deleted";
 $lang['danger']['alias_empty'] = "Alias address must not be empty";
 $lang['danger']['last_key'] = 'Last key cannot be deleted';
 $lang['danger']['goto_empty'] = "Goto address must not be empty";

+ 129 - 221
data/web/user.php

@@ -27,7 +27,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'doma
         <div class="col-sm-9 col-xs-7">
           <p id="tfa_pretty"><?=$tfa_data['pretty'];?></p>
             <div id="tfa_additional">
-              <?php if($tfa_data['additional']):
+              <?php if (!empty($tfa_data['additional'])):
               foreach ($tfa_data['additional'] as $key_info): ?>
                 <form style="display:inline;" method="post">
                 <input type="hidden" name="unset_tfa_key" value="<?=$key_info['id'];?>" />
@@ -63,8 +63,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
 	require_once("inc/header.inc.php");
 	$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 	$username = $_SESSION['mailcow_cc_username'];
-	$get_tls_policy = get_tls_policy($_SESSION['mailcow_cc_username']);
-  $mailboxdata = mailbox_get_mailbox_details($username);
+  $mailboxdata = mailbox('get', 'mailbox_details', $username);
 ?>
 <div class="container">
 <h3><?=$lang['user']['user_settings'];?></h3>
@@ -124,31 +123,64 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
   </div>
   <hr>
   <?php // Show tagging options ?>
-  <form class="form-horizontal" role="form" method="post">
-  <?php $get_tagging_options = get_delimiter_action();?>
+  <?php $get_tagging_options = mailbox('get', 'delimiter_action', $username);?>
   <div class="row">
     <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['tag_handling'];?>:</div>
     <div class="col-md-9 col-xs-7">
-    <input type="hidden" name="edit_delimiter_action" value="1">
-    <select name="tagged_mail_handler" class="selectpicker" onchange="this.form.submit()">
-      <option value="subfolder" <?=($get_tagging_options == "subfolder") ? 'selected' : null; ?>><?=$lang['user']['tag_in_subfolder'];?></option>
-      <option value="subject" <?=($get_tagging_options == "subject") ? 'selected' : null; ?>><?=$lang['user']['tag_in_subject'];?></option>
-    </select>
+    <div class="btn-group">
+
+      <button type="button" class="btn btn-sm btn-default <?=($get_tagging_options == "subfolder") ? 'active' : null; ?>"
+        id="edit_selected"
+        data-item="<?= $username; ?>"
+        data-id="delimiter_action"
+        data-api-url='edit/delimiter_action'
+        data-api-attr='{"tagged_mail_handler":"subfolder"}'><?=$lang['user']['tag_in_subfolder'];?></button>
+
+      <button type="button" class="btn btn-sm btn-default <?=($get_tagging_options == "subject") ? 'active' : null; ?>"
+        id="edit_selected"
+        data-item="<?= $username; ?>"
+        data-id="delimiter_action"
+        data-api-url='edit/delimiter_action'
+        data-api-attr='{"tagged_mail_handler":"subject"}'><?=$lang['user']['tag_in_subject'];?></button>
+
+    </div>
     <p class="help-block"><?=$lang['user']['tag_help_explain'];?></p>
     <p class="help-block"><?=$lang['user']['tag_help_example'];?></p>
     </div>
   </div>
-  </form>
+  <?php // Show TLS policy options ?>
+  <?php $get_tls_policy = mailbox('get', 'tls_policy', $username); ?>
+  <div class="row">
+    <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['tls_policy'];?>:</div>
+    <div class="col-md-9 col-xs-7">
+    <div class="btn-group">
+
+      <button type="button" class="btn btn-sm btn-default <?=($get_tls_policy['tls_enforce_in'] == "1") ? "active" : null;?>"
+        id="edit_selected"
+        data-item="<?= $username; ?>"
+        data-id="tls_policy"
+        data-api-url='edit/tls_policy'
+        data-api-attr='{"tls_enforce_in":<?=($get_tls_policy['tls_enforce_in'] == "1") ? "0" : "1";?>}'><?=$lang['user']['tls_enforce_in'];?></button>
+
+      <button type="button" class="btn btn-sm btn-default <?=($get_tls_policy['tls_enforce_out'] == "1") ? "active" : null;?>"
+        id="edit_selected"
+        data-item="<?= $username; ?>"
+        data-id="tls_policy"
+        data-api-url='edit/tls_policy'
+        data-api-attr='{"tls_enforce_out":<?=($get_tls_policy['tls_enforce_out'] == "1") ? "0" : "1";?>}'><?=$lang['user']['tls_enforce_out'];?></button>
+
+    </div>
+    <p class="help-block"><?=$lang['user']['tls_policy_warning'];?></p>
+    </div>
+  </div>
   <?php // Rest EAS devices ?>
-  <form class="form-horizontal" role="form" method="post">
   <div class="row">
     <div class="col-md-3 col-xs-5 text-right"><?=$lang['user']['eas_reset'];?>:</div>
     <div class="col-md-9 col-xs-7">
-    <button type="submit" name="mailbox_reset_eas" id="mailbox_reset_eas" value="1" class="btn btn-xs btn-default"><?=$lang['user']['eas_reset_now'];?></button>
+    <button class="btn btn-xs btn-default" id="delete_selected" data-text="<?=$lang['user']['eas_reset'];?>?" data-item="<?= $username; ?>" data-id="eas_cache" data-api-url='delete/eas_cache' href="#"><?=$lang['user']['eas_reset_now'];?></button>
     <p class="help-block"><?=$lang['user']['eas_reset_help'];?></p>
     </div>
   </div>
-  </form>
 </div>
 </div>
 
@@ -156,92 +188,50 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
 <ul class="nav nav-pills nav-justified" role="tablist">
 	<li role="presentation" class="active"><a href="#SpamAliases" aria-controls="SpamAliases" role="tab" data-toggle="tab"><?=$lang['user']['spam_aliases'];?></a></li>
 	<li role="presentation"><a href="#Spamfilter" aria-controls="Spamfilter" role="tab" data-toggle="tab"><?=$lang['user']['spamfilter'];?></a></li>
-	<li role="presentation"><a href="#TLSPolicy" aria-controls="TLSPolicy" role="tab" data-toggle="tab"><?=$lang['user']['tls_policy'];?></a></li>
 	<li role="presentation"><a href="#Syncjobs" aria-controls="Syncjobs" role="tab" data-toggle="tab"><?=$lang['user']['sync_jobs'];?></a></li>
 </ul>
 <hr>
 
 <div class="tab-content">
 	<div role="tabpanel" class="tab-pane active" id="SpamAliases">
-		<div class="row">
-			<div class="col-xs-6">
-				<p><b><?=$lang['user']['alias'];?></b></p>
-			</div>
-			<div class="col-xs-2">
-				<p><b><?=$lang['user']['alias_valid_until'];?></b></p>
-			</div>
-			<div class="col-xs-2">
-        <p><b><?=$lang['user']['action'];?></b></p>
-			</div>
-    </div>
-			<?php
-      $get_time_limited_aliases = get_time_limited_aliases($username);
-      if (!empty($get_time_limited_aliases)):
-        foreach ($get_time_limited_aliases as $row):
-        ?>
-		<div class="row">
-      <div class="col-xs-6">
-        <p><?=htmlspecialchars($row['address']);?></p>
-      </div>
-      <div class="col-xs-2">
-        <p><?=htmlspecialchars(date($lang['user']['alias_full_date'], $row['validity']));?></p>
-      </div>
-      <div class="col-xs-1">
-        <form class="form-inline" role="form" method="post">
-          <a class="text-danger" href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-remove"></span></a>
-          <input type="hidden" name="set_time_limited_aliases" value="delete">
-          <input type="hidden" name="item" value="<?=htmlspecialchars($row['address']);?>">
-        </form>
+    <div class="row">
+      <div class="col-md-6 col-sm-12 col-xs-12">
+        <div class="table-responsive">
+          <table class="table table-striped" id="tla_table"></table>
+        </div>
       </div>
-      <div class="col-xs-1">
-        <form class="form-inline" role="form" method="post">
-          <a href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-time"></span> + 1h</a>
-          <input type="hidden" name="set_time_limited_aliases" value="extend">
-          <input type="hidden" name="item" value="<?=htmlspecialchars($row['address']);?>">
-        </form>
+		</div>
+    <div class="mass-actions-user">
+      <div class="btn-group">
+        <div class="btn-group">
+          <a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="tla" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
+          <a class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['mailbox']['quick_actions'];?> <span class="caret"></span></a>
+          <ul class="dropdown-menu">
+            <li><a id="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-time"></span> + 1h</a></li>
+            <li role="separator" class="divider"></li>
+            <li><a id="delete_selected" data-id="tla" data-api-url='delete/time_limited_alias' href="#"><?=$lang['mailbox']['remove'];?></a></li>
+          </ul>
+        </div>
+        <div class="btn-group">
+          <a class="btn btn-sm btn-success dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['user']['alias_create_random'];?> <span class="caret"></span></a>
+          <ul class="dropdown-menu">
+            <li><a id="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"1"}' href="#">1 <?=$lang['user']['hour'];?></a></li>
+            <li><a id="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"6"}' href="#">6 <?=$lang['user']['hours'];?></a></li>
+            <li><a id="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"24"}' href="#">1 <?=$lang['user']['day'];?></a></li>
+            <li><a id="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"168"}' href="#">1 <?=$lang['user']['week'];?></a></li>
+            <li><a id="add_item" data-api-url='add/time_limited_alias' data-api-attr='{"validity":"672"}' href="#">4 <?=$lang['user']['weeks'];?></a></li>
+          </ul>
+        </div>
       </div>
     </div>
-        <?php
-        endforeach;
-			else:
-			?>
-      <div class="col-xs-12">
-        <center><i><?=$lang['user']['no_record'];?></i></center>
-      </div>
-			<?php
-			endif;	
-			?>
-    <form class="form-horizontal" role="form" method="post">
-		<div class="form-group">
-			<div class="col-sm-9">
-				<select id="validity" name="validity" title="<?=$lang['user']['alias_select_validity'];?>">
-					<option value="1">1 <?=$lang['user']['hour'];?></option>
-					<option value="6">6 <?=$lang['user']['hours'];?></option>
-					<option value="24">1 <?=$lang['user']['day'];?></option>
-					<option value="168">1 <?=$lang['user']['week'];?></option>
-					<option value="672">4 <?=$lang['user']['weeks'];?></option>
-				</select>
-				<button type="submit" name="set_time_limited_aliases" id="generate_tla" value="generate" class="btn btn-success"><?=$lang['user']['alias_create_random'];?></button>
-			</div>
-		</div>
-		<div class="form-group">
-			<div class="col-sm-12">
-				<button type="submit" name="set_time_limited_aliases" value="deleteall" class="btn-danger btn btn-sm">
-					<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> <?=$lang['user']['alias_remove_all'];?>
-				</button>
-				<button type="submit" name="set_time_limited_aliases" value="extendall" class="btn-default btn btn-sm">
-					<span class="glyphicon glyphicon-time" aria-hidden="true"></span> <?=$lang['user']['alias_extend_all'];?>
-				</button>
-			</div>
-		</div>
-		</form>
 	</div>
+
 	<div role="tabpanel" class="tab-pane" id="Spamfilter">
 		<h4><?=$lang['user']['spamfilter_behavior'];?></h4>
-		<form class="form-horizontal" role="form" method="post">
+		<form class="form-horizontal" role="form" data-id="spam_score" method="post">
 			<div class="form-group">
 				<div class="col-sm-offset-2 col-sm-10">
-					<input name="score" id="score" type="text" 
+					<input name="spam_score" id="spam_score" type="text" 
 						data-provide="slider"
 						data-slider-min="1"
 						data-slider-max="30"
@@ -249,7 +239,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
 						data-slider-range="true"
 						data-slider-tooltip='always'
 						data-slider-id="slider1"
-						data-slider-value="[<?=get_spam_score($username);?>]"
+						data-slider-value="[<?=mailbox('get', 'spam_score', $username);?>]"
 						data-slider-step="1" />
 					<br /><br />
 					<ul>
@@ -263,149 +253,67 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
 			</div>
 			<div class="form-group">
 				<div class="col-sm-offset-2 col-sm-10">
-					<button type="submit" id="edit_spam_score" name="edit_spam_score" class="btn btn-success"><?=$lang['user']['save_changes'];?></button>
+        <button type="button" class="btn btn-sm btn-success" id="edit_selected"
+          data-item="<?= $username; ?>"
+          data-id="spam_score"
+          data-api-url='edit/spam_score'
+          data-api-attr='{}'><?=$lang['user']['save_changes'];?></button>
 				</div>
 			</div>
 		</form>
 		<hr>
 		<div class="row">
 			<div class="col-sm-6">
-				<h4><span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span> <?=$lang['user']['spamfilter_wl'];?></h4>
-				<p><?=$lang['user']['spamfilter_wl_desc'];?></p>
-				<div class="row">
-					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_rule'];?></b></div>
-					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
-				</div>
-				<?php
-        $get_policy_list = get_policy_list($username);
-				if (empty($get_policy_list['whitelist'])):
-				?>
-					<div class="row">
-						<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
-					</div>
-				<?php
-				else:
-          foreach($get_policy_list['whitelist'] as $wl):
-          ?>
-          <div class="row striped">
-            <form class="form-inline" method="post">
-            <div class="col-xs-6"><code><?=$wl['value'];?></code></div>
-            <div class="col-xs-6">
-              <input type="hidden" name="delete_prefid" value="<?=$wl['prefid'];?>">
-              <?php
-              if (filter_var($wl['object'], FILTER_VALIDATE_EMAIL)):
-              ?>
-                <input type="hidden" name="delete_policy_list_item">
-                <a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
-              <?php
-              else:
-              ?>
-                <span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
-              <?php
-              endif;
-              ?>
-            </div>
-            </form>
+				<h4><?=$lang['user']['spamfilter_wl'];?></h4>
+        <p><?=$lang['user']['spamfilter_wl_desc'];?></p>
+        <div class="table-responsive">
+          <table class="table table-striped table-condensed" id="wl_policy_mailbox_table"></table>
+        </div>
+        <div class="mass-actions-user">
+          <div class="btn-group">
+            <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>
+            </ul>
           </div>
-          <?php
-          endforeach;
-        endif;
-				?>
-				<hr style="margin:5px 0px 7px 0px">
-				<div class="row">
-					<form class="form-inline" method="post">
-					<div class="col-xs-6">
-						<input type="text" class="form-control input-sm" name="object_from" id="object_from" placeholder="*@example.org" required>
-						<input type="hidden" name="object_list" value="wl">
-					</div>
-					<div class="col-xs-6">
-						<button type="submit" id="add_policy_list_item" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
-					</div>
-					</form>
-				</div>
-			</div>
+        </div>
+        <form class="form-inline" method="post">
+          <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>
+            </span>
+          </div>
+        </form>
+      </div>
 			<div class="col-sm-6">
-				<h4><span class="glyphicon glyphicon-thumbs-down" aria-hidden="true"></span> <?=$lang['user']['spamfilter_bl'];?></h4>
-				<p><?=$lang['user']['spamfilter_bl_desc'];?></p>
-				<div class="row">
-					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_rule'];?></b></div>
-					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
-				</div>
-				<?php
-				if (empty($get_policy_list['blacklist'])):
-				?>
-					<div class="row">
-						<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
-					</div>
-				<?php
-				else:
-          foreach($get_policy_list['blacklist'] as $bl):
-          ?>
-          <div class="row striped">
-            <form class="form-inline" method="post">
-            <div class="col-xs-6"><code><?=$bl['value'];?></code></div>
-            <div class="col-xs-6">
-              <?php
-              if (filter_var($bl['object'], FILTER_VALIDATE_EMAIL)):
-              ?>
-                <input type="hidden" name="delete_prefid" value="<?=$bl['prefid'];?>">
-                <input type="hidden" name="delete_policy_list_item">
-                <a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
-              <?php
-              else:
-              ?>
-                <span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
-              <?php
-              endif;
-              ?>
-            </div>
-            </form>
+				<h4><?=$lang['user']['spamfilter_bl'];?></h4>
+        <p><?=$lang['user']['spamfilter_bl_desc'];?></p>
+        <div class="table-responsive">
+          <table class="table table-striped table-condensed" id="bl_policy_mailbox_table"></table>
+        </div>
+        <div class="mass-actions-user">
+          <div class="btn-group">
+            <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>
+            </ul>
           </div>
-          <?php
-          endforeach;
-        endif;
-				?>
-				<hr style="margin:5px 0px 7px 0px">
-				<div class="row">
-					<form class="form-inline" method="post">
-					<div class="col-xs-6">
-						<input type="text" class="form-control input-sm" name="object_from" id="object_from" placeholder="*@example.org" required>
-						<input type="hidden" name="object_list" value="bl">
-					</div>
-					<div class="col-xs-6">
-						<button type="submit" id="add_policy_list_item" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
-					</div>
-					</form>
-				</div>
-			</div>
-		</div>
-	</div>
-	<div role="tabpanel" class="tab-pane" id="TLSPolicy">
-		<form class="form-horizontal" role="form" method="post">
-      <input type="hidden" value="0" name="tls_in">
-      <input type="hidden" value="0" name="tls_out">
-			<p class="help-block"><?=$lang['user']['tls_policy_warning'];?></p>
-			<div class="form-group">
-				<div class="col-sm-6">
-					<div class="checkbox">
-						<h4><span class="glyphicon glyphicon-download" aria-hidden="true"></span> <?=$lang['user']['tls_enforce_in'];?></h4>
-						<input type="checkbox" value="1" id="tls_in" name="tls_in" <?=($get_tls_policy['tls_enforce_in'] == "1") ? "checked" : null;?> data-on-text="<?=$lang['user']['on'];?>" data-off-text="<?=$lang['user']['off'];?>">
-					</div>
-				</div>
-				<div class="col-sm-6">
-					<div class="checkbox">
-						<h4><span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?=$lang['user']['tls_enforce_out'];?></h4>
-						<input type="checkbox" value="1" id="tls_out" name="tls_out" <?=($get_tls_policy['tls_enforce_out'] == "1") ? "checked" : null;?> data-on-text="<?=$lang['user']['on'];?>" data-off-text="<?=$lang['user']['off'];?>">
-					</div>
-				</div>
-			</div>
-			<div class="form-group">
-				<div class="col-sm-12">
-					<button type="submit" id="edit_tls_policy" name="edit_tls_policy" class="btn btn-success"><?=$lang['user']['save_changes'];?></button>
-				</div>
-			</div>
-		</form>
-	</div>
+        </div>
+        <form class="form-inline" method="post">
+          <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>
+            </span>
+          </div>
+        </form>
+      </div>
+    </div>
+  </div>
+
 	<div role="tabpanel" class="tab-pane" id="Syncjobs">
 		<div class="table-responsive">
       <table class="table table-striped" id="sync_job_table"></table>

Some files were not shown because too many files changed in this diff