diff --git a/components/options.php b/components/options.php
index 4c1356bd9321b609349999816cc8fc681e3cb434..b9e97ea757504395be4dd535b683fc571cd2dc44 100644
--- a/components/options.php
+++ b/components/options.php
@@ -2,6 +2,7 @@
 
 // e-mail, password validation functions
 require_once("../lib/validation.php");
+include_once("../lib/date.php");
 
 
 // Some Constants
@@ -13,29 +14,31 @@ $sucsdbname = 'sucs'; // This was stored in config, I just don't have it here in
 // Helper Functions
 // Could these be moved to some kind of library?
 
+// Set next payment date
+$paydate = "Sept. ".(academicYear(time())+1);
 
 // function to change a user's password
 function changePassword ($oldpass, $newpass1, $newpass2) {
-	global $error, $session;
+	global $session;
 
 	if ($newpass1 !== $newpass2) {
 		// new passwords do not match!
-		$error[] = "New passwords do not match";
+		trigger_error("New passwords do not match", E_USER_WARNING);
 		return FALSE;
 	}
 
 	if (!strongPassword($newpass1)) {
-		$error[] = "Password is too weak";
+		trigger_error("New password is too weak.", E_USER_WARNING);
 		return FALSE;
 	}
 
 	if (!($ldap = @ldap_connect("ldap://localhost"))) {
-		$error[] = "LDAP connect failed";
+		trigger_error("LDAP connect failed", E_USER_ERROR);
 		return FALSE;
 	}
 	
 	if (!($ldapbind = ldap_bind($ldap, "uid=".$session->username.",ou=People,dc=sucs,dc=org",$oldpass))) {
-		$error[] = "Existing password incorrect";
+		trigger_error("Existing password incorrect", E_USER_WARNING);
 		ldap_close($ldap);
 		return FALSE;
 	}
@@ -57,13 +60,13 @@ function changeContactDetails($address, $phone, $externalEmail) {
 		return FALSE; // Valid Email handles errors itself
 	// Check valid phone number (do we have a function for this?)
 	if (empty($phone) || (strlen($phone) < 6)) {
-		$error[] = 'You must have a contact phone number!';
+		trigger_error("You must have a contact phone number!", E_USER_WARNING);
 		return FALSE;
 	}
 	// Update 
 	if ($sucsDB->Execute('UPDATE members SET address = ?,phone = ?, email = ?, lastupdate = now(), lastedit = uid WHERE username = ?', 
 			array($address, $phone, $externalEmail, $session->username)) === FALSE) {
-		$error[] = 'There was an error updating your contact details. Please contact admin.';
+		trigger_error("There was an error updating your contact details. Please contact admin.", E_USER_ERROR);
 		return FALSE;
 	}
 	return TRUE;
@@ -73,12 +76,12 @@ function changeGuestnetDetails($wiredMAC) {
 	global $sucsDB, $session, $error;
 	// Get UID as we don't have it yet	
 	if(($uid = $sucsDB->GetOne("SELECt uid FROM members WHERE username = ?", array($session->username))) === FALSE) {
-		$error[] = 'There was an error updating your GuestNET MAC Address. Please contact admin. (UID)';
+		trigger_error("There was an error updating your GuestNET MAC Address. Please contact admin. (UID)", E_USER_ERROR);
 		return FALSE;
 	}
 	// Replace the guestnet record with the one with the new mac
 	if (!$sucsDB->Replace('guestnet', array('mac' => "'$wiredMAC'", 'uid' => $uid), 'uid')) {
-		$error[] = 'There was an error updating your GuestNET MAC Address. Please contact admin. (QUERY)';
+		trigger_error("There was an error updating your GuestNET MAC Address. Please contact admin. (QUERY)", E_USER_ERROR);
 		return FALSE;
 	}
 	exec('/usr/local/bin/update-dhcpd', $placeholder, $returnVar);
@@ -87,7 +90,7 @@ function changeGuestnetDetails($wiredMAC) {
 		return TRUE;
 		//  $message[] = 'GuestNet MAC Address updated. Please wait a minute or two for the changes to take effect.';
 	} else {
-		$error[] = 'There was an error updating your GuestNet Mac Address. Please contact admin. (RETURNVAR)';
+		trigger_error("There was an error updating your GuestNet Mac Address. Please contact admin. (RETURNVAR)", E_USER_ERROR);
 		return FALSE;
 	}
 }
@@ -100,7 +103,6 @@ function isValidMACAddr($mac) {
 
 // Returns the users GuestNet MAC Address if they have one and false otherwise
 function getGuestNetMAC() {
-	global $error;
 	$ip = trim($_SERVER['REMOTE_ADDR']);
 	// Sanity Check ip?
 	// Check we are in the correct ip range (unregistered GuestNET addresses)
@@ -121,7 +123,7 @@ function getGuestNetMAC() {
 			}
 		}
 		// We didn't find their mac address :\
-		$error[] = 'There was an error finding your MAC Address. Please contact admin.';
+		trigger_error("There was an error finding your MAC Address. Please contact admin.", E_USER_ERROR);
 		return FALSE;
 	} else {
 		return FALSE;
@@ -130,26 +132,27 @@ function getGuestNetMAC() {
 
 // Delete the user's hackergotchi file cause they've decided they're too embarrassed by it
 function clearHackergotchi() {
-	global $error,$session;
+	global $session;
 	$imagefilepath = hackergotchiPath($session->username);
 
 	if (unlink($imagefilepath)) {
 		return true;
 	} else { 
-		$error[] = 'Unable to remove hackergotchi file';
+		trigger_error("Unable to remove hackergotchi file", E_USER_ERROR);
 		return false; 
 	}
 }
 
 // construct the filesystem path to a user's hackergotchi picture
 function hackergotchiPath($username) {
-	$path = SUCS_BASEDIR."htdocs/pictures/people/".$username.".png"; 
+	global $base; 
+	$path = $base."htdocs/pictures/people/".$username.".png"; 
 	return $path;
 }
 
 // Takes an entry from $_FILES and makes this the new hackergotchi
 function updateHackergotchi($fileDetails) {
-	global $error,$session;
+	global $session;
 	if ( ((list($width, $height, $type, $attr) = @getimagesize($fileDetails['tmp_name'])) !== false) && 
 	     ($type == IMAGETYPE_PNG) && ($width <= 128) && ($height <= 128)) {
 
@@ -161,10 +164,41 @@ function updateHackergotchi($fileDetails) {
 		}
 	}
 	// We should have returned True by now
-	$error[] = 'There was an error updating your hackergotchi. Please contact admin.';
+	trigger_error("There was an error updating your hackergotchi. Please contact admin.", E_USER_ERROR);
 	return FALSE;
 }
 
+function updateRenew() {
+	global $sucsDB, $session, $error;
+	global $paydate;
+
+	if (!isset($_REQUEST['userid']) || !isset($_REQUEST['supass'])) {
+		trigger_error("Invalid renewal info", E_USER_ERROR);
+		return FALSE;
+	}
+	$userid = (int)$_REQUEST['userid'];
+	$pass = $_REQUEST['supass'];
+	$member = $sucsDB->GetRow("select * from members left join member_type on members.type=member_type.id where username='".$session->username."'");
+
+	$signup = $sucsDB->GetRow("select * from signup where id=?", array($userid));
+	if (!is_array($signup) || count($signup) < 1) {
+		trigger_error("Invalid renewal info", E_USER_ERROR);
+		return FALSE;
+	}
+	if ($signup['password'] != $pass) {
+		trigger_error("Invalid renewal info", E_USER_ERROR);
+		return FALSE;
+	}
+	if ($signup['activated'] != NULL) {
+		trigger_error("Signup slip already used", E_USER_ERROR);
+		return FALSE;
+	}
+
+	$sucsDB->Execute("update members set paid=?, lastupdate=DEFAULT, lastedit=uid where uid=?", array($paydate, $member['uid']));
+	$sucsDB->Execute("update signup set activated=NOW(), username=? where id=?", array($member['username'], $signup['id']));
+	return TRUE;
+}
+
 // Template Setup
 
 $smarty->assign('session', $session);
@@ -182,30 +216,35 @@ if ($session->loggedin === TRUE) {
 		switch($_POST['action']) {
 			case 'changepass' :
 				if (changePassword($_POST['oldpass'], $_POST['newpass1'], $_POST['newpass2'])) {
-					$messages[] = 'Password changed.';
+					message_flash('Password changed.');
 				} else {
 					// Should we log something here for bug trcaking use?
-					$error[] = "Password change failed.";
+					trigger_error("Password change failed.", E_USER_WARNING);
 				}
 				break;
 			case 'changecontact' :
 				if(changeContactDetails($_POST['address'], $_POST['phone'], $_POST['email'])) {
-					$messages[] = 'Contact Details Updated.';
+					message_flash('Contact Details Updated.');
 				}
 				break;
 			case 'changeguestnet' :
 				if(changeGuestNetDetails($newGuestNetMAC)) {
-					$messages[] = 'GuestNet Details Updated!';
+					message_flash('GuestNet Details Updated!');
 				}
 				break;
 			case 'updatehackergotchi' :
 				if (updateHackergotchi($_FILES['hackergotchi'])) {
-					$messages[] = 'Hackergotchi Updated';
+					message_flash('Hackergotchi Updated');
 				} 
 				break;
 			case 'clearhackergotchi' :
 				if (clearHackergotchi()) {
-					$messages[] = 'Hackergotchi Cleared';
+					message_flash('Hackergotchi Cleared');
+				}
+				break;
+			case 'renew' :
+				if (updateRenew()) {
+					message_flash('Account renewed');
 				}
 				break;
 		}
@@ -216,11 +255,12 @@ if ($session->loggedin === TRUE) {
 	// Some checking could be done here to ensure we have a members record. Ideally we should
 	// be able to assume this though if they are logged in.
 
-	if (is_file(SUCS_BASEDIR."htdocs/pictures/people/".$session->username.".png")) $smarty->assign('hackergotchi', TRUE);
+	if (is_file($base."htdocs/pictures/people/".$session->username.".png")) $smarty->assign('hackergotchi', TRUE);
 
 
-	$member = $sucsDB->GetRow("select * from members where username='".$session->username."'");
+	$member = $sucsDB->GetRow("select * from members left join member_type on members.type=member_type.id where username='".$session->username."'");
 	$smarty->assign('member', $member);
+	$smarty->assign('paydate', $paydate);
 
 	if(($currentGuestNetMAC = $sucsDB->GetOne('SELECT * FROM guestnet WHERE uid=?', array((int)$member['uid']))) !== FALSE) {
 		$smarty->assign('currentGuestNetMAC', $currentGuestNetMAC);
@@ -235,10 +275,6 @@ if ($session->loggedin === TRUE) {
 
 }
 
-// merge messages into errors for the time being
-$error = array_merge((array)$error, (array)$messages);
-
-$smarty->assign('error', $error);
 $smarty->assign('url', $component['path']);
 $result = $smarty->fetch('options.tpl');
 $smarty->assign('title', "Options");
diff --git a/templates/options.tpl b/templates/options.tpl
index 3162a337aa19d70a44ee47b9d0175e62904f03dc..a9af61c8fabed91afa272b9fce9f3024bd86e060 100644
--- a/templates/options.tpl
+++ b/templates/options.tpl
@@ -1,18 +1,9 @@
-{if !empty($error) }
-{foreach name=error from=$error item=errorMessage}
-	<div class="errorbar">
-		<div><div><div>
-			{$errorMessage}
-		</div></div></div>
-	</div>
-{/foreach}
-{/if}
 {if $session->loggedin }
 <!-- style="width: 80%; margin: auto;" was in here originally, why? -->
 <div class="box" >
 <div class="boxhead"><h2>User Settings</h2></div>
 <div class="boxcontent">
-<form class="admin" action="{$path}" method="POST">
+<form class="admin" action="{$baseurl}{$path}" method="POST">
 	
 	<fieldset>
 	<legend> System Details </legend>
@@ -30,6 +21,13 @@
 			<div class="note">If your name has changed (e.g. through marriage), please contact a member of admin.</div>
 		</span>
 	</div>
+	<div class="row">
+		<label for="status">Membership status:</label>
+		<span class="textinput">
+			{$member.typename}
+			{if $member.id == 1 || $member.id == 2}(Paid Until: {$member.paid}){/if}
+		</span>
+	</div>
 	<div class="row">
 		<label for="groups">Groups: </label>
 		<span class="textinput"><span class="note"><a href="/Knowledge/Help/Admin%20Tools/Groups">What are &ldquo;Groups&rdquo;?</a></span></span>
@@ -45,11 +43,11 @@
 		</span>
 	</div>
 	<div class="row">
-		<label for="hackergotchi">Hackergotchi:</label>
+		<label for="hackergotchi">Hackergotchi (user avatar):</label>
 		<span class="textinput" id="hackergotchi">
 {if $hackergotchi}
-			<img src="{$smarty.const.SUCS_BASEURL}/pictures/people/{$session->username}.png" />
-	<form action="{$self}" method="post">
+			<img src="{$baseurl}/pictures/people/{$session->username}.png" />
+	<form action="{$baseurl}{$path}" method="post">
 		<input type="hidden" name="action" value="clearhackergotchi" />
 		<input type="submit" value="Clear Hackergotchi" />
 	</form>
@@ -62,11 +60,12 @@
 		
 	</div>
 
-	<form method="post" action="{$self}" enctype="multipart/form-data">
+	<form method="post" action="{$baseurl}{$path}" enctype="multipart/form-data">
 	<div class="row">
 		<label>Update Hackergotchi:</label>
 		<span class="textinput">
 			<input name="hackergotchi" type="file" />
+		<div class="note">See <a href="http://en.wikipedia.org/wiki/Hackergotchi">Wikipedia's entry on Hackergotchis</a> if you've not got a clue what we're on about!</div>
 			<div class="note">This must be an image in PNG format with dimensions no greater than 128x128 pixels.</div>
 		</span>
 	</div>
@@ -78,7 +77,7 @@
 	</form> 
 	</fieldset>
 	
-	<form method="post" action="{$self}">
+	<form method="post" action="{$baseurl}{$path}">
 	<fieldset>
 	<legend> Password </legend>
 	<input type="hidden" name="action" value="changepass" />
@@ -110,7 +109,7 @@
 	</fieldset>
 	</form>
 	
-	<form method="post" action="{$self}">
+	<form method="post" action="{$baseurl}{$path}">
 	<fieldset>
 	<legend> Contact Details </legend>
 	<input type="hidden" name="action" value="changecontact" />
@@ -139,7 +138,7 @@
 	</fieldset>
 	</form>
 
-	<form method="post" action="{$self}">
+	<form method="post" action="{$baseurl}{$path}">
 	<fieldset>
 	<legend> Room Network Configuration </legend>
 	<input type="hidden" name="action" value="changeguestnet" />
@@ -167,6 +166,30 @@
 {/if}
 	</fieldset>
 	</form>
+
+{if ($member.type == 1 || $member.type == 2) && $member.paid != $paydate}
+	<form method="post" action="{$baseurl}{$path}">
+	<fieldset>
+	<legend> Membership Renewal </legend>
+	<input type="hidden" name="action" value="renew" />
+	<div class="row">
+		<label for="userid">ID:</label>
+		<span class="textinput">
+			<input type="text" name="userid" id="userid" value="" />
+		</span>
+		<label for="supass">Password:</label>
+		<span class="textinput">
+			<input type="text" name="supass" id="supass" value="" />
+			<div class="note">You may use a purchased signup slip to renew your account by entering its details here.</div>
+		</span>
+	</div>
+	<div class="row">
+		<input type="submit" value="Renew" />
+	</div>
+	</fieldset>
+	</form>
+{/if}
+
 	<div class="clear"></div>
 </form>
 </div>