From 66e9833c911f5083d57cca57489ffb69a8e6a86d Mon Sep 17 00:00:00 2001
From: andryyy <andre.peters@debinux.de>
Date: Sun, 22 Jan 2017 16:41:45 +0100
Subject: [PATCH] More work on web UI

---
 data/web/add.php               |   8 +-
 data/web/admin.php             |  33 ++-----
 data/web/css/mailbox.css       |  16 ++++
 data/web/css/mailcow.css       |  45 ++++++++++
 data/web/css/tables.css        |  79 +++++++++++++++++
 data/web/delete.php            |   8 +-
 data/web/edit.php              |  16 ++--
 data/web/inc/admin.inc.php     | 146 +++++++++++++++++++++++++++++++
 data/web/inc/functions.inc.php |  41 ++++++++-
 data/web/inc/header.inc.php    | 152 +--------------------------------
 data/web/inc/mailbox.inc.php   |  24 +++++-
 data/web/lang/lang.en.php      |   8 +-
 data/web/user.php              |  51 ++++++-----
 13 files changed, 401 insertions(+), 226 deletions(-)
 create mode 100644 data/web/css/mailbox.css
 create mode 100644 data/web/css/mailcow.css
 create mode 100644 data/web/css/tables.css
 create mode 100644 data/web/inc/admin.inc.php

diff --git a/data/web/add.php b/data/web/add.php
index 5d28d88b..45df8f4b 100644
--- a/data/web/add.php
+++ b/data/web/add.php
@@ -77,7 +77,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-							<button type="submit" name="trigger_mailbox_action" value="adddomain" class="btn btn-success"><?=$lang['add']['save'];?></button>
+							<button type="submit" name="mailbox_add_domain" class="btn btn-success"><?=$lang['add']['save'];?></button>
 						</div>
 					</div>
 					<p><span class="glyphicon glyphicon-exclamation-sign text-danger"></span> <?=$lang['add']['restart_sogo_hint'];?></p>
@@ -112,7 +112,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-							<button type="submit" name="trigger_mailbox_action" value="addalias" class="btn btn-success "><?=$lang['add']['save'];?></button>
+							<button type="submit" name="mailbox_add_alias" class="btn btn-success "><?=$lang['add']['save'];?></button>
 						</div>
 					</div>
 				</form>
@@ -167,7 +167,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-							<button type="submit" name="trigger_mailbox_action" value="addaliasdomain" class="btn btn-success "><?=$lang['add']['save'];?></button>
+							<button type="submit" name="mailbox_add_alias_domain" class="btn btn-success "><?=$lang['add']['save'];?></button>
 						</div>
 					</div>
 				</form>
@@ -247,7 +247,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-							<button type="submit" name="trigger_mailbox_action" value="addmailbox" class="btn btn-success "><?=$lang['add']['save'];?></button>
+							<button type="submit" name="mailbox_add_mailbox" class="btn btn-success "><?=$lang['add']['save'];?></button>
 						</div>
 					</div>
 				</form>
diff --git a/data/web/admin.php b/data/web/admin.php
index 1845bcb5..c6f78a89 100644
--- a/data/web/admin.php
+++ b/data/web/admin.php
@@ -13,25 +13,12 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 		<div class="panel-heading"><?=$lang['admin']['admin_details'];?></div>
 		<div class="panel-body">
 			<form class="form-horizontal" autocapitalize="none" autocorrect="off" role="form" method="post">
