diff --git a/cable.php b/cable.php
new file mode 100644
index 0000000..81a3f46
--- /dev/null
+++ b/cable.php
@@ -0,0 +1,161 @@
+ 'Copper', 'fibre' => 'Fibre',
+                'laser' => 'Laserlink', 'radio' => 'Radiolink');
+
+// ========== ACTIONS START ===================================================
+
+switch ($submit = form_get_action()) {
+
+    case NULL: break;
+
+    case 'add':   $action = ACT_ADD; break;
+    case 'view':  $action = ACT_VIEW; break;
+    case 'edit':  $action = ACT_EDIT; break;
+    case 'del':   $action = ACT_DELETE; break;
+
+    case 'insert':
+        $description = sanitize($_POST['description']);
+        $color = sanitize($_POST['color']);
+        $info = sanitize($_POST['info']);
+        $sql = "INSERT INTO cable
+                    (cable_description, cable_color, cable_info)
+                VALUES
+                    (:description, :color, :info)";
+        $sth = $dbh->prepare($sql);
+        $sth->bindValue(':description', $description, PDO::PARAM_STR);
+        $sth->bindValue(':color', $color, PDO::PARAM_STR);
+        $sth->bindValue(':info', $info, PDO::PARAM_STR);
+        $sth->execute();
+        $id = $dbh->lastInsertId();
+        $action = ACT_VIEW;
+        break;
+
+    case 'update':
+        $description = sanitize($_POST['description']);
+        $color = sanitize($_POST['color']);
+        $length = sanitize($_POST['length']);
+        $type = sanitize($_POST['cable_type']);
+        $info = sanitize($_POST['info']);
+        $sql = "UPDATE cable
+                SET cable_description=:desc,
+                    cable_color=:color,
+                    cable_length=:length,
+                    cable_type=:type,
+                    cable_info=:info
+                WHERE cable_id=:id";
+        $sth = $dbh->prepare($sql);
+        $sth->bindValue(':id', $id, PDO::PARAM_INT);
+        $sth->bindValue(':desc', $description, PDO::PARAM_STR);
+        $sth->bindValue(':length', $length, PDO::PARAM_INT);
+        $sth->bindValue(':color', $color, PDO::PARAM_STR);
+        $sth->bindValue(':type', $type, PDO::PARAM_STR);
+        $sth->bindValue(':info', $info, PDO::PARAM_STR);
+        $sth->execute();
+        $action = ACT_VIEW;
+        break;
+
+    case 'delete':
+        $sth = $dbh->prepare("DELETE FROM cable WHERE cable_id=?");
+        $sth->execute([$id]);
+        $action = ACT_DEFAULT;
+        break;
+
+    default:
+        $g_error->Add(submit_error($submit));
+        $valid = FALSE;
+}
+
+// ========== ACTIONS END =====================================================
+
+$smarty->assign("scripts", 'jscolor.js');
+include("header.php");
+
+// ========== PAGE CONTENT ====================================================
+
+if ($action == ACT_DEFAULT):
+// ========== VARIANT: default behavior =======================================
+
+$sql = "SELECT cable_id AS id, cable_description AS description,
+            cable_from_id, cable_to_id, cable_length, cable_links,
+            cable_type, cable_color,
+            CONCAT(LEFT(cable_info, 60), IF(CHAR_LENGTH(cable_info)>60,'...','')) AS info
+        FROM cable
+        ORDER BY cable_description";
+$sth = $dbh->query($sql);
+$smarty->assign("cables", $sth->fetchAll());
+
+$smarty->display("cable.tpl");
+
+elseif ($action == ACT_ADD):
+// ========== VARIANT: add record =============================================
+
+$smarty->assign('type_options', $ctypes);
+$smarty->display('cableadd.tpl');
+
+elseif ($action == ACT_VIEW):
+// ========== VARIANT: view single record =====================================
+
+$sql = "SELECT cable_id AS id, cable_description AS description,
+            cable_from_id, cable_to_id, cable_length, cable_links,
+            cable_type, cable_color AS color, cable_info AS info
+        FROM cable
+        WHERE cable_id=?";
+$sth = $dbh->prepare($sql);
+$sth->execute([$id]);
+$smarty->assign('cable', $sth->fetch(PDO::FETCH_OBJ));
+
+$smarty->display('cableview.tpl');
+
+elseif ($action == ACT_EDIT):
+// ========== VARIANT: edit single record =====================================
+
+$sql = "SELECT cable_id AS id, cable_description AS description,
+            cable_from_id, cable_to_id, cable_length, cable_links,
+            cable_type, cable_color AS color, cable_info AS info
+        FROM cable
+        WHERE cable_id=?";
+$sth = $dbh->prepare($sql);
+$sth->execute([$id]);
+$smarty->assign('cable', $sth->fetch(PDO::FETCH_OBJ));
+
+$smarty->assign('type_options', $ctypes);
+$smarty->display('cableedit.tpl');
+
+elseif ($action == ACT_DELETE):
+// ========== VARIANT: delete record ==========================================
+
+$sth = $dbh->prepare("SELECT cable_description FROM cable WHERE cable_id=?");
+$sth->execute([$id]);
+$smarty->assign('id', $id);
+$smarty->assign('description', $sth->fetchColumn());
+
+$smarty->display('cabledel.tpl');
+
+else:
+// ========== UNBEKANNTE VARIANTE =============================================
+
+echo "
Unknown function call: Please report to system development!
\n";
+
+endif; // $action == ...
+// ========== END OF VARIANTS =================================================
+
+include("footer.php");
+?>
diff --git a/dbconnect.php b/dbconnect.php
deleted file mode 100644
index 85e91e1..0000000
--- a/dbconnect.php
+++ /dev/null
@@ -1,14 +0,0 @@
-setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
-
-?>
diff --git a/header.php b/header.php
index 6455ede..baf3507 100644
--- a/header.php
+++ b/header.php
@@ -27,15 +27,35 @@ $smarty->assign("suser_name", $_SESSION['suser_displayname']);
 $smarty->assign("search", $search);
 	
 // menu
-$smarty->assign("menu_assets", $_SESSION['suser_menu_assets']=='on');
-$smarty->assign("menu_assetclasses", $_SESSION['suser_menu_assetclasses']=='on');
-$smarty->assign("menu_assetclassgroups", $_SESSION['suser_menu_assetclassgroups']=='on');
-$smarty->assign("menu_locations", $_SESSION['suser_menu_locations']=='on');
-$smarty->assign("menu_nodes", $_SESSION['suser_menu_nodes']=='on');
-$smarty->assign("menu_subnets", $_SESSION['suser_menu_subnets']=='on');
-$smarty->assign("menu_users", $_SESSION['suser_menu_users']=='on');
-$smarty->assign("menu_vlans", $_SESSION['suser_menu_vlans']=='on');
-$smarty->assign("menu_zones", $_SESSION['suser_menu_zones']=='on');
+$menu = array();
+if ($_SESSION['suser_menu_assets']) {
+    $menu[] = '' . $lang['lang_assets'] . "\n";
+}
+if ($_SESSION['suser_menu_assetclasses']) {
+    $menu[] = '' . $lang['lang_assetclasses'] . "\n";
+}
+if ($_SESSION['suser_menu_assetclassgroups']) {
+    $menu[] = '' . $lang['lang_assetclassgroups'] . "\n";
+}
+if ($_SESSION['suser_menu_locations']) {
+    $menu[] = '' . $lang['lang_locations'] . "\n";
+}
+if ($_SESSION['suser_menu_nodes']) {
+    $menu[] = '' . $lang['lang_nodes'] . "\n";
+}
+if ($_SESSION['suser_menu_subnets']) {
+    $menu[] = '' . $lang['lang_subnets'] . "\n";
+}
+if ($_SESSION['suser_menu_vlans']) {
+    $menu[] = '' . $lang['lang_vlans'] . "\n";
+}
+if ($_SESSION['suser_menu_cables']) {
+    $menu[] = '' . $lang['lang_cables'] . "\n";
+}
+if ($_SESSION['suser_menu_zones']) {
+    $menu[] = '' . $lang['lang_zones'] . "\n";
+}
+$smarty->assign("menu", implode(' | ', $menu));
 
 $smarty->display("header.tpl");
 ?>
