diff --git a/webui/user/include/.htaccess b/webui/user/include/.htaccess
new file mode 100644
index 0000000000000000000000000000000000000000..d2ca18f15fec0d7c62a85c1c592587442c279e7f
--- /dev/null
+++ b/webui/user/include/.htaccess
@@ -0,0 +1,4 @@
+<Files *>
+	Order Deny,Allow
+	Deny from all
+</Files>
diff --git a/webui/user/include/auth.php b/webui/user/include/auth.php
new file mode 100644
index 0000000000000000000000000000000000000000..452bc14a9adafc5b39a70e9acdef3fa522469db4
--- /dev/null
+++ b/webui/user/include/auth.php
@@ -0,0 +1,199 @@
+<?php
+# Authentication class
+#
+# Copyright (c) 2005-2008, AllWorldIT
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include('include/db.php');
+
+
+# Authentication class
+class Auth {
+
+	var $loggedIn = false;
+	var $username = "";
+
+	var $loginBoxUsername = "Username";
+	var $loginBoxMsg = "";
+
+
+	# Clean session
+	function _unsetSession() {
+		$this->loggedIn = $_SESSION['loggedIn'] = false;
+		$this->username = $_SESSION['username'] = "";
+	}
+
+
+	# Populate session
+	function _setSession($username) {
+		$this->loggedIn = $_SESSION['loggedIn'] = true;
+		$this->username = $_SESSION['username'] = $username;
+	}
+
+
+	# Load object data from session
+	function _loadSession() {
+		$this->loggedIn = $_SESSION['loggedIn'];
+		$this->username = $_SESSION['username'];
+	} 
+
+
+	# Create object
+	# Args: <section to authenticate to>
+	function Auth($section) {
+		# Make sure sessions are active
+		session_start();
+
+		# Check if we logged in, if we are pull in data
+		if (isset($_SESSION['loggedIn']) && $_SESSION['loggedIn'] == true) {
+			$this->_loadSession();
+		}
+	}
+
+
+	# Set login box username
+	function setLoginBoxUsername($msg) {
+		$this->loginBoxUsername = $msg;
+	}
+
+
+	# Login
+	function _login($username,$password) {
+		global $db;
+		global $DB_TABLE_PREFIX;
+
+		// Authenticate user with SQL, do query for password, compare ... if matches set session
+		// Check if user exists
+		$sql = "SELECT
+				Username, ID
+			FROM
+				${DB_TABLE_PREFIX}users
+			WHERE
+				Username = ".$db->quote($username)."
+			";
+
+		$res = $db->query($sql);
+		if (!$res) {
+			return -1;
+		}
+
+		$row = $res->fetchObject();
+		# Check if we actually have a user...
+		if (!$row) {
+			# If not .... reject
+			return -1;
+		}
+
+		# We're done, close
+		$res->closeCursor();
+
+		# Save username for later	
+		$username = $row->username;
+	
+		# Now check password
+		$sql = "SELECT
+				Value
+			FROM
+				${DB_TABLE_PREFIX}user_attributes
+			WHERE
+				Name = 'User-Password'
+			AND
+				UserID = ".$db->quote($row->id)."
+		";
+		$res = $db->query($sql);
+		$row = $res->fetchObject();
+		# We're done, close
+		$res->closeCursor();
+
+		if ($row->value == $password) {
+			$this->_setSession($username,$row->value);
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+
+
+	# Logout
+	function logout($msg) {
+		if ($msg != "") {
+			$_SESSION['logoutMsg'] = $msg;
+		}
+		$this->_unsetSession();
+	}
+
+
+	# Display login screen
+	function displayLogin() {
+?>
+		<form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="post">
+<?php
+			displayError($this->loginBoxMsg);
+?>
+			<table class="blockcenter">
+				<tr>
+					<td><?php echo $this->loginBoxUsername ?></td>
+					<td><input type="text" name="username" /></td>
+				</tr>
+				<tr>
+					<td>Password</td>
+					<td><input type="password" name="password" /></td>
+				</tr>
+			</table>
+			<div class="text-center">
+				<input type="submit" value="Login" />
+			</div>
+		</form>
+		<p />
+<?php
+	}
+
+
+	# Function to check login details
+	function checkLogin($username,$password) {
+		$res = -1;
+
+		# Set res to 0 if we logged in
+		if ($username != "" && $password != "" && !$this->loggedIn) {
+			switch ($this->_login($username,$password)) {
+				case 0:
+					$res = 0;
+					break;
+				case -1:
+					$this->loginBoxMsg = $this->loginBoxUsername. " or Password invalid.";
+					break;
+				default:
+					$this->loginBoxMsg = "Unknown error, please contact your ISP.";
+					break;
+			}
+		} else {
+			# Check if we have a logout message
+			if (isset($_SESSION['logoutMsg'])) {
+				$this->loginBoxMsg = $_SESSION['logoutMsg'];
+				unset($_SESSION['logoutMsg']);
+			} else {
+				$this->loginBoxMsg = "Unauthorized Access Prohibited";
+			}
+		}
+
+		return $res;
+	}
+
+}
+
+
+# vim: ts=4
+?>
diff --git a/webui/user/include/config.php b/webui/user/include/config.php
new file mode 100644
index 0000000000000000000000000000000000000000..731e8d410f4f12f1f2b0f0099452cd80d865f74c
--- /dev/null
+++ b/webui/user/include/config.php
@@ -0,0 +1,26 @@
+<?php
+
+# mysql:host=xx;dbname=yyy
+#
+# pgsql:host=xx;dbname=yyy
+#
+# sqlite:////full/unix/path/to/file.db?mode=0666
+#
+#$DB_DSN="sqlite:////tmp/cluebringer.sqlite";
+$DB_DSN="mysql:host=localhost;dbname=smradius";
+$DB_USER="root";
+$DB_PASS="root";
+#$DB_PASS="";
+$DB_TABLE_PREFIX="";
+
+
+#
+# THE BELOW SECTION IS UNSUPPORTED AND MEANT FOR THE ORIGINAL SPONSOR OF V2
+#
+
+#$DB_POSTFIX_DSN="mysql:host=localhost;dbname=postfix";
+#$DB_POSTFIX_USER="root";
+#$DB_POSTFIX_PASS="";
+
+# vim: ts=4
+?>
diff --git a/webui/user/include/db.php b/webui/user/include/db.php
new file mode 100644
index 0000000000000000000000000000000000000000..b2b7042f73a17fd8d35fc7cc11818274a8e28899
--- /dev/null
+++ b/webui/user/include/db.php
@@ -0,0 +1,31 @@
+<?php
+
+require_once('include/config.php');
+
+
+# Connect to DB
+function connect_db()
+{
+	global $DB_DSN;
+	global $DB_USER;
+	global $DB_PASS;
+
+	try {
+		$dbh = new PDO($DB_DSN, $DB_USER, $DB_PASS, array(
+			PDO::ATTR_PERSISTENT => false
+		));
+
+		$dbh->setAttribute(PDO::ATTR_CASE,PDO::CASE_LOWER);
+
+	} catch (PDOException $e) {
+		die("Error connecting to Policyd v2 DB: " . $e->getMessage());
+	}
+
+	return $dbh;
+}
+
+# Grab DB handle
+$db = connect_db();
+
+# vim: ts=4
+?>
diff --git a/webui/user/include/footer.php b/webui/user/include/footer.php
new file mode 100644
index 0000000000000000000000000000000000000000..0a0a7b9679741b15b7bb00d866a112c4b86b9518
--- /dev/null
+++ b/webui/user/include/footer.php
@@ -0,0 +1,31 @@
+<?php
+# Footer of page
+#
+# Copyright (c) 2005-2008, AllWorldIT
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+?>
+	<div class="copyright">Copyright (c) 2005-2009, <a href="http://www.allworldit.com" ?>AllWorldIT</a></div>
+	<br />
+
+	</body>
+</html>
+<?php
+	ob_flush();
+
+# vim: ts=4
+?>
diff --git a/webui/user/include/header.php b/webui/user/include/header.php
new file mode 100644
index 0000000000000000000000000000000000000000..a6ae8fdc35853043578235e138b6c816c9b98f70
--- /dev/null
+++ b/webui/user/include/header.php
@@ -0,0 +1,48 @@
+<?php
+# Top part of radius control panel
+#
+# Copyright (c) 2005-2008, AllWorldIT
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+
+
+# Grab version
+require_once("include/version.php");
+
+?>
+<html>
+	<title>User Control Panel</title> 
+	<link rel="stylesheet" href="styles.css" type="text/css">
+
+	<body>
+		<div class="pagetitle">User Control Panel</div>	
+<?php
+	if ($auth->loggedIn) {
+?>
+		<div class="smallinfo">Logged in as <?php echo $auth->username ?> (<a href="./?logout=1">Logout</a>).</div>
+<?php
+	} else {
+?>
+		<div class="smallinfo">v<?php echo $VERSION ?></div>
+<?php
+	}
+?>
+		<br>
+<?php
+
+# vim: ts=4
+?>
diff --git a/webui/user/include/miscfuncs.php b/webui/user/include/miscfuncs.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7fb1c93749b55d4ed5e6ede05629ca657943bfc
--- /dev/null
+++ b/webui/user/include/miscfuncs.php
@@ -0,0 +1,42 @@
+<?php
+# Misc functions we can use
+#
+# Copyright (c) 2005-2008, AllWorldIT
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+# Display error banner
+function displayError($msg)
+{
+?>
+	<div class="error"><?php echo $msg; ?></div>
+<?php
+}
+
+
+# Display success banner
+function displaySuccess($msg)
+{
+?>
+	<div class="success"><?php echo $msg; ?></div>
+<?php
+}
+
+
+
+
+# vim: ts=4
+?>
diff --git a/webui/user/include/pre.php b/webui/user/include/pre.php
new file mode 100644
index 0000000000000000000000000000000000000000..d03449d1342bc7cfa4782fbf15399393bcdd6ed9
--- /dev/null
+++ b/webui/user/include/pre.php
@@ -0,0 +1,51 @@
+<?php
+# Author: Nigel Kukard  <nkukard@lbsd.net>
+# Date: 2007-06-21
+# Desc: This file takes care of authentication for us and gets the soap object
+# License: GPL
+
+
+ob_start();
+
+require_once("auth.php");
+require_once("miscfuncs.php");
+
+# Main authentication object
+$auth = new Auth('Radius');
+
+# First of all check if we in maintenance mode
+if (file_exists("../maintmode")) {
+	include("header.php");
+?>
+	<center>System unavailable due to maintenance, sorry for the inconvenience. Please try again in 5 minutes.</center>
+<?php
+	include("include/footer.php");
+	exit;
+}
+
+# If not ... carry on
+$auth->setLoginBoxUsername('Username');
+
+# Check if we logged in
+if (!$auth->loggedIn) {
+	$username = isset($_POST['username']) ? $_POST['username'] : '';
+	$password = isset($_POST['password']) ? $_POST['password'] : '';
+	# If not, check credentials
+	if ($auth->checkLogin($username,$password) != 0) {
+		include("header.php");
+		$auth->displayLogin();
+		include("include/footer.php");
+		exit;
+	}
+} else {
+	# Log client out
+	if (isset($_REQUEST['logout']) && $_REQUEST['logout'] == 1) {
+		$auth->logout("You have been logged out.");
+		require_once('HTTP.php');
+		HTTP::Redirect('.');
+		exit;
+	}
+}
+
+# vim: ts=4
+?>
diff --git a/webui/user/include/radiuscodes.php b/webui/user/include/radiuscodes.php
new file mode 100644
index 0000000000000000000000000000000000000000..8276211eb752f3d191b200b6099d7dfafd9283d1
--- /dev/null
+++ b/webui/user/include/radiuscodes.php
@@ -0,0 +1,65 @@
+<?php
+# Radius term code mappings
+#
+# Copyright (c) 2005-2008, AllWorldIT
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+
+
+# Return string for radius term code
+function strRadiusTermCode($errCode) {
+
+	if (is_numeric($errCode)) {
+
+		switch ($errCode) {
+			case 0:
+				return "Still logged in";
+			case 45: # Unknown
+			case 46: # Unknown
+			case 63: # Unknown
+			case 1:
+				return "User request";
+			case 2:
+			case 816: # TCP connection reset? unknown
+				return "Carrier loss";
+			case 5:
+				return "Session timeout";
+			case 6: # Admin reset
+			case 10: # NAS request
+			case 11: # NAS reboot
+			case 831: # NAS request? unknown
+			case 841: # NAS request? unknown
+				return "Router reset/reboot";
+			case 8: # Port error
+				return "Port error";
+			case 180: # Unknown
+				return "Local hangup";
+			case 827: # Unknown
+				return "Service unavailable";
+			default:
+				return "Unkown";
+		}
+
+	} else {
+		return "Unknown";
+	}
+
+}
+
+
+# vim: ts=4
+?> 
diff --git a/webui/user/include/version.php b/webui/user/include/version.php
new file mode 100644
index 0000000000000000000000000000000000000000..a37f2ac0b8ddfc619526f175391dbf9249033f1c
--- /dev/null
+++ b/webui/user/include/version.php
@@ -0,0 +1,26 @@
+<?php
+# Versioning for this interface
+#
+# Copyright (c) 2005-2008, AllWorldIT
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+
+
+$VERSION = "0.4.0b1";
+
+# vim: ts=4
+?>
diff --git a/webui/user/index.php b/webui/user/index.php
new file mode 100644
index 0000000000000000000000000000000000000000..8d0783345232616955b7f12b19ee5f2a28ac3809
--- /dev/null
+++ b/webui/user/index.php
@@ -0,0 +1,395 @@
+<?php
+# Main control panel page
+#
+# Copyright (c) 2005-2008, AllWorldIT
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+# pre takes care of authentication and creates soap object we need
+include("include/pre.php");
+# Page header
+include("include/header.php");
+
+# NB: We will only end up here if we authenticated!
+
+
+# Display details
+function displayDetails() { 
+	global $db;
+	global $DB_TABLE_PREFIX;
+
+	$userName = $_SESSION['username'];
+
+	# Get user's ID
+	$sql = "
+		SELECT
+				ID
+		FROM
+				${DB_TABLE_PREFIX}users
+		WHERE
+				Username = '$userName'
+		";
+
+	$res = $db->query($sql);
+	$row = $res->fetchObject();
+	$userID = $row->id;
+
+	# Get accounting data
+	$currentMonth = date("Y-m");
+
+	$sql = "
+		SELECT
+				AcctSessionTime,
+				AcctInputOctets,
+				AcctInputGigawords,
+				AcctOutputOctets,
+				AcctOutputGigawords
+		FROM
+				${DB_TABLE_PREFIX}accounting
+		WHERE
+				Username = '$userName'
+		AND
+				EventTimestamp >= '$currentMonth'
+		ORDER BY
+				EventTimestamp
+		DESC
+		";
+
+	$res = $db->query($sql);
+
+	$totalData = 0;
+	$totalInputData = 0;
+	$totalOutputData = 0;
+	$totalSessionTime = 0;
+
+	while ($row = $res->fetchObject()) {
+
+		# Input
+		$inputDataItem = 0;
+
+		if (!isset($row->acctinputoctets) && $row->acctinputoctets > 0) {
+			$inputDataItem += ($row->accinputoctets / 1024 / 1024);
+		}
+		if (!empty($row->acctinputgigawords) && $row->inputgigawords > 0) {
+			$inputDataItem += ($row->acctinputgigawords * 4096);
+		}
+
+		$totalInputData += $inputDataItem;
+
+		# Output
+		$outputDataItem = 0;
+
+		if (!empty($row->acctoutputoctets) && $row->acctoutputoctets > 0) {
+			$outputDataItem += ($row->acctoutputoctets / 1024 / 1024);
+		}
+		if (!empty($row->acctoutputgigawords) && $row->acctoutputgigawords > 0) {
+			$outputDataItem += ($row->acctoutputgigawords * 4096);
+		}
+
+		$totalOutputData += $outputDataItem;
+
+		$totalData += $totalInputData + $totalOutputData;
+
+		# Time calculation
+		$sessionTimeItem = 0;
+		if (!empty($row->acctsessiontime) && $row->acctsessiontime > 0) {
+			$sessionTimeItem += ($row->acctsessiontime - ($row->acctsessiontime % 60)) / 60;
+		}
+
+		$totalSessionTime += $sessionTimeItem;
+
+	}
+
+	$sql = "
+			SELECT
+					Name, Value
+			FROM
+					${DB_TABLE_PREFIX}user_attributes
+			WHERE
+					UserID = '$userID'
+			";
+
+	$res = $db->query($sql);
+
+	$userPhone = "Unavailable";
+	$userEmail = "Unavailable";
+	$userCap = "Unavailable";
+	$dataCap = "Unavailable";
+	$timeCap = "Unavailable";
+	$userService = "Unavailable";
+
+	while ($row = $res->fetchObject()) {
+		if ($row->name == "SMRadius-Notify-Phone") {
+			$userPhone = $row->value;
+		}
+		if ($row->name == "SMRadius-Notify-Email") {
+			$userEmail = $row->value;
+		}
+		if ($row->name == "SMRadius-Capping-Traffic-Limit") {
+			$dataCap = $row->value;
+		}
+		if ($row->name == "SMRadius-Capping-Time-Limit") {
+			$timeCap = $row->value;
+		}
+		if ($row->name == "SMRadius-User-Service") {
+			$userService = $row->value;
+		}
+	}
+
+	$isDialup = 0;
+
+?>
+
+	<table class="blockcenter">
+		<tr>
+			<td colspan="2" class="section">Account Information</td>
+		</tr>
+		<tr>
+			<td class="title">Username</td>
+			<td class="value"><?php echo $userName; ?></td>
+		</tr>
+		<tr>
+			<td class="title">Service</td>
+			<td class="value"><?php echo $userService; ?></td>
+		</tr>
+
+<?php
+
+		# Only display cap for DSL users
+		if (!$isDialup) {
+
+?>
+
+			<tr>
+				<td colspan="2" class="section">Usage Info</td>
+			</tr>
+			<tr>
+				<td class="title">Bandwidth Cap</td>
+				<td class="title">Used This Month</td>
+			</tr>
+			<tr>
+				<td class="value"><?php echo $dataCap; ?> MB</td>
+				<td class="value"><?php printf('%.2f', $totalData); ?> MB</td>
+			</tr>
+			<tr>
+				<td class="title">Time Cap</td>
+				<td class="title">Used This Month</td>
+			</tr>
+			<tr>
+				<td class="value"><?php echo $timeCap; ?> Min</td>
+				<td class="value"><?php echo $totalSessionTime; ?> Min</td>
+			</tr>
+			<tr>
+				<td colspan="2" class="section">Notifications</td>
+			</tr>
+			<form method="post">
+			<tr>
+				<td class="title">Email Address</td>
+				<td class="value">
+					<input type="text" name="notifyMethodEmail"><?php echo $userEmail; ?></input>
+				</td>
+			</tr>
+			<tr>
+				<td class="title">Cell Number</td>
+				<td class="value">
+					<input type="text" name="notifyMethodCell"><?php echo $userPhone; ?></input>
+				</td>
+			</tr>
+			</form>
+
+<?php
+
+		}
+
+?>
+
+		<tr>
+			<td></td>
+			<td></td>
+		</tr>
+		<tr>
+			<td colspan="2" align="center">
+				<a href="logs.php">Usage Logs</a>
+			</td>
+		</tr>
+	</table>
+
+	<br><br>
+
+	<font size="-1">
+		Note:
+		<li>Please contact your ISP if you have any problem using this interface.</li>
+	</font>
+
+<?php
+
+}
+
+# If this is a post and we're updating
+if (isset($_POST['notifyUpdate']) && $_POST['notifyUpdate'] == "update") {
+
+	$userName = $_SESSION['username'];
+
+	# Get user's ID
+	$sql = "
+		SELECT
+				ID
+		FROM
+				${DB_TABLE_PREFIX}users
+		WHERE
+				Username = '$userName'
+		";
+
+	$res = $db->query($sql);
+	$row = $res->fetchObject();
+	$userID = $row->id;
+
+	$sql = "
+			SELECT
+					Name, Value
+			FROM
+					${DB_TABLE_PREFIX}user_attributes
+			WHERE
+					UserID = '$userID'
+			";
+
+	$res = $db->query($sql);
+
+	$userPhone = "Unavailable";
+	$userEmail = "Unavailable";
+
+	while ($row = $res->fetchObject()) {
+		if ($row->name == "SMRadius-Notify-Phone") {
+			$userPhone = $row->value;
+		}
+		if ($row->name == "SMRadius-Notify-Email") {
+			$userEmail = $row->value;
+		}
+	}
+
+	# If we want to update email address
+	if (isset($_POST['notifyMethodEmail']) && !empty($_POST['notifyMethodEmail'])) {
+
+		$db->beginTransaction();
+
+		# Unavailble if no email address is set yet
+		if ($userEmail == "Unavailable") {
+
+			# Prepare to insert email address for the first time
+			$emailStatement = $db->prepare("INSERT INTO 
+														${DB_TABLE_PREFIX}user_attributes (UserID,Name,Operator,Value)
+											VALUES 
+														('$userID','SMRadius-Notify-Email','=*',?)
+											");
+
+			$emailResult = $emailStatement->execute(array($_POST['notifyMethodEmail'],));
+
+			# If successful, commit
+			if ($emailResult) {
+				$db->commit();
+				echo "<center>Email address updated</center>";
+			# Else, rollback changes and give error
+			} else {
+				$db->rollback();
+				echo "<center>Error updating email address, please contact your ISP.</center>";
+			}
+
+		} else {
+			# Prepare to update existing email address
+			$emailStatement = $db->prepare("UPDATE
+													${DB_TABLE_PREFIX}user_attributes
+											SET
+													Value = ? 
+											WHERE
+													Name = 'SMRadius-Notify-Email'
+											AND
+													UserID = '$userID'
+											");
+
+			$emailResult = $emailStatement->execute(array($_POST['notifyMethodEmail'],));
+
+			# If successful, commit
+			if ($emailResult) {
+				$db->commit();
+				echo "<center>Email address updated</center>";
+			# Else, rollback changes and give error
+			} else {
+				$db->rollback();
+				echo "<center>Error updating email address, please contact your ISP.</center>";
+			}
+		}
+	}
+
+	# If we want to update phone number
+	if (isset($_POST['notifyMethodCell']) && !empty($_POST['notifyMethodCell'])) {
+
+		$db->beginTransaction();
+
+		# Unavailable if there is none found for this user
+		if ($userPhone == "Unavailable") {
+			# Prepare to insert first number
+			$phoneStatement = $db->prepare("INSERT INTO 
+														${DB_TABLE_PREFIX}user_attributes (UserID,Name,Operator,Value)
+											VALUES 
+														('$userID','SMRadius-Notify-Phone','=*',?)
+											");
+
+			$phoneResult = $phoneStatement->execute(array($_POST['notifyMethodCell'],));
+
+			# If successful, commit
+			if ($phoneResult) {
+				$db->commit();
+				echo "<center>Mobile phone number updated</center>";
+			# Else, rollback changes and give error
+			} else {
+				$db->rollback();
+				echo "<center>Error updating mobile phone number, please contact your ISP.</center>";
+			}
+
+		} else {
+			# Prepare to update existing number 
+			$phoneStatement = $db->prepare("UPDATE
+													${DB_TABLE_PREFIX}user_attributes
+											SET
+													Value = ? 
+											WHERE
+													Name = 'SMRadius-Notify-Phone'
+											AND
+													UserID = '$userID'
+											");
+
+			$phoneResult = $phoneStatement->execute(array($_POST['notifyMethodPhone'],));
+
+			# If successful, commit
+			if ($emailResult) {
+				$db->commit();
+				echo "<center>Mobile phone number updated</center>";
+			# Else, rollback changes and give error
+			} else {
+				$db->rollback();
+				echo "<center>Error updating mobile phone number, please contact your ISP.</center>";
+			}
+		}
+	}
+}
+
+displayDetails();
+
+# Footer
+include("include/footer.php");
+
+# vim: ts=4
+?>
diff --git a/webui/user/logs.php b/webui/user/logs.php
new file mode 100644
index 0000000000000000000000000000000000000000..375d8698b54790c251402de5db6717558643c7fd
--- /dev/null
+++ b/webui/user/logs.php
@@ -0,0 +1,232 @@
+<?php
+# Radius user logs
+#
+# Copyright (c) 2005-2008, AllWorldIT
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# pre takes care of authentication and creates soap object we need
+include("include/pre.php");
+# Page header
+include("include/header.php");
+# Database
+include_once("include/db.php");
+# Radius functions
+require_once("include/radiuscodes.php");
+
+
+# NB: We will only end up here if we authenticated!
+
+
+# Display settings
+function displayLogs() {
+
+	global $db;
+	global $DB_TABLE_PREFIX;
+
+	$getuser = $_SESSION['username'];
+
+?>
+
+	<table class="blockcenter" width="750">
+		<tr>
+			<td colspan="4" class="title">
+				<form method="POST">
+					<p class="middle center">
+					Display logs between
+					<input type="text" name="searchFrom" size="11" /> 
+					and 
+					<input type="text" name="searchTo"  size="11" />
+					<input type="submit" value="search">
+					</p>
+				</form>
+			</td>
+			<td colspan="2" class="section">Connect Speed</td>
+			<td colspan="2" class="section">Traffic Usage<br> (Mbyte)</td>
+		</tr>
+		<tr>
+			<td class="section">Timestamp</td>
+			<td class="section">Duration<br> (Min)</td>
+			<td class="section">Caller ID</td>
+			<td class="section">Term Reason</td>
+			<td class="section">Receive</td>
+			<td class="section">Transmit</td>
+			<td class="section">Upload</td>
+			<td class="section">Download</td>
+		</tr>
+
+<?php
+
+		# Extra SQL
+		$extraSQL = "";
+		$extraSQLVals = array();
+		$limitSQL = "";
+
+		if (isset($_POST['searchFrom']) && isset($_POST['searchTo'])) {
+
+			$extraSQL .= " AND EventTimestamp >= ?";
+			array_push($extraSQLVals,$_POST['searchFrom']);
+			$extraSQL .= " AND EventTimestamp <= ?";
+			array_push($extraSQLVals,$_POST['searchTo']);
+
+			# Query to get all default data
+			$sql = "
+				SELECT
+						EventTimestamp, 
+						CallingStationID, 
+						AcctSessionTime, 
+						AcctInputOctets, 
+						AcctInputGigawords, 
+						AcctOutputOctets, 
+						AcctOutputGigawords, 
+						AcctTerminateCause 
+				FROM 
+						${DB_TABLE_PREFIX}accounting 
+				WHERE 
+						Username = '$getuser'
+						$extraSQL
+				ORDER BY
+						EventTimestamp
+				DESC
+				";
+
+			$res = $db->prepare($sql);
+			$res->execute($extraSQLVals);
+
+			# Define totals:
+			$totalData = 0;
+			$totalInputData = 0;
+			$totalOutputData = 0;
+			$totalSessionTime = 0;
+
+			while ($row = $res->fetchObject()) {
+
+				# Input data calculation
+				$inputDataItem = 0;
+
+				if (!empty($row->acctinputoctets) && $row->acctinputoctets > 0) {
+					$inputDataItem += ($row->acctinputoctets / 1024) / 1024;
+				}
+				if (!empty($row->acctinputgigawords) && $row->inputgigawords > 0) {
+					$inputDataItem += ($row->acctinputgigawords * 4096);
+				}
+				$totalInputData += $inputDataItem;
+
+
+				# Output data calculation
+				$outputDataItem = 0;
+
+				if (!empty($row->acctoutputoctets) && $row->acctoutputoctets > 0) {
+					$outputDataItem += ($row->acctoutputoctets / 1024) / 1024;
+				}
+				if (!empty($row->acctoutputgigawords) && $row->acctoutputgigawords > 0) {
+					$outputDataItem += ($row->acctoutputgigawords * 4096);
+				}
+				$totalOutputData += $outputDataItem;
+
+				$totalData += $totalOutputData + $totalInputData;
+
+
+				# Time calculation
+				$sessionTimeItem = 0;
+				if (!empty($row->acctsessiontime) && $row->acctsessiontime > 0) {
+					$sessionTimeItem += ($row->acctsessiontime - ($row->acctsessiontime % 60)) / 60;
+				}
+
+				$totalSessionTime += $sessionTimeItem;
+
+?>
+
+				<tr>
+					<td class="desc"><?php echo $row->eventtimestamp; ?></td>
+					<td class="desc"><?php echo $row->acctsessiontime; ?></td>
+					<td class="desc"><?php echo $row->callingstationid; ?></td>
+					<td class="center desc"><?php echo strRadiusTermCode($row->acctterminatecause); ?></td>
+					<td class="center desc"><?php echo "NASTransmitRate"; ?></td>
+					<td class="center desc"><?php echo "NASReceiveRate"; ?></td>
+					<td class="right desc"><?php printf('%.2f',$inputDataItem); ?></td>
+					<td class="right desc"><?php printf('%.2f',$outputDataItem); ?></td>
+				</tr>
+
+<?php
+
+			}
+			if ($res->rowCount() == 0) {
+
+?>
+
+				<tr>
+					<td colspan="8" class="info">There are no logs for the selected dates</td>
+				</tr>	
+
+<?php
+
+			} else {
+
+?>
+
+				<tr>
+					<td colspan="6" class="right">Sub Total:</td>
+					<td class="right desc"><?php printf('%.2f',$totalInputData); ?></td>
+					<td class="right desc"><?php printf('%.2f',$totalOutputData); ?></td>
+				</tr>
+				<tr>
+					<td colspan="6" class="right">Total:</td>
+					<td colspan="2" class="center desc"><?php printf('%.2f',$totalData); ?></td>
+				</tr>
+
+<?php
+
+			}
+		} else {
+
+?>
+
+			<tr>
+				<td colspan="8" class="info">Please specify dates above in YYYY-MM-DD format and click "search".</td>
+			</tr>
+
+<?php
+
+		}
+
+?>
+
+	</table>
+
+<?php
+
+}
+
+?>
+
+	<a href=".">Back</a><br>
+
+<?php
+
+displayLogs();
+
+?>
+
+	<a href=".">Back</a><br><br>
+
+<?php
+
+
+# Footer
+include("include/footer.php");
+
+# vim: ts=4
+?>
diff --git a/webui/user/styles.css b/webui/user/styles.css
new file mode 100644
index 0000000000000000000000000000000000000000..f9ae6df00231eececd745b535fdf02b06ea12838
--- /dev/null
+++ b/webui/user/styles.css
@@ -0,0 +1,179 @@
+td.section {
+	border-style: solid;
+	border-width: 2px;
+
+	color: #ffffff;
+
+	background-color: #000066;
+ 
+	text-align: center;
+}
+
+
+td.top {
+	vertical-align: top;
+}
+
+
+td.middle {
+	vertical-align: middle;
+}
+
+
+td.right {
+	text-align: right;
+}
+
+
+td.title,div.title {
+	border-style: solid;
+	border-width: 1px;
+
+	background-color: #ffffdd; 
+}
+
+
+div.pagetitle {
+	border-style: solid;
+	border-width: 1px; 
+	border-color: #000000; 
+
+	font-size: larger;
+
+	text-align: center;
+}
+
+
+div.smallinfo {
+	font-size: 10px;
+
+	text-align: center;
+}
+
+
+div.copyright {
+	border-style: solid;
+	border-width: 1px;
+
+	font-size: 10px;
+
+	text-align: center;
+}
+
+
+td.pinfo {
+	border-style: dotted;
+	border-width: 1px;
+
+	font-size: smaller;
+}
+
+
+td.info {
+	border-style: dotted;
+	border-width: 1px;
+
+	font-size: smaller;
+
+	text-align: center;
+}
+
+
+td.value,div.value {
+}
+
+
+td.desc,div.desc {
+	background-color: #eeeeee; 
+}
+
+
+.blockcenter {
+	margin-left: auto;
+	margin-right: auto;
+}
+
+
+.center {
+	text-align: center;
+}
+
+.important {
+	font-style: italic;
+}
+
+body { font-family: verdana; text-align: center; }
+
+a, a:visited {
+	text-decoration: none;
+	color: #004D91;
+}
+
+a:hover {
+	text-decoration: underline;
+}
+
+
+.loginform table {
+	width: 400;
+	margin-left: auto;
+	margin-right: auto;
+}
+
+.loginformt td {
+	text-align: center;
+}
+
+.loginforms {
+	text-align: center;
+}
+
+.loginformud, .loginformpd {
+	text-align: right;
+}
+
+.mtlisttable {
+	border: 1px solid #000000;
+	font-size: 12px;
+	margin-left: auto; margin-right: auto;
+}
+
+.mtlisttabletitle {
+	text-align: center;
+	font-size: 12px;
+	font-weight: bold;
+}
+
+.mtlisttablehead {
+	
+}
+
+.mtlisttabledata {
+	
+}
+
+mtsearchtable {
+	border: 1px solid #000;
+	margin-left: auto;
+	margin-right: auto;
+}
+
+mtsearchtabletitle {
+	font-weight: bold;
+}
+
+mtsearchtablehead {
+
+}
+
+mtsearchtabledata {
+
+}
+
+mtsearchtableorder {
+
+}
+
+mtsearchtablesubmit {
+	font-weight: bold;
+}