-			<?php
-			try {
-			$stmt = $pdo->prepare("SELECT `username` FROM `admin`
-				WHERE `superadmin`='1' and active='1'");
-			$stmt->execute();
-			$AdminData = $stmt->fetch(PDO::FETCH_ASSOC);
-			}
-			catch(PDOException $e) {
-				$_SESSION['return'] = array(
-					'type' => 'danger',
-					'msg' => 'MySQL: '.$e
-				);
-			}
-			?>
-				<input type="hidden" name="admin_user_now" value="<?=htmlspecialchars($AdminData['username']);?>">
+			<?php $admindetails = get_admin_details(); ?>
+				<input type="hidden" name="admin_user_now" value="<?=htmlspecialchars($admindetails['username']);?>">
 				<div class="form-group">
 					<label class="control-label col-sm-2" for="admin_user"><?=$lang['admin']['admin'];?>:</label>
 					<div class="col-sm-10">
-						<input type="text" class="form-control" name="admin_user" id="admin_user" value="<?=htmlspecialchars($AdminData['username']);?>" required>
+						<input type="text" class="form-control" name="admin_user" id="admin_user" value="<?=htmlspecialchars($admindetails['username']);?>" required>
 						&rdsh; <kbd>a-z A-Z - _ .</kbd>
 					</div>
 				</div>
@@ -124,18 +111,8 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 						<div class="col-sm-10">
 							<select title="<?=$lang['admin']['search_domain_da'];?>" style="width:100%" name="domain[]" size="5" multiple>
 							<?php
-							try {
-								$stmt = $pdo->query("SELECT domain FROM domain");
-								$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
-							}
-							catch(PDOException $e) {
-								$_SESSION['return'] = array(
-									'type' => 'danger',
-									'msg' => 'MySQL: '.$e
-								);
-							}
-							while ($row = array_shift($rows)) {
-								echo "<option>".htmlspecialchars($row['domain'])."</option>";
+							foreach (mailbox_get_domains() as $domain) {
+								echo "<option>".htmlspecialchars($domain)."</option>";
 							}
 							?>
 							</select>
diff --git a/data/web/css/mailbox.css b/data/web/css/mailbox.css
new file mode 100644
index 00000000..48fa5e39
--- /dev/null
+++ b/data/web/css/mailbox.css
@@ -0,0 +1,16 @@
+.panel-heading div {
+	margin-top: -18px;
+	font-size: 15px;
+}
+.panel-heading div span {
+	margin-left:5px;
+}
+.panel-body {
+	display: none;
+}
+.clickable {
+	cursor: pointer;
+}
+.progress {
+	margin-bottom: 0px;
+}
\ No newline at end of file
diff --git a/data/web/css/mailcow.css b/data/web/css/mailcow.css
new file mode 100644
index 00000000..ee0b5cc6
--- /dev/null
+++ b/data/web/css/mailcow.css
@@ -0,0 +1,45 @@
+#maxmsgsize { min-width: 80px; }
+#slider1 .slider-selection {
+	background: #FFD700;
+}
+#slider1 .slider-track-high {
+	background: #FF4500;
+}
+#slider1 .slider-track-low {
+	background: #66CD00;
+}
+.striped:nth-child(odd) {
+    background-color: #fff;
+}
+.striped:nth-child(even) {
+    background-color: #fafafa;
+	border:1px solid white;
+}
+.btn {
+   text-transform: none;
+}
+.glyphicon-spin {
+    -webkit-animation: spin 1000ms infinite linear;
+    animation: spin 1000ms infinite linear;
+}
+@-webkit-keyframes spin {
+    0% {
+        -webkit-transform: rotate(0deg);
+        transform: rotate(0deg);
+    }
+    100% {
+        -webkit-transform: rotate(359deg);
+        transform: rotate(359deg);
+    }
+}
+@keyframes spin {
+    0% {
+        -webkit-transform: rotate(0deg);
+        transform: rotate(0deg);
+    }
+    100% {
+        -webkit-transform: rotate(359deg);
+        transform: rotate(359deg);
+    }
+}
+pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word;}
\ No newline at end of file
diff --git a/data/web/css/tables.css b/data/web/css/tables.css
new file mode 100644
index 00000000..651e1665
--- /dev/null
+++ b/data/web/css/tables.css
@@ -0,0 +1,79 @@
+ul[id*="sortable"] { word-wrap: break-word; list-style-type: none; float: left; padding: 0 15px 0 0; width: 48%; cursor:move}
+ul[id$="sortable-active"] li {cursor:move; }
+ul[id$="sortable-inactive"] li {cursor:move }
+.list-heading { cursor:default !important}
+.ui-state-disabled { cursor:no-drop; color:#ccc; }
+.ui-state-highlight {background: #F5F5F5 !important; height: 41px !important; cursor:move }
+table[data-sortable] {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+table[data-sortable] th {
+  vertical-align: bottom;
+  font-weight: bold;
+}
+table[data-sortable] th, table[data-sortable] td {
+  text-align: left;
+  padding: 10px;
+}
+table[data-sortable] th:not([data-sortable="false"]) {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  -ms-user-select: none;
+  -o-user-select: none;
+  user-select: none;
+  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+  -webkit-touch-callout: none;
+  cursor: pointer;
+}
+table[data-sortable] th:after {
+  content: "";
+  visibility: hidden;
+  display: inline-block;
+  vertical-align: inherit;
+  height: 0;
+  width: 0;
+  border-width: 5px;
+  border-style: solid;
+  border-color: transparent;
+  margin-right: 1px;
+  margin-left: 10px;
+  float: right;
+}
+table[data-sortable] th[data-sortable="false"]:after {
+  display: none;
+}
+table[data-sortable] th[data-sorted="true"]:after {
+  visibility: visible;
+}
+table[data-sortable] th[data-sorted-direction="descending"]:after {
+  border-top-color: inherit;
+  margin-top: 8px;
+}
+table[data-sortable] th[data-sorted-direction="ascending"]:after {
+  border-bottom-color: inherit;
+  margin-top: 3px;
+}
+table[data-sortable].sortable-theme-bootstrap thead th {
+  border-bottom: 2px solid #e0e0e0;
+}
+table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"] {
+  color: #3a87ad;
+  background: #d9edf7;
+  border-bottom-color: #bce8f1;
+}
+table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="descending"]:after {
+  border-top-color: #3a87ad;
+}
+table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="ascending"]:after {
+  border-bottom-color: #3a87ad;
+}
+table[data-sortable].sortable-theme-bootstrap.sortable-theme-bootstrap-striped tbody > tr:nth-child(odd) > td {
+  background-color: #f9f9f9;
+}
+#data td, #no-data td {
+	vertical-align: middle;
+}
+.sort-table:hover {
+  border-bottom-color: #00B7DC !important;
+}
\ No newline at end of file
diff --git a/data/web/delete.php b/data/web/delete.php
index 86ac4764..5ba83e06 100644
--- a/data/web/delete.php
+++ b/data/web/delete.php
@@ -30,7 +30,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 				<input type="hidden" name="domain" value="<?php echo htmlspecialchars($domain) ?>">
 					<div class="form-group">
 						<div class="col-sm-offset-1 col-sm-10">
