NobGit
public nobgit read

NobMail

Based on mailcow: dockerized

Languages

Repository composition by tracked source files.

PHP
PHP 49% JavaScript 35% HTML 9% CSS 4% Shell 2% Python 1% Lua 0% Perl 0% Ruby 0% SCSS 0%
Create file Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git

Commit

Cleanup, cleanup and cleanup, much better sender acl handling, imapsync jobs, login as mailbox user X

365abdda
andryyy <[email protected]> 10 years ago
data/web/admin.php             |  152 +--
 data/web/delete.php            |   40 +-
 data/web/edit.php              |  470 ++++----
 data/web/inc/footer.inc.php    |    4 +
 data/web/inc/functions.inc.php | 2304 ++++++++++++++++++++++++----------------
 data/web/inc/init.sql          |    4 +-
 data/web/inc/triggers.inc.php  |    3 +
 data/web/inc/vars.inc.php      |    1 +
 data/web/js/user.js            |    4 -
 data/web/lang/lang.de.php      |   22 +-
 data/web/lang/lang.en.php      |   21 +-
 data/web/mailbox.php           |    4 +-
 data/web/user.php              |  206 ++--
 13 files changed, 1801 insertions(+), 1434 deletions(-)

Diff

diff --git a/data/web/admin.php b/data/web/admin.php
index 24327b02..6d41ba9b 100644
--- a/data/web/admin.php
+++ b/data/web/admin.php
@@ -74,63 +74,36 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 						</thead>
 						<tbody>
 							<?php
