Browse Source

Add resources

andryyy 8 năm trước cách đây
mục cha
commit
eb3fb6d1f8

+ 57 - 20
data/web/add.php

@@ -188,30 +188,13 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 						<div class="col-sm-10">
 							<select id="addSelectDomain" name="domain" id="domain" title="<?=$lang['add']['select'];?>" required>
 							<?php
-							try {
-								$stmt = $pdo->prepare("SELECT `domain` FROM `domain`
-										WHERE `domain` IN (
-											SELECT `domain` FROM `domain_admins`
-													WHERE `username`= :username
-													AND `active`='1'
-											)
-											OR 'admin' = :admin");
-								$stmt->execute(array(':username' => $_SESSION['mailcow_cc_username'], ':admin' => $_SESSION['mailcow_cc_role']));
-								$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>
 						</div>
-					</div>
+					</div> 
 					<div class="form-group">
 						<label class="control-label col-sm-2" for="name"><?=$lang['add']['full_name'];?></label>
 						<div class="col-sm-10">
@@ -253,6 +236,60 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 				</form>
 	<?php
 	}
+	elseif (isset($_GET['resource'])) {
+	?>
+				<h4><?=$lang['add']['resource'];?></h4>
+				<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
+					<div class="form-group">
+						<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
+						<div class="col-sm-10">
+							<input type="text" class="form-control" name="description" id="description" required>
+						</div>
+					</div>
+					<div class="form-group">
+						<label class="control-label col-sm-2" for="domain"><?=$lang['add']['domain'];?>:</label>
+						<div class="col-sm-10">
+							<select name="domain" id="domain" title="<?=$lang['add']['select'];?>" required>
+							<?php
+              foreach (mailbox_get_domains() as $domain) {
+								echo "<option>".htmlspecialchars($domain)."</option>";
+							}
+							?>
+							</select>
+						</div>
+					</div>
+					<div class="form-group">
+						<label class="control-label col-sm-2" for="domain"><?=$lang['add']['kind'];?>:</label>
+						<div class="col-sm-10">
+							<select name="kind" id="kind" title="<?=$lang['add']['select'];?>" required>
+								<option value="location">Location</option>
+								<option value="group">Group</option>
+								<option value="thing">Thing</option>
+							</select>
+						</div>
+					</div>
+					<div class="form-group">
+						<div class="col-sm-offset-2 col-sm-10">
+							<div class="checkbox">
+							<label><input type="checkbox" name="active" checked> <?=$lang['add']['active'];?></label>
+							</div>
+						</div>
+					</div>
+					<div class="form-group">
+						<div class="col-sm-offset-2 col-sm-10">
+							<div class="checkbox">
+							<label><input type="checkbox" name="multiple_bookings" checked> <?=$lang['add']['multiple_bookings'];?></label>
+							</div>
+						</div>
+					</div>
+					<div class="form-group">
+						<div class="col-sm-offset-2 col-sm-10">
+							<button type="submit" name="mailbox_add_resource" class="btn btn-success "><?=$lang['add']['save'];?></button>
+						</div>
+					</div>
+				</form>
+	<?php
+	}
 	else {
 	?>
 				<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>

+ 3 - 0
data/web/css/mailbox.css

@@ -13,4 +13,7 @@
 }
 .progress {
 	margin-bottom: 0px;
+}
+.table>thead>tr>th {
+  vertical-align: top !important;
 }

+ 26 - 1
data/web/delete.php

@@ -112,7 +112,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 				$mailbox = $_GET["mailbox"];
 				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>
+					<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_mailbox_warning'], htmlspecialchars($mailbox));?></div>
 					<p><?=$lang['delete']['remove_mailbox_details'];?></p>
 					<form class="form-horizontal" role="form" method="post" action="/mailbox.php">
 					<input type="hidden" name="username" value="<?=htmlspecialchars($mailbox);?>">
@@ -130,6 +130,31 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 				<?php
 				}
 		}