-							<button type="submit" name="trigger_mailbox_action" value="deletedomain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
+							<button type="submit" name="mailbox_delete_domain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
 						</div>
 					</div>
 				</form>
@@ -49,7 +49,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					<input type="hidden" name="address" value="<?php echo htmlspecialchars($_GET["alias"]) ?>">
 						<div class="form-group">
 							<div class="col-sm-offset-1 col-sm-10">
-								<button type="submit" name="trigger_mailbox_action" value="deletealias" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
+								<button type="submit" name="mailbox_delete_alias" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
 							</div>
 						</div>
 					</form>
@@ -75,7 +75,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					<input type="hidden" name="alias_domain" value="<?php echo htmlspecialchars($alias_domain) ?>">
 						<div class="form-group">
 							<div class="col-sm-offset-1 col-sm-10">
-								<button type="submit" name="trigger_mailbox_action" value="deletealiasdomain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
+								<button type="submit" name="mailbox_delete_alias_domain" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
 							</div>
 						</div>
 					</form>
@@ -118,7 +118,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					<input type="hidden" name="username" value="<?=htmlspecialchars($mailbox);?>">
 						<div class="form-group">
 							<div class="col-sm-offset-1 col-sm-10">
-								<button type="submit" name="trigger_mailbox_action" value="deletemailbox" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
+								<button type="submit" name="mailbox_delete_mailbox" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
 							</div>
 						</div>
 					</form>
diff --git a/data/web/edit.php b/data/web/edit.php
index d9f54b4f..ce54a2af 100644
--- a/data/web/edit.php
+++ b/data/web/edit.php
@@ -42,7 +42,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 						</div>
 						<div class="form-group">
 							<div class="col-sm-offset-2 col-sm-10">
-								<button type="submit" name="trigger_mailbox_action" value="editalias" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
+								<button type="submit" name="mailbox_edit_alias" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
 							</div>
 						</div>
 					</form>