-							try {
-								$stmt = $pdo->query("SELECT DISTINCT
-									`username`, 
-									CASE WHEN `active`='1' THEN '".$lang['admin']['yes']."' ELSE '".$lang['admin']['no']."' END AS `active`
-										FROM `domain_admins` 
-											WHERE `username` IN (
-												SELECT `username` FROM `admin`
-													WHERE `superadmin`!='1'
-											)");
-								$rows_username = $stmt->fetchAll(PDO::FETCH_ASSOC);
-							}
-							catch(PDOException $e) {
-								$_SESSION['return'] = array(
-									'type' => 'danger',
-									'msg' => 'MySQL: '.$e
-								);
-							}
-							if(!empty($rows_username)):
-							while ($row_user_state = array_shift($rows_username)):
+              foreach (get_domain_admins() as $domain_admin) {
+                $da_data = get_domain_admin_details($domain_admin); 
+                if (!empty($da_data)):
 							?>
 							<tr id="data">
-								<td><?=htmlspecialchars(strtolower($row_user_state['username']));?></td>
+								<td><?=htmlspecialchars(strtolower($domain_admin));?></td>
 								<td>
 								<?php
-								try {
-									$stmt = $pdo->prepare("SELECT `domain` FROM `domain_admins` WHERE `username` = :username");
-									$stmt->execute(array('username' => $row_user_state['username']));
-									$rows_domain = $stmt->fetchAll(PDO::FETCH_ASSOC);
-								}
-								catch(PDOException $e) {
-									$_SESSION['return'] = array(
-										'type' => 'danger',
-										'msg' => 'MySQL: '.$e
-									);
-								}
-								while ($row_domain = array_shift($rows_domain)) {
-									echo htmlspecialchars($row_domain['domain']).'<br />';
+								foreach ($da_data['selected_domains'] as $domain) {
+									echo htmlspecialchars($domain).'<br />';
 								}
 								?>
 								</td>
-								<td><?=$row_user_state['active'];?></td>
+								<td><?=$da_data['active'];?></td>
 								<td style="text-align: right;">
 									<div class="btn-group">
-										<a href="edit.php?domainadmin=<?=$row_user_state['username'];?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['admin']['edit'];?></a>
-										<a href="delete.php?domainadmin=<?=$row_user_state['username'];?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['admin']['remove'];?></a>
+										<a href="edit.php?domainadmin=<?=$domain_admin;?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['admin']['edit'];?></a>
+										<a href="delete.php?domainadmin=<?=$domain_admin;?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['admin']['remove'];?></a>
 									</div>
 								</td>
 								</td>
 							</tr>
 
 							<?php
-							endwhile;
 							else:
 							?>
 								<tr id="no-data"><td colspan="4" style="text-align: center; font-style: italic;"><?=$lang['admin']['no_record'];?></td></tr>
 							<?php
 							endif;
+              }
 							?>
 						</tbody>
 					</table>
@@ -204,41 +177,93 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 <div class="panel-heading"><?=$lang['admin']['dkim_keys'];?></div>
 <div id="collapseDKIM" class="panel-collapse">
 <div class="panel-body">
+  <p style="margin-bottom:40px"><?=$lang['admin']['dkim_key_hint'];?></p>
 	<?php
-	$dnstxt_folder = scandir($GLOBALS["MC_DKIM_TXTS"]);
-	$dnstxt_files = array_diff($dnstxt_folder, array('.', '..'));
-	foreach($dnstxt_files as $file) {
-		$pubKey = file_get_contents($GLOBALS["MC_DKIM_TXTS"]."/".$file);
-		$domain = substr($file, 0, -5);
-	?>
-		<div class="row">
-			<div class="col-xs-2">
-				<p>Domain: <strong><?=htmlspecialchars($domain);?></strong> (dkim._domainkey)</p>
-			</div>
-			<div class="col-xs-9">
-				<pre>v=DKIM1;k=rsa;t=s;s=email;p=<?=$pubKey;?></pre>
-			</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-remove-circle"></span></a>
-				<input type="hidden" name="delete_dkim_record" value="<?=htmlspecialchars($file);?>">
-                <input type="hidden" name="dkim[domain]" value="<?=$domain;?>">
-				</form>
-			</div>
-		</div>
-	<?php
+	foreach(mailbox_get_domains() as $domain) {
+    if ($pubkey = dkim_table('get', $domain)) {
+    ?>
+      <div class="row">
+        <div class="col-xs-3">
+          <p>Domain: <strong><?=htmlspecialchars($domain);?></strong><br /><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
+        </div>
+        <div class="col-xs-8">
+          <pre><?=$pubkey;?></pre>
+        </div>
+        <div class="col-xs-1">
+          <form class="form-inline" method="post">
+            <input type="hidden" name="dkim[domain]" value="<?=$domain;?>">
+            <input type="hidden" name="delete_dkim_record" value="1">
+            <a href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-remove-circle"></span></a>
+          </form>
+        </div>
+      </div>
+    <?php
+    }
+    foreach(mailbox_get_alias_domains($domain) as $alias_domain) {
+      if ($pubkey = dkim_table('get', $alias_domain)) {
+      ?>
+        <div class="row">
+          <div class="col-xs-offset-1 col-xs-2">
+            <p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
+          </div>
+          <div class="col-xs-8">
+            <pre><?=$pubkey;?></pre>
+          </div>
+          <div class="col-xs-1">
+            <form class="form-inline" method="post">
+              <input type="hidden" name="dkim[domain]" value="<?=$alias_domain;?>">
+              <input type="hidden" name="delete_dkim_record" value="1">
+              <a href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-remove-circle"></span></a>
+            </form>
+          </div>
+        </div>
+      <?php
+      }
+    }
 	}
+  ?><hr><?php
+  foreach(dkim_table('keys-without-domain', null) as $key_wo_domain) {
+    if ($pubkey = dkim_table('get', $key_wo_domain)) {
+    ?>
+      <div class="row">
+        <div class="col-xs-3">
+          <p>Domain: <strong><?=htmlspecialchars($key_wo_domain);?></strong><br /><span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span></p>
+        </div>
+          <div class="col-xs-8">
+            <pre><?=$pubkey;?></pre>
+          </div>
+          <div class="col-xs-1">
+            <form class="form-inline" method="post">
+              <input type="hidden" name="dkim[domain]" value="<?=$key_wo_domain;?>">
+              <input type="hidden" name="delete_dkim_record" value="1">
+              <a href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-remove-circle"></span></a>
+            </form>
+          </div>
+      </div>
+    <?php
+    }
+  }
+  ?><hr><?php
+  foreach(dkim_table('domains-without-key', null) as $domain_wo_key) {
+  ?>
+    <div class="row">
+      <div class="col-xs-12">
+        <p>(Alias-)Domain: <strong><?=htmlspecialchars($domain_wo_key);?></strong><br /><span class="label label-danger"><?=$lang['admin']['dkim_key_missing'];?></span></p>
+      </div>
+    </div>
+  <?php
+  }
 	?>
-	<legend><?=$lang['admin']['dkim_add_key'];?></legend>
+	<legend style="margin-top:40px"><?=$lang['admin']['dkim_add_key'];?></legend>
 	<form class="form-inline" role="form" method="post">
 		<div class="form-group">
 			<label for="dkim_domain">Domain</label>
 			<input class="form-control" id="dkim_domain" name="dkim[domain]" placeholder="example.org" required>
 		</div>
 		<div class="form-group">
-			<select class="form-control" id="dkim_key_size" name="dkim[key_size]" title="<?=$lang['admin']['dkim_key_length'];?>" required>
-				<option>1024</option>
-				<option>2048</option>
+			<select data-width="200px" class="form-control" id="dkim_key_size" name="dkim[key_size]" title="<?=$lang['admin']['dkim_key_length'];?>" required>
+				<option data-subtext="bits">1024</option>
+				<option data-subtext="bits">2048</option>
 			</select>
 		</div>
 		<button type="submit" name="add_dkim_record" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['add'];?></button>
@@ -246,7 +271,6 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 </div>
 </div>
 </div>
-
 </div> <!-- /container -->
 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js" integrity="sha384-YWP9O4NjmcGo4oEJFXvvYSEzuHIvey+LbXkBNJ1Kd0yfugEZN9NCQNpRYBVC1RvA" crossorigin="anonymous"></script>
diff --git a/data/web/delete.php b/data/web/delete.php
index f058b42a..867459c8 100644
--- a/data/web/delete.php
+++ b/data/web/delete.php
@@ -66,20 +66,9 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 			isset($_GET["aliasdomain"]) &&
 			is_valid_domain_name($_GET["aliasdomain"]) && 
 			!empty($_GET["aliasdomain"])) {
-				$alias_domain = strtolower(trim($_GET["aliasdomain"]));
-				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
-					);
-				}
-				if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $DomainData['target_domain'])) {
+        $alias_domain = $_GET["aliasdomain"];
+        $result = mailbox_get_alias_domain_details($alias_domain);
+				if (!empty($result)) {
 				?>
 					<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_domainalias_warning'], htmlspecialchars($_GET["aliasdomain"]));?></div>
 					<form class="form-horizontal" role="form" method="post" action="/mailbox.php">
@@ -102,7 +91,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		elseif (isset($_GET["domainadmin"]) &&
 			ctype_alnum(str_replace(array('_', '.', '-'), '', $_GET["domainadmin"])) &&
 			!empty($_GET["domainadmin"]) &&
-			$_SESSION['mailcow_cc_role'] == "admin") {
+        $_SESSION['mailcow_cc_role'] == "admin") {
 				$domain_admin = $_GET["domainadmin"];
 				?>
 				<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_domainadmin_warning'], htmlspecialchars($_GET["domainadmin"]));?></div>
@@ -121,8 +110,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 			filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) &&
 			!empty($_GET["mailbox"])) {
 				$mailbox = $_GET["mailbox"];
-				$domain = substr(strrchr($mailbox, "@"), 1);
-				if (hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+				if (hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $mailbox)) {
 				?>
 					<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_mailbox_warning'], htmlspecialchars($_GET["mailbox"]));?></div>
 					<p><?=$lang['delete']['remove_mailbox_details'];?></p>
@@ -153,21 +141,11 @@ elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] ==
 		if (isset($_GET["syncjob"]) &&
 			is_numeric($_GET["syncjob"]) &&
       filter_var($_SESSION['mailcow_cc_username'], FILTER_VALIDATE_EMAIL)) {
-        try {
-          $stmt = $pdo->prepare("SELECT `user2` FROM `imapsync`
-              WHERE `id` = :id AND user2 = :user2");
-          $stmt->execute(array(':id' => $_GET["syncjob"], ':user2' => $_SESSION['mailcow_cc_username']));
-          $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
-        }
-        catch(PDOException $e) {
-          $_SESSION['return'] = array(
-            'type' => 'danger',
-            'msg' => 'MySQL: '.$e
-          );
-        }
-				if ($num_results != 0 && !empty($num_results)) {
+        $id = $_GET["syncjob"];
+        $result = get_syncjob_details($id);
+        if (!empty($result)) {
 				?>
-					<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_syncjob_warning'], htmlspecialchars($_SESSION['mailcow_cc_username']));?></div>
+					<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_syncjob_warning'], htmlspecialchars($result['user2']));?></div>
 					<p><?=$lang['delete']['remove_syncjob_details'];?></p>
 					<form class="form-horizontal" role="form" method="post" action="/user.php">
 					<input type="hidden" name="username" value="<?=htmlspecialchars($mailbox);?>">
diff --git a/data/web/edit.php b/data/web/edit.php
index 3ab5fff0..0c93a0c9 100644
--- a/data/web/edit.php
+++ b/data/web/edit.php
@@ -20,34 +20,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		if (isset($_GET["alias"]) &&
 			!empty($_GET["alias"])) {
 				$alias = $_GET["alias"];
-				$domain = substr(strrchr($alias, "@"), 1);
-				try {
-					$stmt = $pdo->prepare("SELECT * FROM `alias`
-						WHERE `address`= :address 
-						AND `goto` != :goto
-						AND (
-							`domain` IN (
-								SELECT `domain` FROM `domain_admins`
-									WHERE `active`='1'
-									AND `username`= :username
-							)
-							OR 'admin'= :admin
-						)");
-					$stmt->execute(array(
-						':address' => $alias,
-						':goto' => $alias,
-						':username' => $_SESSION['mailcow_cc_username'],
-						':admin' => $_SESSION['mailcow_cc_role']
-					));
-					$result = $stmt->fetch(PDO::FETCH_ASSOC);
-				}
-				catch(PDOException $e) {
-					$_SESSION['return'] = array(
-						'type' => 'danger',
-						'msg' => 'MySQL: '.$e
-					);
-				}
-				if ($result !== false) {
+        $result = mailbox_get_alias_details($alias);
+				if (!empty($result)) {
 				?>
 					<h4><?=$lang['edit']['alias'];?></h4>
 					<br />
@@ -62,7 +36,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 						<div class="form-group">
 							<div class="col-sm-offset-2 col-sm-10">
 								<div class="checkbox">
-								<label><input type="checkbox" name="active" <?php if (isset($result['active']) && $result['active']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
+								<label><input type="checkbox" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
 								</div>
 							</div>
 						</div>
@@ -86,68 +60,34 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 			$_GET["domainadmin"] != 'admin' &&
 			$_SESSION['mailcow_cc_role'] == "admin") {
 				$domain_admin = $_GET["domainadmin"];
-				try {
-					$stmt = $pdo->prepare("SELECT * FROM `domain_admins` WHERE `username`= :domain_admin");
-					$stmt->execute(array(
-						':domain_admin' => $domain_admin
-					));
-					$result = $stmt->fetch(PDO::FETCH_ASSOC);
-				}
-				catch(PDOException $e) {
-					$_SESSION['return'] = array(
-						'type' => 'danger',
-						'msg' => 'MySQL: '.$e
-					);
-				}
-				if ($result !== false) {
+        $result = get_domain_admin_details($domain_admin);
+				if (!empty($result)) {
 				?>
 				<h4><?=$lang['edit']['domain_admin'];?></h4>
 				<br />
 				<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
 				<input type="hidden" name="username" value="<?=htmlspecialchars($domain_admin);?>">
+					<div class="form-group">
+						<label class="control-label col-sm-2" for="username"><?=$lang['edit']['username'];?></label>
+						<div class="col-sm-10">
+              <input class="form-control" type="text" disabled value="<?=htmlspecialchars($domain_admin);?>" />
+						</div>
+					</div>
 					<div class="form-group">
 						<label class="control-label col-sm-2" for="domain"><?=$lang['edit']['domains'];?></label>
 						<div class="col-sm-10">
 							<select id="domain" name="domain[]" multiple>
 							<?php
-							try {
-								$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
-									WHERE `domain` IN (
-										SELECT `domain` FROM `domain_admins`
-											WHERE `username`= :domain_admin)");
-								$stmt->execute(array(':domain_admin' => $domain_admin));
-								$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-							}
-							catch(PDOException $e) {
-								$_SESSION['return'] = array(
-									'type' => 'danger',
-									'msg' => 'MySQL: '.$e
-								);
-							}
-							while ($row_selected = array_shift($rows)):
+							foreach ($result['selected_domains'] as $domain):
 							?>
-								<option selected><?=htmlspecialchars($row_selected['domain']);?></option>
+								<option selected><?=htmlspecialchars($domain);?></option>
 							<?php
-							endwhile;
-							try {
-								$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
-									WHERE `domain` NOT IN (
-										SELECT `domain` FROM `domain_admins`
-											WHERE `username`= :domain_admin)");
-								$stmt->execute(array(':domain_admin' => $domain_admin));
-								$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-							}
-							catch(PDOException $e) {
-								$_SESSION['return'] = array(
-									'type' => 'danger',
-									'msg' => 'MySQL: '.$e
-								);
-							}
-							while ($row_unselected = array_shift($rows)):
+							endforeach;
+							foreach ($result['unselected_domains'] as $domain):
 							?>
-								<option><?=htmlspecialchars($row_unselected['domain']);?></option>
+								<option><?=htmlspecialchars($domain);?></option>
 							<?php
-							endwhile;
+							endforeach;
 							?>
 							</select>
 						</div>
@@ -167,7 +107,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
 							<div class="checkbox">
-							<label><input type="checkbox" name="active" <?php if (isset($result['active']) && $result['active']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
+							<label><input type="checkbox" name="active" <?php if (isset($result['active_int']) && $result['active_int']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['active'];?></label>
 							</div>
 						</div>
 					</div>
@@ -189,29 +129,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		is_valid_domain_name($_GET["domain"]) &&
 		!empty($_GET["domain"])) {
 			$domain = $_GET["domain"];
-			try {
-				$stmt = $pdo->prepare("SELECT * FROM `domain` WHERE `domain`='".$domain."'
-				AND (
-					`domain` IN (
-						SELECT `domain` from `domain_admins`
-							WHERE `active`='1'
-							AND `username` = :username
-					)
-					OR 'admin'= :admin
-				)");
-				$stmt->execute(array(
-					':username' => $_SESSION['mailcow_cc_username'],
-					':admin' => $_SESSION['mailcow_cc_role']
-				));
-				$result = $stmt->fetch(PDO::FETCH_ASSOC);
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-			}
-			if ($result !== false) {
+      $result = mailbox_get_domain_details($domain);
+			if (!empty($result)) {
 			?>
 				<h4><?=$lang['edit']['domain'];?></h4>
 				<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
@@ -228,34 +147,34 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					<div class="form-group">
 						<label class="control-label col-sm-2" for="aliases"><?=$lang['edit']['max_aliases'];?></label>
 						<div class="col-sm-10">
-							<input type="number" class="form-control" name="aliases" id="aliases" value="<?=intval($result['aliases']);?>">
+							<input type="number" class="form-control" name="aliases" id="aliases" value="<?=intval($result['max_num_aliases_for_domain']);?>">
 						</div>
 					</div>
 					<div class="form-group">
 						<label class="control-label col-sm-2" for="mailboxes"><?=$lang['edit']['max_mailboxes'];?></label>
 						<div class="col-sm-10">
-							<input type="number" class="form-control" name="mailboxes" id="mailboxes" value="<?=intval($result['mailboxes']);?>">
+							<input type="number" class="form-control" name="mailboxes" id="mailboxes" value="<?=intval($result['max_num_mboxes_for_domain']);?>">
 						</div>
 					</div>
 					<div class="form-group">
 						<label class="control-label col-sm-2" for="maxquota"><?=$lang['edit']['max_quota'];?></label>
 						<div class="col-sm-10">
-							<input type="number" class="form-control" name="maxquota" id="maxquota" value="<?=intval($result['maxquota']);?>">
+							<input type="number" class="form-control" name="maxquota" id="maxquota" value="<?=intval($result['max_quota_for_mbox_mib']);?>">
 						</div>
 					</div>
 					<div class="form-group">
 						<label class="control-label col-sm-2" for="quota"><?=$lang['edit']['domain_quota'];?></label>
 						<div class="col-sm-10">
-							<input type="number" class="form-control" name="quota" id="quota" value="<?=intval($result['quota']);?>">
+							<input type="number" class="form-control" name="quota" id="quota" value="<?=intval($result['max_quota_for_domain_mib']);?>">
 						</div>
 					</div>
 					<div class="form-group">
 						<label class="control-label col-sm-2"><?=$lang['edit']['backup_mx_options'];?></label>
 						<div class="col-sm-10">
 							<div class="checkbox">
-								<label><input type="checkbox" name="backupmx" <?php if (isset($result['backupmx']) && $result['backupmx']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['relay_domain'];?></label>
+								<label><input type="checkbox" name="backupmx" <?=(isset($result['backupmx_int']) && $result['backupmx_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['relay_domain'];?></label>
 								<br />
-								<label><input type="checkbox" name="relay_all_recipients" <?php if (isset($result['relay_all_recipients']) && $result['relay_all_recipients']=="1") { echo "checked"; }; ?>> <?=$lang['edit']['relay_all'];?></label>
+								<label><input type="checkbox" name="relay_all_recipients" <?=(isset($result['relay_all_recipients']) && $result['relay_all_recipients']=="1") ? "checked" : null;?>> <?=$lang['edit']['relay_all'];?></label>
 								<p><?=$lang['edit']['relay_all_info'];?></p>
 							</div>
 						</div>
@@ -266,7 +185,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
 							<div class="checkbox">
-								<label><input type="checkbox" name="active" <?php if (isset($result['active']) && $result['active']=="1") { echo "checked "; }; if ($_SESSION['mailcow_cc_role']=="domainadmin") { echo "disabled"; }; ?>> <?=$lang['edit']['active'];?></label>
+								<label><input type="checkbox" name="active" <?=(isset($result['active_int']) && $result['active_int']=="1") ? "checked" : null;?> <?=($_SESSION['mailcow_cc_role'] == "admin") ? null : "disabled";?>> <?=$lang['edit']['active'];?></label>
 							</div>
 						</div>
 					</div>
@@ -277,26 +196,137 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 				</form>
 				<?php
-				if (file_exists($GLOBALS["MC_DKIM_TXTS"]. "/" . $domain . "." . "dkim")) {
-					$pubKey = file_get_contents($GLOBALS["MC_DKIM_TXTS"]. "/" . $domain . "." . "dkim");
+				if ($pubkey = dkim_table('get', $result['domain_name'])) {
+				?>
+        <hr>
+        <div class="row">
+          <div class="col-xs-2">
+            <p>Domain: <strong><?=htmlspecialchars($result['domain_name']);?></strong> (dkim._domainkey)</p>
+          </div>
+          <div class="col-xs-10">
+            <pre><?=$pubkey;?></pre>
+          </div>
+        </div>
+				<?php
+				}
+        ?>
+		<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-xs-2">
-							<p>Domain: <strong><?=htmlspecialchars($domain);?></strong> (dkim._domainkey)</p>
-						</div>
-						<div class="col-xs-9">
-							<pre>v=DKIM1;k=rsa;t=s;s=email;p=<?=$pubKey;?></pre>
-						</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-remove-circle"></span></a>
-							<input type="hidden" name="delete_dkim_record" value="<?=htmlspecialchars($file);?>">
-							<input type="hidden" name="dkim[domain]" value="<?=$domain;?>">
-							</form>
-						</div>
+						<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="trigger_set_policy_list">
+                <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>
+          </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" id="trigger_set_policy_list" name="trigger_set_policy_list" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
+					</div>
+					</form>
+				</div>
+			</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="trigger_set_policy_list">
+                <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>
+          </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" id="trigger_set_policy_list" name="trigger_set_policy_list" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
+					</div>
+					</form>
+				</div>
+			</div>
+		</div>
+        <?php
 			}
 			else {
 			?>
@@ -308,31 +338,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 		is_valid_domain_name($_GET["aliasdomain"]) &&
 		!empty($_GET["aliasdomain"])) {
 			$alias_domain = $_GET["aliasdomain"];
-			try {
-				$stmt = $pdo->prepare("SELECT * FROM `alias_domain`
-					WHERE `alias_domain`= :alias_domain 
-					AND (
-						`target_domain` IN (
-							SELECT `domain` FROM `domain_admins`
-								WHERE `active`='1'
-								AND `username`= :username
-						)
-						OR 'admin'= :admin
-					)");
-				$stmt->execute(array(
-					':alias_domain' => $alias_domain,
-					':username' => $_SESSION['mailcow_cc_username'],
-					':admin' => $_SESSION['mailcow_cc_role']
-				));
-				$result = $stmt->fetch(PDO::FETCH_ASSOC);
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-			}
-			if ($result !== false) {
+      $result = mailbox_get_alias_domain_details($alias_domain);
+      if (!empty($result)) {
 			?>
 				<h4><?=$lang['edit']['edit_alias_domain'];?></h4>
 				<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
@@ -346,7 +353,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
 							<div class="checkbox">
-								<label><input type="checkbox" name="active" <?= (isset($result['active']) && $result['active']=="1") ?  "checked" : null ?>> <?=$lang['edit']['active'];?></label>
+								<label><input type="checkbox" name="active" <?=(isset($result['active_int']) && $result['active_int']=="1") ?  "checked" : null ?>> <?=$lang['edit']['active'];?></label>
 							</div>
 						</div>
 					</div>
@@ -357,35 +364,17 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 				</form>
 				<?php
-				$dnstxt_folder = scandir($GLOBALS["MC_DKIM_TXTS"]);
-				$dnstxt_files = array_diff($dnstxt_folder, array('.', '..'));
-				foreach($dnstxt_files as $file) {
-					if (explode("_", $file)[1] == $domain) {
-						$str = file_get_contents($GLOBALS["MC_DKIM_TXTS"]."/".$file);
-						$str = preg_replace('/\r|\t|\n/', '', $str);
-						preg_match('/\(.*\)/im', $str, $matches);
-						if(isset($matches[0])) {
-							$str = str_replace(array(' ', '"', '(', ')'), '', $matches[0]);
-						}
+				if ($pubkey = dkim_table('get', $result['alias_domain'])) {
 				?>
-						<div class="row">
-							<div class="col-xs-2">
-								<p class="text-right"><?=$lang['edit']['dkim_signature'];?></p>
-							</div>
-							<div class="col-xs-10">
-								<div class="col-md-2"><b><?=$lang['edit']['dkim_txt_name'];?></b></div>
-								<div class="col-md-10">
-									<pre><?=htmlspecialchars(explode("_", $file)[0]);?>._domainkey</pre>
-								</div>
-								<div class="col-md-2"><b><?=$lang['edit']['dkim_txt_value'];?></b></div>
-								<div class="col-md-10">
-									<pre><?=htmlspecialchars($str);?></pre>
-									<?=$lang['edit']['dkim_record_info'];?>
-								</div>
-							</div>
+					<div class="row">
+						<div class="col-xs-2">
+							<p>Domain: <strong><?=htmlspecialchars($result['alias_domain']);?></strong> (dkim._domainkey)</p>
 						</div>
+						<div class="col-xs-10">
+							<pre><?=$pubkey;?></pre>
+						</div>
+					</div>
 				<?php
-					}
 				}
 			}
 			else {
@@ -396,22 +385,10 @@ 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"];
-			try {
-				$stmt = $pdo->prepare("SELECT `username`, `domain`, `name`, `quota`, `active` FROM `mailbox` WHERE `username` = :username1");
-				$stmt->execute(array(
-					':username1' => $mailbox,
-				));
-				$result = $stmt->fetch(PDO::FETCH_ASSOC);
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-			}
-			if ($result !== false && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $result['domain'])) {
-				$left_m = remaining_specs($result['domain'], $_GET['mailbox'])['left_m'];
-			?>
+      $result = mailbox_get_mailbox_details($mailbox);
+      if (!empty($result)) {
+        $left_m = remaining_specs($result['domain'], $_GET['mailbox'])['left_m'];
+        ?>
 				<h4><?=$lang['edit']['mailbox'];?></h4>
 				<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
 				<input type="hidden" name="username" value="<?=htmlspecialchars($result['username']);?>">
@@ -426,55 +403,59 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 							<br /><span id="quotaBadge" class="badge">max. <?=intval($left_m)?> MiB</span>
 						</label>
 						<div class="col-sm-10">
-							<input type="number" name="quota" id="quota" id="destroyable" style="width:100%" min="1" max="<?=intval($left_m);?>" value="<?=intval($result['quota']) / 1048576;?>" class="form-control">
+							<input type="number" name="quota" id="quota" id="destroyable" style="width:100%" min="1" max="<?=intval($left_m);?>" value="<?=intval($result['quota_bytes']) / 1048576;?>" class="form-control">
 						</div>
 					</div>
 					<div class="form-group">
 						<label class="control-label col-sm-2" for="sender_acl"><?=$lang['edit']['sender_acl'];?>:</label>
 						<div class="col-sm-10">
-							<select style="width:100%" id="sender_acl" name="sender_acl[]" size="10" multiple>
+							<select data-width="50%" style="width:100%" id="sender_acl" name="sender_acl[]" size="10" multiple>
 							<?php
-							$rows = get_sender_acl_handles($mailbox, "preselected");
-							while ($row_goto_from_alias = array_shift($rows)):
-							?>
-								<option disabled selected><?=htmlspecialchars($row_goto_from_alias['address']);?></option>
-							<?php
-							endwhile;
+							$sender_acl_handles = get_sender_acl_handles($mailbox);
 
-							// All manual selected
-							$rows = get_sender_acl_handles($mailbox, "selected");
-							while ($row_selected_sender_acl = array_shift($rows)):
-									if (!filter_var($row_selected_sender_acl['send_as'], FILTER_VALIDATE_EMAIL)):
-									?>
-										<option data-divider="true"></option>
-											<option value="<?=htmlspecialchars($row_selected_sender_acl['send_as']);?>" selected><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], str_replace('@', '', $row_selected_sender_acl['send_as'])));?></option>
-										<option data-divider="true"></option>
-									<?php
-									else:
-									?>
-										<option selected><?=htmlspecialchars($row_selected_sender_acl['send_as']);?></option>
-									<?php
-									endif;
-							endwhile;
-							
-							// Unselected domains
-							$rows = get_sender_acl_handles($mailbox, "unselected-domains");
-							while ($row_unselected_sender_acl = array_shift($rows)):
-							?>
-								<option data-divider="true"></option>
-									<option value="@<?=htmlspecialchars($row_unselected_sender_acl['domain']);?>"><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $row_unselected_sender_acl['domain']));?></option>
-								<option data-divider="true"></option>
-							<?php
-							endwhile;
+              foreach ($sender_acl_handles['sender_acl_domains']['ro'] as $domain):
+                ?>
+                <option data-subtext="Admin" value="<?=htmlspecialchars($domain);?>" disabled selected><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
+                <?php
+              endforeach;
 
-							// Unselected addresses
-							$rows = get_sender_acl_handles($mailbox, "unselected-addresses");
-							while ($row_unselected_sender_acl = array_shift($rows)):
-							?>
-								<option><?=htmlspecialchars($row_unselected_sender_acl['address']);?></option>
-							<?php
-							endwhile;
-							?>
+              foreach ($sender_acl_handles['sender_acl_addresses']['ro'] as $domain):
+                ?>
+              <option data-subtext="Admin" disabled selected><?=htmlspecialchars($alias);?></option>
+                <?php
+              endforeach;
+
+              foreach ($sender_acl_handles['fixed_sender_aliases'] as $alias):
+                ?>
+								<option data-subtext="Alias" disabled selected><?=htmlspecialchars($alias);?></option>
+                <?php
+              endforeach;
+
+              foreach ($sender_acl_handles['sender_acl_domains']['rw'] as $domain):
+                ?>
+                <option value="<?=htmlspecialchars($domain);?>" selected><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
+                <?php
+              endforeach;
+
+              foreach ($sender_acl_handles['sender_acl_domains']['selectable'] as $domain):
+                ?>
+                <option value="<?=htmlspecialchars($domain);?>"><?=htmlspecialchars(sprintf($lang['edit']['dont_check_sender_acl'], $domain));?></option>
+                <?php
+              endforeach;
+
+              foreach ($sender_acl_handles['sender_acl_addresses']['rw'] as $address):
+                ?>
+                  <option selected><?=htmlspecialchars($address);?></option>
+                <?php
+              endforeach;
+
+              foreach ($sender_acl_handles['sender_acl_addresses']['selectable'] as $address):
+                ?>
+                  <option><?=htmlspecialchars($address);?></option>
+                <?php
+              endforeach;
+
+              ?>
 							</select>
 						</div>
 					</div>
@@ -493,7 +474,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
 							<div class="checkbox">
-							<label><input type="checkbox" name="active" <?=($result['active']=="1") ? "checked" : "";?>> <?=$lang['edit']['active'];?></label>
+							<label><input type="checkbox" name="active" <?=($result['active_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['active'];?></label>
 							</div>
 						</div>
 					</div>
@@ -519,25 +500,10 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 }
 elseif (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "user")) {
 	if (isset($_GET['syncjob']) &&
-    is_numeric($_GET["syncjob"]) &&
-    filter_var($_SESSION['mailcow_cc_username'], FILTER_VALIDATE_EMAIL)) {
+    is_numeric($_GET['syncjob'])) {
 			$id = $_GET["syncjob"];
-      $username = $_SESSION['mailcow_cc_username'];
-			try {
-				$stmt = $pdo->prepare("SELECT * FROM `imapsync` WHERE `user2` = :username AND id = :id");
-				$stmt->execute(array(
-					':username' => $username,
-					':id' => $id
-				));
-				$result = $stmt->fetch(PDO::FETCH_ASSOC);
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-      }
-      if ($result && !empty($result)) {
+      $result = get_syncjob_details($id);
+      if (!empty($result)) {
 			?>
 				<h4><?=$lang['edit']['syncjob'];?></h4>
 				<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
diff --git a/data/web/inc/footer.inc.php b/data/web/inc/footer.inc.php
index d2adca8e..642242a4 100644
--- a/data/web/inc/footer.inc.php
+++ b/data/web/inc/footer.inc.php
@@ -21,6 +21,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admi
 <?php
 endif;
 ?>
+<div style="margin-bottom:100px"></div>
 <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
 <script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/js/bootstrap-switch.min.js"></script>
 <script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/7.0.2/bootstrap-slider.min.js"></script>
@@ -33,6 +34,9 @@ function setLang(sel) {
 }
 
 $(document).ready(function() {
+  $(function () {
+    $('[data-toggle="tooltip"]').tooltip()
+  })
 	// Hide alerts after n seconds
 	$("#alert-fade").fadeTo(7000, 500).slideUp(500, function(){
 		$("#alert-fade").alert('close');
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index c21b6d2a..f259461d 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -15,22 +15,52 @@ function hasDomainAccess($username, $role, $domain) {
 		return false;
 	}
 	try {
-		$stmt = $pdo->prepare("SELECT `domain` FROM `domain_admins`
-			WHERE (
-				`active`='1'
-				AND `username` = :username
-				AND `domain` = :domain
-			)
-			OR 'admin' = :role");
-		$stmt->execute(array(':username' => $username, ':domain' => $domain, ':role' => $role));
+		$stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain` = :domain1
+      AND (`domain` in (
+        SELECT `domain` FROM `domain_admins`
+          WHERE (
+            `username` = :username
+            AND `domain` = :domain2
+          )
+      ) OR 'admin' = :role)");
+		$stmt->execute(array(':username' => $username, ':domain1' => $domain, ':domain2' => $domain, ':role' => $role));
 		$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
-	} catch(PDOException $e) {
-		error_log($e);
+	}
+  catch(PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+    return false;
+  }
+	if (!empty($num_results)) {
+		return true;
+	}
+	return false;
+}
+function hasMailboxObjectAccess($username, $role, $object) {
+	global $pdo;
+	if (!filter_var($username, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) {
+		return false;
+	}
+	if ($role != 'admin' && $role != 'domainadmin' && $role != 'user') {
 		return false;
 	}
-	if ($num_results != 0 && !empty($num_results)) {
+	if ($username == $object) {
 		return true;
 	}
+	try {
+		$stmt = $pdo->prepare("SELECT `domain` FROM `mailbox` WHERE `username` = :object");
+		$stmt->execute(array(':object' => $object));
+		$row = $stmt->fetch(PDO::FETCH_ASSOC);
+    if (isset($row['domain']) && hasDomainAccess($username, $role, $row['domain'])) {
+      return true;
+    }
+	}
+  catch(PDOException $e) {
+		error_log($e);
+		return false;
+	}
 	return false;
 }
 function init_db_schema() {
@@ -187,15 +217,23 @@ function formatBytes($size, $precision = 2) {
 }
 function dkim_table($action, $item) {
 	global $lang;
+	global $pdo;
 	switch ($action) {
 		case "delete":
+    	if ($_SESSION['mailcow_cc_role'] != "admin") {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['access_denied'])
+        );
+        return false;
+      }
 			$domain = preg_replace('/[^A-Za-z0-9._\-]/', '_', $item['dkim']['domain']);
 			if (!is_valid_domain_name($domain)) {
 				$_SESSION['return'] = array(
 					'type' => 'danger',
 					'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
 				);
-				break;
+				return false;
 			}
 			exec('rm ' . escapeshellarg($GLOBALS['MC_DKIM_TXTS'] . '/' . $domain . '.dkim'), $out, $return);
 			if ($return != "0") {
@@ -203,39 +241,46 @@ function dkim_table($action, $item) {
 					'type' => 'danger',
 					'msg' => sprintf($lang['danger']['dkim_remove_failed'])
 				);
-				break;
+				return false;
 			}
 			exec('rm ' . escapeshellarg($GLOBALS['MC_DKIM_KEYS'] . '/' . $domain . '.dkim'), $out, $return);
-            if ($return != "0") {
-                $_SESSION['return'] = array(
-                    'type' => 'danger',
-                    'msg' => sprintf($lang['danger']['dkim_remove_failed'])
-                );
-                break;
-            }
+      if ($return != "0") {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['dkim_remove_failed'])
+        );
+        return false;
+      }
 			$_SESSION['return'] = array(
 				'type' => 'success',
 				'msg' => sprintf($lang['success']['dkim_removed'])
 			);
 			break;
 		case "add":
+    	if ($_SESSION['mailcow_cc_role'] != "admin") {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['access_denied'])
+        );
+        return false;
+      }
 			$domain = preg_replace('/[^A-Za-z0-9._\-]/', '_', $item['dkim']['domain']);
 			$key_length	= intval($item['dkim']['key_size']);
-            if (!is_valid_domain_name($domain) || !is_numeric($key_length)) {
-                $_SESSION['return'] = array(
-                    'type' => 'danger',
-                    'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
-                );
-                break;
-            }
-
-            if (!empty(glob($GLOBALS['MC_DKIM_TXTS'] . '/' . $domain . '.dkim'))) {
-                $_SESSION['return'] = array(
-                    'type' => 'danger',
-                    'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
-                );
-                break;
-            }
+      if (!is_valid_domain_name($domain) || !is_numeric($key_length)) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
+        );
+        return false;
+      }
+
+      if (!empty(glob($GLOBALS['MC_DKIM_TXTS'] . '/' . $domain . '.dkim'))) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['dkim_domain_or_sel_invalid'])
+        );
+        return false;
+      }
 
 			$config = array(
 				"digest_alg" => "sha256",
@@ -259,6 +304,67 @@ function dkim_table($action, $item) {
 				'msg' => sprintf($lang['success']['dkim_added'])
 			);
 			break;
+		case "get":
+      try {
+        $stmt = $pdo->prepare("SELECT `target_domain`
+          FROM `alias_domain`
+            WHERE `alias_domain` = :item");
+        $stmt->execute(array(':item' => $item));
+        $AdDomainData = $stmt->fetch(PDO::FETCH_ASSOC);
+      }
+      catch(PDOException $e) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => 'MySQL: '.$e
+        );
+        return false;
+      }
+      (is_valid_domain_name($AdDomainData['target_domain'])) ? $item = $AdDomainData['target_domain'] : null;
+    	if (!isset($_SESSION['mailcow_cc_role'])) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['access_denied'])
+        );
+        return false;
+      }
+      $dkim_pubkey_file = escapeshellarg($GLOBALS["MC_DKIM_TXTS"]. "/" . $item . "." . "dkim");
+      if (file_exists(substr($dkim_pubkey_file, 1, -1))) {
+        return 'v=DKIM1;k=rsa;t=s;s=email;p=' . file_get_contents($GLOBALS["MC_DKIM_TXTS"]. "/" . $item . "." . "dkim");
+      }
+      return false;
+			break;
+		case "keys-without-domain":
+    	if ($_SESSION['mailcow_cc_role'] != "admin") {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['access_denied'])
+        );
+        return false;
+      }
+      $dnstxt_folder = scandir($GLOBALS["MC_DKIM_TXTS"]);
+      $dnstxt_files = array_diff($dnstxt_folder, array('.', '..'));
+      foreach($dnstxt_files as $file) {
+        $pubKey = file_get_contents($GLOBALS["MC_DKIM_TXTS"]."/".$file);
+        $domains[] = substr($file, 0, -5);
+      }
+      return array_diff($domains, mailbox_get_domains());
+      break;
+		case "domains-without-key":
+    	if ($_SESSION['mailcow_cc_role'] != "admin") {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['access_denied'])
+        );
+        return false;
+      }
+      $dnstxt_folder = scandir($GLOBALS["MC_DKIM_TXTS"]);
+      $dnstxt_files = array_diff($dnstxt_folder, array('.', '..'));
+      foreach($dnstxt_files as $file) {
+        $pubKey = file_get_contents($GLOBALS["MC_DKIM_TXTS"]."/".$file);
+        $domains[] = substr($file, 0, -5);
+      }
+      return array_diff(mailbox_get_domains(), $domains);
+      break;
 	}
 }
 function mailbox_add_domain($postarray) {
@@ -366,6 +472,7 @@ function mailbox_add_domain($postarray) {
 		);
 	}
 	catch (PDOException $e) {
+    mailbox_delete_domain(array('domain' => $domain));
 		$_SESSION['return'] = array(
 			'type' => 'danger',
 			'msg' => 'MySQL: '.$e
@@ -413,43 +520,37 @@ function mailbox_add_alias($postarray) {
 				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) {
-			$_SESSION['return'] = array(
-				'type' => 'danger',
-				'msg' => sprintf($lang['danger']['domain_not_found'], $domain)
-			);
-			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;
-		}
+      if ($num_results == 0) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['domain_not_found'], $domain)
+        );
+        return false;
+      }
 
-		try {
 			$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(
@@ -458,31 +559,19 @@ function mailbox_add_alias($postarray) {
 			);
 			return false;
 		}
-		if ($num_results != 0) {
-			$_SESSION['return'] = array(
-				'type' => 'danger',
-				'msg' => sprintf($lang['danger']['is_alias_or_mailbox'], htmlspecialchars($address))
-			);
-			return false;
-		}
 
-		try {
-			$stmt = $pdo->prepare("SELECT `address` FROM `spamalias`
-				WHERE `address`= :address");
-			$stmt->execute(array(':address' => $address));
-			$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
-		}
-		catch(PDOException $e) {
+		if ((!filter_var($address, FILTER_VALIDATE_EMAIL) === true) && !empty($local_part)) {
 			$_SESSION['return'] = array(
 				'type' => 'danger',
-				'msg' => 'MySQL: '.$e
+				'msg' => sprintf($lang['danger']['alias_invalid'])
 			);
 			return false;
 		}
-		if ($num_results != 0) {
+
+		if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
 			$_SESSION['return'] = array(
 				'type' => 'danger',
-				'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($address))
+				'msg' => sprintf($lang['danger']['access_denied'])
 			);
 			return false;
 		}
@@ -545,6 +634,7 @@ function mailbox_add_alias($postarray) {
 			);
 		}
 		catch (PDOException $e) {
+      mailbox_delete_alias(array('address' => $address));
 			$_SESSION['return'] = array(
 				'type' => 'danger',
 				'msg' => 'MySQL: '.$e
@@ -605,29 +695,27 @@ function mailbox_add_alias_domain($postarray) {
 			WHERE `domain`= :target_domain");
 		$stmt->execute(array(':target_domain' => $target_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) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['targetd_not_found'])
-		);
-		return false;
-	}
+    if ($num_results == 0) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['targetd_not_found'])
+      );
+      return false;
+    }
 
-	try {
 		$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',
@@ -635,13 +723,6 @@ function mailbox_add_alias_domain($postarray) {
 		);
 		return false;
 	}
-	if ($num_results != 0) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['aliasd_exists'])
-		);
-		return false;
-	}
 
 	try {
 		$stmt = $pdo->prepare("INSERT INTO `alias_domain` (`alias_domain`, `target_domain`, `created`, `modified`, `active`)
@@ -659,102 +740,13 @@ function mailbox_add_alias_domain($postarray) {
 		);
 	}
 	catch (PDOException $e) {
+    mailbox_delete_alias_domain(array('alias_domain' => $alias_domain));
 		$_SESSION['return'] = array(
 			'type' => 'danger',
 			'msg' => 'MySQL: '.$e
 		);
 		return false;
 	}
-
-}
-function mailbox_edit_alias_domain($postarray) {
-  // Array elements
-  // active             int
-  // alias_domain_now   string
-  // alias_domain       string
-	global $lang;
-	global $pdo;
-	isset($postarray['active']) ? $active = '1' : $active = '0';
-	$alias_domain       = idn_to_ascii(strtolower(trim($postarray['alias_domain'])));
-	$alias_domain_now   = strtolower(trim($postarray['alias_domain_now']));
-	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($alias_domain_now)) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['alias_domain_invalid'])
-		);
-		return false;
-	}
-
-	try {
-		$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
-				WHERE `alias_domain`= :alias_domain_now");
-		$stmt->execute(array(':alias_domain_now' => $alias_domain_now));
-		$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("SELECT `target_domain` FROM `alias_domain`
-		WHERE `target_domain`= :alias_domain");
-		$stmt->execute(array(':alias_domain' => $alias_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) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['aliasd_targetd_identical'])
-		);
-		return false;
-	}
-
-	try {
-		$stmt = $pdo->prepare("UPDATE `alias_domain` SET `alias_domain` = :alias_domain, `active` = :active WHERE `alias_domain` = :alias_domain_now");
-		$stmt->execute(array(
-			':alias_domain' => $alias_domain,
-			':alias_domain_now' => $alias_domain_now,
-			':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($alias_domain))
-	);
 }
 function mailbox_add_mailbox($postarray) {
   // Array elements
@@ -808,21 +800,20 @@ function mailbox_add_mailbox($postarray) {
 		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);
-	}
-	catch(PDOException $e) {
+	if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
-			'msg' => 'MySQL: '.$e
+			'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`
@@ -830,68 +821,51 @@ function mailbox_add_mailbox($postarray) {
 					WHERE `domain` = :domain");
 		$stmt->execute(array(':domain' => $domain));
 		$MailboxData = $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;
-	}
 
-	try {
 		$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));
-	}
-	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($username))
-		);
-		return false;
-	}
+    if ($num_results != 0) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($username))
+      );
+      return false;
+    }
 
-	try {
 		$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :username");
 		$stmt->execute(array(':username' => $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']['is_alias'], htmlspecialchars($username))
-		);
-		return false;
-	}
+    if ($num_results != 0) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['is_alias'], htmlspecialchars($username))
+      );
+      return false;
+    }
 
-	try {
 		$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',
@@ -899,13 +873,6 @@ function mailbox_add_mailbox($postarray) {
 		);
 		return false;
 	}
-	if ($num_results != 0) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($username))
-		);
-		return false;
-	}
 
 	if (!is_numeric($quota_m) || $quota_m == "0") {
 		$_SESSION['return'] = array(
@@ -941,26 +908,6 @@ function mailbox_add_mailbox($postarray) {
 		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));
-	}
-	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_not_found'], $domain)
-		);
-		return false;
-	}
-
 	if ($quota_m > $DomainData['maxquota']) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
@@ -1014,6 +961,91 @@ function mailbox_add_mailbox($postarray) {
 			'msg' => sprintf($lang['success']['mailbox_added'], htmlspecialchars($username))
 		);
 	}
+	catch (PDOException $e) {
+    mailbox_delete_mailbox(array('address' => $username));
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => 'MySQL: '.$e
+		);
+		return false;
+	}
+}
+function mailbox_edit_alias_domain($postarray) {
+  // Array elements
+  // active             int
+  // alias_domain_now   string
+  // alias_domain       string
+	global $lang;
+	global $pdo;
+	isset($postarray['active']) ? $active = '1' : $active = '0';
+	$alias_domain       = idn_to_ascii(strtolower(trim($postarray['alias_domain'])));
+	$alias_domain_now   = strtolower(trim($postarray['alias_domain_now']));
+	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($alias_domain_now)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['alias_domain_invalid'])
+		);
+		return false;
+	}
+
+	try {
+		$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
+				WHERE `alias_domain`= :alias_domain_now");
+		$stmt->execute(array(':alias_domain_now' => $alias_domain_now));
+		$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("SELECT `target_domain` FROM `alias_domain`
+		WHERE `target_domain`= :alias_domain");
+		$stmt->execute(array(':alias_domain' => $alias_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) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['aliasd_targetd_identical'])
+		);
+		return false;
+	}
+
+	try {
+		$stmt = $pdo->prepare("UPDATE `alias_domain` SET `alias_domain` = :alias_domain, `active` = :active WHERE `alias_domain` = :alias_domain_now");
+		$stmt->execute(array(
+			':alias_domain' => $alias_domain,
+			':alias_domain_now' => $alias_domain_now,
+			':active' => $active
+		));
+	}
 	catch (PDOException $e) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
@@ -1021,6 +1053,11 @@ function mailbox_add_mailbox($postarray) {
 		);
 		return false;
 	}
+
+	$_SESSION['return'] = array(
+		'type' => 'success',
+		'msg' => sprintf($lang['success']['aliasd_modified'], htmlspecialchars($alias_domain))
+	);
 }
 function mailbox_edit_alias($postarray) {
   // Array elements
@@ -1112,138 +1149,408 @@ function mailbox_edit_domain($postarray) {
 
 	global $lang;
 	global $pdo;
-	$domain       = idn_to_ascii($postarray['domain']);
-	$description  = $postarray['description'];
-
-	$aliases		= filter_var($postarray['aliases'], FILTER_SANITIZE_NUMBER_FLOAT);
-	$mailboxes  = filter_var($postarray['mailboxes'], FILTER_SANITIZE_NUMBER_FLOAT);
-	$maxquota		= filter_var($postarray['maxquota'], FILTER_SANITIZE_NUMBER_FLOAT);
-	$quota			= filter_var($postarray['quota'], FILTER_SANITIZE_NUMBER_FLOAT);
-
-	isset($postarray['relay_all_recipients']) ? $relay_all_recipients = '1' : $relay_all_recipients = '0';
-	isset($postarray['backupmx']) ? $backupmx = '1' : $backupmx = '0';
-	isset($postarray['relay_all_recipients']) ? $backupmx = '1' : true;
-	isset($postarray['active']) ? $active = '1' : $active = '0';
-
-	try {
-		$stmt = $pdo->prepare("SELECT 
-				COUNT(*) AS count,
-				MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `maxquota`,
-				COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota`
-					FROM `mailbox`
-						WHERE domain= :domain");
-		$stmt->execute(array(':domain' => $domain));
-		$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
-	}
-	catch(PDOException $e) {
+  
+  $domain       = idn_to_ascii($postarray['domain']);
+	if (!is_valid_domain_name($domain)) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
-			'msg' => 'MySQL: '.$e
+			'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  = $postarray['description'];
+    isset($postarray['active']) ? $active = '1' : $active = '0';
+    try {
+      $stmt = $pdo->prepare("UPDATE `domain` SET 
+      `modified`= :modified,
+      `description` = :description
+        WHERE `domain` = :domain");
+      $stmt->execute(array(
+        ':modified' => date('Y-m-d H:i:s'),
+        ':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") {
+    $description  = $postarray['description'];
+    isset($postarray['active']) ? $active = '1' : $active = '0';
+    $aliases		= filter_var($postarray['aliases'], FILTER_SANITIZE_NUMBER_FLOAT);
+    $mailboxes  = filter_var($postarray['mailboxes'], FILTER_SANITIZE_NUMBER_FLOAT);
+    $maxquota		= filter_var($postarray['maxquota'], FILTER_SANITIZE_NUMBER_FLOAT);
+    $quota			= filter_var($postarray['quota'], FILTER_SANITIZE_NUMBER_FLOAT);
+    isset($postarray['relay_all_recipients']) ? $relay_all_recipients = '1' : $relay_all_recipients = '0';
+    isset($postarray['backupmx']) ? $backupmx = '1' : $backupmx = '0';
+    isset($postarray['relay_all_recipients']) ? $backupmx = '1' : true;
+    try {
+      // GET MAILBOX DATA
+      $stmt = $pdo->prepare("SELECT 
+          COUNT(*) AS count,
+          MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `maxquota`,
+          COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota`
+            FROM `mailbox`
+              WHERE domain= :domain");
+      $stmt->execute(array(':domain' => $domain));
+      $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
+      // GET ALIAS DATA
+      $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;
+    }
 
-	try {
-		$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 (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['access_denied'])
-		);
-		return false;
-	}
-	
-	if ($maxquota > $quota) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['mailbox_quota_exceeds_domain_quota'])
-		);
-		return false;
-	}
-	
-	if ($MailboxData['maxquota'] > $maxquota) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['max_quota_in_use'], $MailboxData['maxquota'])
-		);
-		return false;
-	}
-	
-	if ($MailboxData['quota'] > $quota) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['domain_quota_m_in_use'], $MailboxData['quota'])
-		);
-		return false;
-	}
-	
-	if ($MailboxData['count'] > $mailboxes) {
-		$_SESSION['return'] = array(
+    if ($MailboxData['maxquota'] > $maxquota) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['max_quota_in_use'], $MailboxData['maxquota'])
+      );
+      return false;
+    }
+
+    if ($MailboxData['quota'] > $quota) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['domain_quota_m_in_use'], $MailboxData['quota'])
+      );
+      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 
+      `modified`= :modified,
+      `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,
+        ':modified' => date('Y-m-d H:i:s'),
+        ':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;
+    }
+  }
+}
+function mailbox_edit_mailbox($postarray) {
+	global $lang;
+	global $pdo;
+	isset($postarray['active']) ? $active = '1' : $active = '0';
+	if (!filter_var($postarray['username'], FILTER_VALIDATE_EMAIL)) {
+		$_SESSION['return'] = array(
 			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['mailboxes_in_use'], $MailboxData['count'])
+			'msg' => sprintf($lang['danger']['username_invalid'])
 		);
 		return false;
 	}
-	
-	if ($AliasData['count'] > $aliases) {
+	$quota_m      = $postarray['quota'];
+	$quota_b      = $quota_m*1048576;
+	$username     = $postarray['username'];
+	$name         = $postarray['name'];
+	$password     = $postarray['password'];
+	$password2    = $postarray['password2'];
+
+	try {
+		$stmt = $pdo->prepare("SELECT `domain`
+			FROM `mailbox`
+				WHERE username = :username");
+		$stmt->execute(array(':username' => $username));
+		$MailboxData1 = $stmt->fetch(PDO::FETCH_ASSOC);
+
+		$stmt = $pdo->prepare("SELECT 
+			COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota_m_now`
+				FROM `mailbox`
+					WHERE `username` = :username");
+		$stmt->execute(array(':username' => $username));
+		$MailboxData2 = $stmt->fetch(PDO::FETCH_ASSOC);
+
+		$stmt = $pdo->prepare("SELECT 
+			COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota_m_in_use`
+				FROM `mailbox`
+					WHERE `domain` = :domain");
+		$stmt->execute(array(':domain' => $MailboxData1['domain']));
+		$MailboxData3 = $stmt->fetch(PDO::FETCH_ASSOC);
+
+		$stmt = $pdo->prepare("SELECT `quota`, `maxquota`
+			FROM `domain`
+				WHERE `domain` = :domain");
+		$stmt->execute(array(':domain' => $MailboxData1['domain']));
+		$DomainData = $stmt->fetch(PDO::FETCH_ASSOC);
+	}
+	catch(PDOException $e) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['aliases_in_use'], $AliasData['count'])
+			'msg' => 'MySQL: '.$e
 		);
 		return false;
 	}
 
-	if (!is_valid_domain_name($domain)) {
+	if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $MailboxData1['domain'])) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['domain_invalid'])
+			'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 (($MailboxData3['quota_m_in_use'] - $MailboxData2['quota_m_now'] + $quota_m) > $DomainData['quota']) {
+		$quota_left_m = ($DomainData['quota'] - $MailboxData3['quota_m_in_use'] + $MailboxData2['quota_m_now']);
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['mailbox_quota_left_exceeded'], $quota_left_m)
 		);
 		return false;
 	}
+
+  // Get sender_acl items set by admin
+  $sender_acl_admin = array_merge(
+    get_sender_acl_handles($username)['sender_acl_domains']['ro'],
+    get_sender_acl_handles($username)['sender_acl_addresses']['ro']
+  );
+
+  // Get sender_acl items from POST array
+  (isset($postarray['sender_acl'])) ? $sender_acl_domain_admin = $postarray['sender_acl'] : $sender_acl_domain_admin = array();
+
+	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 ($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
+					`modified` = :modified,
+					`active` = :active
+						WHERE `address` = :address");
+			$stmt->execute(array(
+				':address' => $username,
+				':modified' => date('Y-m-d H:i:s'),
+				':active' => $active
+			));
+			$stmt = $pdo->prepare("UPDATE `mailbox` SET
+					`modified` = :modified,
+					`active` = :active,
+					`password` = :password_hashed,
+					`name`= :name,
+					`quota` = :quota_b
+						WHERE `username` = :username");
+			$stmt->execute(array(
+				':modified' => date('Y-m-d H:i:s'),
+				':password_hashed' => $password_hashed,
+				':active' => $active,
+				':name' => $name,
+				':quota_b' => $quota_b,
+				':username' => $username
+			));
+			$_SESSION['return'] = array(
+				'type' => 'success',
+				'msg' => sprintf($lang['success']['mailbox_modified'], $username)
+			);
+			return true;
+		}
+		catch (PDOException $e) {
+			$_SESSION['return'] = array(
+				'type' => 'danger',
+				'msg' => 'MySQL: '.$e
+			);
+			return false;
+		}
+	}
 	try {
-		$stmt = $pdo->prepare("UPDATE `domain` SET 
-		`modified`= :modified,
-		`relay_all_recipients` = :relay_all_recipients,
-		`backupmx` = :backupmx,
-		`active` = :active,
-		`quota` = :quota,
-		`maxquota` = :maxquota,
-		`mailboxes` = :mailboxes,
-		`aliases` = :aliases,
-		`description` = :description
-			WHERE `domain` = :domain");
+		$stmt = $pdo->prepare("UPDATE `alias` SET
+				`modified` = :modified,
+				`active` = :active
+					WHERE `address` = :address");
+		$stmt->execute(array(
+			':address' => $username,
+			':modified' => date('Y-m-d H:i:s'),
+			':active' => $active
+		));
+		$stmt = $pdo->prepare("UPDATE `mailbox` SET
+				`modified` = :modified,
+				`active` = :active,
+				`name`= :name,
+				`quota` = :quota_b
+					WHERE `username` = :username");
 		$stmt->execute(array(
-			':relay_all_recipients' => $relay_all_recipients,
-			':backupmx' => $backupmx,
 			':active' => $active,
-			':quota' => $quota,
-			':maxquota' => $maxquota,
-			':mailboxes' => $mailboxes,
-			':aliases' => $aliases,
 			':modified' => date('Y-m-d H:i:s'),
-			':description' => $description,
-			':domain' => $domain
+			':name' => $name,
+			':quota_b' => $quota_b,
+			':username' => $username
 		));
 		$_SESSION['return'] = array(
 			'type' => 'success',
-			'msg' => sprintf($lang['success']['domain_modified'], htmlspecialchars($domain))
+			'msg' => sprintf($lang['success']['mailbox_modified'], $username)
 		);
+		return true;
 	}
 	catch (PDOException $e) {
 		$_SESSION['return'] = array(
@@ -1252,7 +1559,6 @@ function mailbox_edit_domain($postarray) {
 		);
 		return false;
 	}
-
 }
 function mailbox_get_mailboxes($domain) {
 	global $lang;
@@ -1355,6 +1661,7 @@ function mailbox_get_alias_details($address) {
       `domain`,
       `goto`,
       `address`,
+      `active` as `active_int`,
       CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
       `created`,
       `modified`
@@ -1370,8 +1677,16 @@ function mailbox_get_alias_details($address) {
       $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'])) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['access_denied'])
+        );
+        return false;
+      }
     }
   }
   catch (PDOException $e) {
@@ -1381,13 +1696,6 @@ function mailbox_get_alias_details($address) {
     );
     return false;
   }
-  if (isset($aliasdata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $aliasdata['domain'])) {
-    $_SESSION['return'] = array(
-      'type' => 'danger',
-      'msg' => sprintf($lang['danger']['access_denied'])
-    );
-    return false;
-  }
   return $aliasdata;
 }
 function mailbox_get_alias_domain_details($aliasdomain) {
@@ -1398,6 +1706,7 @@ function mailbox_get_alias_domain_details($aliasdomain) {
     $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`
@@ -1411,6 +1720,7 @@ function mailbox_get_alias_domain_details($aliasdomain) {
       $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'];
     }
@@ -1462,339 +1772,146 @@ function mailbox_get_domains() {
   }
   return $domains;
 }