+		// DELETE RESOURCE
+		elseif (isset($_GET["resource"]) &&
+			filter_var($_GET["resource"], FILTER_VALIDATE_EMAIL) &&
+			!empty($_GET["resource"])) {
+				$resource = $_GET["resource"];
+				if (hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resource)) {
+				?>
+					<div class="alert alert-warning" role="alert"><?=sprintf($lang['delete']['remove_resource_warning'], htmlspecialchars($resource));?></div>
+					<p><?=$lang['delete']['remove_resource_details'];?></p>
+					<form class="form-horizontal" role="form" method="post" action="/mailbox.php">
+					<input type="hidden" name="name" value="<?=htmlspecialchars($resource);?>">
+						<div class="form-group">
+							<div class="col-sm-offset-1 col-sm-10">
+								<button type="submit" name="mailbox_delete_resource" class="btn btn-default btn-sm"><?=$lang['delete']['remove_button'];?></button>
+							</div>
+						</div>
+					</form>
+				<?php
+				}
+				else {
+				?>
+					<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>
+				<?php
+				}
+		}
 		else {
 		?>
 			<div class="alert alert-info" role="alert"><?=$lang['info']['no_action'];?></div>

+ 118 - 71
data/web/edit.php

@@ -392,90 +392,130 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 			}
 	}
 	elseif (isset($_GET['mailbox']) && filter_var($_GET["mailbox"], FILTER_VALIDATE_EMAIL) && !empty($_GET["mailbox"])) {
-			$mailbox = $_GET["mailbox"];
-      $result = mailbox_get_mailbox_details($mailbox);
-      if (!empty($result)) {
-        ?>
-				<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']);?>">
-					<div class="form-group">
-						<label class="control-label col-sm-2" for="name"><?=$lang['edit']['full_name'];?>:</label>
-						<div class="col-sm-10">
-						<input type="text" class="form-control" name="name" id="name" value="<?=htmlspecialchars($result['name'], ENT_QUOTES, 'UTF-8');?>">
-						</div>
-					</div>
-					<div class="form-group">
-						<label class="control-label col-sm-2" for="quota"><?=$lang['edit']['quota_mb'];?>:
-							<br /><span id="quotaBadge" class="badge">max. <?=intval($result['max_new_quota'] / 1048576)?> MiB</span>
-						</label>
-						<div class="col-sm-10">
-							<input type="number" name="quota" id="quota" id="destroyable" style="width:100%" min="1" max="<?=intval($result['max_new_quota'] / 1048576);?>" value="<?=intval($result['quota']) / 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 data-width="50%" style="width:100%" id="sender_acl" name="sender_acl[]" size="10" multiple>
-							<?php
-							$sender_acl_handles = mailbox_get_sender_acl_handles($mailbox);
-
-              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;
+    $mailbox = $_GET["mailbox"];
+    $result = mailbox_get_mailbox_details($mailbox);
+    if (!empty($result)) {
+      ?>
+      <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']);?>">
+        <div class="form-group">
+          <label class="control-label col-sm-2" for="name"><?=$lang['edit']['full_name'];?>:</label>
+          <div class="col-sm-10">
+          <input type="text" class="form-control" name="name" id="name" value="<?=htmlspecialchars($result['name'], ENT_QUOTES, 'UTF-8');?>">
+          </div>
+        </div>
+        <div class="form-group">
+          <label class="control-label col-sm-2" for="quota"><?=$lang['edit']['quota_mb'];?>:
+            <br /><span id="quotaBadge" class="badge">max. <?=intval($result['max_new_quota'] / 1048576)?> MiB</span>
+          </label>
+          <div class="col-sm-10">
+            <input type="number" name="quota" id="quota" id="destroyable" style="width:100%" min="1" max="<?=intval($result['max_new_quota'] / 1048576);?>" value="<?=intval($result['quota']) / 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 data-width="50%" style="width:100%" id="sender_acl" name="sender_acl[]" size="10" multiple>
+            <?php
+            $sender_acl_handles = mailbox_get_sender_acl_handles($mailbox);
 
-              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['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;
 
-              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_addresses']['ro'] as $domain):
+              ?>
+            <option data-subtext="Admin" 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['fixed_sender_aliases'] as $alias):
+              ?>
+              <option data-subtext="Alias" disabled selected><?=htmlspecialchars($alias);?></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_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_addresses']['rw'] as $address):
-                ?>
-                  <option selected><?=htmlspecialchars($address);?></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']['selectable'] as $address):
-                ?>
-                  <option><?=htmlspecialchars($address);?></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):
               ?>
-							</select>
-						</div>
-					</div>
+                <option><?=htmlspecialchars($address);?></option>
+              <?php
+            endforeach;
+
+            ?>
+            </select>
+          </div>
+        </div>
+        <div class="form-group">
+          <label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
+          <div class="col-sm-10">
+          <input type="password" class="form-control" name="password" id="password" placeholder="<?=$lang['edit']['unchanged_if_empty'];?>">
+          </div>
+        </div>
+        <div class="form-group">
+          <label class="control-label col-sm-2" for="password2"><?=$lang['edit']['password_repeat'];?></label>
+          <div class="col-sm-10">
+          <input type="password" class="form-control" name="password2" id="password2">
+          </div>
+        </div>
+        <div class="form-group">
+          <div class="col-sm-offset-2 col-sm-10">
+            <div class="checkbox">
+            <label><input type="checkbox" name="active" <?=($result['active_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['active'];?></label>
+            </div>
+          </div>
+        </div>
+        <div class="form-group">
+          <div class="col-sm-offset-2 col-sm-10">
+            <button type="submit" name="mailbox_edit_mailbox" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
+          </div>
+        </div>
+      </form>
+    <?php
+    }
+  }
+	elseif (isset($_GET['resource']) && filter_var($_GET["resource"], FILTER_VALIDATE_EMAIL) && !empty($_GET["resource"])) {
+			$resource = $_GET["resource"];
+      $result = mailbox_get_resource_details($resource);
+      if (!empty($result)) {
+        ?>
+				<h4><?=$lang['edit']['resource'];?></h4>
+				<form class="form-horizontal" role="form" method="post" action="<?=($FORM_ACTION == "previous") ? $_SESSION['return_to'] : null;?>">
+          <input type="hidden" name="name" value="<?=htmlspecialchars($result['name']);?>">
 					<div class="form-group">
-						<label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
+						<label class="control-label col-sm-2" for="description"><?=$lang['add']['description'];?></label>
 						<div class="col-sm-10">
-						<input type="password" class="form-control" name="password" id="password" placeholder="<?=$lang['edit']['unchanged_if_empty'];?>">
+							<input type="text" class="form-control" name="description" id="description" value="<?=$result['description'];?>" required>
 						</div>
 					</div>
 					<div class="form-group">
-						<label class="control-label col-sm-2" for="password2"><?=$lang['edit']['password_repeat'];?></label>
+						<label class="control-label col-sm-2" for="domain"><?=$lang['edit']['kind'];?>:</label>
 						<div class="col-sm-10">
-						<input type="password" class="form-control" name="password2" id="password2">
+							<select name="kind" id="kind" title="<?=$lang['edit']['select'];?>" required>
+								<option value="location" <?=($result['kind'] == "location") ? "selected" : null;?>>Location</option>
+								<option value="group" <?=($result['kind'] == "group") ? "selected" : null;?>>Group</option>
+								<option value="thing" <?=($result['kind'] == "thing") ? "selected" : null;?>>Thing</option>
+							</select>
 						</div>
 					</div>
 					<div class="form-group">
@@ -487,7 +527,14 @@ 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="mailbox_edit_mailbox" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
+							<div class="checkbox">
+							<label><input type="checkbox" name="multiple_bookings" <?=($result['multiple_bookings_int']=="1") ? "checked" : null;?>> <?=$lang['edit']['multiple_bookings'];?></label>
+							</div>
+						</div>
+					</div>
+					<div class="form-group">
+						<div class="col-sm-offset-2 col-sm-10">
+							<button type="submit" name="mailbox_edit_resource" class="btn btn-success btn-sm"><?=$lang['edit']['save'];?></button>
 						</div>
 					</div>
 				</form>

+ 421 - 21
data/web/inc/functions.inc.php

@@ -203,8 +203,9 @@ function check_login($user, $pass) {
 		}
 	}
 	$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
-			WHERE `active`='1'
-			AND `username` = :user");
+			WHERE `kind` NOT REGEXP 'location|thing|group'
+        AND `active`='1'
+        AND `username` = :user");
 	$stmt->execute(array(':user' => $user));
 	$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
 	foreach ($rows as $row) {
@@ -555,7 +556,8 @@ function edit_user_account($postarray) {
 	}
 
 	$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
-			WHERE `username` = :user");
+			WHERE `kind` NOT REGEXP 'location|thing|group'
+        AND `username` = :user");
 	$stmt->execute(array(':user' => $username));
 	$row = $stmt->fetch(PDO::FETCH_ASSOC);
   if (!verify_ssha256($row['password'], $password_old)) {
@@ -1842,7 +1844,7 @@ function set_tfa($postarray) {
 		case "u2f":
       try {
         $reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($postarray['token']));
-        $stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`) values (?, 'u2f', ?, ?, ?, ?)");
+        $stmt = $pdo->prepare("INSERT INTO `tfa` (`username`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`) VALUES (?, 'u2f', ?, ?, ?, ?)");
         $stmt->execute(array($username, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
         $_SESSION['return'] = array(
           'type' => 'success',
@@ -2573,6 +2575,19 @@ function mailbox_add_alias($postarray) {
 			$goto_local_part	= strstr($goto, '@', true);
 			$goto				= $goto_local_part.'@'.$goto_domain;
 
+			$stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
+				WHERE `kind` REGEXP 'location|thing|group'
+          AND `username`= :goto");
+			$stmt->execute(array(':goto' => $goto));
+			$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+      if ($num_results != 0) {
+				$_SESSION['return'] = array(
+					'type' => 'danger',
+					'msg' => sprintf($lang['danger']['goto_invalid'])
+				);
+				return false;
+      }
+
 			if (!filter_var($goto, FILTER_VALIDATE_EMAIL) === true) {
 				$_SESSION['return'] = array(
 					'type' => 'danger',
@@ -2806,7 +2821,8 @@ function mailbox_add_mailbox($postarray) {
 			COUNT(*) as count,
 			COALESCE(ROUND(SUM(`quota`)/1048576), 0) as `quota`
 				FROM `mailbox`
-					WHERE `domain` = :domain");
+					WHERE `kind` NOT REGEXP 'location|thing|group'
+            AND `domain` = :domain");
 		$stmt->execute(array(':domain' => $domain));
 		$MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
 
@@ -2950,7 +2966,147 @@ function mailbox_add_mailbox($postarray) {
 		);
 	}
 	catch (PDOException $e) {
-    mailbox_delete_mailbox(array('address' => $username));
+    mailbox_delete_mailbox(array('username' => $username));
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => 'MySQL: '.$e
+		);
+		return false;
+	}
+}
+function mailbox_add_resource($postarray) {
+  // Array elements
+  // active             int
+  // domain             string
+  // description        string
+  // multiple_bookings  int
+  // kind               string
+
+	global $pdo;
+	global $lang;
+	$domain             = idn_to_ascii(strtolower(trim($postarray['domain'])));
+  $description        = $postarray['description'];
+  $local_part         = preg_replace('/[^\da-z]/i', '', preg_quote($description, '/'));
+  $name               = $local_part . '@' . $domain;
+  $kind               = $postarray['kind'];
+	isset($postarray['active']) ? $active = '1' : $active = '0';
+	isset($postarray['multiple_bookings']) ? $multiple_bookings = '1' : $multiple_bookings = '0';
+
+	if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['resource_invalid'])
+		);
+		return false;
+	}
+
+	if (empty($description)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['description_invalid'])
+		);
+		return false;
+  }
+  
+	if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['resource_invalid'])
+		);
+		return false;
+	}
+
+	if (!is_valid_domain_name($domain)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['domain_invalid'])
+		);
+		return false;
+	}
+
+	if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['access_denied'])
+		);
+		return false;
+	}
+
+	try {
+		$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :name");
+		$stmt->execute(array(':name' => $name));
+		$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+    if ($num_results != 0) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['object_exists'], htmlspecialchars($name))
+      );
+      return false;
+    }
+
+		$stmt = $pdo->prepare("SELECT `address` FROM `alias` WHERE address= :name");
+		$stmt->execute(array(':name' => $name));
+		$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+    if ($num_results != 0) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['is_alias'], htmlspecialchars($name))
+      );
+      return false;
+    }
+
+		$stmt = $pdo->prepare("SELECT `address` FROM `spamalias` WHERE `address`= :name");
+		$stmt->execute(array(':name' => $name));
+		$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+    if ($num_results != 0) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['is_spam_alias'], htmlspecialchars($name))
+      );
+      return false;
+    }
+
+		$stmt = $pdo->prepare("SELECT `domain` FROM `domain` WHERE `domain`= :domain");
+		$stmt->execute(array(':domain' => $domain));
+		$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
+    if ($num_results == 0) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => sprintf($lang['danger']['domain_not_found'], $domain)
+      );
+      return false;
+    }
+  }
+	catch(PDOException $e) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => 'MySQL: '.$e
+		);
+		return false;
+	}
+
+	try {
+		$stmt = $pdo->prepare("INSERT INTO `mailbox` (`username`, `password`, `name`, `maildir`, `quota`, `local_part`, `domain`, `created`, `modified`, `active`, `multiple_bookings`, `kind`) 
+			VALUES (:name, 'RESOURCE', :description, 'RESOURCE', 0, :local_part, :domain, :created, :modified, :active, :multiple_bookings, :kind)");
+		$stmt->execute(array(
+			':name' => $name,
+			':description' => $description,
+			':local_part' => $local_part,
+			':domain' => $domain,
+			':created' => date('Y-m-d H:i:s'),
+			':modified' => date('Y-m-d H:i:s'),
+			':active' => $active,
+			':kind' => $kind,
+			':multiple_bookings' => $multiple_bookings
+		));
+
+		$_SESSION['return'] = array(
+			'type' => 'success',
+			'msg' => sprintf($lang['success']['resource_added'], htmlspecialchars($name))
+		);
+	}
+	catch (PDOException $e) {
+    mailbox_delete_resource(array('name' => $name));
 		$_SESSION['return'] = array(
 			'type' => 'danger',
 			'msg' => 'MySQL: '.$e
@@ -3200,7 +3356,8 @@ function mailbox_edit_domain($postarray) {
           MAX(COALESCE(ROUND(`quota`/1048576), 0)) AS `maxquota`,
           COALESCE(ROUND(SUM(`quota`)/1048576), 0) AS `quota`
             FROM `mailbox`
-              WHERE domain= :domain");
+              WHERE `kind` NOT REGEXP 'location|thing|group'
+                AND domain = :domain");
       $stmt->execute(array(':domain' => $domain));
       $MailboxData = $stmt->fetch(PDO::FETCH_ASSOC);
       // GET ALIAS DATA
@@ -3562,6 +3719,78 @@ function mailbox_edit_mailbox($postarray) {
 		return false;
 	}
 }
+function mailbox_edit_resource($postarray) {
+	global $lang;
+	global $pdo;
+
+	isset($postarray['active']) ? $active = '1' : $active = '0';
+	isset($postarray['multiple_bookings']) ? $multiple_bookings = '1' : $multiple_bookings = '0';
+	$name               = $postarray['name'];
+	$kind               = $postarray['kind'];
+	$description        = $postarray['description'];
+
+	if (!filter_var($name, FILTER_VALIDATE_EMAIL)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['resource_invalid'])
+		);
+		return false;
+	}
+
+	if (empty($description)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['description_invalid'])
+		);
+		return false;
+  }
+
+	if ($kind != 'location' && $kind != 'group' && $kind != 'thing') {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['resource_invalid'])
+		);
+		return false;
+	}
+
+  if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => sprintf($lang['danger']['access_denied'])
+    );
+    return false;
+  }
+
+	try {
+		$stmt = $pdo->prepare("UPDATE `mailbox` SET
+				`modified` = :modified,
+				`active` = :active,
+				`name`= :description,
+				`kind`= :kind,
+				`multiple_bookings`= :multiple_bookings
+          WHERE `username` = :name");
+		$stmt->execute(array(
+			':active' => $active,
+			':modified' => date('Y-m-d H:i:s'),
+			':description' => $description,
+			':multiple_bookings' => $multiple_bookings,
+			':kind' => $kind,
+			':name' => $name
+		));
+		$_SESSION['return'] = array(
+			'type' => 'success',
+			'msg' => sprintf($lang['success']['resource_modified'], $name)
+		);
+		return true;
+	}
+	catch (PDOException $e) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => 'MySQL: '.$e
+		);
+		return false;
+	}
+}
 function mailbox_get_mailboxes($domain = null) {
 	global $lang;
 	global $pdo;
@@ -3575,7 +3804,7 @@ function mailbox_get_mailboxes($domain = null) {
 	}
   elseif (isset($domain) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
     try {
-      $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `domain` != 'ALL' AND `domain` = :domain");
+      $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` != 'ALL' AND `domain` = :domain");
       $stmt->execute(array(
         ':domain' => $domain,
       ));
@@ -3594,7 +3823,7 @@ function mailbox_get_mailboxes($domain = null) {
   }
   else {
     try {
-      $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
+      $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
       $stmt->execute(array(
         ':username' => $_SESSION['mailcow_cc_username'],
         ':role' => $_SESSION['mailcow_cc_role'],
@@ -3614,6 +3843,58 @@ function mailbox_get_mailboxes($domain = null) {
   }
   return $mailboxes;
 }
+function mailbox_get_resources($domain = null) {
+	global $lang;
+	global $pdo;
+  $resources = array();
+	if (isset($domain) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['access_denied'])
+		);
+		return false;
+	}
+  elseif (isset($domain) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+    try {
+      $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` != 'ALL' AND `domain` = :domain");
+      $stmt->execute(array(
+        ':domain' => $domain,
+      ));
+      $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+      while($row = array_shift($rows)) {
+        $resources[] = $row['username'];
+      }
+    }
+    catch (PDOException $e) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => 'MySQL: '.$e
+      );
+      return false;
+    }
+  }
+  else {
+    try {
+      $stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `domain` IN (SELECT `domain` FROM `domain_admins` WHERE `active` = '1' AND `username` = :username) OR 'admin' = :role");
+      $stmt->execute(array(
+        ':username' => $_SESSION['mailcow_cc_username'],
+        ':role' => $_SESSION['mailcow_cc_role'],
+      ));
+      $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
+      while($row = array_shift($rows)) {
+        $resources[] = $row['username'];
+      }
+    }
+    catch (PDOException $e) {
+      $_SESSION['return'] = array(
+        'type' => 'danger',
+        'msg' => 'MySQL: '.$e
+      );
+      return false;
+    }
+  }
+  return $resources;
+}
 function mailbox_get_alias_domains($domain = null) {
   // Get all domains assigned to mailcow_cc_username or domain, if set
   // Domain admin needs to be active
@@ -3853,7 +4134,7 @@ function mailbox_get_domain_details($domain) {
       ':domain' => $domain,
     ));
     $row = $stmt->fetch(PDO::FETCH_ASSOC);