@@ -191,7 +191,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-							<button type="submit" name="trigger_mailbox_action" value="editdomain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
+							<button type="submit" name="mailbox_edit_domain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
 						</div>
 					</div>
 				</form>
@@ -238,7 +238,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
               if ($wl['object'] == $domain):
               ?>
                 <input type="hidden" name="delete_prefid" value="<?=$wl['prefid'];?>">
-                <input type="hidden" name="trigger_delete_policy_list_item">
+                <input type="hidden" name="delete_policy_list_item">
                 <input type="hidden" name="domain" value="<?=$domain;?>">
                 <a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
               <?php
@@ -264,7 +264,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 						<input type="hidden" name="domain" value="<?=$domain;?>">
 					</div>
 					<div class="col-xs-6">
-						<button type="submit" id="trigger_add_policy_list_item" name="trigger_add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
+						<button type="submit" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
 					</div>
 					</form>
 				</div>
@@ -294,7 +294,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
               <?php
               if ($bl['object'] == $domain):
               ?>
-                <input type="hidden" name="trigger_delete_policy_list_item">
+                <input type="hidden" name="delete_policy_list_item">
                 <input type="hidden" name="domain" value="<?=$domain;?>">
                 <a href="#" onclick="$(this).closest('form').submit()" data-toggle="tooltip" data-placement="left" title="<?=$lang['user']['delete_now'];?>"><span class="glyphicon glyphicon-remove"></span></a>
               <?php
@@ -320,7 +320,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 						<input type="hidden" name="domain" value="<?=$domain;?>">
 					</div>
 					<div class="col-xs-6">
-						<button type="submit" id="trigger_add_policy_list_item" name="trigger_add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
+						<button type="submit" name="add_policy_list_item" class="btn btn-xs btn-default"><?=$lang['user']['spamfilter_table_add'];?></button>
 					</div>
 					</form>
 				</div>
@@ -359,7 +359,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-							<button type="submit" name="trigger_mailbox_action" value="editaliasdomain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
+							<button type="submit" name="mailbox_edit_alias_domain" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
 						</div>
 					</div>
 				</form>
@@ -480,7 +480,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 					</div>
 					<div class="form-group">
 						<div class="col-sm-offset-2 col-sm-10">
-							<button type="submit" name="trigger_mailbox_action" value="editmailbox" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
+							<button type="submit" name="mailbox_edit_mailbox" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
 						</div>
 					</div>
 				</form>
diff --git a/data/web/inc/admin.inc.php b/data/web/inc/admin.inc.php
new file mode 100644
index 00000000..d77d225d
--- /dev/null
+++ b/data/web/inc/admin.inc.php
@@ -0,0 +1,146 @@
+<?php
+function get_admin_details() {
+  // No parameter to be given, only one admin should exist
+	global $pdo;
+	global $lang;
+  $data = array();
+  if ($_SESSION['mailcow_cc_role'] != 'admin') {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => sprintf($lang['danger']['access_denied'])
+    );
+    return false;
+  }
+  try {
+    $stmt = $pdo->prepare("SELECT `username`, `modified`, `created` FROM `admin`WHERE `superadmin`='1' AND active='1'");
+    $stmt->execute();
+    $data = $stmt->fetch(PDO::FETCH_ASSOC);
+  }
+  catch(PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+  }
+  return $data;
+}
+function edit_admin($postarray) {
+	global $lang;
+	global $pdo;
+	$username     = $postarray['username'];
+	$password     = $postarray['password'];
+	$password2    = $postarray['password2'];
+	isset($postarray['active']) ? $active = '1' : $active = '0';
+
+	if ($_SESSION['mailcow_cc_role'] != "admin") {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['access_denied'])
+		);
+		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))) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['username_invalid'])
+		);
+		return false;
+	}
+
+	try {
+		$stmt = $pdo->prepare("DELETE FROM `domain_admins` WHERE `username` = :username");
+		$stmt->execute(array(
+			':username' => $username,
+		));
+	}
+	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)) {
+		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 `admin` SET `modified` = :modified, `active` = :active, `password` = :password_hashed WHERE `username` = :username");
+			$stmt->execute(array(
+				':password_hashed' => $password_hashed,
+				':username' => $username,
+				':modified' => date('Y-m-d H:i:s'),
+				':active' => $active
+			));
+		}
+		catch (PDOException $e) {
+			$_SESSION['return'] = array(
+				'type' => 'danger',
+				'msg' => 'MySQL: '.$e
+			);
+			return false;
+		}
+	}
+	else {
+		try {
+			$stmt = $pdo->prepare("UPDATE `admin` SET `modified` = :modified, `active` = :active WHERE `username` = :username");
+			$stmt->execute(array(
+				':username' => $username,
+				':modified' => date('Y-m-d H:i:s'),
+				':active' => $active
+			));
+		}
+		catch (PDOException $e) {
+			$_SESSION['return'] = array(
+				'type' => 'danger',
+				'msg' => 'MySQL: '.$e
+			);
+			return false;
+		}
+	}
+	$_SESSION['return'] = array(
+		'type' => 'success',
+		'msg' => sprintf($lang['success']['domain_admin_modified'], htmlspecialchars($username))
+	);
+}
\ No newline at end of file
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index cc19ffcf..4e591d2a 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -2,6 +2,7 @@
 require_once 'dkim.inc.php';
 require_once 'mailbox.inc.php';
 require_once 'domainadmin.inc.php';