-function mailbox_get_domain_details($domain) {
-	global $lang;
-	global $pdo;
-
-	$domain = idn_to_ascii(strtolower(trim($domain)));
-
-	if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['access_denied'])
-		);
-		return false;
-	}
-
-  try {
-    $stmt = $pdo->prepare("SELECT 
-        `domain`,
-        `aliases`,
-        `mailboxes`, 
-        `maxquota`,
-        `quota`,
-        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' => $domain,
-    ));
-    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-    while($row = array_shift($rows)) {
-      $domaindata['domain_name'] = $row['domain'];
-      $domaindata['max_num_aliases_for_domain'] = $row['aliases'];
-      $domaindata['max_num_mboxes_for_domain'] = $row['mailboxes'];
-      $domaindata['max_quota_for_mbox'] = formatBytes(intval($row['maxquota'] * 1048576), 2);
-      $domaindata['max_quota_for_domain'] = formatBytes(intval($row['quota'] * 1048576), 2);
-      $domaindata['backupmx'] = $row['backupmx'];
-      $domaindata['active'] = $row['active'];
-    }
-
-    $stmt = $pdo->prepare("SELECT COUNT(*) AS `alias_count` FROM `alias`
-      WHERE `domain`= :domain
-        AND `address` NOT IN (
-          SELECT `username` FROM `mailbox`
-        )");
-    $stmt->execute(array(
-      ':domain' => $domain,
-    ));
-    $row = $stmt->fetchAll();
-    $domaindata['aliases_in_domain'] = $row[0]['alias_count'];
-
-    $stmt = $pdo->prepare("SELECT COUNT(`username`) AS `mailbox_count`, SUM(`quota`) AS `quota` FROM `mailbox`
-        WHERE `domain` = :domain");
-    $stmt->execute(array(
-      ':domain' => $domain,
-    ));
-    $row = $stmt->fetchAll();
-    $domaindata['mboxes_in_domain'] = $row[0]['mailbox_count'];
-    $domaindata['quota_used_in_domain'] = formatBytes(intval($row[0]['quota']), 2);
-  }
-  catch (PDOException $e) {
-    $_SESSION['return'] = array(
-      'type' => 'danger',
-      'msg' => 'MySQL: '.$e
-    );
-    return false;
-  }
-
-  return $domaindata;
-}
-function mailbox_get_mailbox_details($mailbox) {
-	global $lang;
-	global $pdo;
-  try {
-    $stmt = $pdo->prepare("SELECT
-        `domain`.`backupmx`,
-        `mailbox`.`username`,
-        `mailbox`.`name`,
-        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`.`username` = `quota2`.`username` AND `domain`.`domain` = `mailbox`.`domain` AND `mailbox`.`username` = :mailbox");
-    $stmt->execute(array(
-      ':mailbox' => $mailbox,
-    ));
-    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-    while($row = array_shift($rows)) {
-      $mailboxdata['username'] = $row['username'];
-      $mailboxdata['is_relayed'] = $row['backupmx'];
-      $mailboxdata['name'] = $row['name'];
-      $mailboxdata['active'] = $row['active'];
-      $mailboxdata['domain'] = $row['domain'];
-      $mailboxdata['quota'] = formatBytes(intval($row['quota']), 2);
-      $mailboxdata['quota_used'] = formatBytes(intval($row['bytes']), 2);
-      $mailboxdata['percent_in_use'] = round((intval($row['bytes']) / intval($row['quota'])) * 100);
-      $mailboxdata['messages'] = $row['messages'];
-      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;
-  }
-  if (isset($mailboxdata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $mailboxdata['domain'])) {
-    $_SESSION['return'] = array(
-      'type' => 'danger',
-      'msg' => sprintf($lang['danger']['access_denied'])
-    );
-    return false;
-  }
-  return $mailboxdata;
-}
-function mailbox_edit_mailbox($postarray) {
-	global $lang;
-	global $pdo;
-	isset($postarray['active']) ? $active = '1' : $active = '0';
-	if (!filter_var($postarray['username'], FILTER_VALIDATE_EMAIL)) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['username_invalid'])
-		);
-		return false;
-	}
-	$quota_m		= $postarray['quota'];
-	$quota_b		= $quota_m*1048576;
-	$username		= $postarray['username'];
-	$name			= $postarray['name'];
-	$password		= $postarray['password'];
-	$password2		= $postarray['password2'];
-
-	try {
-		$stmt = $pdo->prepare("SELECT `domain`
-			FROM `mailbox`
-				WHERE username = :username");
-		$stmt->execute(array(':username' => $username));
-		$MailboxData1 = $stmt->fetch(PDO::FETCH_ASSOC);
-
-		$stmt = $pdo->prepare("SELECT 
-			COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota_m_now`
-				FROM `mailbox`
-					WHERE `username` = :username");
-		$stmt->execute(array(':username' => $username));
-		$MailboxData2 = $stmt->fetch(PDO::FETCH_ASSOC);
-
-		$stmt = $pdo->prepare("SELECT 
-			COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota_m_in_use`
-				FROM `mailbox`
-					WHERE `domain` = :domain");
-		$stmt->execute(array(':domain' => $MailboxData1['domain']));
-		$MailboxData3 = $stmt->fetch(PDO::FETCH_ASSOC);
-
-		$stmt = $pdo->prepare("SELECT `quota`, `maxquota`
-			FROM `domain`
-				WHERE `domain` = :domain");
-		$stmt->execute(array(':domain' => $MailboxData1['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'], $MailboxData1['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 (($MailboxData3['quota_m_in_use'] - $MailboxData2['quota_m_now'] + $quota_m) > $DomainData['quota']) {
-		$quota_left_m = ($DomainData['quota'] - $MailboxData3['quota_m_in_use'] + $MailboxData2['quota_m_now']);
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['mailbox_quota_left_exceeded'], $quota_left_m)
-		);
-		return false;
-	}
-
-	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 (isset($postarray['sender_acl']) && is_array($postarray['sender_acl'])) {
-		foreach ($postarray['sender_acl'] as $sender_acl) {
-			if (!filter_var($sender_acl, FILTER_VALIDATE_EMAIL) && 
-				!is_valid_domain_name(str_replace('@', '', $sender_acl))) {
-					$_SESSION['return'] = array(
-						'type' => 'danger',
-						'msg' => sprintf($lang['danger']['sender_acl_invalid'])
-					);
-					return false;
-			}
-		}
-		foreach ($postarray['sender_acl'] as $sender_acl) {
-			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;
-			}
-		}
-	}
-	if (!empty($password) && !empty($password2)) {
-		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
-					`modified` = :modified,
-					`active` = :active
-						WHERE `address` = :address");
-			$stmt->execute(array(
-				':address' => $username,
-				':modified' => date('Y-m-d H:i:s'),
-				':active' => $active
-			));
-			$stmt = $pdo->prepare("UPDATE `mailbox` SET
-					`modified` = :modified,
-					`active` = :active,
-					`password` = :password_hashed,
-					`name`= :name,
-					`quota` = :quota_b
-						WHERE `username` = :username");
-			$stmt->execute(array(
-				':modified' => date('Y-m-d H:i:s'),
-				':password_hashed' => $password_hashed,
-				':active' => $active,
-				':name' => $name,
-				':quota_b' => $quota_b,
-				':username' => $username
-			));
-			$_SESSION['return'] = array(
-				'type' => 'success',
-				'msg' => sprintf($lang['success']['mailbox_modified'], $username)
-			);
-			return true;
-		}
-		catch (PDOException $e) {
-			$_SESSION['return'] = array(
-				'type' => 'danger',
-				'msg' => 'MySQL: '.$e
-			);
-			return false;
-		}
-	}
-	try {
-		$stmt = $pdo->prepare("UPDATE `alias` SET
-				`modified` = :modified,
-				`active` = :active
-					WHERE `address` = :address");
-		$stmt->execute(array(
-			':address' => $username,
-			':modified' => date('Y-m-d H:i:s'),
-			':active' => $active
-		));
-		$stmt = $pdo->prepare("UPDATE `mailbox` SET
-				`modified` = :modified,
-				`active` = :active,
-				`name`= :name,
-				`quota` = :quota_b
-					WHERE `username` = :username");
-		$stmt->execute(array(
-			':active' => $active,
-			':modified' => date('Y-m-d H:i:s'),
-			':name' => $name,
-			':quota_b' => $quota_b,
-			':username' => $username
-		));
-		$_SESSION['return'] = array(
-			'type' => 'success',
-			'msg' => sprintf($lang['success']['mailbox_modified'], $username)
-		);
-		return true;
-	}
-	catch (PDOException $e) {
+function mailbox_get_domain_details($domain) {
+	global $lang;
+	global $pdo;
+
+  $domaindata = array();
+	$domain = idn_to_ascii(strtolower(trim($domain)));
+
+	if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
-			'msg' => 'MySQL: '.$e
+			'msg' => sprintf($lang['danger']['access_denied'])
 		);
 		return false;
 	}
+
+  try {
+    $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' => $domain,
+    ));
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+    while($row = array_shift($rows)) {
+      $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'] = formatBytes(intval($row['maxquota'] * 1048576), 2);
+      $domaindata['max_quota_for_mbox_mib'] = $row['maxquota'];
+      $domaindata['max_quota_for_domain'] = formatBytes(intval($row['quota'] * 1048576), 2);
+      $domaindata['max_quota_for_domain_mib'] = $row['quota'];
+      $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'];
+      $domaindata['relay_all_recipients'] = $row['relay_all_recipients'];
+
+      $stmt = $pdo->prepare("SELECT COUNT(*) AS `alias_count` FROM `alias`
+        WHERE `domain`= :domain
+          AND `address` NOT IN (
+            SELECT `username` FROM `mailbox`
+          )");
+      $stmt->execute(array(
+        ':domain' => $domain,
+      ));
+      $row = $stmt->fetchAll();
+      (isset($row[0]['alias_count'])) ? $domaindata['aliases_in_domain'] = $row[0]['alias_count'] : null;
+      $stmt = $pdo->prepare("SELECT COUNT(`username`) AS `mailbox_count`, SUM(`quota`) AS `quota` FROM `mailbox`
+          WHERE `domain` = :domain");
+      $stmt->execute(array(
+        ':domain' => $domain,
+      ));
+      $row = $stmt->fetchAll();
+      $domaindata['mboxes_in_domain'] = $row[0]['mailbox_count'];
+      $domaindata['quota_used_in_domain'] = formatBytes(intval($row[0]['quota']), 2);
+    }
+  }
+  catch (PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+    return false;
+  }
+
+  return $domaindata;
+}
+function mailbox_get_mailbox_details($mailbox) {
+	global $lang;
+	global $pdo;
+  $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`.`username` = `quota2`.`username` AND `domain`.`domain` = `mailbox`.`domain` AND `mailbox`.`username` = :mailbox");
+    $stmt->execute(array(
+      ':mailbox' => $mailbox,
+    ));
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+    while($row = array_shift($rows)) {
+      $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'] = formatBytes(intval($row['quota']), 2);
+      $mailboxdata['quota_bytes'] = $row['quota'];
+      $mailboxdata['quota_used'] = formatBytes(intval($row['bytes']), 2);
+      $mailboxdata['percent_in_use'] = round((intval($row['bytes']) / intval($row['quota'])) * 100);
+      $mailboxdata['messages'] = $row['messages'];
+      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;
+  }
+  if (isset($mailboxdata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $mailboxdata['domain'])) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => sprintf($lang['danger']['access_denied'])
+    );
+    return false;
+  }
+  return $mailboxdata;
 }
 function mailbox_delete_domain($postarray) {
 	global $lang;
@@ -2027,6 +2144,10 @@ function mailbox_delete_mailbox($postarray) {
 		$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
@@ -2076,14 +2197,16 @@ function edit_domain_admin($postarray) {
 		return false;
 	}
 	
-	foreach ($postarray['domain'] as $domain) {
-		if (!is_valid_domain_name($domain)) {
-			$_SESSION['return'] = array(
-				'type' => 'danger',
-				'msg' => sprintf($lang['danger']['domain_invalid'])
-			);
-			return false;
-		}
+  if(isset($postarray['domain'])) {
+    foreach ($postarray['domain'] as $domain) {
+      if (!is_valid_domain_name($domain)) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['domain_invalid'])
+        );
+        return false;
+      }
+    }
 	}
 
 	if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $username))) {
@@ -2108,24 +2231,26 @@ function edit_domain_admin($postarray) {
 		return false;
 	}
 
-	foreach ($postarray['domain'] as $domain) {
-		try {
-			$stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
-				VALUES (:username, :domain, :created, :active)");
-			$stmt->execute(array(
-				':username' => $username,
-				':domain' => $domain,
-				':created' => date('Y-m-d H:i:s'),
-				':active' => $active
-			));
-		}
-		catch (PDOException $e) {
-			$_SESSION['return'] = array(
-				'type' => 'danger',
-				'msg' => 'MySQL: '.$e
-			);
-			return false;
-		}
+  if(isset($postarray['domain'])) {
+    foreach ($postarray['domain'] as $domain) {
+      try {
+        $stmt = $pdo->prepare("INSERT INTO `domain_admins` (`username`, `domain`, `created`, `active`)
+          VALUES (:username, :domain, :created, :active)");
+        $stmt->execute(array(
+          ':username' => $username,
+          ':domain' => $domain,
+          ':created' => date('Y-m-d H:i:s'),
+          ':active' => $active
+        ));
+      }
+      catch (PDOException $e) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => 'MySQL: '.$e
+        );
+        return false;
+      }
+    }
 	}
 
 	if (!empty($password) && !empty($password2)) {
@@ -2279,7 +2404,26 @@ function set_admin_account($postarray) {
 function set_time_limited_aliases($postarray) {
 	global $lang;
 	global $pdo;
-	$username	= $_SESSION['mailcow_cc_username'];
+  (isset($postarray['username'])) ? $username = $postarray['username'] : $username = $_SESSION['mailcow_cc_username'];
+
+  if ($_SESSION['mailcow_cc_role'] != "user" &&
+    $_SESSION['mailcow_cc_role'] != "admin") {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['access_denied'])
+      );
+      return false;
+  }
+  if (filter_var($username, FILTER_VALIDATE_EMAIL)) {
+    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("SELECT `domain` FROM `mailbox` WHERE `username` = :username");
     $stmt->execute(array(':username' => $username));
@@ -2403,6 +2547,49 @@ function set_time_limited_aliases($postarray) {
 		break;
 	}
 }
+function get_time_limited_aliases($username = null) {
+  // 'username' can be be set, if not, default to mailcow_cc_username
+  global $lang;
+	global $pdo;
+  $spamaliasdata = array();
+	if ($_SESSION['mailcow_cc_role'] != "user" &&
+		$_SESSION['mailcow_cc_role'] != "admin") {
+			$_SESSION['return'] = array(
+				'type' => 'danger',
+				'msg' => sprintf($lang['danger']['access_denied'])
+			);
+			return false;
+	}
+  if (isset($username) && filter_var($username, FILTER_VALIDATE_EMAIL)) {
+    if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['access_denied'])
+      );
+      return false;
+    }
+  }
+  else {
+    $username = $_SESSION['mailcow_cc_username'];
+  }
+  try {
+    $stmt = $pdo->prepare("SELECT `address`,
+      `goto`,
+      `validity`
+        FROM `spamalias`
+          WHERE `goto` = :username
+            AND `validity` >= :unixnow");
+    $stmt->execute(array(':username' => $username, ':unixnow' => time()));
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+  }
+  catch(PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+  }
+  return $rows;
+}
 function set_user_account($postarray) {
 	global $lang;
 	global $pdo;
@@ -2561,6 +2748,7 @@ function add_domain_admin($postarray) {
 				));
 			}
 			catch (PDOException $e) {
+        delete_domain_admin(array('username' => $username));
 				$_SESSION['return'] = array(
 					'type' => 'danger',
 					'msg' => 'MySQL: '.$e
@@ -2639,15 +2827,114 @@ function delete_domain_admin($postarray) {
 		'msg' => sprintf($lang['success']['domain_admin_removed'], htmlspecialchars($username))
 	);
 }
-function get_spam_score($username) {
+function get_domain_admins() {
 	global $pdo;
-	$default = "5, 15";
-	if ($_SESSION['mailcow_cc_role'] != "user") {
+	global $lang;
+  $domainadmins = array();
+	if ($_SESSION['mailcow_cc_role'] != "admin") {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['access_denied'])
+		);
 		return false;
 	}
-	if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
-		return $default;
+  try {
+    $stmt = $pdo->query("SELECT DISTINCT
+      `username`
+        FROM `domain_admins` 
+          WHERE `username` IN (
+            SELECT `username` FROM `admin`
+              WHERE `superadmin`!='1'
+          )");
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+    while ($row = array_shift($rows)) {
+      $domainadmins[] = $row['username'];
+    }
+  }
+  catch(PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+  }
+  return $domainadmins;
+}
+function get_domain_admin_details($domain_admin) {
+	global $pdo;
+	global $lang;
+  $domainadmindata = array();
+	if ($_SESSION['mailcow_cc_role'] != "admin") {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['access_denied'])
+		);
+		return false;
+	}
+  if (!ctype_alnum(str_replace(array('_', '.', '-'), '', $domain_admin))) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['username_invalid'])
+		);
+		return false;
+	}
+  try {
+    $stmt = $pdo->prepare("SELECT
+      `created`,
+      `active` AS `active_int`,
+      CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`
+        FROM `domain_admins`
+          WHERE `username`= :domain_admin");
+    $stmt->execute(array(
+      ':domain_admin' => $domain_admin
+    ));
+    $row = $stmt->fetch(PDO::FETCH_ASSOC);
+    $domainadmindata['active'] = $row['active'];
+    $domainadmindata['active_int'] = $row['active_int'];
+    $domainadmindata['created'] = $row['created'];
+    // GET SELECTED
+    $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
+      WHERE `domain` IN (
+        SELECT `domain` FROM `domain_admins`
+          WHERE `username`= :domain_admin)");
+    $stmt->execute(array(':domain_admin' => $domain_admin));
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+    while($row = array_shift($rows)) {
+      $domainadmindata['selected_domains'][] = $row['domain'];
+    }
+    // GET UNSELECTED
+    $stmt = $pdo->prepare("SELECT `domain` FROM `domain`
+      WHERE `domain` NOT IN (
+        SELECT `domain` FROM `domain_admins`
+          WHERE `username`= :domain_admin)");
+    $stmt->execute(array(':domain_admin' => $domain_admin));
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+    while($row = array_shift($rows)) {
+      $domainadmindata['unselected_domains'][] = $row['domain'];
+    }
+  }
+  catch(PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+  }
+  return $domainadmindata;
+}
+function get_spam_score($username = null) {
+	global $pdo;
+	$default = "5, 15";
+	if ($_SESSION['mailcow_cc_role'] != "user" &&
+		$_SESSION['mailcow_cc_role'] != "admin") {
+			return false;
 	}
+  if (isset($username) && filter_var($username, FILTER_VALIDATE_EMAIL)) {
+    if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+      return false;
+    }
+  }
+  else {
+    $username = $_SESSION['mailcow_cc_username'];
+  }
 	try {
 		$stmt = $pdo->prepare("SELECT `value` FROM `filterconf` WHERE `object` = :username AND
 			(`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
@@ -2661,7 +2948,7 @@ function get_spam_score($username) {
 		);
 		return false;
 	}
-	if ($num_results == 0 || empty ($num_results)) {
+	if (empty($num_results)) {
 		return $default;
 	}
 	else {
@@ -2745,29 +3032,81 @@ function set_spam_score($postarray) {
 		'msg' => sprintf($lang['success']['mailbox_modified'], $username)
 	);
 }
-function set_policy_list($postarray) {
+function get_policy_list($object = null) {
+  // 'object' can be be set, if not, default to mailcow_cc_username
 	global $lang;
 	global $pdo;
-	if ($_SESSION['mailcow_cc_role'] != "admin" &&
-		$_SESSION['mailcow_cc_role'] != "domainadmin" &&
-		$_SESSION['mailcow_cc_role'] != "user") {
+	if (!isset($_SESSION['mailcow_cc_role'])) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
 			'msg' => sprintf($lang['danger']['access_denied'])
 		);
 		return false;
 	}
-	(isset($postarray['domain'])) ? $object = $postarray['domain'] : $object = $_SESSION['mailcow_cc_username'];
-	($postarray['object_list'] == "bl") ? $object_list = "blacklist_from" : $object_list = "whitelist_from";
-	$object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($postarray['object_from']))), '.'));
-	if (!filter_var($object, FILTER_VALIDATE_EMAIL) && !is_valid_domain_name($object)) {
+  if (isset($object)) {
+    if (!filter_var($object, FILTER_VALIDATE_EMAIL) && is_valid_domain_name($object)) {
+      $object = idn_to_ascii(strtolower(trim($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;
+      }
+    }
+    elseif (filter_var($object, FILTER_VALIDATE_EMAIL)) {
+      if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
+        $_SESSION['return'] = array(
+          'type' => 'danger',
+          'msg' => sprintf($lang['danger']['access_denied'])
+        );
+        return false;
+      }
+    }
+  }
+  else {
+     $object = $_SESSION['mailcow_cc_username'];
+  }
+  try {
+    // WHITELIST
+    $stmt = $pdo->prepare("SELECT `object`, `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND (`object` = :username OR `object` = SUBSTRING_INDEX(:username_domain, '@' ,-1))");
+    $stmt->execute(array(':username' => $object, ':username_domain' => $object));
+    $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` = SUBSTRING_INDEX(:username_domain, '@' ,-1))");
+    $stmt->execute(array(':username' => $object, ':username_domain' => $object));
+    $rows['blacklist'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
+  }
+  catch(PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+  }
+  return $rows;
+}
+function set_policy_list($postarray) {
+  // Array data
+  // Either 'domain' or 'username' can be be set
+  // If none of the above is set, default to mailcow_cc_username
+  //
+  // If 'delete_prefid' then delete item id
+	global $lang;
+	global $pdo;
+  (isset($postarray['username'])) ? $object = $postarray['username'] : null;
+  (isset($postarray['domain']))   ? $object = $postarray['domain'] : null;
+  (!isset($object))               ? $object = $_SESSION['mailcow_cc_username'] : null;
+
+  // Can be user, domainadmin or admin
+	if (!isset($_SESSION['mailcow_cc_role'])) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['username_invalid'])
+			'msg' => sprintf($lang['danger']['access_denied'])
 		);
 		return false;
 	}
-	if (is_valid_domain_name($object)) {
+
+  if (is_valid_domain_name($object)) {
 		if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
 			$_SESSION['return'] = array(
 				'type' => 'danger',
@@ -2775,9 +3114,21 @@ function set_policy_list($postarray) {
 			);
 			return false;
 		}
-	}
-	if (isset($postarray['prefid'])) {
-		if (!is_numeric($postarray['prefid'])) {
+    $object = idn_to_ascii(strtolower(trim($object)));
+  }
+  else {
+		if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
+			$_SESSION['return'] = array(
+				'type' => 'danger',
+				'msg' => sprintf($lang['danger']['access_denied'])
+			);
+			return false;
+		}
+  }
+
+  // DELETE
+	if (isset($postarray['delete_prefid'])) {
+		if (!is_numeric($postarray['delete_prefid'])) {
 			$_SESSION['return'] = array(
 				'type' => 'danger',
 				'msg' => sprintf($lang['danger']['access_denied'])
@@ -2788,7 +3139,7 @@ function set_policy_list($postarray) {
 			$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :object AND `prefid` = :prefid");
 			$stmt->execute(array(
 				':object' => $object,
-				':prefid' => $postarray['prefid']
+				':prefid' => $postarray['delete_prefid']
 			));
 		}
 		catch (PDOException $e) {
@@ -2800,17 +3151,29 @@ function set_policy_list($postarray) {
 		}
 		$_SESSION['return'] = array(
 			'type' => 'success',
-			'msg' => sprintf($lang['success']['mailbox_modified'], $object)
+			'msg' => sprintf($lang['success']['object_modified'], $object)
 		);
 		return true;
 	}
-	if (!ctype_alnum(str_replace(array('@', '.', '-', '*'), '', $object_from))) {
+  
+  // ADD WL/BL
+	($postarray['object_list'] == "bl") ? $object_list = "blacklist_from" : null;
+	($postarray['object_list'] == "wl") ? $object_list = "whitelist_from" : null;
+	$object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($postarray['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')
@@ -2818,6 +3181,13 @@ function set_policy_list($postarray) {
 				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(
@@ -2826,13 +3196,7 @@ function set_policy_list($postarray) {
 		);
 		return false;
 	}
-	if ($num_results != 0) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['policy_list_from_exists'])
-		);
-		return false;
-	}
+
 	try {
 		$stmt = $pdo->prepare("INSERT INTO `filterconf` (`object`, `option` ,`value`)
 			VALUES (:object, :object_list, :object_from)");
@@ -2851,53 +3215,95 @@ function set_policy_list($postarray) {
 	}
 	$_SESSION['return'] = array(
 		'type' => 'success',
-		'msg' => sprintf($lang['success']['mailbox_modified'], $object)
+		'msg' => sprintf($lang['success']['object_modified'], $object)
 	);
 }
-function set_tls_policy($postarray) {
+function get_syncjobs($username = null) {
+  // 'username' can be be set, if not, default to mailcow_cc_username
 	global $lang;
 	global $pdo;
-	if ($_SESSION['mailcow_cc_role'] != "user") {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['access_denied'])
-		);
-		return false;
-	}
-	isset($postarray['tls_in']) ? $tls_in = '1' : $tls_in = '0';
-	isset($postarray['tls_out']) ? $tls_out = '1' : $tls_out = '0';
-	$username = $_SESSION['mailcow_cc_username'];
-	if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => sprintf($lang['danger']['username_invalid'])
-		);
-		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_out,
-			':tls_in' => $tls_in,
-			':username' => $username
-		));
+  $syncjobs = array();
+	if ($_SESSION['mailcow_cc_role'] != "user" &&
+		$_SESSION['mailcow_cc_role'] != "admin") {
+			$_SESSION['return'] = array(
+				'type' => 'danger',
+				'msg' => sprintf($lang['danger']['access_denied'])
+			);
+			return false;
 	}
-	catch (PDOException $e) {
-		$_SESSION['return'] = array(
-			'type' => 'danger',
-			'msg' => 'MySQL: '.$e
-		);
-		return false;
+  if (isset($username) && filter_var($username, FILTER_VALIDATE_EMAIL)) {
+    if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['access_denied'])
+      );
+      return false;
+    }
+  }
+  else {
+    $username = $_SESSION['mailcow_cc_username'];
+  }
+  try {
+    $stmt = $pdo->prepare("SELECT *, CONCAT(LEFT(`password1`, 3), '…') as `password1_short`
+        FROM `imapsync`
+          WHERE `user2` = :username");
+    $stmt->execute(array(':username' => $username));
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+  }
+  catch(PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+  }
+  return $rows;
+}
+function get_syncjob_details($id) {
+	global $lang;
+	global $pdo;
+  $syncjobdetails = array();
+	if ($_SESSION['mailcow_cc_role'] != "user" &&
+		$_SESSION['mailcow_cc_role'] != "admin") {
+			$_SESSION['return'] = array(
+				'type' => 'danger',
+				'msg' => sprintf($lang['danger']['access_denied'])
+			);
+			return false;
 	}
-	$_SESSION['return'] = array(
-		'type' => 'success',
-		'msg' => sprintf($lang['success']['mailbox_modified'], $username)
-	);
+  if (!isset($id) || !is_numeric($id)) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => sprintf($lang['danger']['access_denied'])
+    );
+    return false;
+  }
+  try {
+    $stmt = $pdo->prepare("SELECT * FROM `imapsync` WHERE (`user2` = :username OR 'admin' = :role) AND id = :id");
+    $stmt->execute(array(':id' => $id, ':role' => $_SESSION['mailcow_cc_role'], ':username' => $_SESSION['mailcow_cc_username']));
+    $syncjobdetails = $stmt->fetch(PDO::FETCH_ASSOC);
+  }
+  catch(PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+  }
+  return $syncjobdetails;
 }
 function set_syncjob($postarray, $action) {
 	global $lang;
 	global $pdo;
-  $username = $_SESSION['mailcow_cc_username'];
+  if (isset($postarray['username']) && filter_var($username, FILTER_VALIDATE_EMAIL)) {
+    if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $postarray['username'])) {
+      return false;
+    }
+    else {
+      $username = $postarray['username'];
+    }
+  }
+  else {
+    $username = $_SESSION['mailcow_cc_username'];
+  }
   if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
     $_SESSION['return'] = array(
       'type' => 'danger',
@@ -2905,7 +3311,7 @@ function set_syncjob($postarray, $action) {
     );
     return false;
   }
-  if ($_SESSION['mailcow_cc_role'] != "user") {
+  if ($_SESSION['mailcow_cc_role'] != "user" && $_SESSION['mailcow_cc_role'] != "admin") {
     $_SESSION['return'] = array(
       'type' => 'danger',
       'msg' => sprintf($lang['danger']['access_denied'])
@@ -2959,16 +3365,8 @@ function set_syncjob($postarray, $action) {
     if (empty($subfolder2)) {
       $subfolder2 = "";
     }
-    if (empty($maxage)) {
-      $maxage = 0;
-    }
-
-    if (!filter_var($maxage, FILTER_VALIDATE_INT, array('options' => array('min_range' => 0, 'max_range' => 32767)))) {
-      $_SESSION['return'] = array(
-        'type' => 'danger',
-        'msg' => sprintf($lang['danger']['access_denied'])
-      );
-      return false;
+    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(
@@ -3174,12 +3572,19 @@ function set_syncjob($postarray, $action) {
     return true;
   }
 }
-function get_tls_policy($username) {
+function set_tls_policy($postarray) {
 	global $lang;
 	global $pdo;
 	if ($_SESSION['mailcow_cc_role'] != "user") {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['access_denied'])
+		);
 		return false;
 	}
+	isset($postarray['tls_in']) ? $tls_in = '1' : $tls_in = '0';
+	isset($postarray['tls_out']) ? $tls_out = '1' : $tls_out = '0';
+	$username = $_SESSION['mailcow_cc_username'];
 	if (!filter_var($username, FILTER_VALIDATE_EMAIL)) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
@@ -3187,6 +3592,50 @@ function get_tls_policy($username) {
 		);
 		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_out,
+			':tls_in' => $tls_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'], $username)
+	);
+}
+function get_tls_policy($username = null) {
+	global $lang;
+	global $pdo;
+  $TLSData = array();
+	if ($_SESSION['mailcow_cc_role'] != "user" &&
+		$_SESSION['mailcow_cc_role'] != "admin") {
+			$_SESSION['return'] = array(
+				'type' => 'danger',
+				'msg' => sprintf($lang['danger']['access_denied'])
+			);
+			return false;
+	}
+  if (isset($username) && filter_var($username, FILTER_VALIDATE_EMAIL)) {
+    if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['access_denied'])
+      );
+      return false;
+    }
+  }
+  else {
+    $username = $_SESSION['mailcow_cc_username'];
+  }
 	try {
 		$stmt = $pdo->prepare("SELECT `tls_enforce_out`, `tls_enforce_in` FROM `mailbox` WHERE `username` = :username");
 		$stmt->execute(array(':username' => $username));
@@ -3243,121 +3692,102 @@ function remaining_specs($domain, $object = null, $js = null) {
 	}
 	return $spec;
 }
-function get_sender_acl_handles($mailbox, $which) {
+function get_sender_acl_handles($mailbox) {
 	global $pdo;
+	global $lang;
 	if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
-		return false;
-	}
-	switch ($which) {
-		case "preselected":
-			try {
-				$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` = :goto AND `address` NOT LIKE '@%'");
-				$stmt->execute(array(':goto' => $mailbox));
-				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-				return $rows;
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-				return false;
-			}
-			break;
-		case "selected":
-			try {
-				$stmt = $pdo->prepare("SELECT `send_as` FROM `sender_acl` WHERE `logged_in_as` = :logged_in_as");
-				$stmt->execute(array(':logged_in_as' => $mailbox));
-				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-				return $rows;
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-				return false;
-			}
-			break;
-		case "unselected-domains":
-			try {
-				if ($_SESSION['mailcow_cc_role'] == "admin"  ) {
-					$stmt = $pdo->prepare("SELECT DISTINCT `domain` FROM `domain`
-						WHERE `domain` NOT IN (
-							SELECT REPLACE(`send_as`, '@', '') FROM `sender_acl` 
-								WHERE `logged_in_as` = :logged_in_as)
-						AND	`domain` NOT IN (
-								SELECT REPLACE(`address`, '@', '') FROM `alias` 
-									WHERE `goto` = :goto)");
-					$stmt->execute(array(
-						':logged_in_as' => $mailbox,
-						':goto' => $mailbox,
-					));
-				}
-				else {
-					$stmt = $pdo->prepare("SELECT DISTINCT `domain` FROM `domain_admins`
-						WHERE `username` = :username
-							AND `domain` != 'ALL'
-							AND	`domain` NOT IN (
-								SELECT REPLACE(`send_as`, '@', '') FROM `sender_acl` 
-									WHERE `logged_in_as` = :logged_in_as)");
-					$stmt->execute(array(
-						':logged_in_as' => $mailbox,
-						':username' => $_SESSION['mailcow_cc_username']
-					));
-				}
-				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-				return $rows;
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-				return false;
-			}
-			break;
-		case "unselected-addresses":
-			try {
-				if ($_SESSION['mailcow_cc_role'] == "admin"  ) {
-					$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)");
-					$stmt->execute(array(
-						':logged_in_as' => $mailbox,
-						':goto' => $mailbox
-					));
-				}
-				else {
-					$stmt = $pdo->prepare("SELECT `address` FROM `alias`
-						WHERE `goto` != :goto
-							AND `domain` IN (
-								SELECT `domain` FROM `domain_admins`
-									WHERE `username` = :username)
-							AND `address` NOT IN (
-								SELECT `send_as` FROM `sender_acl` 
-									WHERE `logged_in_as` = :logged_in_as)");
-					$stmt->execute(array(
-						':logged_in_as' => $mailbox,
-						':goto' => $mailbox,
-						':username' => $_SESSION['mailcow_cc_username']
-					));
-				}
-				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-				return $rows;
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-				return false;
-			}
-			break;
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => sprintf($lang['danger']['access_denied'])
+    );
+    return false;
 	}
-	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 {
+    $stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE `goto` = :goto AND `address` NOT LIKE '@%'");
+    $stmt->execute(array(':goto' => $mailbox));
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+    while ($row = array_shift($rows)) {
+      $data['fixed_sender_aliases'][] = $row['address'];
+    }
+
+    // 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' => $mailbox));
+    $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' => $mailbox));
+    $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' => $mailbox,
+    ));
+    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+    while ($row = array_shift($rows)) {
+      if (is_valid_domain_name($row['domain']) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $row['domain'])) {
+        $data['sender_acl_domains']['selectable'][] = $row['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' => $mailbox,
+      ':goto' => $mailbox
+    ));
+    while ($row = array_shift($rows)) {
+      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;
 }
 function tagging_options($action, $data = null) {
 	global $lang;
diff --git a/data/web/inc/init.sql b/data/web/inc/init.sql
index 64d7da5a..624f3398 100644
--- a/data/web/inc/init.sql
+++ b/data/web/inc/init.sql
@@ -115,11 +115,11 @@ CREATE TABLE IF NOT EXISTS `imapsync` (
   `password1` VARCHAR(255) NOT NULL,
   `exclude` VARCHAR(500) NOT NULL DEFAULT '',
   `maxage` SMALLINT NOT NULL DEFAULT '0',
-  `mins_INTerval` VARCHAR(50) NOT NULL,
+  `mins_interval` VARCHAR(50) NOT NULL,
   `port1` SMALLINT NOT NULL,
   `enc1` ENUM('TLS','SSL','PLAIN') DEFAULT 'TLS',
   `delete2duplicates` TINYINT(1) NOT NULL DEFAULT '1',
-  `returned_TEXT` TEXT,
+  `returned_text` TEXT,
   `last_run` TIMESTAMP NULL DEFAULT NULL,
   `created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
   `modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
diff --git a/data/web/inc/triggers.inc.php b/data/web/inc/triggers.inc.php
index 00de3a9e..1d52ceb7 100644
--- a/data/web/inc/triggers.inc.php
+++ b/data/web/inc/triggers.inc.php
@@ -95,6 +95,9 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 			break;
 		}
 	}
+	if (isset($_POST["trigger_set_policy_list"])) {
+		set_policy_list($_POST);
+	}
 	if (isset($_POST["trigger_mailbox_action"])) {
 		switch ($_POST["trigger_mailbox_action"]) {
 			case "adddomain":
diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php
index 29720c89..76abf325 100644
--- a/data/web/inc/vars.inc.php
+++ b/data/web/inc/vars.inc.php
@@ -1,5 +1,6 @@
 <?php
 error_reporting(E_ALL);
+//error_reporting(E_ERROR | E_WARNING);
 
 /*
 PLEASE USE THE FILE "vars.local.inc.php" TO OVERWRITE SETTINGS AND MAKE THEM PERSISTENT!
diff --git a/data/web/js/user.js b/data/web/js/user.js
index 9dbca08c..adde2f3a 100644
--- a/data/web/js/user.js
+++ b/data/web/js/user.js
@@ -14,10 +14,6 @@ $(document).ready(function() {
 			$(".passFields").slideUp();
 		}
 	});
-
-  $(function () {
-    $('[data-toggle="tooltip"]').tooltip()
-  })
 	// Show generate button after time selection
 	$('#trigger_set_time_limited_aliases').hide(); 
 	$('#validity').change(function(){
diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php
index de983776..b22db9c7 100644
--- a/data/web/lang/lang.de.php
+++ b/data/web/lang/lang.de.php
@@ -10,13 +10,13 @@ $lang['footer']['restart_sogo'] = 'SOGo neustarten';
 $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['dkim']['confirm'] = 'Sind Sie sicher?';
-$lang['danger']['dkim_not_found'] = 'DKIM-Record nicht gefunden';
-$lang['danger']['dkim_remove_failed'] = 'Kann DKIM-Record nicht entfernen';
-$lang['danger']['dkim_add_failed'] = 'Kann DKIM-Record nicht hinzufügen';
+$lang['danger']['dkim_not_found'] = 'DKIM-Key nicht gefunden';
+$lang['danger']['dkim_remove_failed'] = 'Kann DKIM-Key nicht entfernen';
+$lang['danger']['dkim_add_failed'] = 'Kann DKIM-Key nicht hinzufügen';
 $lang['danger']['dkim_domain_or_sel_invalid'] = 'DKIM-Domain oder -Selector nicht korrekt';
 $lang['danger']['dkim_key_length_invalid'] = 'DKIM Schlüssellänge ungültig';
-$lang['success']['dkim_removed'] = 'DKIM-Record wurde entfernt';
-$lang['success']['dkim_added'] = 'DKIM-Record wurde hinzugefügt';
+$lang['success']['dkim_removed'] = 'DKIM-Key wurde entfernt';
+$lang['success']['dkim_added'] = 'DKIM-Key wurde hinzugefügt';
 $lang['danger']['access_denied'] = 'Zugriff verweigert oder unvollständige/ungültige Daten';
 $lang['danger']['whitelist_from_invalid'] = 'Whitelist-Eintrag ist ungültig';
 $lang['danger']['domain_invalid'] = 'Domainname ist ungültig';
@@ -39,6 +39,7 @@ $lang['success']['alias_added'] = 'Alias-Adresse(n) wurden angelegt';
 $lang['success']['alias_modified'] = 'Änderungen an Alias %s wurden gespeichert';
 $lang['success']['aliasd_modified'] = 'Änderungen an Alias-Domain %s wurden gespeichert';
 $lang['success']['mailbox_modified'] = 'Änderungen an Mailbox %s wurden gespeichert';
+$lang['success']['object_modified'] = "Änderungen an Objekt %s wurden gespeichert";
 $lang['success']['msg_size_saved'] = 'Limit wurde gesetzt';
 $lang['danger']['aliasd_not_found'] = 'Alias-Domain nicht gefunden';
 $lang['danger']['targetd_not_found'] = 'Ziel-Domain nicht gefunden';
@@ -137,6 +138,7 @@ $lang['user']['spamfilter_yellow'] = 'Gelb: Die Nachricht ist vielleicht Spam, w
 $lang['user']['spamfilter_red'] = 'Rot: Die Nachricht ist eindeutig Spam und wird vom Server abgelehnt';
 $lang['user']['spamfilter_default_score'] = 'Standardwert:';
 $lang['user']['spamfilter_hint'] = 'Der erste Wert beschreibt den "low spam score", der zweite Wert den "high spam score".';
+$lang['user']['spamfilter_table_domain_policy'] = "n.v. (Domainrichtlinie)";
 
 $lang['user']['tls_policy_warning'] = '<strong>Vorsicht:</strong> Entscheiden Sie sich unverschlüsselte Verbindungen abzulehnen, kann dies dazu führen, dass Kontakte Sie nicht mehr erreichen.<br />Nachrichten, die die Richtlinie nicht erfüllen, werden durch einen Hard-Fail im Mailsystem abgewiesen.';
 $lang['user']['tls_policy'] = 'Verschlüsselungsrichtlinie';
@@ -224,6 +226,7 @@ $lang['mailbox']['remove'] = 'Entfernen';
 $lang['mailbox']['edit'] = 'Bearbeiten';
 $lang['mailbox']['archive'] = 'Archiv-Zugriff';
 $lang['mailbox']['no_record'] = 'Kein Eintrag für Objekt %s';
+$lang['mailbox']['no_record_single'] = 'Kein Eintrag';
 $lang['mailbox']['add_domain'] = 'Domain hinzufügen';
 $lang['mailbox']['add_domain_alias'] = 'Domain-Alias hinzufügen';
 $lang['mailbox']['add_mailbox'] = 'Mailbox hinzufügen';
@@ -378,9 +381,12 @@ $lang['admin']['msg_size_limit_details'] = 'Diese Einstellung wird Postfix und d
 $lang['admin']['save'] = 'Änderungen speichern';
 $lang['admin']['maintenance'] = 'Wartung und Information';
 $lang['admin']['sys_info'] = 'Systeminformation';
-$lang['admin']['dkim_add_key'] = 'DKIM-Record hinzufügen';
-$lang['admin']['dkim_keys'] = 'DKIM-Records';
-$lang['admin']['dkim_key_length'] = 'DKIM Schlüssellänge (Bits)';
+$lang['admin']['dkim_add_key'] = 'DKIM-Key hinzufügen';
+$lang['admin']['dkim_keys'] = 'DKIM-Keys';
+$lang['admin']['dkim_key_valid'] = 'Key gültig';
+$lang['admin']['dkim_key_unused'] = 'Key ohne Zuweisung';
+$lang['admin']['dkim_key_missing'] = 'Key fehlt';
+$lang['admin']['dkim_key_hint'] = 'Der Selector für DKIM-Keys lautet immer <code>dkim</code>.';
 $lang['admin']['add'] = 'Hinzufügen';
 $lang['admin']['configuration'] = 'Konfiguration';
 $lang['admin']['password'] = 'Passwort';
diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php
index e764985c..8bc5d50d 100644
--- a/data/web/lang/lang.en.php
+++ b/data/web/lang/lang.en.php
@@ -10,13 +10,13 @@ $lang['footer']['restart_sogo'] = 'Restart SOGo';
 $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['dkim']['confirm'] = "Are you sure?";
-$lang['danger']['dkim_not_found'] = "DKIM record not found";
-$lang['danger']['dkim_remove_failed'] = "Cannot remove selected DKIM record";
-$lang['danger']['dkim_add_failed'] = "Cannot add given DKIM record";
+$lang['danger']['dkim_not_found'] = "DKIM key not found";
+$lang['danger']['dkim_remove_failed'] = "Cannot remove selected DKIM key";
+$lang['danger']['dkim_add_failed'] = "Cannot add given DKIM key";
 $lang['danger']['dkim_domain_or_sel_invalid'] = "DKIM domain or selector invalid";
 $lang['danger']['dkim_key_length_invalid'] = "DKIM key length invalid";
-$lang['success']['dkim_removed'] = "DKIM record has been removed";
-$lang['success']['dkim_added'] = "DKIM record has been saved";
+$lang['success']['dkim_removed'] = "DKIM key has been removed";
+$lang['success']['dkim_added'] = "DKIM key has been saved";
 $lang['danger']['access_denied'] = "Access denied or invalid form data";
 $lang['danger']['whitelist_from_invalid'] = "Whitelist entry invalid";
 $lang['danger']['domain_invalid'] = "Domain name is invalid";
@@ -41,6 +41,7 @@ $lang['success']['alias_added'] = "Alias address/es has/have been added";
 $lang['success']['alias_modified'] = "Changes to alias have been saved";
 $lang['success']['aliasd_modified'] = "Changes to alias domain have been saved";
 $lang['success']['mailbox_modified'] = "Changes to mailbox %s have been saved";
+$lang['success']['object_modified'] = "Changes to object %s have been saved";
 $lang['success']['msg_size_saved'] = "Message size limit has been set";
 $lang['danger']['aliasd_not_found'] = "Alias domain not found";
 $lang['danger']['targetd_not_found'] = "Target domain not found";
@@ -139,6 +140,7 @@ $lang['user']['spamfilter_yellow'] = 'Yellow: this message may be spam, will be
 $lang['user']['spamfilter_red'] = 'Red: This message is spam and will be rejected by the server';
 $lang['user']['spamfilter_default_score'] = 'Default values:';
 $lang['user']['spamfilter_hint'] = 'The first value describes the "low spam score", the second represents the "high spam score".';
+$lang['user']['spamfilter_table_domain_policy'] = "n/a (domain policy)";
 
 $lang['user']['tls_policy_warning'] = '<strong>Warning:</strong> If you decide to enforce encrypted mail transfer, you may lose emails.<br />Messages to not satisfy the policy will be bounced with a hard fail by the mail system.';
 $lang['user']['tls_policy'] = 'Encryption policy';
@@ -226,6 +228,7 @@ $lang['mailbox']['remove'] = 'Remove';
 $lang['mailbox']['edit'] = 'Edit';
 $lang['mailbox']['archive'] = 'Archive';
 $lang['mailbox']['no_record'] = 'No Record for object %s';
+$lang['mailbox']['no_record_single'] = 'No Record';
 $lang['mailbox']['add_domain'] = 'Add domain';
 $lang['mailbox']['add_domain_alias'] = 'Add domain alias';
 $lang['mailbox']['add_mailbox'] = 'Add mailbox';
@@ -379,6 +382,10 @@ $lang['admin']['privacy_anon_mail'] = 'Anonymize outgoing mail';
 $lang['admin']['dkim_txt_name'] = 'TXT record name:';
 $lang['admin']['dkim_txt_value'] = 'TXT record value:';
 $lang['admin']['dkim_key_length'] = 'DKIM key length (bits)';
+$lang['admin']['dkim_key_valid'] = 'Key valid';
+$lang['admin']['dkim_key_unused'] = 'Key unused';
+$lang['admin']['dkim_key_missing'] = 'Key missing';
+$lang['admin']['dkim_key_hint'] = 'Selector for DKIM keys is always dkim.';
 $lang['admin']['previous'] = 'Previous page';
 $lang['admin']['quota_mb'] = 'Quota (MiB):';
 $lang['admin']['sender_acl'] = 'Allow to send as:';
@@ -388,8 +395,8 @@ $lang['admin']['msg_size_limit_details'] = 'Applying a new limit will reload Pos
 $lang['admin']['save'] = 'Save changes';
 $lang['admin']['maintenance'] = 'Maintenance and Information';
 $lang['admin']['sys_info'] = 'System information';
-$lang['admin']['dkim_add_key'] = 'Add DKIM record';
-$lang['admin']['dkim_keys'] = 'DKIM records';
+$lang['admin']['dkim_add_key'] = 'Add DKIM key';
+$lang['admin']['dkim_keys'] = 'DKIM keys';
 $lang['admin']['add'] = 'Add';
 $lang['admin']['configuration'] = 'Configuration';
 $lang['admin']['password'] = 'Password';
diff --git a/data/web/mailbox.php b/data/web/mailbox.php
index 26c799b6..fffd8c58 100644
--- a/data/web/mailbox.php
+++ b/data/web/mailbox.php
@@ -1,7 +1,7 @@
 <?php
 require_once "inc/prerequisites.inc.php";
 
-if ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin") {
+if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "admin" || $_SESSION['mailcow_cc_role'] == "domainadmin")) {
 require_once "inc/header.inc.php";
 $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 ?>
@@ -91,7 +91,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
             endforeach;
             else:
 							?>
-              <tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['no_record'];?></td></tr>
+              <tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=$lang['mailbox']['no_record_single'];?></td></tr>
             <?php
             endif;
             ?>
diff --git a/data/web/user.php b/data/web/user.php
index 33e26e81..8697017f 100644
--- a/data/web/user.php
+++ b/data/web/user.php
@@ -1,6 +1,5 @@
 <?php
 require_once("inc/prerequisites.inc.php");
-
 if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user') {
 	require_once("inc/header.inc.php");
 	$_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
@@ -124,40 +123,25 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
         <p><b><?=$lang['user']['action'];?></b></p>
 			</div>
 			<?php
-			try {
-				$stmt = $pdo->prepare("SELECT `address`,
-					`goto`,
-					`validity`
-						FROM `spamalias`
-							WHERE `goto` = :username
-								AND `validity` >= :unixnow");
-				$stmt->execute(array(':username' => $username, ':unixnow' => time()));
-				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-			}
-			if(!empty($rows)):
-			while ($row = array_shift($rows)):
-			?>
-			<div class="col-xs-5">
-				<p><?=htmlspecialchars($row['address']);?></p>
-			</div>
-			<div class="col-xs-4">
-				<p><?=htmlspecialchars(date($lang['user']['alias_full_date'], $row['validity']));?></p>
-			</div>
-			<div class="col-xs-3">
-				<form class="form-inline" role="form" method="post">
-          <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>
-          <input type="hidden" name="trigger_set_time_limited_aliases" value="delete">
-          <input type="hidden" name="item" value="<?=htmlspecialchars($row['address']);?>">
-				</form>
-			</div>
-			<?php
-			endwhile;
+      $get_time_limited_aliases = get_time_limited_aliases($username);
+      if (!empty($get_time_limited_aliases)):
+        foreach ($get_time_limited_aliases as $row):
+        ?>
+        <div class="col-xs-5">
+          <p><?=htmlspecialchars($row['address']);?></p>
+        </div>
+        <div class="col-xs-4">
+          <p><?=htmlspecialchars(date($lang['user']['alias_full_date'], $row['validity']));?></p>
+        </div>
+        <div class="col-xs-3">
+          <form class="form-inline" role="form" method="post">
+            <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>
+            <input type="hidden" name="trigger_set_time_limited_aliases" value="delete">
+            <input type="hidden" name="item" value="<?=htmlspecialchars($row['address']);?>">
+          </form>
+        </div>
+        <?php
+        endforeach;
 			else:
 			?>
       <div class="col-xs-12">
@@ -233,49 +217,39 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
 					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
 				</div>
 				<?php
-				try {
-					$stmt = $pdo->prepare("SELECT `value`, `prefid` FROM `filterconf` WHERE `option`='whitelist_from' AND `object`= :username");
-					$stmt->execute(array(':username' => $username));
-					$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-				}
-				catch(PDOException $e) {
-					$_SESSION['return'] = array(
-						'type' => 'danger',
-						'msg' => 'MySQL: '.$e
-					);
-				}
-				if (count($rows) == 0):
+        $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
-				endif;
-				while ($whitelistRow = array_shift($rows)):
-				?>
-				<div class="row striped">
-					<form class="form-inline" method="post">
-					<div class="col-xs-6"><code><?=$whitelistRow['value'];?></code></div>
-					<div class="col-xs-6">
-						<input type="hidden" name="prefid" value="<?=$whitelistRow['prefid'];?>">
-						<?php
-						if ($whitelistRow['username'] != array_pop(explode('@', $username))):
-						?>
-							<input type="hidden" name="trigger_set_policy_list">
-							<a href="#n" onclick="$(this).closest('form').submit()"><?=$lang['user']['spamfilter_table_remove'];?></a>
-						<?php
-						else:
-						?>
-							<span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
-						<?php
-						endif;
-						?>
-					</div>
-					</form>
-				</div>
-
-				<?php
-				endwhile;
+				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="trigger_set_policy_list">
+                <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>
+          </div>
+          <?php
+          endforeach;
+        endif;
 				?>
 				<hr style="margin:5px 0px 7px 0px">
 				<div class="row">
@@ -298,48 +272,38 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
 					<div class="col-sm-6"><b><?=$lang['user']['spamfilter_table_action'];?></b></div>
 				</div>
 				<?php
-				try {
-					$stmt = $pdo->prepare("SELECT `value`, `prefid` FROM `filterconf` WHERE `option`='blacklist_from' AND `object`= :username");
-					$stmt->execute(array(':username' => $username));
-					$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-				}
-				catch(PDOException $e) {
-					$_SESSION['return'] = array(
-						'type' => 'danger',
-						'msg' => 'MySQL: '.$e
-					);
-				}
-				if (count($rows) == 0):
+				if (empty($get_policy_list['blacklist'])):
 				?>
 					<div class="row">
 						<div class="col-sm-12"><i><?=$lang['user']['spamfilter_table_empty'];?></i></div>
 					</div>
 				<?php
-				endif;
-				while ($blacklistRow = array_shift($rows)):
-				?>
-				<div class="row striped">
-					<form class="form-inline" method="post">
-					<div class="col-xs-6"><code><?=$blacklistRow['value'];?></code></div>
-					<div class="col-xs-6">
-						<input type="hidden" name="prefid" value="<?=$blacklistRow['prefid'];?>">
-						<?php
-						if ($blacklistRow['username'] != array_pop(explode('@', $username))):
-						?>
-							<input type="hidden" name="trigger_set_policy_list">
-							<a href="#n" onclick="$(this).closest('form').submit()"><?=$lang['user']['spamfilter_table_remove'];?></a>
-						<?php
-						else:
-						?>
-							<span style="cursor:not-allowed"><?=$lang['user']['spamfilter_table_domain_policy'];?></span>
-						<?php
-						endif;
-						?>
-					</div>
-					</form>
-				</div>
-				<?php
-				endwhile;
+				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="trigger_set_policy_list">
+                <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>
+          </div>
+          <?php
+          endforeach;
+        endif;
 				?>
 				<hr style="margin:5px 0px 7px 0px">
 				<div class="row">
@@ -398,21 +362,9 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
 			</thead>
 			<tbody>
 			<?php
-			try {
-				$stmt = $pdo->prepare("SELECT *, CONCAT(LEFT(`password1`, 3), '…') as `password1_short`
-						FROM `imapsync`
-							WHERE `user2` = :username");
-				$stmt->execute(array(':username' => $username));
-				$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-			}
-			if(!empty($rows)):
-			while ($row = array_shift($rows)):
+      $get_syncjobs = get_syncjobs($username);
+			if (!empty($get_syncjobs)):
+			foreach ($get_syncjobs as $row):
 			?>
 				<tr id="data">
 				<td><?=htmlspecialchars($row['host1'] . ':' . $row['port1']);?></td>
@@ -442,7 +394,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
         </td>
 				</tr>
 			<?php
-			endwhile;
+			endforeach;
 			else:
 			?>
 				<tr id="no-data"><td colspan="9" style="text-align: center; font-style: italic;"><?=$lang['user']['no_record'];?></td></tr>
@@ -462,7 +414,7 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
 		</div>
 	</div>
 </div>
-<br />
+<div style="margin-bottom:200px;"></div>
 <div class="modal fade" id="logModal" tabindex="-1" role="dialog" aria-labelledby="logTextLabel">
   <div class="modal-dialog" style="width:90%" role="document">
     <div class="modal-content">