-    $stmt = $pdo->prepare("SELECT COUNT(*) AS `count`, COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE `domain` = :domain");
+    $stmt = $pdo->prepare("SELECT COUNT(*) AS `count`, COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` = :domain");
     $stmt->execute(array(':domain' => $row['domain']));
     $MailboxDataDomain	= $stmt->fetch(PDO::FETCH_ASSOC);
 
@@ -3901,6 +4182,13 @@ function mailbox_get_domain_details($domain) {
 function mailbox_get_mailbox_details($mailbox) {
 	global $lang;
 	global $pdo;
+  if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $mailbox)) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => sprintf($lang['danger']['access_denied'])
+    );
+    return false;
+  }
   $mailboxdata = array();
   try {
     $stmt = $pdo->prepare("SELECT
@@ -3914,7 +4202,7 @@ function mailbox_get_mailbox_details($mailbox) {
         `quota2`.`bytes`,
         `quota2`.`messages`
           FROM `mailbox`, `quota2`, `domain`
-            WHERE `mailbox`.`username` = `quota2`.`username` AND `domain`.`domain` = `mailbox`.`domain` AND `mailbox`.`username` = :mailbox");
+            WHERE `mailbox`.`kind` NOT REGEXP 'location|thing|group' AND `mailbox`.`username` = `quota2`.`username` AND `domain`.`domain` = `mailbox`.`domain` AND `mailbox`.`username` = :mailbox");
     $stmt->execute(array(
       ':mailbox' => $mailbox,
     ));
@@ -3924,7 +4212,7 @@ function mailbox_get_mailbox_details($mailbox) {
     $stmt->execute(array(':domain' => $row['domain']));
     $DomainQuota  = $stmt->fetch(PDO::FETCH_ASSOC);
 
-    $stmt = $pdo->prepare("SELECT COUNT(*) AS `count`, COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE `domain` = :domain AND `username` != :username");
+    $stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE `kind` NOT REGEXP 'location|thing|group' AND `domain` = :domain AND `username` != :username");
     $stmt->execute(array(':domain' => $row['domain'], ':username' => $row['username']));
     $MailboxUsage	= $stmt->fetch(PDO::FETCH_ASSOC);
 
@@ -3960,8 +4248,54 @@ function mailbox_get_mailbox_details($mailbox) {
     );
     return false;
   }
-  if (!isset($mailboxdata['domain']) ||
-    (isset($mailboxdata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $mailboxdata['domain']))) {
+  return $mailboxdata;
+}
+function mailbox_get_resource_details($resource) {
+	global $lang;
+	global $pdo;
+  $resourcedata = array();
+  if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resource)) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => sprintf($lang['danger']['access_denied'])
+    );
+    return false;
+  }
+  try {
+    $stmt = $pdo->prepare("SELECT
+        `username`,
+        `name`,
+        `kind`,
+        `multiple_bookings` AS `multiple_bookings_int`,
+        `local_part`,
+        `active` AS `active_int`,
+        CASE `multiple_bookings` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `multiple_bookings`,
+        CASE `active` WHEN 1 THEN '".$lang['mailbox']['yes']."' ELSE '".$lang['mailbox']['no']."' END AS `active`,
+        `domain`
+          FROM `mailbox` WHERE `kind` REGEXP 'location|thing|group' AND `username` = :resource");
+    $stmt->execute(array(
+      ':resource' => $resource,
+    ));
+    $row = $stmt->fetch(PDO::FETCH_ASSOC);
+    $resourcedata['name'] = $row['username'];
+    $resourcedata['kind'] = $row['kind'];
+    $resourcedata['multiple_bookings'] = $row['multiple_bookings'];
+    $resourcedata['multiple_bookings_int'] = $row['multiple_bookings'];
+    $resourcedata['description'] = $row['name'];
+    $resourcedata['active'] = $row['active'];
+    $resourcedata['active_int'] = $row['active_int'];
+    $resourcedata['domain'] = $row['domain'];
+    $resourcedata['local_part'] = $row['local_part'];
+  }
+  catch (PDOException $e) {
+    $_SESSION['return'] = array(
+      'type' => 'danger',
+      'msg' => 'MySQL: '.$e
+    );
+    return false;
+  }
+  if (!isset($resourcedata['domain']) ||
+    (isset($resourcedata['domain']) && !hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $resourcedata['domain']))) {
     $_SESSION['return'] = array(
       'type' => 'danger',
       'msg' => sprintf($lang['danger']['access_denied'])
@@ -3969,7 +4303,7 @@ function mailbox_get_mailbox_details($mailbox) {
     return false;
   }
   
-  return $mailboxdata;
+  return $resourcedata;
 }
 function mailbox_delete_domain($postarray) {
 	global $lang;
@@ -3989,8 +4323,7 @@ function mailbox_delete_domain($postarray) {
 		);
 		return false;
 	}
-	$domain	= strtolower(trim($domain));
-
+	$domain	= idn_to_ascii(strtolower(trim($domain)));
 
 	try {
 		$stmt = $pdo->prepare("SELECT `username` FROM `mailbox`
@@ -4113,6 +4446,7 @@ function mailbox_delete_alias($postarray) {
 function mailbox_delete_alias_domain($postarray) {
 	global $lang;
 	global $pdo;
+  $alias_domain = $postarray['alias_domain'];
 	if (!is_valid_domain_name($postarray['alias_domain'])) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
@@ -4120,7 +4454,6 @@ function mailbox_delete_alias_domain($postarray) {
 		);
 		return false;
 	}
-	$alias_domain = $postarray['alias_domain'];
 	try {
 		$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain`
 			WHERE `alias_domain`= :alias_domain");
@@ -4169,7 +4502,7 @@ function mailbox_delete_mailbox($postarray) {
 	global $lang;
 	global $pdo;
 	$username	= $postarray['username'];
-  $domain = mailbox_get_mailbox_details($username)['domain'];
+
 	if (!filter_var($postarray['username'], FILTER_VALIDATE_EMAIL)) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
@@ -4177,7 +4510,8 @@ function mailbox_delete_mailbox($postarray) {
 		);
 		return false;
 	}
-	if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
+
+	if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
 		$_SESSION['return'] = array(
 			'type' => 'danger',
 			'msg' => sprintf($lang['danger']['access_denied'])
@@ -4214,6 +4548,34 @@ function mailbox_delete_mailbox($postarray) {
 		$stmt->execute(array(
 			':username' => $username
 		));
+    $stmt = $pdo->prepare("DELETE FROM `sogo_user_profile` WHERE `c_uid` = :username");
+    $stmt->execute(array(
+      ':username' => $username
+    ));
+    $stmt = $pdo->prepare("DELETE FROM `sogo_cache_folder` WHERE `c_uid` = :username");
+    $stmt->execute(array(
+      ':username' => $username
+    ));
+    $stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $username . "/%' OR `c_uid` = :username");
+    $stmt->execute(array(
+      ':username' => $username
+    ));
+    $stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+    $stmt->execute(array(
+      ':username' => $username
+    ));
+    $stmt = $pdo->prepare("DELETE FROM `sogo_quick_contact` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+    $stmt->execute(array(
+      ':username' => $username
+    ));
+    $stmt = $pdo->prepare("DELETE FROM `sogo_quick_appointment` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+    $stmt->execute(array(
+      ':username' => $username
+    ));
+    $stmt = $pdo->prepare("DELETE FROM `sogo_folder_info` WHERE `c_path2` = :username");
+    $stmt->execute(array(
+      ':username' => $username
+    ));
 		$stmt = $pdo->prepare("SELECT `address`, `goto` FROM `alias`
 				WHERE `goto` LIKE :username");
 		$stmt->execute(array(':username' => '%'.$username.'%'));
@@ -4247,6 +4609,44 @@ function mailbox_delete_mailbox($postarray) {
 		'msg' => sprintf($lang['success']['mailbox_removed'], htmlspecialchars($username))
 	);
 }
+function mailbox_delete_resource($postarray) {
+	global $lang;
+	global $pdo;
+	$name	= $postarray['name'];
+	if (!filter_var($postarray['name'], FILTER_VALIDATE_EMAIL)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['access_denied'])
+		);
+		return false;
+	}
+
+	if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $name)) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => sprintf($lang['danger']['access_denied'])
+		);
+		return false;
+	}
+
+	try {
+		$stmt = $pdo->prepare("DELETE FROM `mailbox` WHERE `username` = :name");
+		$stmt->execute(array(
+			':name' => $name
+		));
+	}
+	catch (PDOException $e) {
+		$_SESSION['return'] = array(
+			'type' => 'danger',
+			'msg' => 'MySQL: '.$e
+		);
+		return false;
+	}
+	$_SESSION['return'] = array(
+		'type' => 'success',
+		'msg' => sprintf($lang['success']['resource_removed'], htmlspecialchars($name))
+	);
+}
 function mailbox_get_sender_acl_handles($mailbox) {
 	global $pdo;
 	global $lang;
@@ -4369,7 +4769,7 @@ function get_u2f_registrations($username) {
 function add_u2f_registration($username, $reg) {
   global $pdo;
   global $lang;
-  $ins = $pdo->prepare("INSERT INTO `tfa` (`username`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`) values (?, 'u2f', ?, ?, ?, ?)");
+  $ins = $pdo->prepare("INSERT INTO `tfa` (`username`, `authmech`, `keyHandle`, `publicKey`, `certificate`, `counter`) VALUES (?, 'u2f', ?, ?, ?, ?)");
   $ins->execute(array($username, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
 	$_SESSION['return'] = array(
 		'type' => 'success',

+ 2 - 2
data/web/inc/init.sql

@@ -205,7 +205,7 @@ CREATE TABLE IF NOT EXISTS sogo_folder_info (
 	UNIQUE KEY c_folder_id (c_folder_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
 
-CREATE TABLE IF NOT EXISTS sogo_quick_appoINTment (
+CREATE TABLE IF NOT EXISTS sogo_quick_appointment (
 	c_folder_id INTeger NOT NULL,
 	c_name character varying(255) NOT NULL,
 	c_uid character varying(255) NOT NULL,
@@ -230,7 +230,7 @@ CREATE TABLE IF NOT EXISTS sogo_quick_appoINTment (
 	c_component character varying(10) NOT NULL,
 	c_nextalarm INTeger,
 	c_description TEXT,
-	CONSTRAINT sogo_quick_appoINTment_pkey PRIMARY KEY (c_folder_id, c_name)
+	CONSTRAINT sogo_quick_appointment_pkey PRIMARY KEY (c_folder_id, c_name)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
 
 CREATE TABLE IF NOT EXISTS sogo_quick_contact (

+ 8 - 2
data/web/inc/triggers.inc.php

@@ -130,8 +130,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 	if (isset($_POST["mailbox_add_mailbox"])) {
 		mailbox_add_mailbox($_POST);
 	}
-	if (isset($_POST["mailbox_add_mailbox"])) {
-		mailbox_add_mailbox($_POST);
+	if (isset($_POST["mailbox_add_resource"])) {
+		mailbox_add_resource($_POST);
 	}
 	if (isset($_POST["mailbox_edit_alias"])) {
 		mailbox_edit_alias($_POST);
@@ -145,6 +145,9 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 	if (isset($_POST["mailbox_edit_alias_domain"])) {
 		mailbox_edit_alias_domain($_POST);
 	}
+	if (isset($_POST["mailbox_edit_resource"])) {
+		mailbox_edit_resource($_POST);
+	}
 	if (isset($_POST["trigger_delete_policy_list_item"])) {
 		delete_policy_list_item($_POST);
 	}
@@ -160,5 +163,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
 	if (isset($_POST["mailbox_delete_mailbox"])) {
 		mailbox_delete_mailbox($_POST);
 	}
+	if (isset($_POST["mailbox_delete_resource"])) {
+		mailbox_delete_resource($_POST);
+	}
 }
 ?>

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

@@ -5,10 +5,12 @@ $(document).ready(function() {
 	var rowCountDomain = $('#domaintable >tbody >#data').length;
 	var rowCountMailbox = $('#mailboxtable >tbody >#data').length;
 	var rowCountAlias = $('#aliastable >tbody >#data').length;
+	var rowCountResource = $('#resourcetable >tbody >#data').length;
 	$("#numRowsDomainAlias").text(rowCountDomainAlias);
 	$("#numRowsDomain").text(rowCountDomain);
 	$("#numRowsMailbox").text(rowCountMailbox);
 	$("#numRowsAlias").text(rowCountAlias);
+	$("#numRowsResource").text(rowCountResource);
 
 	// Filter table function
 	$.fn.extend({

+ 19 - 4
data/web/lang/lang.de.php

@@ -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']['resource_modified'] = "Änderungen an Ressource %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';
@@ -59,10 +60,9 @@ $lang['danger']['password_complexity'] = 'Passwort entspricht nicht den Vorgaben
 $lang['danger']['password_empty'] = 'Passwort darf nicht leer sein';
 $lang['danger']['login_failed'] = 'Anmeldung fehlgeschlagen';
 $lang['danger']['mailbox_invalid'] = 'Mailboxname ist ungültig';
+$lang['danger']['resource_invalid'] = 'Ressourcenname ist ungültig';
+$lang['danger']['description_invalid'] = 'Ressourcenbeschreibung ist ungültig';
 $lang['danger']['mailbox_invalid_suggest'] = 'Mailboxname ist ungültig, meinten Sie vielleicht "%s"?';
-$lang['info']['fetchmail_planned'] = 'Aufgabe zur Mailabholung wurde geplant. Bitte prüfen Sie den Vorgangsstatus zu einem späteren Zeitpunkt noch einmal.';
-$lang['danger']['fetchmail_source_empty'] = 'Bitte geben Sie einen Quell-Ordner an';
-$lang['danger']['fetchmail_dest_empty'] = 'Bitte geben Sie einen Ziel-Ordner an';
 $lang['danger']['is_alias'] = '%s lautet bereits eine Alias-Adresse';
 $lang['danger']['is_alias_or_mailbox'] = "Eine Mailbox oder ein Alias mit der Adresse %s ist bereits vorhanden";
 $lang['danger']['is_spam_alias'] = '%s lautet bereits eine Spam-Alias-Adresse';
@@ -72,11 +72,13 @@ $lang['danger']['max_mailbox_exceeded'] = 'Anzahl an Mailboxen überschritten (%
 $lang['danger']['mailbox_quota_exceeded'] = 'Speicherplatz überschreitet das Limit (max. %d MiB)';
 $lang['danger']['mailbox_quota_left_exceeded'] = 'Nicht genügend Speicherplatz vorhanden (Speicherplatz anwendbar: %d MiB)';
 $lang['success']['mailbox_added'] = 'Mailbox %s wurde angelegt';
+$lang['success']['resource_added'] = 'Ressource %s wurde angelegt';
 $lang['success']['domain_removed'] = 'Domain %s wurde entfernt';
 $lang['success']['alias_removed'] = 'Alias-Adresse %s wurde entfernt';
 $lang['success']['alias_domain_removed'] = 'Alias-Domain %s wurde entfernt';
 $lang['success']['domain_admin_removed'] = 'Domain-Administrator %s wurde entfernt';
 $lang['success']['mailbox_removed'] = 'Mailbox %s wurde entfernt';
+$lang['success']['resource_removed'] = 'Ressource %s wurde entfernt';
 $lang['danger']['max_quota_in_use'] = 'Mailbox Speicherplatzlimit muss größer oder gleich %d MiB sein';
 $lang['danger']['domain_quota_m_in_use'] = 'Domain Speicherplatzlimit muss größer oder gleich %d MiB sein';
 $lang['danger']['mailboxes_in_use'] = 'Maximale Anzahl an Mailboxen muss größer oder gleich %d sein';
@@ -85,7 +87,6 @@ $lang['danger']['sender_acl_invalid'] = 'Sender ACL Wert muss eine Adresse oder
 $lang['danger']['domain_not_empty'] = 'Kann nur leere Domains entfernen';
 $lang['warning']['spam_alias_temp_error'] = 'Kann zur Zeit keinen Spam-Alias erstellen, bitte versuchen Sie es später noch einmal.';
 $lang['danger']['spam_alias_max_exceeded'] = 'Maximale Anzahl an Spam-Alias-Adressen erreicht';
-$lang['danger']['fetchmail_active'] = 'Ein Vorgang zur Mailabholung ist bereits aktiv, bitte haben Sie etwas Geduld.';
 $lang['danger']['validity_missing'] = 'Bitte geben Sie eine Gültigkeitsdauer an';
 $lang['user']['on'] = 'Ein';
 $lang['user']['off'] = 'Aus';
@@ -203,6 +204,10 @@ $lang['header']['locale'] = 'Sprache';
 $lang['mailbox']['domain'] = 'Domain';
 $lang['mailbox']['alias'] = 'Alias';
 $lang['mailbox']['aliases'] = 'Aliasse';
+$lang['mailbox']['multiple_bookings'] = 'Mehrfachbuchen';
+$lang['mailbox']['kind'] = 'Art';
+$lang['mailbox']['description'] = 'Beschreibung';
+$lang['mailbox']['resource_name'] = 'Ressourcenname';
 $lang['mailbox']['domains'] = 'Domains';
 $lang['mailbox']['mailboxes'] = 'Mailboxen';
 $lang['mailbox']['mailbox_quota'] = 'Max. Größe einer Mailbox';
@@ -230,6 +235,7 @@ $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';
+$lang['mailbox']['add_resource'] = 'Ressource hinzufügen';
 $lang['mailbox']['add_alias'] = 'Alias hinzufügen';
 
 $lang['info']['no_action'] = 'Keine Aktion anwendbar';
@@ -242,6 +248,8 @@ $lang['delete']['remove_alias_warning'] = '<b>Warnung:</b> Sie entfernen die Ali
 $lang['delete']['remove_syncjob_warning'] = '<b>Warnung:</b> Sie entfernen einen Sync-Job des Benutzers <b>%s</b>!';
 $lang['delete']['remove_mailbox_warning'] = '<b>Warnung:</b> Sie entfernen die Mailbox <b>%s</b>!';
 $lang['delete']['remove_mailbox_details'] = 'Die Mailbox wird <b>vollständig und permanent</b> entfernt!';
+$lang['delete']['remove_resource_warning'] = '<b>Warnung:</b> Sie entfernen die Ressource <b>%s</b>!';
+$lang['delete']['remove_resource_details'] = 'Die Ressource wird <b>vollständig und permanent</b> entfernt!';
 $lang['delete']['remove_domain_details'] = 'Diese Aktion entfernt ebenfalls Domain-Aliasse.<br /><br /><b>Eine Domain muss leer sein, um entfernt zu werden.</b>';
 $lang['delete']['remove_syncjob_details'] = 'Objekte dieses Sync-Jobs werden nicht mehr vom entfernten Server abgeholt.';
 $lang['delete']['remove_alias_details'] = 'Benutzer werden keine Nachrichten mehr von dieser Adresse erhalten und versenden koennen!</b>';
@@ -294,6 +302,9 @@ $lang['edit']['dkim_txt_value'] = 'TXT-Record Wert:';
 $lang['edit']['previous'] = 'Vorherige Seite';
 $lang['edit']['unchanged_if_empty'] = 'Unverändert, wenn leer';
 $lang['edit']['dont_check_sender_acl'] = 'Absender für Domain %s nicht prüfen';
+$lang['edit']['multiple_bookings'] = 'Mehrfaches Buchen';
+$lang['edit']['kind'] = 'Art';
+$lang['edit']['resource'] = 'Ressource';
 
 $lang['add']['syncjob'] = 'Sync-Job erstellen';
 $lang['add']['syncjob_hint'] = 'Passwörter werden unverschlüsselt abgelegt!';
@@ -309,6 +320,7 @@ $lang['add']['delete2duplicates'] = 'Lösche Duplikate im Ziel';
 $lang['add']['title'] = 'Objekt anlegen';
 $lang['add']['domain'] = 'Domain';
 $lang['add']['active'] = 'Aktiv';
+$lang['add']['multiple_bookings'] = 'Mehrfaches Buchen möglich';
 $lang['add']['save'] = 'Änderungen speichern';
 $lang['add']['description'] = 'Beschreibung:';
 $lang['add']['max_aliases'] = 'Max. mögliche Aliasse:';
@@ -330,7 +342,10 @@ $lang['add']['alias_domain'] = 'Alias-Domain';
 $lang['add']['select'] = 'Bitte auswählen';
 $lang['add']['target_domain'] = 'Ziel-Domain:';
 $lang['add']['mailbox'] = 'Mailbox';
+$lang['add']['resource'] = 'Ressource';
+$lang['add']['kind'] = 'Art';
 $lang['add']['mailbox_username'] = 'Benutzername (linker Teil der E-Mail-Adresse):';
+$lang['add']['resource_name'] = 'Ressourcenname:';
 $lang['add']['full_name'] = 'Vor- und Zuname:';
 $lang['add']['quota_mb'] = 'Speicherplatz (MiB):';
 $lang['add']['select_domain'] = 'Bitte zuerst eine Domain auswählen';

+ 19 - 5
data/web/lang/lang.en.php

@@ -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']['resource_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";
@@ -61,10 +62,9 @@ $lang['danger']['password_complexity'] = "Password does not meet requirements (u
 $lang['danger']['password_empty'] = "Password must not be empty";
 $lang['danger']['login_failed'] = "Login failed";
 $lang['danger']['mailbox_invalid'] = "Mailbox name is invalid";
+$lang['danger']['description_invalid'] = 'Resource description is invalid';
+$lang['danger']['resource_invalid'] = "Resource name is invalid";
 $lang['danger']['mailbox_invalid_suggest'] = 'Mailbox name is invalid, did you mean to type "%s"?';
-$lang['info']['fetchmail_planned'] = "Task to fetch emails has been planned. Please check the process at a later time.";
-$lang['danger']['fetchmail_source_empty'] = "Please define a source folder";
-$lang['danger']['fetchmail_dest_empty'] = "Please define a target folder";
 $lang['danger']['is_alias'] = "%s is already known as an alias address";
 $lang['danger']['is_alias_or_mailbox'] = "%s is already known as an alias or a mailbox";
 $lang['danger']['is_spam_alias'] = "%s is already known as a spam alias address";
@@ -74,11 +74,13 @@ $lang['danger']['max_mailbox_exceeded'] = "Max. mailboxes exceeded (%d of %d)";
 $lang['danger']['mailbox_quota_exceeded'] = "Quota exceeds the domain limit (max. %d MiB)";
 $lang['danger']['mailbox_quota_left_exceeded'] = "Not enough space left (space left: %d MiB)";
 $lang['success']['mailbox_added'] = "Mailbox %s has been added";
+$lang['success']['resource_added'] = "Resource %s has been added";
 $lang['success']['domain_removed'] = "Domain %s has been removed";
 $lang['success']['alias_removed'] = "Alias-Adresse %s has been removed";
 $lang['success']['alias_domain_removed'] = "Alias domain %s has been removed";
 $lang['success']['domain_admin_removed'] = "Domain administrator %s has been removed";
 $lang['success']['mailbox_removed'] = "Mailbox %s has been removed";
+$lang['success']['resource_removed'] = "Resource %s has been removed";
 $lang['danger']['max_quota_in_use'] = "Mailbox quota must be greater or equal to %d MiB";
 $lang['danger']['domain_quota_m_in_use'] = "Domain quota must be greater or equal to %s MiB";
 $lang['danger']['mailboxes_in_use'] = "Max. mailboxes must be greater or equal to %d";
@@ -87,9 +89,7 @@ $lang['danger']['sender_acl_invalid'] = "Sender ACL value is invalid";
 $lang['danger']['domain_not_empty'] = "Cannot remove non-empty domain";
 $lang['warning']['spam_alias_temp_error'] = "Temporary error: Cannot add spam alias, please try again later.";
 $lang['danger']['spam_alias_max_exceeded'] = "Max. allowed spam alias addresses exceeded";
-$lang['danger']['fetchmail_active'] = "A process is already running, please wait for it to finish.";
 $lang['danger']['validity_missing'] = 'Please assign a period of validity';
-$lang['danger']['tfa_token_invalid'] = 'TFA token is invalid';
 $lang['user']['on'] = "On";
 $lang['user']['off'] = "Off";
 $lang['user']['user_change_fn'] = "";
@@ -204,7 +204,11 @@ $lang['header']['logged_in_as_logout'] = 'Logged in as <b>%s</b> (logout)';
 $lang['header']['logged_in_as_logout_dual'] = 'Logged in as <b>%s <span class="text-info">[%s]</span></b>';
 $lang['header']['locale'] = 'Language';
 $lang['mailbox']['domain'] = 'Domain';
+$lang['mailbox']['multiple_bookings'] = 'Multiple bookings';
+$lang['mailbox']['kind'] = 'Kind';
+$lang['mailbox']['description'] = 'Description';
 $lang['mailbox']['alias'] = 'Alias';
+$lang['mailbox']['resource_name'] = 'Resource name';
 $lang['mailbox']['aliases'] = 'Aliases';
 $lang['mailbox']['domains'] = 'Domains';
 $lang['mailbox']['mailboxes'] = 'Mailboxes';
@@ -233,6 +237,7 @@ $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';
+$lang['mailbox']['add_resource'] = 'Add resource';
 $lang['mailbox']['add_alias'] = 'Add alias';
 
 $lang['info']['no_action'] = 'No action applicable';
@@ -245,6 +250,8 @@ $lang['delete']['remove_domainadmin_warning'] = '<b>Warning:</b> You are about t
 $lang['delete']['remove_alias_warning'] = '<b>Warning:</b> You are about to remove the alias address <b>%s</b>!';
 $lang['delete']['remove_mailbox_warning'] = '<b>Warning:</b> You are about to remove the mailbox <b>%s</b>!';
 $lang['delete']['remove_mailbox_details'] = 'The mailbox will be <b>purged permanently</b>!';
+$lang['delete']['remove_resource_warning'] = '<b>Warning:</b> You are about to remove the resource <b>%s</b>!';
+$lang['delete']['remove_resource_details'] = 'The resource will be <b>purged permanently</b>!';
 $lang['delete']['remove_domain_details'] = 'This also removes domain aliases.<br /><br /><b>A domain must be empty to be removed.</b>';
 $lang['delete']['remove_syncjob_details'] = 'Objects from this sync job will not be pulled from the remote server anymore.';
 $lang['delete']['remove_alias_details'] = 'Users will no longer be able to receive mail for or send mail from this address.</b>';
@@ -298,6 +305,9 @@ $lang['edit']['dkim_txt_value'] = 'TXT record value:';
 $lang['edit']['previous'] = 'Previous page';
 $lang['edit']['unchanged_if_empty'] = 'If unchanged leave blank';
 $lang['edit']['dont_check_sender_acl'] = 'Do not check sender for domain %s';
+$lang['edit']['multiple_bookings'] = 'Multiple bookings';
+$lang['edit']['kind'] = 'Kind';
+$lang['edit']['resource'] = 'Resource';
 
 $lang['add']['syncjob'] = 'Add sync job';
 $lang['add']['syncjob_hint'] = 'Be aware that passwords need to be saved plain-text!';
@@ -313,9 +323,11 @@ $lang['add']['delete2duplicates'] = 'Delete duplicates on destination';
 $lang['add']['title'] = 'Add object';
 $lang['add']['domain'] = 'Domain';
 $lang['add']['active'] = 'Active';
+$lang['add']['multiple_bookings'] = 'Multiple bookings';
 $lang['add']['save'] = 'Save changes';
 $lang['add']['description'] = 'Description:';
 $lang['add']['max_aliases'] = 'Max. possible aliases:';
+$lang['add']['resource_name'] = 'Resource name';
 $lang['add']['max_mailboxes'] = 'Max. possible mailboxes:';
 $lang['add']['mailbox_quota_m'] = 'Max. quota per mailbox (MiB):';
 $lang['add']['domain_quota_m'] = 'Total domain quota (MiB):';
@@ -334,6 +346,8 @@ $lang['add']['alias_domain'] = 'Alias domain';
 $lang['add']['select'] = 'Please select...';
 $lang['add']['target_domain'] = 'Target domain:';
 $lang['add']['mailbox'] = 'Mailbox';
+$lang['add']['resource'] = 'Resource';
+$lang['add']['kind'] = 'Kind';
 $lang['add']['mailbox_username'] = 'Username (left part of an email address):';
 $lang['add']['full_name'] = 'Full name:';
 $lang['add']['quota_mb'] = 'Quota (MiB):';

+ 136 - 64
data/web/mailbox.php

@@ -118,61 +118,78 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 		<div class="col-md-12">
 			<div class="panel panel-default">
 				<div class="panel-heading">
-					<h3 class="panel-title"><?=$lang['mailbox']['domain_aliases'];?> <span class="badge" id="numRowsDomainAlias"></span></h3>
+					<h3 class="panel-title"><?=$lang['mailbox']['mailboxes'];?> <span class="badge" id="numRowsMailbox"></span></h3>
 					<div class="pull-right">
 						<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
 							<i class="glyphicon glyphicon-filter"></i>
 						</span>
-						<a href="/add.php?aliasdomain"><span class="glyphicon glyphicon-plus"></span></a>
+						<a href="/add.php?mailbox"><span class="glyphicon glyphicon-plus"></span></a>
 					</div>
 				</div>
 				<div class="panel-body">
-					<input type="text" class="form-control" id="domainaliastable-filter" data-action="filter" data-filters="#domainaliastable" placeholder="Filter" />
+					<input type="text" class="form-control" id="mailboxtable-filter" data-action="filter" data-filters="#mailboxtable" placeholder="Filter" />
 				</div>
 				<div class="table-responsive">
-				<table class="table table-striped sortable-theme-bootstrap" data-sortable id="domainaliastable">
+				<table class="table table-striped sortable-theme-bootstrap" data-sortable id="mailboxtable">
 					<thead>
 						<tr>
-							<th class="sort-table" style="min-width: 67px;"><?=$lang['mailbox']['alias'];?></th>
-							<th class="sort-table" style="min-width: 127px;"><?=$lang['mailbox']['target_domain'];?></th>
+							<th class="sort-table" style="min-width: 100px;"><?=$lang['mailbox']['username'];?></th>
+							<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['fname'];?></th>
+							<th class="sort-table" style="min-width: 86px;"><?=$lang['mailbox']['domain'];?></th>
+							<th class="sort-table" style="min-width: 75px;"><?=$lang['mailbox']['quota'];?></th>
+							<th class="sort-table" style="min-width: 99px;"><?=$lang['mailbox']['in_use'];?></th>
+							<th class="sort-table" style="min-width: 100px;"><?=$lang['mailbox']['msg_num'];?></th>
 							<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
 							<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
 						</tr>
 					</thead>
 					<tbody>
-					<?php
-          foreach (mailbox_get_domains() as $domain) {
-            $alias_domains = mailbox_get_alias_domains($domain);
-            if (!empty($alias_domains)) {
-              foreach ($alias_domains as $alias_domain) {
-                $aliasdomaindata = mailbox_get_alias_domain_details($alias_domain);
-                ?>
-                <tr id="data">
-                  <td><?=htmlspecialchars($aliasdomaindata['alias_domain']);?></td>
-                  <td><?=htmlspecialchars($aliasdomaindata['target_domain']);?></td>
-                  <td><?=$aliasdomaindata['active'];?></td>
-                  <td style="text-align: right;">
-                    <div class="btn-group">
-                      <a href="/edit.php?aliasdomain=<?=urlencode($aliasdomaindata['alias_domain']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
-                      <a href="/delete.php?aliasdomain=<?=urlencode($aliasdomaindata['alias_domain']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
-                    </div>
-                  </td>
-                </tr>
-                <?php
+						<?php
+            foreach (mailbox_get_domains() as $domain) {
+              $mailboxes = mailbox_get_mailboxes($domain);
+              if (!empty($mailboxes)) {
+                foreach ($mailboxes as $mailbox) {
+                  $mailboxdata = mailbox_get_mailbox_details($mailbox);
+						?>
+						<tr id="data">
+							<td><?=($mailboxdata['is_relayed'] == "0") ? htmlspecialchars($mailboxdata['username']) : '<span data-toggle="tooltip" title="Relayed"><i class="glyphicon glyphicon-forward"></i>' . htmlspecialchars($mailboxdata['username']) . '</span>';?></td>
+							<td><?=htmlspecialchars($mailboxdata['name'], ENT_QUOTES, 'UTF-8');?></td>
+							<td><?=htmlspecialchars($mailboxdata['domain']);?></td>
+							<td><?=formatBytes($mailboxdata['quota_used'], 2);?> / <?=formatBytes($mailboxdata['quota'], 2);?></td>
+							<td style="min-width:120px;">
+								<div class="progress">
+									<div class="progress-bar progress-bar-<?=$mailboxdata['percent_class'];?>" role="progressbar" aria-valuenow="<?=$mailboxdata['percent_in_use'];?>" aria-valuemin="0" aria-valuemax="100" style="min-width:2em;width: <?=$mailboxdata['percent_in_use'];?>%;">
+										<?=$mailboxdata['percent_in_use'];?>%
+									</div>
+								</div>
+							</td>
+							<td><?=$mailboxdata['messages'];?></td>
+							<td><?=$mailboxdata['active'];?></td>
+							<td style="text-align: right;">
+								<div class="btn-group">
+									<a href="/edit.php?mailbox=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
+									<a href="/delete.php?mailbox=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
+									<?php if ($_SESSION['mailcow_cc_role'] == "admin"): ?>
+                  <a href="/index.php?duallogin=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>
+                  <?php endif; ?>
+								</div>
+							</td>
+						</tr>
+						<?php
+                }
               }
-            }
-            else {
-	        ?>
+              else {
+                  ?>
                   <tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
-	        <?php
+                  <?php
+              }
             }
-          }
-          ?>
+						?>
 					</tbody>
 					<tfoot>
 						<tr id="no-data">
 							<td colspan="8" style="text-align: center; border-top: 1px solid #e7e7e7;">
-								<a href="/add.php?aliasdomain"><?=$lang['mailbox']['add_domain_alias'];?></a>
+								<a href="/add.php?mailbox"><?=$lang['mailbox']['add_mailbox'];?></a>
 							</td>
 						</tr>
 					</tfoot>
@@ -185,27 +202,25 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 		<div class="col-md-12">
 			<div class="panel panel-default">
 				<div class="panel-heading">
-					<h3 class="panel-title"><?=$lang['mailbox']['mailboxes'];?> <span class="badge" id="numRowsMailbox"></span></h3>
+					<h3 class="panel-title">Resources <span class="badge" id="numRowsResource"></span></h3>
 					<div class="pull-right">
 						<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
 							<i class="glyphicon glyphicon-filter"></i>
 						</span>
-						<a href="/add.php?mailbox"><span class="glyphicon glyphicon-plus"></span></a>
+						<a href="/add.php?resource"><span class="glyphicon glyphicon-plus"></span></a>
 					</div>
 				</div>
 				<div class="panel-body">
-					<input type="text" class="form-control" id="mailboxtable-filter" data-action="filter" data-filters="#mailboxtable" placeholder="Filter" />
+					<input type="text" class="form-control" id="resourcetable-filter" data-action="filter" data-filters="#resourcetable" placeholder="Filter" />
 				</div>
 				<div class="table-responsive">
-				<table class="table table-striped sortable-theme-bootstrap" data-sortable id="mailboxtable">
+				<table class="table table-striped sortable-theme-bootstrap" data-sortable id="resourcetable">
 					<thead>
 						<tr>
-							<th class="sort-table" style="min-width: 100px;"><?=$lang['mailbox']['username'];?></th>
-							<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['fname'];?></th>
+							<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['description'];?></th>
+							<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['kind'];?></th>
 							<th class="sort-table" style="min-width: 86px;"><?=$lang['mailbox']['domain'];?></th>
-							<th class="sort-table" style="min-width: 75px;"><?=$lang['mailbox']['quota'];?></th>
-							<th class="sort-table" style="min-width: 99px;"><?=$lang['mailbox']['in_use'];?></th>
-							<th class="sort-table" style="min-width: 100px;"><?=$lang['mailbox']['msg_num'];?></th>
+							<th class="sort-table" style="min-width: 98px;"><?=$lang['mailbox']['multiple_bookings'];?></th>
 							<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
 							<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
 						</tr>
@@ -213,32 +228,21 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 					<tbody>
 						<?php
             foreach (mailbox_get_domains() as $domain) {
-              $mailboxes = mailbox_get_mailboxes($domain);
-              if (!empty($mailboxes)) {
-                foreach ($mailboxes as $mailbox) {
-                  $mailboxdata = mailbox_get_mailbox_details($mailbox);
+              $resources = mailbox_get_resources($domain);
+              if (!empty($resources)) {
+                foreach ($resources as $resource) {
+                  $resourcedata = mailbox_get_resource_details($resource);
 						?>
 						<tr id="data">
-							<td><?=($mailboxdata['is_relayed'] == "0") ? htmlspecialchars($mailboxdata['username']) : '<span data-toggle="tooltip" title="Relayed"><i class="glyphicon glyphicon-forward"></i>' . htmlspecialchars($mailboxdata['username']) . '</span>';?></td>
-							<td><?=htmlspecialchars($mailboxdata['name'], ENT_QUOTES, 'UTF-8');?></td>
-							<td><?=htmlspecialchars($mailboxdata['domain']);?></td>
-							<td><?=formatBytes($mailboxdata['quota_used'], 2);?> / <?=formatBytes($mailboxdata['quota'], 2);?></td>
-							<td style="min-width:120px;">
-								<div class="progress">
-									<div class="progress-bar progress-bar-<?=$mailboxdata['percent_class'];?>" role="progressbar" aria-valuenow="<?=$mailboxdata['percent_in_use'];?>" aria-valuemin="0" aria-valuemax="100" style="min-width:2em;width: <?=$mailboxdata['percent_in_use'];?>%;">
-										<?=$mailboxdata['percent_in_use'];?>%
-									</div>
-								</div>
-							</td>
-							<td><?=$mailboxdata['messages'];?></td>
-							<td><?=$mailboxdata['active'];?></td>
+							<td><?=htmlspecialchars($resourcedata['description'], ENT_QUOTES, 'UTF-8');?></td>
+							<td><?=$resourcedata['kind'];?></td>
+							<td><?=htmlspecialchars($resourcedata['domain']);?></td>
+							<td><?=$resourcedata['multiple_bookings'];?></td>
+							<td><?=$resourcedata['active'];?></td>
 							<td style="text-align: right;">
 								<div class="btn-group">
-									<a href="/edit.php?mailbox=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
-									<a href="/delete.php?mailbox=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
-									<?php if ($_SESSION['mailcow_cc_role'] == "admin"): ?>
-                  <a href="/index.php?duallogin=<?=urlencode($mailboxdata['username']);?>" class="btn btn-xs btn-success"><span class="glyphicon glyphicon-user"></span> Login</a>
-                  <?php endif; ?>
+									<a href="/edit.php?resource=<?=urlencode($resourcedata['name']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
+									<a href="/delete.php?resource=<?=urlencode($resourcedata['name']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
 								</div>
 							</td>
 						</tr>
@@ -256,7 +260,74 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 					<tfoot>
 						<tr id="no-data">
 							<td colspan="8" style="text-align: center; border-top: 1px solid #e7e7e7;">
-								<a href="/add.php?mailbox"><?=$lang['mailbox']['add_mailbox'];?></a>
+								<a href="/add.php?resource"><?=$lang['mailbox']['add_resource'];?></a>
+							</td>
+						</tr>
+					</tfoot>
+				</table>
+				</div>
+			</div>
+		</div>
+	</div>
+	<div class="row">
+		<div class="col-md-12">
+			<div class="panel panel-default">
+				<div class="panel-heading">
+					<h3 class="panel-title"><?=$lang['mailbox']['domain_aliases'];?> <span class="badge" id="numRowsDomainAlias"></span></h3>
+					<div class="pull-right">
+						<span class="clickable filter" data-toggle="tooltip" title="<?=$lang['mailbox']['filter_table'];?>" data-container="body">
+							<i class="glyphicon glyphicon-filter"></i>
+						</span>
+						<a href="/add.php?aliasdomain"><span class="glyphicon glyphicon-plus"></span></a>
+					</div>
+				</div>
+				<div class="panel-body">
+					<input type="text" class="form-control" id="domainaliastable-filter" data-action="filter" data-filters="#domainaliastable" placeholder="Filter" />
+				</div>
+				<div class="table-responsive">
+				<table class="table table-striped sortable-theme-bootstrap" data-sortable id="domainaliastable">
+					<thead>
+						<tr>
+							<th class="sort-table" style="min-width: 67px;"><?=$lang['mailbox']['alias'];?></th>
+							<th class="sort-table" style="min-width: 127px;"><?=$lang['mailbox']['target_domain'];?></th>
+							<th class="sort-table" style="min-width: 76px;"><?=$lang['mailbox']['active'];?></th>
+							<th style="text-align: right; min-width: 200px;" data-sortable="false"><?=$lang['mailbox']['action'];?></th>
+						</tr>
+					</thead>
+					<tbody>
+					<?php
+          foreach (mailbox_get_domains() as $domain) {
+            $alias_domains = mailbox_get_alias_domains($domain);
+            if (!empty($alias_domains)) {
+              foreach ($alias_domains as $alias_domain) {
+                $aliasdomaindata = mailbox_get_alias_domain_details($alias_domain);
+                ?>
+                <tr id="data">
+                  <td><?=htmlspecialchars($aliasdomaindata['alias_domain']);?></td>
+                  <td><?=htmlspecialchars($aliasdomaindata['target_domain']);?></td>
+                  <td><?=$aliasdomaindata['active'];?></td>
+                  <td style="text-align: right;">
+                    <div class="btn-group">
+                      <a href="/edit.php?aliasdomain=<?=urlencode($aliasdomaindata['alias_domain']);?>" class="btn btn-xs btn-default"><span class="glyphicon glyphicon-pencil"></span> <?=$lang['mailbox']['edit'];?></a>
+                      <a href="/delete.php?aliasdomain=<?=urlencode($aliasdomaindata['alias_domain']);?>" class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span> <?=$lang['mailbox']['remove'];?></a>
+                    </div>
+                  </td>
+                </tr>
+                <?php
+              }
+            }
+            else {
+	        ?>
+                  <tr id="no-data"><td colspan="8" style="text-align: center; font-style: italic;"><?=sprintf($lang['mailbox']['no_record'], $domain);?></td></tr>
+	        <?php
+            }
+          }
+          ?>
+					</tbody>
+					<tfoot>
+						<tr id="no-data">
+							<td colspan="8" style="text-align: center; border-top: 1px solid #e7e7e7;">
+								<a href="/add.php?aliasdomain"><?=$lang['mailbox']['add_domain_alias'];?></a>
 							</td>
 						</tr>
 					</tfoot>
@@ -265,6 +336,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
 			</div>
 		</div>
 	</div>
+
 	<div class="row">
 		<div class="col-md-12">
 			<div class="panel panel-default">