+require_once 'admin.inc.php';
 function hash_password($password) {
 	$salt_str = bin2hex(openssl_random_pseudo_bytes(8));
 	return "{SSHA256}".base64_encode(hash('sha256', $password . $salt_str, true) . $salt_str);
@@ -433,11 +434,11 @@ function set_time_limited_aliases($postarray) {
 				'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($username))
 			);
 		break;
-		case "extend":
+		case "extendall":
 			try {
-				$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = (`validity` + 3600)
-					WHERE `goto` = :username 
-						AND `validity` >= :validity");
+				$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = (`validity` + 3600) WHERE
+          `goto` = :username AND
+					`validity` >= :validity");
 				$stmt->execute(array(
 					':username' => $username,
 					':validity' => time(),
@@ -455,6 +456,38 @@ function set_time_limited_aliases($postarray) {
 				'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($username))
 			);
 		break;
+		case "extend":
+			if (empty($postarray['item']) || !filter_var($postarray['item'], FILTER_VALIDATE_EMAIL)) {
+				$_SESSION['return'] = array(
+					'type' => 'danger',
+					'msg' => sprintf($lang['danger']['access_denied'])
+				);
+				return false;
+			}
+      $item	= $postarray['item'];
+			try {
+				$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = (`validity` + 3600) WHERE 
+          `goto` = :username AND
+					`address` = :item AND
+					`validity` >= :validity");
+				$stmt->execute(array(
+					':username' => $username,
+					':item' => $item,
+					':validity' => time(),
+				));
+			}
+			catch (PDOException $e) {
+				$_SESSION['return'] = array(
+					'type' => 'danger',
+					'msg' => 'MySQL: '.$e
+				);
+				return false;
+			}
+			$_SESSION['return'] = array(
+				'type' => 'success',
+				'msg' => sprintf($lang['success']['mailbox_modified'], htmlspecialchars($username))
+			);
+		break;
 	}
 }
 function get_time_limited_aliases($username = null) {
diff --git a/data/web/inc/header.inc.php b/data/web/inc/header.inc.php
index 43e1119c..e2d0c865 100644
--- a/data/web/inc/header.inc.php
+++ b/data/web/inc/header.inc.php
@@ -17,157 +17,11 @@
 <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-switch/3.3.2/css/bootstrap3/bootstrap-switch.min.css">
 <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600,700&subset=latin,latin-ext">
 <link rel="stylesheet" href="/inc/languages.min.css">
+<link rel="stylesheet" href="/css/mailcow.css">
+<link rel="stylesheet" href="/css/tables.css">
+<?=(preg_match("/mailbox.php/i", $_SERVER['REQUEST_URI'])) ? '<link rel="stylesheet" href="/css/mailbox.css">' : null;?>
 <link rel="shortcut icon" href="/favicon.png" type="image/png">
 <link rel="icon" href="/favicon.png" type="image/png">
-<style>
-#maxmsgsize { min-width: 80px; }
-ul[id*="sortable"] { word-wrap: break-word; list-style-type: none; float: left; padding: 0 15px 0 0; width: 48%; cursor:move}
-ul[id$="sortable-active"] li {cursor:move; }
-ul[id$="sortable-inactive"] li {cursor:move }
-.list-heading { cursor:default !important}
-.ui-state-disabled { cursor:no-drop; color:#ccc; }
-.ui-state-highlight {background: #F5F5F5 !important; height: 41px !important; cursor:move }
-#slider1 .slider-selection {
-	background: #FFD700;
-}
-#slider1 .slider-track-high {
-	background: #FF4500;
-}
-#slider1 .slider-track-low {
-	background: #66CD00;
-}
-table[data-sortable] {
-  border-collapse: collapse;
-  border-spacing: 0;
-}
-table[data-sortable] th {
-  vertical-align: bottom;
-  font-weight: bold;
-}
-table[data-sortable] th, table[data-sortable] td {
-  text-align: left;
-  padding: 10px;
-}
-table[data-sortable] th:not([data-sortable="false"]) {
-  -webkit-user-select: none;
-  -moz-user-select: none;
-  -ms-user-select: none;
-  -o-user-select: none;
-  user-select: none;
-  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-  -webkit-touch-callout: none;
-  cursor: pointer;
-}
-table[data-sortable] th:after {
-  content: "";
-  visibility: hidden;
-  display: inline-block;
-  vertical-align: inherit;
-  height: 0;
-  width: 0;
-  border-width: 5px;
-  border-style: solid;
-  border-color: transparent;
-  margin-right: 1px;
-  margin-left: 10px;
-  float: right;
-}
-table[data-sortable] th[data-sortable="false"]:after {
-  display: none;
-}
-table[data-sortable] th[data-sorted="true"]:after {
-  visibility: visible;
-}
-table[data-sortable] th[data-sorted-direction="descending"]:after {
-  border-top-color: inherit;
-  margin-top: 8px;
-}
-table[data-sortable] th[data-sorted-direction="ascending"]:after {
-  border-bottom-color: inherit;
-  margin-top: 3px;
-}
-table[data-sortable].sortable-theme-bootstrap thead th {
-  border-bottom: 2px solid #e0e0e0;
-}
-table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"] {
-  color: #3a87ad;
-  background: #d9edf7;
-  border-bottom-color: #bce8f1;
-}
-table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="descending"]:after {
-  border-top-color: #3a87ad;
-}
-table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="ascending"]:after {
-  border-bottom-color: #3a87ad;
-}
-table[data-sortable].sortable-theme-bootstrap.sortable-theme-bootstrap-striped tbody > tr:nth-child(odd) > td {
-  background-color: #f9f9f9;
-}
-.btn {
-   text-transform: none;
-}
-#data td, #no-data td {
-	vertical-align: middle;
-}
-.sort-table:hover {
-  border-bottom-color: #00B7DC !important;
-}
-.striped:nth-child(odd) {
-    background-color: #fff;
-}
-.striped:nth-child(even) {
-    background-color: #fafafa;
-	border:1px solid white;
-}
-.glyphicon-spin {
-    -webkit-animation: spin 1000ms infinite linear;
-    animation: spin 1000ms infinite linear;
-}
-@-webkit-keyframes spin {
-    0% {
-        -webkit-transform: rotate(0deg);
-        transform: rotate(0deg);
-    }
-    100% {
-        -webkit-transform: rotate(359deg);
-        transform: rotate(359deg);
-    }
-}
-@keyframes spin {
-    0% {
-        -webkit-transform: rotate(0deg);
-        transform: rotate(0deg);
-    }
-    100% {
-        -webkit-transform: rotate(359deg);
-        transform: rotate(359deg);
-    }
-}
-</style>
-<?php
-if (preg_match("/mailbox.php/i", $_SERVER['REQUEST_URI'])):
-?>
-<style>
-.panel-heading div {
-	margin-top: -18px;
-	font-size: 15px;
-}
-.panel-heading div span {
-	margin-left:5px;
-}
-.panel-body {
-	display: none;
-}
-.clickable {
-	cursor: pointer;
-}
-.progress {
-	margin-bottom: 0px;
-}
-</style>
-<?php
-endif;
-?>
 </head>
 <body style="padding-top:70px">
 <nav class="navbar navbar-default navbar-fixed-top"  role="navigation">