diff --git a/images/admin.png b/images/admin.png
new file mode 100644
index 0000000..b3454e1
Binary files /dev/null and b/images/admin.png differ
diff --git a/images/cancel.png b/images/cancel.png
new file mode 100644
index 0000000..c149c2b
Binary files /dev/null and b/images/cancel.png differ
diff --git a/images/information.png b/images/information.png
new file mode 100644
index 0000000..12cd1ae
Binary files /dev/null and b/images/information.png differ
diff --git a/images/manage.png b/images/manage.png
new file mode 100644
index 0000000..d6626cb
Binary files /dev/null and b/images/manage.png differ
diff --git a/images/note.png b/images/note.png
new file mode 100644
index 0000000..244e6ca
Binary files /dev/null and b/images/note.png differ
diff --git a/images/plugin.png b/images/plugin.png
new file mode 100644
index 0000000..6187b15
Binary files /dev/null and b/images/plugin.png differ
diff --git a/includes.php b/includes.php
index 5e02318..2b175e7 100644
--- a/includes.php
+++ b/includes.php
@@ -11,13 +11,18 @@ session_name('ipreg');
 session_start();
 
 // check for user_id, if unnkown, redirect to login
-if(empty($_SESSION['suser_id'])) {
-	header("Location: login.php");
-	exit;
+if (empty($_SESSION['suser_id'])) {
+    $_SESSION['prelogin'] = $_SERVER['REQUEST_URI'];
+    header("Location: login.php");
+    exit;
 }
 	
 include("config.php");
-include("dbconnect.php");
+
+// connect to database
+$dbh = new PDO("mysql:host=$config_mysql_host;dbname=$config_mysql_dbname;charset=utf8", $config_mysql_username, $config_mysql_password);
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
 		
 include("lib.php");
 
diff --git a/install/mysql.sql b/install/mysql.sql
index bb3be4f..f114243 100644
--- a/install/mysql.sql
+++ b/install/mysql.sql
@@ -22,7 +22,7 @@ CREATE TABLE assetclass (
 CREATE TABLE assetclassgroup (
   assetclassgroup_id int(10) NOT NULL AUTO_INCREMENT,
   assetclassgroup_name varchar(100) NOT NULL,
-  assetclassgroup_color varchar(6) NOT NULL DEFAULT '000000',
+  assetclassgroup_color char(6) NOT NULL DEFAULT '000000',
   assetclassgroup_description varchar(100) DEFAULT NULL,
   PRIMARY KEY (assetclassgroup_id),
   INDEX ix_assetclassgroup_name (assetclassgroup_name)
@@ -37,11 +37,20 @@ CREATE TABLE cable (
   cable_length smallint(5) UNSIGNED DEFAULT NULL,
   cable_links smallint(5) UNSIGNED DEFAULT 1,
   cable_type enum('copper','fibre','laser','radio') DEFAULT NULL,
+  cable_color char(6) NOT NULL DEFAULT '000000',
   cable_info text DEFAULT NULL,
   PRIMARY KEY (cable_id),
   UNIQUE INDEX ix_cable_description (cable_description)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
+-- WIP
+CREATE TABLE cablevlan (
+  cablevlan_id int(10) NOT NULL AUTO_INCREMENT,
+  cable_id int(10) NOT NULL,
+  vlan_id int(10) NOT NULL,
+  PRIMARY KEY (cablevlan_id)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
 -- WIP
 -- Reference to external systems
 CREATE TABLE extlink (
@@ -130,27 +139,23 @@ CREATE TABLE user (
   user_dateformat varchar(10) NOT NULL DEFAULT 'd M Y H:i',
   user_dns1suffix varchar(100) DEFAULT NULL,
   user_dns2suffix varchar(100) DEFAULT NULL,
-  user_menu_assets varchar(2) NOT NULL DEFAULT 'on',
-  user_menu_assetclasses varchar(2) NOT NULL DEFAULT 'on',
-  user_menu_assetclassgroups varchar(2) NOT NULL DEFAULT 'on',
-  user_menu_locations varchar(2) NOT NULL DEFAULT 'on',
-  user_menu_nodes varchar(2) NOT NULL DEFAULT 'on',
-  user_menu_subnets varchar(2) NOT NULL DEFAULT 'on',
-  user_menu_users varchar(2) NOT NULL DEFAULT 'on',
-  user_menu_vlans varchar(2) NOT NULL DEFAULT 'on',
-  user_menu_zones varchar(2) NOT NULL DEFAULT 'on',
   user_tooltips varchar(2) NOT NULL DEFAULT 'on',
+  user_menu set('asset','cable','class','group','location','nat','node',
+                'subnet','vlan','zone') NOT NULL DEFAULT 'asset,class,group,location,node,subnet,vlan',
+  user_role set('add','edit','delete','manage','admin') DEFAULT NULL,
+  user_flags set('deleted','locked'),
   PRIMARY KEY (user_id),
   UNIQUE INDEX ix_username (user_name)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
-INSERT INTO user (user_name, user_pass, user_displayname) VALUES
-('admin', '$2y$10$HTs0lSaFrfr.q4Gmy5zWfeDg3jhYZkqEGZEnDkMiHZ641nso38mt6', 'Administrator');
+INSERT INTO user (user_name, user_pass, user_displayname, user_role) VALUES
+('admin', '$2y$10$HTs0lSaFrfr.q4Gmy5zWfeDg3jhYZkqEGZEnDkMiHZ641nso38mt6', 'Administrator', 'admin');
 
 CREATE TABLE vlan (
   vlan_id int(10) NOT NULL AUTO_INCREMENT,
   vlan_number int(3) NOT NULL,
   vlan_name varchar(100) NOT NULL,
+  vlan_color char(6) NOT NULL DEFAULT '000000',
   vlan_info text DEFAULT NULL,
   PRIMARY KEY (vlan_id)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
diff --git a/install/mysql_sample.sql b/install/mysql_sample.sql
index 3b5373f..424baf4 100644
--- a/install/mysql_sample.sql
+++ b/install/mysql_sample.sql
@@ -57,4 +57,4 @@ INSERT INTO vlan (vlan_number, vlan_name) VALUES
 (1, 'DEFAULT_VLAN');
 
 INSERT INTO zone (zone_soa, zone_origin, zone_hostmaster, zone_serial, zone_ns1) VALUES
-('ns1.example.com.', 'example.com.', 'hostmaster@example.com', '2023021301', 'ns1.example.com');
+('ns1.example.com.', 'example.com.', 'hostmaster.example.com.', '2023021301', 'ns1.example.com');
diff --git a/lang/de.php b/lang/de.php
index 9a30f39..7839e91 100644
--- a/lang/de.php
+++ b/lang/de.php
@@ -9,6 +9,8 @@ $lang = array(
     'lang_assetclasses' => 'Objektklassen',
     'lang_assetclassgroup' => 'Objektklassengruppe',
     'lang_assetclassgroups' => 'Objektklassengruppen',
+    'lang_cable' => 'Kabel',
+    'lang_cables' => 'Kabel',
     'lang_location' => 'Standort',
     'lang_locations' => 'Standorte',
     'lang_menu' => 'Menü',
@@ -27,7 +29,7 @@ $lang = array(
     'lang_vlans' => 'VLANs',
 
     'lang_about' => 'Über',
-    'lang_all' => 'Allw',
+    'lang_all' => 'Alle',
     'lang_cancel' => 'Abbruch',
     'lang_color' => 'Farbe',
     'lang_error' => 'Fehler',
@@ -48,6 +50,7 @@ $lang = array(
     'lang_empty' => 'leer',
     'lang_source' => 'Quelle',
     'lang_target' => 'Ziel',
+    'lang_length' => 'Länge',
 
     'lang_asset_add' => 'Objekt hinzufügen',
     'lang_asset_del' => 'Objekt löschen',
@@ -99,6 +102,10 @@ $lang = array(
     'lang_locationsubnet' => 'Standort/Subnetz',
     'lang_locationsubnet_edit' => 'Standort/Subnetz bearbeiten',
 
+    'lang_cable_info' => 'Kabelinfo',
+    'lang_cable_type' => 'Kabeltyp',
+    'lang_cable_none' => 'Es sind keine Kabel vorhanden',
+
     'lang_node_add' => 'Knoten hinzufügen',
     'lang_node_del' => 'Knoten löschen',
     'lang_node_edit' => 'Knoten ändern',
@@ -151,6 +158,12 @@ $lang = array(
     'lang_user_password' => 'Kennwort',
     'lang_user_language' => 'Sprache',
     'lang_user_realm' => 'Realm',
+    'lang_user_roles' => 'Rechte',
+    'lang_user_role_add' => 'Anlegen',
+    'lang_user_role_edit' => 'Bearbeiten',
+    'lang_user_role_delete' => 'Löschen',
+    'lang_user_role_manage' => 'Konfigurieren',
+    'lang_user_role_admin' => 'Adminstration',
 
     'lang_zone_add' => 'Zone hinzufügen',
     'lang_zone_del' => 'Zone löschen',
@@ -178,6 +191,7 @@ $lang = array(
     'lang_comments_usernameinuse' => 'Benutzername wird bereits verwendet',
     'lang_comments_invalidpass' => 'Das Kennwort ist falsch',
     'lang_comments_invalidnewpass' => 'Das neue Kennwort wurde nicht korrekt eingegeben',
+    'lang_comments_accessdenied' => 'Zugriff verweigert. Keine Berechtigung.',
 
     'lang_options_ipreg' => 'IP Reg Optionen',
     'lang_options_display' => 'Anzeigeeinstellungen',
@@ -192,9 +206,9 @@ $lang = array(
     'lang_options_dateformat' => 'Datumsformat',
     'lang_options_dateformat_help' => 'Format in which dates are displayed using the php-date-format (see http://www.php.net/date for more info)',
     'lang_options_dns1suffix' => 'DNS Name suffix',
-    'lang_options_dns1suffix_help' => 'Default DNS Name suffix für neue Knoten',
+    'lang_options_dns1suffix_help' => 'Standard DNS Name Suffix für neue Knoten',
     'lang_options_dns2suffix' => 'DNS Alias suffix',
-    'lang_options_dns2suffix_help' => 'Default DNS Alias suffix für neue Knoten',
+    'lang_options_dns2suffix_help' => 'Standard DNS Alias Suffix für neue Knoten',
     'lang_options_currentpassword' => 'Aktuelles Kennwort',
     'lang_options_currentpassword_help' => 'Bitte geben Sie hier Ihr bisheriges Kennwort ein',
     'lang_options_newpassword1' => 'Neues Kennwort',
diff --git a/lang/en.php b/lang/en.php
index 21b873b..ae3a365 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -9,6 +9,8 @@ $lang = array(
     'lang_assetclasses' => 'Assetclasses',
     'lang_assetclassgroup' => 'Assetclassgroup',
     'lang_assetclassgroups' => 'Assetclassgroups',
+    'lang_cable' => 'Cable',
+    'lang_cables' => 'Cables',
     'lang_location' => 'Location',
     'lang_locations' => 'Locations',
     'lang_menu' => 'Menu',
@@ -48,6 +50,7 @@ $lang = array(
     'lang_empty' => 'empty',
     'lang_source' => 'Source',
     'lang_target' => 'Target',
+    'lang_length' => 'Length',
 
     'lang_asset_add' => 'Add asset',
     'lang_asset_del' => 'Delete asset',
@@ -99,6 +102,10 @@ $lang = array(
     'lang_locationsubnet' => 'Location/Subnet',
     'lang_locationsubnet_edit' => 'Edit Location/Subnet',
 
+    'lang_cable_info' => 'Cable info',
+    'lang_cable_type' => 'Cable type',
+    'lang_cable_none' => 'There are no cables defined',
+
     'lang_node_add' => 'Add node',
     'lang_node_del' => 'Delete node',
     'lang_node_edit' => 'Modify node',
@@ -151,6 +158,12 @@ $lang = array(
     'lang_user_password' => 'Password',
     'lang_user_language' => 'Language',
     'lang_user_realm' => 'Realm',
+    'lang_user_roles' => 'Roles',
+    'lang_user_role_add' => 'Add',
+    'lang_user_role_edit' => 'Edit',
+    'lang_user_role_delete' => 'Delete',
+    'lang_user_role_manage' => 'Manage',
+    'lang_user_role_admin' => 'Adminstration',
 
     'lang_zone_add' => 'Add zone',
     'lang_zone_del' => 'Delete zone',
@@ -178,6 +191,7 @@ $lang = array(
     'lang_comments_usernameinuse' => 'Username in use',
     'lang_comments_invalidpass' => 'Invalid password',
     'lang_comments_invalidnewpass' => 'Invalid new password',
+    'lang_comments_accessdenied' => 'Access denied',
 
     'lang_options_ipreg' => 'IP Reg options',
     'lang_options_display' => 'Display options',
diff --git a/lib.php b/lib.php
index 9fb723d..a55513f 100644
--- a/lib.php
+++ b/lib.php
@@ -7,6 +7,26 @@ Copyright (C) 2011-2023 Thomas Hooge
 SPDX-License-Identifier: GPL-3.0-or-later
 *****************************************************************************/
 
+// ========== CONSTANT DEFINITIONS ============================================
+
+// page actions
+define ('ACT_DEFAULT',      0);
+define ('ACT_ADD',          1);
+define ('ACT_VIEW',         2);
+define ('ACT_EDIT',         3);
+define ('ACT_DELETE',       4);
+define ('ACT_COPY',         5);
+define ('ACT_JOIN',         6);
+define ('ACT_LEAVE',        7);
+define ('ACT_EDIT_DETAIL',  8);
+define ('ACT_DEL_DETAIL',   9);
+define ('ACT_LINK',        10);
+define ('ACT_UNLINK',      11);
+define ('ACT_MAIL',        12);
+define ('ACT_VIEW_LIST',   13);
+
+// ========== GLOBAL PAGE START CODE ==========================================
+
 // global version string
 $config_version = 'v0.8';
 
@@ -15,19 +35,128 @@ $config_lang = array('de', 'en');
 
 include("lib/functions.php");
 
-//require("lib/db.class.php");
-//$db = new Db($dblink);
-
-//require("lib/user.class.php");
-// $user = new User();
-
 require_once('smarty3/Smarty.class.php');
 $smarty = new Smarty();
 $smarty->template_dir = 'tpl';
 $smarty->compile_dir = 'tpl_c';
 $smarty->registerPlugin('function', 'treelist', 'print_tree');
-
+$smarty->registerPlugin('function', 'msgout', 'msgout');
+$smarty->assign("suser_name", $_SESSION['suser_displayname']);
 $smarty->assign("suser_tooltips", $_SESSION['suser_tooltips'] ?? 'off');
+$smarty->assign("suser_add", $_SESSION['suser_role_add']);
+$smarty->assign("suser_edit", $_SESSION['suser_role_edit']);
+$smarty->assign("suser_delete", $_SESSION['suser_role_delete']);
+$smarty->assign("suser_manage", $_SESSION['suser_role_manage']);
+$smarty->assign("suser_admin", $_SESSION['suser_role_admin']);
+
+// prepare global message system
+$g_message = new Message;
+$g_warning = new MessageWarning;
+$g_error = new MessageError;
+
+$action = ACT_DEFAULT;
+
+// ========== FEEDBACK FUNCTIONS ==============================================
+
+class Message {
+
+    var $count = 0;
+    var $text = array();
+    var $caption;
+
+    function Message() {
+        $this->caption = 'Information';
+    }
+
+    function SetCaption($str) {
+        $this->caption = $str;
+    }
+
+    function Add($msg) {
+        $this->count++;
+        $this->text[$this->count] = $msg;
+    }
+
+    function GetCount() {
+        return $this->count;
+    }
+
+    function PrintOut() {
+        if ($this->count > 0) {
+            echo '', "\n";
+            echo '
', $this->caption, "
\n";
+            echo "
\n";
+            for ($i=1; $i<=$this->count; $i++) {
+                echo "\t- ", $this->text[$i],"
 \n";
+            }
+            echo "
\n";
+            echo "
 \n";
+        }
+    }
+
+}
+
+class MessageWarning extends Message {
+    function MessageWarning() {
+        $this->caption = 'Warning';
+    }
+    function PrintOut() {
+        if ($this->count > 0) {
+            echo '', "\n";
+            echo '
', $this->caption, "
\n";
+            echo "
\n";
+            for ($i=1; $i<=$this->count; $i++) {
+                echo "\t- ", $this->text[$i],"
 \n";
+            }
+            echo "
\n";
+            echo "
 \n";
+        }
+    }
+}
+
+class MessageError extends Message {
+    function MessageError() {
+        $this->caption = 'Error';
+    }
+    function PrintOut() {
+        if ($this->count > 0) {
+            echo '', "\n";
+            echo '
', $this->caption, "
\n";
+            echo "
\n";
+            for ($i=1; $i<=$this->count; $i++) {
+                echo "\t- ", $this->text[$i],"
 \n";
+            }
+            echo "
\n";
+            echo "
 \n";
+        }
+    }
+}
+
+// ========== FORM FUNCTIONS ==================================================
+
+function form_get_action() {
+    if (!isset($_POST['submit'])) {
+        if (isset($_GET['f'])) {
+            $submit = $_GET['f'];
+        } else {
+            $submit = NULL;
+        }
+    } else {
+        $submit = $_POST['submit'];
+    }
+    if (is_array($submit)) {
+        $submit = key($submit);
+    }
+    return strtolower($submit);
+}
+
+function submit_error($action) {
+    /* Submit buttons that return an unknown value end up in this
+       function by default. An exit() is conscious here *not* installed,
+       since it could be that despite such an error the program
+       execution should be continued. */
+    return sprintf('The action "%s" is unknown. It is probably a program error.
 Please inform your administrator of the exact circumstances of how this situation came about.', strtoupper($action));
+}
 
 // ========== DATABASE FUCTIONS ===============================================
 
diff --git a/lib/functions.php b/lib/functions.php
index 88a5e35..cf988e5 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -152,4 +152,12 @@ function print_tree($params, Smarty_Internal_Template $template) {
     }
 }
 
+function msgout(array $parameters, Smarty_Internal_Template $smarty)
+{
+    // This is just a quick hack around missing {php} in Smarty3
+    $GLOBALS['g_error']->PrintOut();
+    $GLOBALS['g_warning']->PrintOut();
+    $GLOBALS['g_message']->PrintOut();
+}
+
 ?>
diff --git a/lib/user.class.php b/lib/user.class.php
deleted file mode 100644
index 1a3921e..0000000
--- a/lib/user.class.php
+++ /dev/null
@@ -1,171 +0,0 @@
-.
-
-    For more information, visit http://sourceforge.net/projects/ipreg,
-    or contact me at wietsew@users.sourceforge.net
-    *****************************************************************************/
-
-    class User {
-        function check_strlen($string) {
-            // check length
-            if(strlen($string)<1) {
-                return FALSE;
-            } else {
-                return TRUE;
-            }
-        }
-
-        function check_ldap_bind($user_name, $user_pass) {
-            global $config_ldap_host;
-            global $config_ldap_port;
-            global $config_ldap_base_dn;
-            global $config_ldap_bind_dn;
-            global $config_ldap_bind_pass;
-            global $config_ldap_login_attr;
-            $ldap_conn = NULL;
-            foreach ($config_ldap_host as $server) {
-                if ($ldap_conn = ldap_connect($server, $config_ldap_port)) {
-                    if ($res = ldap_bind($ldap_conn, $config_ldap_bind_dn, $config_ldap_bind_pass)) {
-                        ldap_set_option($ldap_conn, LDAP_OPT_REFERRALS, 0);
-                        ldap_set_option($ldap_conn, LDAP_OPT_PROTOCOL_VERSION, 3);
-                        $filter = "(&(objectClass=user)($config_ldap_login_attr=$user_name))";
-                        $res = ldap_search($ldap_conn, $config_ldap_base_dn, $filter, ['dn']);
-                        if ($res) {
-                            $info = ldap_get_entries($ldap_conn, $res);
-                            $user_dn = $info[0]['dn'];
-                            $res = ldap_bind($ldap_conn, $user_dn, $user_pass);
-                            if ($res) {
-                                return TRUE;
-                            }
-                        }
-                    }
-                    return FALSE;
-                }
-            }
-            return FALSE;
-        }
-
-        function user_login($user_name, $user_pass) {
-            global $dblink;
-            // check user_name length
-            if($this->check_strlen($user_name)==FALSE) {
-                return FALSE;
-            }
-
-            // check user_pass length
-            if($this->check_strlen($user_pass)==FALSE) {
-                return FALSE;
-            }
-
-            // get user data
-                // initiate class
-                $db = new Db($dblink);
-
-                // build query
-                $query = "SELECT
-                    user.user_id,
-                    user.user_pass,
-                    user.user_realm,
-                    user.user_displayname,
-                    user.user_language,
-                    user.user_imagesize,
-                    user.user_imagecount,
-                    user.user_mac,
-                    user.user_dateformat,
-                    user.user_dns1suffix,
-                    user.user_dns2suffix,
-                    user.user_menu_assets,
-                    user.user_menu_assetclasses,
-                    user.user_menu_assetclassgroups,
-                    user.user_menu_locations,
-                    user.user_menu_nodes,
-                    user.user_menu_subnets,
-                    user.user_menu_users,
-                    user.user_menu_vlans,
-                    user.user_menu_zones,
-                    user.user_tooltips
-                FROM
-                    user
-                WHERE
-                    user.user_name='" . $user_name . "'";
-
-                // run query
-                $users = $db->db_select($query);
-
-                // count results
-                $user_counter = count($users);
-
-                // any users?
-                if ($user_counter>0) {
-                    if ($users[0]['user_realm'] == 'ldap') {
-                        // check LDAP auth
-                        if (! $this->check_ldap_bind($user_name, $user_pass)) {
-                            return FALSE;
-                        }
-                        // TODO sync LDAP data to local
-                    } else {
-                        // compare local passwords
-                        if(!strcmp(md5($user_pass), rtrim($users[0]['user_pass']))) {
-                            // all ok: user is logged in
-
-                            // md5 match but outdated. rewrite with new algo
-                            $newhash = password_hash($user_pass, PASSWORD_BCRYPT);
-                            $query = "UPDATE user SET user_pass='" . $newhash. "' WHERE user_id=" . $users[0]['user_id'];
-                            $db->db_update($query);
-
-                        } else {
-                            if (! password_verify($user_pass, $users[0]['user_pass'])) {
-                                return FALSE;
-                            }
-                        }
-                    }
-                } else {
-                    return FALSE;
-                }
-
-            // register session data
-                $_SESSION['suser_id'] = $users[0]['user_id'];
-                $_SESSION['suser_displayname'] = $users[0]['user_displayname'];
-                $_SESSION['suser_language'] = $users[0]['user_language'];
-                $_SESSION['suser_imagesize'] = $users[0]['user_imagesize'];
-                $_SESSION['suser_imagecount'] = $users[0]['user_imagecount'];
-                $_SESSION['suser_mac'] = $users[0]['user_mac'];
-                $_SESSION['suser_dateformat'] = $users[0]['user_dateformat'];
-                $_SESSION['suser_dns1suffix'] = $users[0]['user_dns1suffix'];
-                $_SESSION['suser_dns2suffix'] = $users[0]['user_dns2suffix'];
-                $_SESSION['suser_menu_assets'] = $users[0]['user_menu_assets'];
-                $_SESSION['suser_menu_assetclasses'] = $users[0]['user_menu_assetclasses'];
-                $_SESSION['suser_menu_assetclassgroups'] = $users[0]['user_menu_assetclassgroups'];
-                $_SESSION['suser_menu_locations'] = $users[0]['user_menu_locations'];
-                $_SESSION['suser_menu_nodes'] = $users[0]['user_menu_nodes'];
-                $_SESSION['suser_menu_subnets'] = $users[0]['user_menu_subnets'];
-                $_SESSION['suser_menu_users'] = $users[0]['user_menu_users'];
-                $_SESSION['suser_menu_vlans'] = $users[0]['user_menu_vlans'];
-                $_SESSION['suser_menu_zones'] = $users[0]['user_menu_zones'];
-                $_SESSION['suser_tooltips'] = $users[0]['user_tooltips'];
-
-            // no errors found, return
-            return TRUE;
-        }
-
-        function user_logout() {
-            // clear and destroy session
-            $_SESSION = array();
-        }
-    }
-?>
diff --git a/login.php b/login.php
index 3c5d67a..abb3c69 100644
--- a/login.php
+++ b/login.php
@@ -11,8 +11,13 @@ session_name('ipreg');
 session_start();
 
 include("config.php");
-include("dbconnect.php");
-include("lib.php");
+
+// connect to database
+$dbh = new PDO("mysql:host=$config_mysql_host;dbname=$config_mysql_dbname;charset=utf8", $config_mysql_username, $config_mysql_password);
+$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
+
+include("lib.php"); // only for get_language from browser. TODO: simplify
 
 function user_login ($user_name, $user_pass) {
     global $dbh;
@@ -27,11 +32,8 @@ function user_login ($user_name, $user_pass) {
 
     $sql = "SELECT user_id, user_pass, user_displayname, user_language,
                 user_imagesize, user_imagecount, user_mac, user_dateformat,
-                user_dns1suffix, user_dns2suffix, user_menu_assets,
-                user_menu_assetclasses, user_menu_assetclassgroups,
-                user_menu_locations, user_menu_nodes, user_menu_subnets,
-                user_menu_users, user_menu_vlans, user_menu_zones,
-                user_tooltips
+                user_dns1suffix, user_dns2suffix, user_tooltips,
+                user_menu, user_role, user_flags
             FROM user
             WHERE user_name=?";
     $sth = $dbh->prepare($sql);
@@ -55,6 +57,7 @@ function user_login ($user_name, $user_pass) {
         $sth->execute([$newhash, $user->user_id]);
     }
 
+
     // all ok: user is logged in, register session data
     $_SESSION['suser_id'] = $user->user_id;
     $_SESSION['suser_displayname'] = $user->user_displayname;
@@ -65,17 +68,26 @@ function user_login ($user_name, $user_pass) {
     $_SESSION['suser_dateformat'] = $user->user_dateformat;
     $_SESSION['suser_dns1suffix'] = $user->user_dns1suffix;
     $_SESSION['suser_dns2suffix'] = $user->user_dns2suffix;
-    $_SESSION['suser_menu_assets'] = $user->user_menu_assets;
-    $_SESSION['suser_menu_assetclasses'] = $user->user_menu_assetclasses;
-    $_SESSION['suser_menu_assetclassgroups'] = $user->user_menu_assetclassgroups;
-    $_SESSION['suser_menu_locations'] = $user->user_menu_locations;
-    $_SESSION['suser_menu_nodes'] = $user->user_menu_nodes;
-    $_SESSION['suser_menu_subnets'] = $user->user_menu_subnets;
-    $_SESSION['suser_menu_users'] = $user->user_menu_users;
-    $_SESSION['suser_menu_vlans'] = $user->user_menu_vlans;
-    $_SESSION['suser_menu_zones'] = $user->user_menu_zones;
     $_SESSION['suser_tooltips'] = $user->user_tooltips;
 
+    $roles = explode(',', $user->user_role);
+    $_SESSION['suser_role_add'] = in_array('add', $roles);
+    $_SESSION['suser_role_edit'] = in_array('edit', $roles);
+    $_SESSION['suser_role_delete'] = in_array('delete', $roles);
+    $_SESSION['suser_role_manage'] = in_array('manage', $roles);
+    $_SESSION['suser_role_admin'] = in_array('admin', $roles);
+
+    $menu = explode(',', $user->user_menu);
+    $_SESSION['suser_menu_assets'] = in_array('asset', $menu);
+    $_SESSION['suser_menu_assetclasses'] = in_array('class', $menu);
+    $_SESSION['suser_menu_assetclassgroups'] = in_array('group', $menu);
+    $_SESSION['suser_menu_cables'] = in_array('cable', $menu);
+    $_SESSION['suser_menu_locations'] = in_array('location', $menu);
+    $_SESSION['suser_menu_nodes'] = in_array('node', $menu);
+    $_SESSION['suser_menu_subnets'] = in_array('subnet', $menu);
+    $_SESSION['suser_menu_vlans'] = in_array('vlan', $menu);
+    $_SESSION['suser_menu_zones'] = in_array('zone', $menu);
+
     return TRUE;
 }
 
@@ -84,13 +96,13 @@ function user_login ($user_name, $user_pass) {
 $language = lang_getfrombrowser($config_lang, $config_lang_default, null, false);
 include('lang/' . $language . '.php');
 
-if ($_SERVER['REQUEST_METHOD']=="POST" ) {
+if ($_SERVER['REQUEST_METHOD'] == "POST" ) {
 
     $user_name = sanitize($_POST['user_name']);
     $user_pass = sanitize($_POST['user_pass']);
 
     if (user_login($user_name, $user_pass) == TRUE) {
-        header_location("index.php");
+        header_location($_SESSION['prelogin'] ?? 'index.php');
     } else {
         $_SESSION = array();
         session_destroy();
diff --git a/optionseditdisplay.php b/optionseditdisplay.php
index 14235d9..ae868f9 100644
--- a/optionseditdisplay.php
+++ b/optionseditdisplay.php
@@ -31,6 +31,12 @@ if($_SESSION['suser_menu_assetclassgroups']=='on') {
 } else {
 	$user_menu_assetclassgroups_checked = '';
 }
+// cables
+if($_SESSION['suser_menu_cables']=='on') {
+	$user_menu_cables_checked = 'checked';
+} else {
+	$user_menu_cables_checked = '';
+}
 // locations
 if($_SESSION['suser_menu_locations']=='on') {
 	$user_menu_locations_checked = 'checked';
@@ -49,12 +55,6 @@ if($_SESSION['suser_menu_subnets']=='on') {
 } else {
 	$user_menu_subnets_checked = '';
 }
-// users
-if($_SESSION['suser_menu_users']=='on') {
-	$user_menu_users_checked = 'checked';
-} else {
-	$user_menu_users_checked = '';
-}
 // vlans
 if($_SESSION['suser_menu_vlans']=='on') {
 	$user_menu_vlans_checked = 'checked';
@@ -85,10 +85,10 @@ $smarty->assign("user_language", $_SESSION['suser_language']);
 $smarty->assign("user_menu_assets_checked", $user_menu_assets_checked);
 $smarty->assign("user_menu_assetclasses_checked", $user_menu_assetclasses_checked);
 $smarty->assign("user_menu_assetclassgroups_checked", $user_menu_assetclassgroups_checked);
+$smarty->assign("user_menu_cables_checked", $user_menu_cables_checked);
 $smarty->assign("user_menu_locations_checked", $user_menu_locations_checked);
 $smarty->assign("user_menu_nodes_checked", $user_menu_nodes_checked);
 $smarty->assign("user_menu_subnets_checked", $user_menu_subnets_checked);
-$smarty->assign("user_menu_users_checked", $user_menu_users_checked);
 $smarty->assign("user_menu_vlans_checked", $user_menu_vlans_checked);
 $smarty->assign("user_menu_zones_checked", $user_menu_zones_checked);
 $smarty->assign("user_tooltips_checked", $user_tooltips_checked);
diff --git a/submit.php b/submit.php
index 75b5878..bf43511 100644
--- a/submit.php
+++ b/submit.php
@@ -329,11 +329,12 @@ if (isset($_POST['add'])) {
             $vlan_name = sanitize($_POST['vlan_name']);
             $vlan_number = sanitize($_POST['vlan_number']);
             $vlan_info = sanitize($_POST['vlan_info']);
+            $vlan_color = sanitize($_POST['vlan_color']);
 
-            $sql = "INSERT INTO vlan (vlan_name, vlan_number, vlan_info)
-                    VALUE (?, ?, ?)";
+            $sql = "INSERT INTO vlan (vlan_name, vlan_number, vlan_color, vlan_info)
+                    VALUE (?, ?, ?, ?)";
             $sth = $dbh->prepare($sql);
-            $sth->execute([$vlan_name, $vlan_number, $vlan_info]);
+            $sth->execute([$vlan_name, $vlan_number, $vlan_color, $vlan_info]);
 
             header_location("vlanview.php?vlan_id=" . $dbh->lastInsertId());
             break;
@@ -497,7 +498,7 @@ if (isset($_POST['del'])) {
         case ("vlan") :
             $vlan_id = sanitize($_POST['vlan_id']);
 
-            $sth = $dbh->prepare("DELETE FROM vlan WHERE vlan_id=");
+            $sth = $dbh->prepare("DELETE FROM vlan WHERE vlan_id=?");
             $sth->execute([$vlan_id]);
 
             header_location("vlan.php");
@@ -623,31 +624,41 @@ if (isset($_POST['edit'])) {
             $dateformat = sanitize($_POST['user_dateformat']);
             $dns1suffix = sanitize($_POST['user_dns1suffix']);
             $dns2suffix = sanitize($_POST['user_dns2suffix']);
+            $tooltips = sanitize($_POST['user_tooltips']);
+
             $menu_assets = sanitize($_POST['user_menu_assets']);
             $menu_assetclasses = sanitize($_POST['user_menu_assetclasses']);
             $menu_assetclassgroups = sanitize($_POST['user_menu_assetclassgroups']);
+            $menu_cables = sanitize($_POST['user_menu_cables']);
             $menu_locations = sanitize($_POST['user_menu_locations']);
             $menu_nodes = sanitize($_POST['user_menu_nodes']);
             $menu_subnets = sanitize($_POST['user_menu_subnets']);
-            $menu_users = sanitize($_POST['user_menu_users']);
             $menu_vlans = sanitize($_POST['user_menu_vlans']);
             $menu_zones = sanitize($_POST['user_menu_zones']);
-            $tooltips = sanitize($_POST['user_tooltips']);
+
+            // construct menu set
+            $menu = array();
+            if ($menu_assets) $menu[] = 'asset';
+            if ($menu_assetclasses) $menu[] = 'class';
+            if ($menu_assetclassgroups) $menu[] = 'group';
+            if ($menu_cables) $menu[] = 'cable';
+            if ($menu_locations) $menu[] = 'location';
+            if ($menu_nodes) $menu[] = 'node';
+            if ($menu_subnets) $menu[] = 'subnet';
+            if ($menu_vlans) $menu[] = 'vlan';
+            if ($menu_zones) $menu[] = 'zone';
 
             $sql = "UPDATE user SET
-                    user_language=?, user_imagesize=?, user_imagecount=?, user_mac=?, user_dateformat=?,
-                    user_dns1suffix=?, user_dns2suffix=?, user_menu_assets=?, user_menu_assetclasses=?,
-                    user_menu_assetclassgroups=?, user_menu_locations=?, user_menu_nodes=?,
-                    user_menu_subnets=?, user_menu_users=?, user_menu_vlans=?, user_menu_zones=?,
-                    user_tooltips=?
+                    user_language=?, user_imagesize=?, user_imagecount=?,
+                    user_mac=?, user_dateformat=?, user_dns1suffix=?,
+                    user_dns2suffix=?, user_tooltips=?, user_menu=?
                 WHERE
                     user_id=?";
             $sth = $dbh->prepare($sql);
-            $sth->execute([$language, $imagesize, $imagecount, $mac, $dateformat,
-                           $dns1suffix, $dns2suffix, $menu_assets, $menu_assetclasses,
-                           $menu_assetclassgroups, $menu_locations, $menu_nodes,
-                           $menu_subnets, $menu_users, $menu_vlans, $menu_zones,
-                           $tooltips, $id]);
+            $sth->execute([$language, $imagesize, $imagecount,
+                           $mac, $dateformat, $dns1suffix,
+                           $dns2suffix, $tooltips, implode(',', $menu),
+                           $id]);
 
             $_SESSION['suser_language'] = $language;
             $_SESSION['suser_imagesize'] = $imagesize;
@@ -659,10 +670,10 @@ if (isset($_POST['edit'])) {
             $_SESSION['suser_menu_assets'] = $menu_assets;
             $_SESSION['suser_menu_assetclasses'] = $menu_assetclasses;
             $_SESSION['suser_menu_assetclassgroups'] = $menu_assetclassgroups;
+            $_SESSION['suser_menu_cables'] = $menu_cables;
             $_SESSION['suser_menu_locations'] = $menu_locations;
             $_SESSION['suser_menu_nodes'] = $menu_nodes;
             $_SESSION['suser_menu_subnets'] = $menu_subnets;
-            $_SESSION['suser_menu_users'] = $menu_users;
             $_SESSION['suser_menu_vlans'] = $menu_vlans;
             $_SESSION['suser_menu_zones'] = $menu_zones;
             $_SESSION['suser_tooltips'] = $tooltips;
@@ -720,10 +731,29 @@ if (isset($_POST['edit'])) {
             $user_name = sanitize($_POST['user_name']);
             $user_displayname = sanitize($_POST['user_displayname']);
             $user_realm = sanitize($_POST['user_realm']);
+            // roles
+            $role_add = sanitize($_POST['role_add']);
+            $role_edit = sanitize($_POST['role_edit']);
+            $role_delete = sanitize($_POST['role_delete']);
+            $role_manage = sanitize($_POST['role_manage']);
+            $role_admin = sanitize($_POST['role_admin']);
+
+            // construct menu set
+            $role = array();
+            if ($role_add) $role[] = 'add';
+            if ($role_edit) $role[] = 'edit';
+            if ($role_delete) $role[] = 'delete';
+            if ($role_manage) $role[] = 'manage';
+            if ($role_admin) $role[] = 'admin';
 
-            $sql = "UPDATE user SET user_name=?, user_displayname=?, user_realm=? WHERE user_id=?";
+
+            $sql = "UPDATE user SET
+                        user_name=?, user_displayname=?, user_realm=?,
+                        user_role=?
+                    WHERE user_id=?";
             $sth = $dbh->prepare($sql);
-            $sth->execute([$user_name ,$user_displayname, $user_realm, $user_id]);
+            $sth->execute([$user_name ,$user_displayname, $user_realm,
+                           implode(',', $role), $user_id]);
 
             header_location("userview.php?user_id=" . $user_id);
             break;
@@ -733,10 +763,11 @@ if (isset($_POST['edit'])) {
             $vlan_name = sanitize($_POST['vlan_name']);
             $vlan_number = sanitize($_POST['vlan_number']);
             $vlan_info = sanitize($_POST['vlan_info']);
+            $vlan_color = sanitize($_POST['vlan_color']);
 
-            $sql = "UPDATE vlan SET vlan_name=?, vlan_number=?, vlan_info=? WHERE vlan_id=?";
+            $sql = "UPDATE vlan SET vlan_name=?, vlan_number=?, vlan_color=?, vlan_info=? WHERE vlan_id=?";
             $sth = $dbh->prepare($sql);
-            $sth->execute([$vlan_name, $vlan_number, $vlan_info, $vlan_id]);
+            $sth->execute([$vlan_name, $vlan_number, $vlan_color, $vlan_info, $vlan_id]);
 
             header_location("vlanview.php?vlan_id=" . $vlan_id);
             break;
diff --git a/subnetvlanadd.php b/subnetvlanadd.php
index 3b0dbfa..203e5d1 100644
--- a/subnetvlanadd.php
+++ b/subnetvlanadd.php
@@ -33,7 +33,7 @@ $sth->execute([$subnet_id]);
 		
 $vlans = $sth->fetchAll();
 foreach ($vlans as $vlan) {
-    $vlan_options[$vlan['vlan_id']] =  $vlan['vlan_name'];
+    $vlan_options[$vlan['vlan_id']] =  $vlan['vlan_name'] . '(' . $vlan['vlan_number']. ')';
 }
 $smarty->assign("vlan_options", $vlan_options);
 
diff --git a/tpl/asset.tpl b/tpl/asset.tpl
index 51da3ed..e99164e 100644
--- a/tpl/asset.tpl
+++ b/tpl/asset.tpl
@@ -4,7 +4,9 @@
         {$lang_assets} ({$assets|@count} / {$assetcount})
     
     
+{if $suser_add}
          
+{/if}
      | 
 
 
diff --git a/tpl/assetclass.tpl b/tpl/assetclass.tpl
index c84ed25..ef94660 100644
--- a/tpl/assetclass.tpl
+++ b/tpl/assetclass.tpl
@@ -4,7 +4,9 @@
         {$lang_assetclasses} ({$assetclasses|@count})
     
     
+{if $suser_add || $suser_admin}
          
+{/if}
      | 
 
 
diff --git a/tpl/assetclassgroup.tpl b/tpl/assetclassgroup.tpl
index 1af661d..0c49fc1 100644
--- a/tpl/assetclassgroup.tpl
+++ b/tpl/assetclassgroup.tpl
@@ -4,7 +4,9 @@
         {$lang_assetclassgroups} ({$assetclassgroups|@count})
     
     
+{if $suser_add || $suser_admin}
          
+{/if}
      | 
 
 
diff --git a/tpl/assetclassview.tpl b/tpl/assetclassview.tpl
index f59d56f..6bac64b 100644
--- a/tpl/assetclassview.tpl
+++ b/tpl/assetclassview.tpl
@@ -1,7 +1,7 @@
 
 
     
     
          
diff --git a/tpl/assetview.tpl b/tpl/assetview.tpl
index 093713d..9547410 100644
--- a/tpl/assetview.tpl
+++ b/tpl/assetview.tpl
@@ -1,7 +1,7 @@
 
 
     
     
          
diff --git a/tpl/cable.tpl b/tpl/cable.tpl
new file mode 100644
index 0000000..42aaaca
--- /dev/null
+++ b/tpl/cable.tpl
@@ -0,0 +1,52 @@
+
+
+    
+    
+{if $suser_add || $suser_admin}
+         
+{/if}
+     | 
+ 
+ 
+
+
+
+    
+    
+    
+    
+ 
+{foreach item=cable from=$cables}
+
+    
+         
+        {$cable.description}
+     | 
+    
+        {$cable.cable_length} m
+     | 
+    
+        {$cable.cable_type}
+     | 
+    
+        {$cable.info}
+     | 
+ 
+{foreachelse}
+
+    | 
+        {$lang_cable_none}
+     | 
+ 
+{/foreach}
+ 
diff --git a/tpl/cableadd.tpl b/tpl/cableadd.tpl
new file mode 100644
index 0000000..9ee0ab7
--- /dev/null
+++ b/tpl/cableadd.tpl
@@ -0,0 +1,75 @@
+
diff --git a/tpl/cabledel.tpl b/tpl/cabledel.tpl
new file mode 100644
index 0000000..401d644
--- /dev/null
+++ b/tpl/cabledel.tpl
@@ -0,0 +1,39 @@
+
diff --git a/tpl/cableedit.tpl b/tpl/cableedit.tpl
new file mode 100644
index 0000000..ae9a7ca
--- /dev/null
+++ b/tpl/cableedit.tpl
@@ -0,0 +1,76 @@
+
diff --git a/tpl/cableview.tpl b/tpl/cableview.tpl
new file mode 100644
index 0000000..89a878f
--- /dev/null
+++ b/tpl/cableview.tpl
@@ -0,0 +1,63 @@
+
+    
+        
+        
+             
+             
+         | 
+     
+ 
+
+
+
+    
+    
+ 
+
+    | 
+        {$lang_description}
+     | 
+    
+        {$cable->description}
+     | 
+ 
+
+    | 
+        {$lang_cable_type} XXX
+     | 
+    
+        {$cable->cable_type}
+     | 
+ 
+
+    | 
+        {$lang_length}
+     | 
+    
+        {$cable->cable_length} m
+     | 
+ 
+
+    | 
+        {$lang_color}
+     | 
+    
+         
+        #{$cable->color}
+     | 
+ 
+
+    | 
+        {$lang_cable_info}
+     | 
+    
+        {$cable->info}
+     | 
+ 
+ 
diff --git a/tpl/header.tpl b/tpl/header.tpl
index 0e30e12..e35de4e 100644
--- a/tpl/header.tpl
+++ b/tpl/header.tpl
@@ -26,14 +26,7 @@
          
      | 
     
-        {if $menu_assets}{$lang_assets} | {/if}
-        {if $menu_assetclasses}{$lang_assetclasses} | {/if}
-        {if $menu_assetclassgroups}{$lang_assetclassgroups} | {/if}
-        {if $menu_locations}{$lang_locations} | {/if}
-        {if $menu_nodes}{$lang_nodes} | {/if}
-        {if $menu_subnets}{$lang_subnets} | {/if}
-        {if $menu_vlans}{$lang_vlans} | {/if}
-        {if $menu_zones}{$lang_zones} {/if}
+        {$menu}
      | 
     
         {$suser_name} | 
@@ -49,7 +42,6 @@
  |  
  
 
-
 
+{msgout}
diff --git a/tpl/location.tpl b/tpl/location.tpl
index 4a379d9..17ce48c 100644
--- a/tpl/location.tpl
+++ b/tpl/location.tpl
@@ -5,7 +5,9 @@
         {$lang_locations} ({$locations|@count})
      | 
     
+{if $suser_add || $suser_admin}
          
+{/if}
      | 
 
 
diff --git a/tpl/locationview.tpl b/tpl/locationview.tpl
index 31fc122..c8aa8dc 100644
--- a/tpl/locationview.tpl
+++ b/tpl/locationview.tpl
@@ -2,7 +2,7 @@
 
     
     
          
diff --git a/tpl/login.tpl b/tpl/login.tpl
index a1c1511..e4cbe8e 100644
--- a/tpl/login.tpl
+++ b/tpl/login.tpl
@@ -1,4 +1,4 @@
-
+
 
 
 	{$lang_ipreg}
diff --git a/tpl/node.tpl b/tpl/node.tpl
index 97e90d9..a0f0066 100644
--- a/tpl/node.tpl
+++ b/tpl/node.tpl
@@ -5,7 +5,9 @@
         {$lang_nodes} {if $subnet_id}in {$subnet}{/if} ({$nodes|@count})
      | 
     
+{if $suser_add || $suser_admin}
          
+{/if}
      | 
 
 
@@ -40,4 +42,4 @@
         
     
     {/foreach}
-
\ No newline at end of file
+
diff --git a/tpl/options.tpl b/tpl/options.tpl
index 6e6253f..96f3795 100644
--- a/tpl/options.tpl
+++ b/tpl/options.tpl
@@ -26,9 +26,11 @@
 		{$lang_options_display}
 	
 
+{if $suser_admin || $suser_manage}
 
 	| 
 		{$lang_users}
 	 | 
 
+{/if}
 
diff --git a/tpl/optionseditdisplay.tpl b/tpl/optionseditdisplay.tpl
index a0e61dc..e23e5cc 100644
--- a/tpl/optionseditdisplay.tpl
+++ b/tpl/optionseditdisplay.tpl
@@ -89,10 +89,12 @@
 				{$lang_assets}
 				{$lang_assetclasses}
 				{$lang_assetclassgroups}
+{if $suser_admin}
+				{$lang_cables}
+{/if}
 				{$lang_locations}
 				{$lang_nodes}
 				{$lang_subnets}
-				{$lang_users}
 				{$lang_vlans}
 				{$lang_zones}
 			
diff --git a/tpl/style.css b/tpl/style.css
index baad967..1a2ecf6 100644
--- a/tpl/style.css
+++ b/tpl/style.css
@@ -201,3 +201,41 @@ table.subnetview td {
 	padding-left: 0;
 	background-image: none;
 }
+
+/* ========== Error and other messages ===== ================================ */
+
+div.error, div.warning, div.info, div.note {
+    padding: 0 1em 0 36px;
+    margin: 1em 0 0 0;
+    -moz-border-radius: 12px;
+}
+div.error {
+    border: 1px solid #8b0000;
+    background: #ff9999 url("../images/cancel.png") no-repeat scroll 4px 4px;
+}
+div.warning {
+    border: 1px solid #827206;
+    background: #ffdd00 url("../images/error.png") no-repeat scroll 4px 4px;
+}
+div.info {
+    border: 1px solid #006400;
+    background:  #b0e1a9 url("../images/information.png") no-repeat scroll 4px 4px;
+}
+div.note {
+    border: 1px solid #00008b;
+    background: #c3d4de url("../images/note.png") no-repeat scroll 4px 4px;
+}
+div.error h3,
+div.warning h3,
+div.info h3,
+div.note h3  {
+    font-size: 0.9em;
+    margin: 0.8em 0.5em 0.5em 0;
+    color: black;
+}
+div.error p,
+div.warning p,
+div.info p,
+div.note p {
+    margin: 0.5em 0.5em 0.5em 0;
+}
diff --git a/tpl/subnet.tpl b/tpl/subnet.tpl
index 6e619bb..ea1ac02 100644
--- a/tpl/subnet.tpl
+++ b/tpl/subnet.tpl
@@ -1,10 +1,13 @@
 
 
     
     
+{if $suser_add || $suser_admin}
          
+{/if}
      | 
 
 
diff --git a/tpl/user.tpl b/tpl/user.tpl
index 708a564..c9b3a5b 100644
--- a/tpl/user.tpl
+++ b/tpl/user.tpl
@@ -21,6 +21,9 @@
     
+    
 
 {foreach item=user from=$users}
 
@@ -33,6 +36,23 @@
     | 
         {$user.displayname}
      | 
+    
+{if in_array('add', $user.role)}
+         
+{/if}
+{if in_array('edit', $user.role)}
+         
+{/if}
+{if in_array('delete', $user.role)}
+         
+{/if}
+{if in_array('manage', $user.role)}
+         
+{/if}
+{if in_array('admin', $user.role)}
+         
+{/if}
+     | 
 
 {/foreach}
 
diff --git a/tpl/useredit.tpl b/tpl/useredit.tpl
index e321991..bbe14c6 100644
--- a/tpl/useredit.tpl
+++ b/tpl/useredit.tpl
@@ -45,9 +45,64 @@
         {$lang_user_realm}
     
     
-{html_radios name=user_realm values=$realm_ids output=$realm_names selected=$realm_selected}
+        {html_radios name=user_realm values=$realm_ids output=$realm_names selected=$user->realm}
      | 
 
+
+    | 
+        Rechte
+     | 
+    
+         
+     | 
+
+
+    | 
+        {$lang_user_role_add}
+     | 
+    
+         
+        role)} checked="checked"{/if}
+     | 
+
+
+    | 
+        {$lang_user_role_edit}
+     | 
+    
+         
+        role)} checked="checked"{/if}
+     | 
+
+
+    | 
+        {$lang_user_role_delete}
+     | 
+    
+         
+        role)} checked="checked"{/if}
+     | 
+
+{if $suser_admin}
+
+    | 
+        {$lang_user_role_manage}
+     | 
+    
+         
+        role)} checked="checked"{/if}
+     | 
+
+
+    | 
+        {$lang_user_role_admin}
+     | 
+    
+         
+        role)} checked="checked"{/if}
+     | 
+
+{/if}
 
 
 
diff --git a/tpl/userview.tpl b/tpl/userview.tpl
index ff5a7bb..c920811 100644
--- a/tpl/userview.tpl
+++ b/tpl/userview.tpl
@@ -44,4 +44,26 @@
         {$user->realm}
     
 
+
+    | 
+        {$lang_user_roles}
+     | 
+    
+{if in_array('add', $user->role)}
+         
+{/if}
+{if in_array('edit', $user->role)}
+         
+{/if}
+{if in_array('delete', $user->role)}
+         
+{/if}
+{if in_array('manage', $user->role)}
+         
+{/if}
+{if in_array('admin', $user->role)}
+         
+{/if}
+     | 
+
 
diff --git a/tpl/vlan.tpl b/tpl/vlan.tpl
index b4433dd..585beba 100644
--- a/tpl/vlan.tpl
+++ b/tpl/vlan.tpl
@@ -4,7 +4,9 @@
         {$lang_vlans} ({$vlans|@count})
     
     
+{if $suser_add || $suser_admin}
          
+{/if}
      | 
 
 
@@ -27,6 +29,7 @@
         {$vlan.number}
     
     
+         
         {$vlan.name}
      | 
     
diff --git a/tpl/vlanadd.tpl b/tpl/vlanadd.tpl
index d7380be..664b4f2 100644
--- a/tpl/vlanadd.tpl
+++ b/tpl/vlanadd.tpl
@@ -35,6 +35,14 @@
         
      | 
 
+
+    | 
+        {$lang_color}
+     | 
+    
+        #
+     | 
+
 
     
         {$lang_vlan_info}
diff --git a/tpl/vlandel.tpl b/tpl/vlandel.tpl
index c37a3cc..3a59c3a 100644
--- a/tpl/vlandel.tpl
+++ b/tpl/vlandel.tpl
@@ -5,7 +5,7 @@
 
 
     
     
          
diff --git a/tpl/vlanedit.tpl b/tpl/vlanedit.tpl
index db516f2..7f5b510 100644
--- a/tpl/vlanedit.tpl
+++ b/tpl/vlanedit.tpl
@@ -1,11 +1,11 @@
  |    |