diff --git a/data/web/inc/mailbox.inc.php b/data/web/inc/mailbox.inc.php
index 2b66ea20..f8c9f6ea 100644
--- a/data/web/inc/mailbox.inc.php
+++ b/data/web/inc/mailbox.inc.php
@@ -671,9 +671,14 @@ function mailbox_edit_alias_domain($postarray) {
 	}
 
 	try {
-		$stmt = $pdo->prepare("UPDATE `alias_domain` SET `alias_domain` = :alias_domain, `active` = :active WHERE `alias_domain` = :alias_domain_now");
+		$stmt = $pdo->prepare("UPDATE `alias_domain` SET
+      `alias_domain` = :alias_domain,
+      `active` = :active,
+      `modified` = :modified,
+        WHERE `alias_domain` = :alias_domain_now");
 		$stmt->execute(array(
 			':alias_domain' => $alias_domain,
+      ':modified' => date('Y-m-d H:i:s'),
 			':alias_domain_now' => $alias_domain_now,
 			':active' => $active
 		));
@@ -747,11 +752,16 @@ function mailbox_edit_alias($postarray) {
 	}
 
 	try {
-		$stmt = $pdo->prepare("UPDATE `alias` SET `goto` = :goto, `active`= :active WHERE `address` = :address");
+		$stmt = $pdo->prepare("UPDATE `alias` SET
+      `goto` = :goto,
+      `active`= :active,
+      `modified` = :modified,
+        WHERE `address` = :address");
 		$stmt->execute(array(
 			':goto' => $goto,
 			':active' => $active,
-			':address' => $address
+			':address' => $address,
+      ':modified' => date('Y-m-d H:i:s'),
 		));
 		$_SESSION['return'] = array(
 			'type' => 'success',
@@ -903,6 +913,7 @@ function mailbox_edit_domain($postarray) {
       `active` = :active,
       `quota` = :quota,
       `maxquota` = :maxquota,
+      `modified` = :modified,
       `mailboxes` = :mailboxes,
       `aliases` = :aliases,
       `description` = :description
@@ -913,6 +924,7 @@ function mailbox_edit_domain($postarray) {
         ':active' => $active,
         ':quota' => $quota,
         ':maxquota' => $maxquota,
+        ':modified' => date('Y-m-d H:i:s'),
         ':mailboxes' => $mailboxes,
         ':aliases' => $aliases,
         ':modified' => date('Y-m-d H:i:s'),
@@ -1856,9 +1868,13 @@ function mailbox_delete_mailbox($postarray) {
 				unset($goto_exploded[$key]);
 			}
 			$gotos_rebuild = implode(',', $goto_exploded);
-			$stmt = $pdo->prepare("UPDATE `alias` SET `goto` = :goto WHERE `address` = :address");
+			$stmt = $pdo->prepare("UPDATE `alias` SET
+        `goto` = :goto,
+        `modified` = :modified,
+          WHERE `address` = :address");
 			$stmt->execute(array(
 				':goto' => $gotos_rebuild,
+        ':modified' => date('Y-m-d H:i:s'),
 				':address' => $gotos['address']
 			));
 		}
diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php
index c7d7415e..26f8824e 100644
--- a/data/web/lang/lang.en.php
+++ b/data/web/lang/lang.en.php
@@ -146,7 +146,7 @@ $lang['user']['tls_policy_warning'] = '<strong>Warning:</strong> If you decide t
 $lang['user']['tls_policy'] = 'Encryption policy';
 $lang['user']['tls_enforce_in'] = 'Enforce TLS incoming';
 $lang['user']['tls_enforce_out'] = 'Enforce TLS outgoing';
-$lang['user']['no_record'] = 'No Record';
+$lang['user']['no_record'] = 'No record';
 
 $lang['user']['misc_settings'] = 'Other profile settings';
 $lang['user']['misc_delete_profile'] = 'Other profile settings';
@@ -227,8 +227,8 @@ $lang['mailbox']['msg_num'] = 'Message #';
 $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']['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';
@@ -420,5 +420,5 @@ $lang['admin']['invalid_max_msg_size'] = 'Invalid max. message size';
 $lang['admin']['site_not_found'] = 'Cannot locate mailcow site configuration';
 $lang['admin']['public_folder_empty'] = 'Public folder name must not be empty';
 $lang['admin']['set_rr_failed'] = 'Cannot set Postfix restrictions';
-$lang['admin']['no_record'] = 'No Record';
+$lang['admin']['no_record'] = 'No record';
 ?>
diff --git a/data/web/user.php b/data/web/user.php
index 32542b01..8fe71561 100644
--- a/data/web/user.php
+++ b/data/web/user.php
@@ -113,33 +113,43 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
 <div class="tab-content">
 	<div role="tabpanel" class="tab-pane active" id="SpamAliases">
 		<div class="row">
-			<div class="col-xs-5">
+			<div class="col-xs-6">
 				<p><b><?=$lang['user']['alias'];?></b></p>
 			</div>
-			<div class="col-xs-4">
+			<div class="col-xs-2">
 				<p><b><?=$lang['user']['alias_valid_until'];?></b></p>
 			</div>
-			<div class="col-xs-3">
+			<div class="col-xs-2">
         <p><b><?=$lang['user']['action'];?></b></p>
 			</div>
+    </div>
 			<?php
       $get_time_limited_aliases = get_time_limited_aliases($username);
       if (!empty($get_time_limited_aliases)):
         foreach ($get_time_limited_aliases as $row):
         ?>
-        <div class="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>
+		<div class="row">
+      <div class="col-xs-6">
+        <p><?=htmlspecialchars($row['address']);?></p>
+      </div>
+      <div class="col-xs-2">
+        <p><?=htmlspecialchars(date($lang['user']['alias_full_date'], $row['validity']));?></p>
+      </div>
+      <div class="col-xs-1">
+        <form class="form-inline" role="form" method="post">
+          <a class="text-danger" href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-remove"></span></a>
+          <input type="hidden" name="set_time_limited_aliases" value="delete">
+          <input type="hidden" name="item" value="<?=htmlspecialchars($row['address']);?>">
+        </form>
+      </div>
+      <div class="col-xs-1">
+        <form class="form-inline" role="form" method="post">
+          <a href="#" onclick="$(this).closest('form').submit()"><span class="glyphicon glyphicon-time"></span> + 1h</a>
+          <input type="hidden" name="set_time_limited_aliases" value="extend">
+          <input type="hidden" name="item" value="<?=htmlspecialchars($row['address']);?>">
+        </form>
+      </div>
+    </div>
         <?php
         endforeach;
 			else:
@@ -150,7 +160,6 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
 			<?php
 			endif;	
 			?>
-		</div>
     <form class="form-horizontal" role="form" method="post">
 		<div class="form-group">
 			<div class="col-sm-9">
@@ -161,16 +170,16 @@ if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == 'user
 					<option value="168">1 <?=$lang['user']['week'];?></option>
 					<option value="672">4 <?=$lang['user']['weeks'];?></option>
 				</select>
-				<button type="submit" id="trigger_set_time_limited_aliases" name="trigger_set_time_limited_aliases" value="generate" class="btn btn-success"><?=$lang['user']['alias_create_random'];?></button>
+				<button type="submit" name="set_time_limited_aliases" value="generate" class="btn btn-success"><?=$lang['user']['alias_create_random'];?></button>
 			</div>
 		</div>
 		<div class="form-group">
 			<div class="col-sm-12">
-				<button style="border-color:#f5f5f5;background:none;color:red" type="submit" name="trigger_set_time_limited_aliases" value="deleteall" class="btn btn-sm">
+				<button type="submit" name="set_time_limited_aliases" value="deleteall" class="btn-danger btn btn-sm">
 					<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> <?=$lang['user']['alias_remove_all'];?>
 				</button>
-				<button style="border-color:#f5f5f5;background:none;color:grey" type="submit" name="trigger_set_time_limited_aliases" value="extend" class="btn btn-sm">
-					<span class="glyphicon glyphicon-hourglass" aria-hidden="true"></span> <?=$lang['user']['alias_extend_all'];?>
+				<button type="submit" name="set_time_limited_aliases" value="extendall" class="btn-default btn btn-sm">
+					<span class="glyphicon glyphicon-time" aria-hidden="true"></span> <?=$lang['user']['alias_extend_all'];?>
 				</button>
 			</div>
 		</div>