diff --git a/upload/admin_bans.php b/upload/admin_bans.php
index 9a1fdc8..2583d38 100644
--- a/upload/admin_bans.php
+++ b/upload/admin_bans.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -30,16 +13,19 @@ define('PUN_ROOT', './');
 require PUN_ROOT.'include/common.php';
 require PUN_ROOT.'include/common_admin.php';
 
+
 if ($pun_user['g_id'] != PUN_ADMIN && ($pun_user['g_moderator'] != '1' || $pun_user['g_mod_ban_users'] == '0'))
 	message($lang_common['No permission']);
 
+// Load the admin_bans.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_bans.php';
 
 // Add/edit a ban (stage 1)
 if (isset($_REQUEST['add_ban']) || isset($_GET['edit_ban']))
 {
 	if (isset($_GET['add_ban']) || isset($_POST['add_ban']))
 	{
-		// If the id of the user to ban was provided through GET (a link from profile.php)
+		// If the ID of the user to ban was provided through GET (a link from profile.php)
 		if (isset($_GET['add_ban']))
 		{
 			$add_ban = intval($_GET['add_ban']);
@@ -52,11 +38,11 @@ if (isset($_REQUEST['add_ban']) || isset($_GET['edit_ban']))
 			if ($db->num_rows($result))
 				list($group_id, $ban_user, $ban_email) = $db->fetch_row($result);
 			else
-				message('No user by that ID registered.');
+				message($lang_admin_bans['No user ID message']);
 		}
-		else	// Otherwise the username is in POST
+		else // Otherwise the username is in POST
 		{
-			$ban_user = trim($_POST['new_ban_user']);
+			$ban_user = pun_trim($_POST['new_ban_user']);
 
 			if ($ban_user != '')
 			{
@@ -64,13 +50,13 @@ if (isset($_REQUEST['add_ban']) || isset($_GET['edit_ban']))
 				if ($db->num_rows($result))
 					list($user_id, $group_id, $ban_user, $ban_email) = $db->fetch_row($result);
 				else
-					message('No user by that username registered. If you want to add a ban not tied to a specific username just leave the username blank.');
+					message($lang_admin_bans['No user message']);
 			}
 		}
 
 		// Make sure we're not banning an admin
 		if (isset($group_id) && $group_id == PUN_ADMIN)
-			message('The user '.pun_htmlspecialchars($ban_user).' is an administrator and can\'t be banned. If you want to ban an administrator, you must first demote him/her to moderator or user.');
+			message(sprintf($lang_admin_bans['User is admin message'], pun_htmlspecialchars($ban_user)));
 
 		// If we have a $user_id, we can try to find the last known IP of that user
 		if (isset($user_id))
@@ -81,7 +67,7 @@ if (isset($_REQUEST['add_ban']) || isset($_GET['edit_ban']))
 
 		$mode = 'add';
 	}
-	else	// We are editing a ban
+	else // We are editing a ban
 	{
 		$ban_id = intval($_GET['edit_ban']);
 		if ($ban_id < 1)
@@ -98,75 +84,75 @@ if (isset($_REQUEST['add_ban']) || isset($_GET['edit_ban']))
 		$mode = 'edit';
 	}
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Bans';
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Bans']);
 	$focus_element = array('bans2', 'ban_user');
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 	generate_admin_menu('bans');
 
-
 ?>
 	<div class="blockform">
-		<h2><span>Ban advanced settings</span></h2>
+		<h2><span><?php echo $lang_admin_bans['Ban advanced head'] ?></span></h2>
 		<div class="box">
 			<form id="bans2" method="post" action="admin_bans.php">
 				<div class="inform">
 				<input type="hidden" name="mode" value="<?php echo $mode ?>" />
 <?php if ($mode == 'edit'): ?>				<input type="hidden" name="ban_id" value="<?php echo $ban_id ?>" />
 <?php endif; ?>				<fieldset>
-						<legend>Supplement ban with IP and e-mail</legend>
+						<legend><?php echo $lang_admin_bans['Ban advanced subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Username</th>
+									<th scope="row"><?php echo $lang_admin_bans['Username label'] ?></th>
 									<td>
 										<input type="text" name="ban_user" size="25" maxlength="25" value="<?php if (isset($ban_user)) echo pun_htmlspecialchars($ban_user); ?>" tabindex="1" />
-										<span>The username to ban.</span>
+										<span><?php echo $lang_admin_bans['Username help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">IP-adresses</th>
+									<th scope="row"><?php echo $lang_admin_bans['IP label'] ?></th>
 									<td>
 										<input type="text" name="ban_ip" size="45" maxlength="255" value="<?php if (isset($ban_ip)) echo $ban_ip; ?>" tabindex="2" />
-										<span>The IP or IP-ranges you wish to ban (e.g. 150.11.110.1 or 150.11.110). Separate addresses with spaces. If an IP is entered already it is the last known IP of this user in the database.<?php if ($ban_user != '' && isset($user_id)) echo ' Click <a href="admin_users.php?ip_stats='.$user_id.'">here</a> to see IP statistics for this user.' ?></span>
+										<span><?php echo $lang_admin_bans['IP help'] ?><?php if ($ban_user != '' && isset($user_id)) printf(' '.$lang_admin_bans['IP help link'], '<a href="admin_users.php?ip_stats='.$user_id.'">'.$lang_admin_common['here'].'</a>') ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">E-mail/domain</th>
+									<th scope="row"><?php echo $lang_admin_bans['E-mail label'] ?></th>
 									<td>
-										<input type="text" name="ban_email" size="40" maxlength="50" value="<?php if (isset($ban_email)) echo strtolower($ban_email); ?>" tabindex="3" />
-										<span>The e-mail or e-mail domain you wish to ban (e.g. someone@somewhere.com or somewhere.com). See "Allow banned e-mail addresses" in Permissions for more info.</span>
+										<input type="text" name="ban_email" size="40" maxlength="80" value="<?php if (isset($ban_email)) echo strtolower($ban_email); ?>" tabindex="3" />
+										<span><?php echo $lang_admin_bans['E-mail help'] ?></span>
 									</td>
 								</tr>
 							</table>
-							<p class="topspace"><strong class="warntext">You should be very careful when banning an IP-range because of the possibility of multiple users matching the same partial IP.</strong></p>
+							<p class="topspace"><strong class="warntext"><?php echo $lang_admin_bans['Ban IP range info'] ?></strong></p>
 						</div>
 					</fieldset>
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Ban message and expiry</legend>
+						<legend><?php echo $lang_admin_bans['Message expiry subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Ban message</th>
+									<th scope="row"><?php echo $lang_admin_bans['Ban message label'] ?></th>
 									<td>
 										<input type="text" name="ban_message" size="50" maxlength="255" value="<?php if (isset($ban_message)) echo pun_htmlspecialchars($ban_message); ?>" tabindex="4" />
-										<span>A message that will be displayed to the banned user when he/she visits the forums.</span>
+										<span><?php echo $lang_admin_bans['Ban message help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Expire date</th>
+									<th scope="row"><?php echo $lang_admin_bans['Expire date label'] ?></th>
 									<td>
 										<input type="text" name="ban_expire" size="17" maxlength="10" value="<?php if (isset($ban_expire)) echo $ban_expire; ?>" tabindex="5" />
-										<span>The date when this ban should be automatically removed (format: YYYY-MM-DD). Leave blank to remove manually.</span>
+										<span><?php echo $lang_admin_bans['Expire date help'] ?></span>
 									</td>
 								</tr>
 							</table>
 						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="add_edit_ban" value=" Save " tabindex="6" /></p>
+				<p class="submitend"><input type="submit" name="add_edit_ban" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="6" /></p>
 			</form>
 		</div>
 	</div>
@@ -177,33 +163,32 @@ if (isset($_REQUEST['add_ban']) || isset($_GET['edit_ban']))
 	require PUN_ROOT.'footer.php';
 }
 
-
 // Add/edit a ban (stage 2)
 else if (isset($_POST['add_edit_ban']))
 {
 	confirm_referrer('admin_bans.php');
 
-	$ban_user = trim($_POST['ban_user']);
+	$ban_user = pun_trim($_POST['ban_user']);
 	$ban_ip = trim($_POST['ban_ip']);
 	$ban_email = strtolower(trim($_POST['ban_email']));
-	$ban_message = trim($_POST['ban_message']);
+	$ban_message = pun_trim($_POST['ban_message']);
 	$ban_expire = trim($_POST['ban_expire']);
 
 	if ($ban_user == '' && $ban_ip == '' && $ban_email == '')
-		message('You must enter either a username, an IP address or an e-mail address (at least).');
+		message($lang_admin_bans['Must enter message']);
 	else if (strtolower($ban_user) == 'guest')
-		message('The guest user cannot be banned.');
+		message($lang_admin_bans['Cannot ban guest message']);
 
 	// Validate IP/IP range (it's overkill, I know)
 	if ($ban_ip != '')
 	{
-		$ban_ip = preg_replace('/[\s]{2,}/', ' ', $ban_ip);
+		$ban_ip = preg_replace('/\s{2,}/S', ' ', $ban_ip);
 		$addresses = explode(' ', $ban_ip);
-		$addresses = array_map('trim', $addresses);
+		$addresses = array_map('pun_trim', $addresses);
 
 		for ($i = 0; $i < count($addresses); ++$i)
 		{
-			if (strpos($addresses[$i], ':') !== false) 
+			if (strpos($addresses[$i], ':') !== false)
 			{
 				$octets = explode(':', $addresses[$i]);
 
@@ -212,7 +197,7 @@ else if (isset($_POST['add_edit_ban']))
 					$octets[$c] = ltrim($octets[$c], "0");
 
 					if ($c > 7 || (!empty($octets[$c]) && !ctype_xdigit($octets[$c])) || intval($octets[$c], 16) > 65535)
-						message('You entered an invalid IP/IP-range.');
+						message($lang_admin_bans['Invalid IP message']);
 				}
 
 				$cur_address = implode(':', $octets);
@@ -227,7 +212,7 @@ else if (isset($_POST['add_edit_ban']))
 					$octets[$c] = (strlen($octets[$c]) > 1) ? ltrim($octets[$c], "0") : $octets[$c];
 
 					if ($c > 3 || preg_match('/[^0-9]/', $octets[$c]) || intval($octets[$c]) > 255)
-						message('You entered an invalid IP/IP-range.');
+						message($lang_admin_bans['Invalid IP message']);
 				}
 
 				$cur_address = implode('.', $octets);
@@ -242,7 +227,7 @@ else if (isset($_POST['add_edit_ban']))
 	if ($ban_email != '' && !is_valid_email($ban_email))
 	{
 		if (!preg_match('/^[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/', $ban_email))
-			message('The e-mail address (e.g. user@domain.com) or partial e-mail address domain (e.g. domain.com) you entered is invalid.');
+			message($lang_admin_bans['Invalid e-mail message']);
 	}
 
 	if ($ban_expire != '' && $ban_expire != 'Never')
@@ -250,7 +235,7 @@ else if (isset($_POST['add_edit_ban']))
 		$ban_expire = strtotime($ban_expire);
 
 		if ($ban_expire == -1 || $ban_expire <= time())
-			message('You entered an invalid expire date. The format should be YYYY-MM-DD and the date must be at least one day in the future.');
+			message($lang_admin_bans['Invalid date message'].' '.$lang_admin_bans['Invalid date reasons']);
 	}
 	else
 		$ban_expire = 'NULL';
@@ -271,10 +256,12 @@ else if (isset($_POST['add_edit_ban']))
 
 	generate_bans_cache();
 
-	redirect('admin_bans.php', 'Ban '.(($_POST['mode'] == 'edit') ? 'edited' : 'added').'. Redirecting &hellip;');
+	if ($_POST['mode'] == 'edit')
+		redirect('admin_bans.php', $lang_admin_bans['Ban edited redirect']);
+	else
+		redirect('admin_bans.php', $lang_admin_bans['Ban added redirect']);
 }
 
-
 // Remove a ban
 else if (isset($_GET['del_ban']))
 {
@@ -292,31 +279,179 @@ else if (isset($_GET['del_ban']))
 
 	generate_bans_cache();
 
-	redirect('admin_bans.php', 'Ban removed. Redirecting &hellip;');
+	redirect('admin_bans.php', $lang_admin_bans['Ban removed redirect']);
 }
 
+// Find bans
+else if (isset($_GET['find_ban']))
+{
+	$form = isset($_GET['form']) ? $_GET['form'] : array();
+
+	// trim() all elements in $form
+	$form = array_map('pun_trim', $form);
+	$conditions = $query_str = array();
+
+	$expire_after = isset($_GET['expire_after']) ? trim($_GET['expire_after']) : '';
+	$expire_before = isset($_GET['expire_before']) ? trim($_GET['expire_before']) : '';
+	$order_by = isset($_GET['order_by']) && in_array($_GET['order_by'], array('username', 'ip', 'email', 'expire')) ? $_GET['order_by'] : 'username';
+	$direction = isset($_GET['direction']) && $_GET['direction'] == 'DESC' ? 'DESC' : 'ASC';
+
+	$query_str[] = 'order_by='.$order_by;
+	$query_str[] = 'direction='.$direction;
+
+	// Try to convert date/time to timestamps
+	if ($expire_after != '')
+	{
+		$query_str[] = 'expire_after='.$expire_after;
+
+		$expire_after = strtotime($expire_after);
+		if ($expire_after === false || $expire_after == -1)
+			message($lang_admin_bans['Invalid date message']);
+
+		$conditions[] = 'expire>'.$expire_after;
+	}
+	if ($expire_before != '')
+	{
+		$query_str[] = 'expire_before='.$expire_before;
+
+		$expire_before = strtotime($expire_before);
+		if ($expire_before === false || $expire_before == -1)
+			message($lang_admin_bans['Invalid date message']);
+
+		$conditions[] = 'expire<'.$expire_before;
+	}
+
+	$like_command = ($db_type == 'pgsql') ? 'ILIKE' : 'LIKE';
+	while (list($key, $input) = @each($form))
+	{
+		if ($input != '' && in_array($key, array('username', 'ip', 'email', 'message')))
+		{
+			$conditions[] = 'b.'.$db->escape($key).' '.$like_command.' \''.$db->escape(str_replace('*', '%', $input)).'\'';
+			$query_str[] = 'form%5B'.$key.'%5D='.urlencode($input);
+		}
+	}
+
+	// Fetch ban count
+	$result = $db->query('SELECT COUNT(id) FROM '.$db->prefix.'bans as b WHERE b.id>0'.(!empty($conditions) ? ' AND '.implode(' AND ', $conditions) : '')) or error('Unable to fetch ban list', __FILE__, __LINE__, $db->error());
+	$num_bans = $db->result($result);
+
+	// Determine the ban offset (based on $_GET['p'])
+	$num_pages = ceil($num_bans / 50);
+
+	$p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
+	$start_from = 50 * ($p - 1);
+
+	// Generate paging links
+	$paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_bans.php?find_ban=&amp;'.implode('&amp;', $query_str));
+
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Bans'], $lang_admin_bans['Results head']);
+	define('PUN_ACTIVE_PAGE', 'admin');
+	require PUN_ROOT.'header.php';
+
+?>
+<div class="linkst">
+	<div class="inbox crumbsplus">
+		<ul class="crumbs">
+			<li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="admin_bans.php"><?php echo $lang_admin_common['Bans'] ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_admin_bans['Results head'] ?></strong></li>
+		</ul>
+		<p class="pagelink"><?php echo $paging_links ?></p>
+		<div class="clearer"></div>
+	</div>
+</div>
+
+
+<div id="bans1" class="blocktable">
+	<h2><span><?php echo $lang_admin_bans['Results head'] ?></span></h2>
+	<div class="box">
+		<div class="inbox">
+			<table cellspacing="0">
+			<thead>
+				<tr>
+					<th class="tcl" scope="col"><?php echo $lang_admin_bans['Results username head'] ?></th>
+					<th class="tc2" scope="col"><?php echo $lang_admin_bans['Results e-mail head'] ?></th>
+					<th class="tc3" scope="col"><?php echo $lang_admin_bans['Results IP address head'] ?></th>
+					<th class="tc4" scope="col"><?php echo $lang_admin_bans['Results expire head'] ?></th>
+					<th class="tc5" scope="col"><?php echo $lang_admin_bans['Results message head'] ?></th>
+					<th class="tc6" scope="col"><?php echo $lang_admin_bans['Results banned by head'] ?></th>
+					<th class="tcr" scope="col"><?php echo $lang_admin_bans['Results actions head'] ?></th>
+				</tr>
+			</thead>
+			<tbody>
+<?php
+
+	$result = $db->query('SELECT b.id, b.username, b.ip, b.email, b.message, b.expire, b.ban_creator, u.username AS ban_creator_username FROM '.$db->prefix.'bans AS b LEFT JOIN '.$db->prefix.'users AS u ON b.ban_creator=u.id WHERE b.id>0'.(!empty($conditions) ? ' AND '.implode(' AND ', $conditions) : '').' ORDER BY '.$db->escape($order_by).' '.$db->escape($direction).' LIMIT '.$start_from.', 50') or error('Unable to fetch ban list', __FILE__, __LINE__, $db->error());
+	if ($db->num_rows($result))
+	{
+		while ($ban_data = $db->fetch_assoc($result))
+		{
+
+			$actions = '<a href="admin_bans.php?edit_ban='.$ban_data['id'].'">'.$lang_admin_common['Edit'].'</a> | <a href="admin_bans.php?del_ban='.$ban_data['id'].'">'.$lang_admin_common['Remove'].'</a>';
+			$expire = format_time($ban_data['expire'], true);
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Bans';
+?>
+				<tr>
+					<td class="tcl"><?php echo ($ban_data['username'] != '') ? pun_htmlspecialchars($ban_data['username']) : '&nbsp;' ?></td>
+					<td class="tc2"><?php echo ($ban_data['email'] != '') ? $ban_data['email'] : '&nbsp;' ?></td>
+					<td class="tc3"><?php echo ($ban_data['ip'] != '') ? $ban_data['ip'] : '&nbsp;' ?></td>
+					<td class="tc4"><?php echo $expire ?></td>
+					<td class="tc5"><?php echo ($ban_data['message'] != '') ? pun_htmlspecialchars($ban_data['message']) : '&nbsp;' ?></td>
+					<td class="tc6"><?php echo ($ban_data['ban_creator_username'] != '') ? '<a href="profile.php?id='.$ban_data['ban_creator'].'">'.pun_htmlspecialchars($ban_data['ban_creator_username']).'</a>' : $lang_admin_bans['Unknown'] ?></td>
+					<td class="tcr"><?php echo $actions ?></td>
+				</tr>
+<?php
+
+		}
+	}
+	else
+		echo "\t\t\t\t".'<tr><td class="tcl" colspan="7">'.$lang_admin_bans['No match'].'</td></tr>'."\n";
+
+?>
+			</tbody>
+			</table>
+		</div>
+	</div>
+</div>
+
+<div class="linksb">
+	<div class="inbox crumbsplus">
+		<p class="pagelink"><?php echo $paging_links ?></p>
+		<ul class="crumbs">
+			<li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="admin_bans.php"><?php echo $lang_admin_common['Bans'] ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_admin_bans['Results head'] ?></strong></li>
+		</ul>
+		<div class="clearer"></div>
+	</div>
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Bans']);
 $focus_element = array('bans', 'new_ban_user');
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('bans');
 
 ?>
 	<div class="blockform">
-		<h2><span>New ban</span></h2>
+		<h2><span><?php echo $lang_admin_bans['New ban head'] ?></span></h2>
 		<div class="box">
 			<form id="bans" method="post" action="admin_bans.php?action=more">
 				<div class="inform">
 					<fieldset>
-						<legend>Add ban</legend>
+						<legend><?php echo $lang_admin_bans['Add ban subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Username<div><input type="submit" name="add_ban" value=" Add " tabindex="2" /></div></th>
+									<th scope="row"><?php echo $lang_admin_bans['Username label'] ?><div><input type="submit" name="add_ban" value="<?php echo $lang_admin_common['Add'] ?>" tabindex="2" /></div></th>
 									<td>
 										<input type="text" name="new_ban_user" size="25" maxlength="25" tabindex="1" />
-										<span>The username to ban (case insensitive). The next page will let you enter a custom IP and e-mail. If you just want to ban a specific IP/IP-range or e-mail just leave it blank.</span>
+										<span><?php echo $lang_admin_bans['Username advanced help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -326,58 +461,62 @@ generate_admin_menu('bans');
 			</form>
 		</div>
 
-		<h2 class="block2"><span>Existing bans</span></h2>
+		<h2><span><?php echo $lang_admin_bans['Ban search head'] ?></span></h2>
 		<div class="box">
-			<div class="fakeform">
-<?php
-
-$result = $db->query('SELECT b.id, b.username, b.ip, b.email, b.message, b.expire, b.ban_creator, u.username AS ban_creator_username FROM '.$db->prefix.'bans AS b LEFT JOIN '.$db->prefix.'users AS u ON b.ban_creator=u.id ORDER BY b.id') or error('Unable to fetch ban list', __FILE__, __LINE__, $db->error());
-if ($db->num_rows($result))
-{
-	while ($cur_ban = $db->fetch_assoc($result))
-	{
-		$expire = format_time($cur_ban['expire'], true);
-
-?>
+			<form id="find_band" method="get" action="admin_bans.php">
+				<p class="submittop"><input type="submit" name="find_ban" value="<?php echo $lang_admin_bans['Submit search'] ?>" tabindex="3" /></p>
 				<div class="inform">
 					<fieldset>
-						<legend>Ban expires: <?php echo $expire ?></legend>
+						<legend><?php echo $lang_admin_bans['Ban search subhead'] ?></legend>
 						<div class="infldset">
-							<table cellspacing="0">
-<?php if ($cur_ban['username'] != ''): ?>								<tr>
-									<th>Username</th>
-									<td><?php echo pun_htmlspecialchars($cur_ban['username']) ?></td>
+							<p><?php echo $lang_admin_bans['Ban search info'] ?></p>
+							<table class="aligntop" cellspacing="0">
+								<tr>
+									<th scope="row"><?php echo $lang_admin_bans['Username label'] ?></th>
+									<td><input type="text" name="form[username]" size="25" maxlength="25" tabindex="4" /></td>
 								</tr>
-<?php endif; ?><?php if ($cur_ban['email'] != ''): ?>								<tr>
-									<th>E-mail</th>
-									<td><?php echo $cur_ban['email'] ?></td>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_bans['IP label'] ?></th>
+									<td><input type="text" name="form[ip]" size="30" maxlength="255" tabindex="5" /></td>
 								</tr>
-<?php endif; ?><?php if ($cur_ban['ip'] != ''): ?>								<tr>
-									<th>IP/IP-ranges</th>
-									<td><?php echo $cur_ban['ip'] ?></td>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_bans['E-mail label'] ?></th>
+									<td><input type="text" name="form[email]" size="30" maxlength="80" tabindex="6" /></td>
 								</tr>
-<?php endif; ?><?php if ($cur_ban['message'] != ''): ?>								<tr>
-									<th>Reason</th>
-									<td><?php echo pun_htmlspecialchars($cur_ban['message']) ?></td>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_bans['Message label'] ?></th>
+									<td><input type="text" name="form[message]" size="30" maxlength="255" tabindex="7" /></td>
+								</tr>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_bans['Expire after label'] ?></th>
+									<td><input type="text" name="expire_after" size="10" maxlength="10" tabindex="8" />
+									<span><?php echo $lang_admin_bans['Date help'] ?></span></td>
+								</tr>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_bans['Expire before label'] ?></th>
+									<td><input type="text" name="expire_before" size="10" maxlength="10" tabindex="9" />
+									<span><?php echo $lang_admin_bans['Date help'] ?></span></td>
 								</tr>
-<?php endif; ?><?php if (!empty($cur_ban['ban_creator_username'])): ?>								<tr>
-									<th>Banned by</th>
-									<td><a href="profile.php?id=<?php echo $cur_ban['ban_creator'] ?>"><?php echo pun_htmlspecialchars($cur_ban['ban_creator_username']) ?></a></td>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_bans['Order by label'] ?></th>
+									<td>
+										<select name="order_by" tabindex="10">
+											<option value="username" selected="selected"><?php echo $lang_admin_bans['Order by username'] ?></option>
+											<option value="ip"><?php echo $lang_admin_bans['Order by ip'] ?></option>
+											<option value="email"><?php echo $lang_admin_bans['Order by e-mail'] ?></option>
+											<option value="expire"><?php echo $lang_admin_bans['Order by expire'] ?></option>
+										</select>&nbsp;&nbsp;&nbsp;<select name="direction" tabindex="11">
+											<option value="ASC" selected="selected"><?php echo $lang_admin_bans['Ascending'] ?></option>
+											<option value="DESC"><?php echo $lang_admin_bans['Descending'] ?></option>
+										</select>
+									</td>
 								</tr>
-<?php endif; ?>							</table>
-							<p class="linkactions"><a href="admin_bans.php?edit_ban=<?php echo $cur_ban['id'] ?>">Edit</a> - <a href="admin_bans.php?del_ban=<?php echo $cur_ban['id'] ?>">Remove</a></p>
+							</table>
 						</div>
 					</fieldset>
 				</div>
-<?php
-
-	}
-}
-else
-	echo "\t\t\t\t".'<p>No bans in list.</p>'."\n";
-
-?>
-			</div>
+				<p class="submitend"><input type="submit" name="find_ban" value="<?php echo $lang_admin_bans['Submit search'] ?>" tabindex="12" /></p>
+			</form>
 		</div>
 	</div>
 	<div class="clearer"></div>
diff --git a/upload/admin_categories.php b/upload/admin_categories.php
index 8325620..7d4129e 100644
--- a/upload/admin_categories.php
+++ b/upload/admin_categories.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,22 +17,23 @@ require PUN_ROOT.'include/common_admin.php';
 if ($pun_user['g_id'] != PUN_ADMIN)
 	message($lang_common['No permission']);
 
+// Load the admin_categories.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_categories.php';
 
 // Add a new category
 if (isset($_POST['add_cat']))
 {
 	confirm_referrer('admin_categories.php');
 
-	$new_cat_name = trim($_POST['new_cat_name']);
+	$new_cat_name = pun_trim($_POST['new_cat_name']);
 	if ($new_cat_name == '')
-		message('You must enter a name for the category.');
+		message($lang_admin_categories['Must enter name message']);
 
 	$db->query('INSERT INTO '.$db->prefix.'categories (cat_name) VALUES(\''.$db->escape($new_cat_name).'\')') or error('Unable to create category', __FILE__, __LINE__, $db->error());
 
-	redirect('admin_categories.php', 'Category added. Redirecting &hellip;');
+	redirect('admin_categories.php', $lang_admin_categories['Category added redirect']);
 }
 
-
 // Delete a category
 else if (isset($_POST['del_cat']) || isset($_POST['del_cat_comply']))
 {
@@ -59,7 +43,7 @@ else if (isset($_POST['del_cat']) || isset($_POST['del_cat_comply']))
 	if ($cat_to_delete < 1)
 		message($lang_common['Bad request']);
 
-	if (isset($_POST['del_cat_comply']))	// Delete a category with all forums and posts
+	if (isset($_POST['del_cat_comply'])) // Delete a category with all forums and posts
 	{
 		@set_time_limit(0);
 
@@ -92,40 +76,41 @@ else if (isset($_POST['del_cat']) || isset($_POST['del_cat_comply']))
 		// Delete the category
 		$db->query('DELETE FROM '.$db->prefix.'categories WHERE id='.$cat_to_delete) or error('Unable to delete category', __FILE__, __LINE__, $db->error());
 
-		// Regenerate the quickjump cache
+		// Regenerate the quick jump cache
 		if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 			require PUN_ROOT.'include/cache.php';
 
 		generate_quickjump_cache();
 
-		redirect('admin_categories.php', 'Category deleted. Redirecting &hellip;');
+		redirect('admin_categories.php', $lang_admin_categories['Category deleted redirect']);
 	}
-	else	// If the user hasn't comfirmed the delete
+	else // If the user hasn't comfirmed the delete
 	{
 		$result = $db->query('SELECT cat_name FROM '.$db->prefix.'categories WHERE id='.$cat_to_delete) or error('Unable to fetch category info', __FILE__, __LINE__, $db->error());
 		$cat_name = $db->result($result);
 
-		$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Categories';
+		$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Categories']);
+		define('PUN_ACTIVE_PAGE', 'admin');
 		require PUN_ROOT.'header.php';
 
 		generate_admin_menu('categories');
 
 ?>
 	<div class="blockform">
-		<h2><span>Category delete</span></h2>
+		<h2><span><?php echo $lang_admin_categories['Delete category head'] ?></span></h2>
 		<div class="box">
 			<form method="post" action="admin_categories.php">
 				<div class="inform">
 				<input type="hidden" name="cat_to_delete" value="<?php echo $cat_to_delete ?>" />
 					<fieldset>
-						<legend>Confirm delete category</legend>
+						<legend><?php echo $lang_admin_categories['Confirm delete subhead'] ?></legend>
 						<div class="infldset">
-							<p>Are you sure that you want to delete the category "<?php echo pun_htmlspecialchars($cat_name) ?>"?</p>
-							<p>WARNING! Deleting a category will delete all forums and posts (if any) in that category!</p>
+							<p><?php printf($lang_admin_categories['Confirm delete info'], pun_htmlspecialchars($cat_name)) ?></p>
+							<p class="warntext"><?php echo $lang_admin_categories['Delete category warn'] ?></p>
 						</div>
 					</fieldset>
 				</div>
-				<p><input type="submit" name="del_cat_comply" value="Delete" /><a href="javascript:history.go(-1)">Go back</a></p>
+				<p class="buttons"><input type="submit" name="del_cat_comply" value="<?php echo $lang_admin_common['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
 			</form>
 		</div>
 	</div>
@@ -137,13 +122,12 @@ else if (isset($_POST['del_cat']) || isset($_POST['del_cat_comply']))
 	}
 }
 
-
-else if (isset($_POST['update']))	// Change position and name of the categories
+else if (isset($_POST['update'])) // Change position and name of the categories
 {
 	confirm_referrer('admin_categories.php');
 
-	$cat_order = $_POST['cat_order'];
-	$cat_name = $_POST['cat_name'];
+	$cat_order = array_map('trim', $_POST['cat_order']);
+	$cat_name = array_map('pun_trim', $_POST['cat_name']);
 
 	$result = $db->query('SELECT id, disp_position FROM '.$db->prefix.'categories ORDER BY disp_position') or error('Unable to fetch category list', __FILE__, __LINE__, $db->error());
 	$num_cats = $db->num_rows($result);
@@ -151,26 +135,25 @@ else if (isset($_POST['update']))	// Change position and name of the categories
 	for ($i = 0; $i < $num_cats; ++$i)
 	{
 		if ($cat_name[$i] == '')
-			message('You must enter a category name.');
+			message($lang_admin_categories['Must enter name message']);
 
-		if (!@preg_match('#^\d+$#', $cat_order[$i]))
-			message('Position must be an integer value.');
+		if ($cat_order[$i] == '' || preg_match('/[^0-9]/', $cat_order[$i]))
+			message($lang_admin_categories['Must enter integer message']);
 
 		list($cat_id, $position) = $db->fetch_row($result);
 
 		$db->query('UPDATE '.$db->prefix.'categories SET cat_name=\''.$db->escape($cat_name[$i]).'\', disp_position='.$cat_order[$i].' WHERE id='.$cat_id) or error('Unable to update category', __FILE__, __LINE__, $db->error());
 	}
 
-	// Regenerate the quickjump cache
+	// Regenerate the quick jump cache
 	if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 		require PUN_ROOT.'include/cache.php';
 
 	generate_quickjump_cache();
 
-	redirect('admin_categories.php', 'Categories updated. Redirecting &hellip;');
+	redirect('admin_categories.php', $lang_admin_categories['Categories updated redirect']);
 }
 
-
 // Generate an array with all categories
 $result = $db->query('SELECT id, cat_name, disp_position FROM '.$db->prefix.'categories ORDER BY disp_position') or error('Unable to fetch category list', __FILE__, __LINE__, $db->error());
 $num_cats = $db->num_rows($result);
@@ -178,83 +161,105 @@ $num_cats = $db->num_rows($result);
 for ($i = 0; $i < $num_cats; ++$i)
 	$cat_list[] = $db->fetch_row($result);
 
-
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Categories';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Categories']);
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('categories');
 
 ?>
 	<div class="blockform">
-		<h2><span>Add/remove/edit categories</span></h2>
+		<h2><span><?php echo $lang_admin_categories['Add categories head'] ?></span></h2>
+		<div class="box">
+			<form method="post" action="admin_categories.php?action=foo">
+				<div class="inform">
+					<fieldset>
+						<legend><?php echo $lang_admin_categories['Add categories subhead'] ?></legend>
+						<div class="infldset">
+							<table class="aligntop" cellspacing="0">
+								<tr>
+									<th scope="row"><?php echo $lang_admin_categories['Add category label'] ?><div><input type="submit" name="add_cat" value="<?php echo $lang_admin_categories['Add new submit'] ?>" tabindex="2" /></div></th>
+									<td>
+										<input type="text" name="new_cat_name" size="35" maxlength="80" tabindex="1" />
+										<span><?php printf($lang_admin_categories['Add category help'], '<a href="admin_forums.php">'.$lang_admin_common['Forums'].'</a>') ?></span>
+									</td>
+								</tr>
+							</table>
+						</div>
+					</fieldset>
+				</div>
+			</form>
+		</div>
+
+<?php if ($num_cats): ?>		<h2 class="block2"><span><?php echo $lang_admin_categories['Delete categories head'] ?></span></h2>
 		<div class="box">
-		<form method="post" action="admin_categories.php?action=foo">
-			<div class="inform">
-				<fieldset>
-					<legend>Add/delete categories</legend>
-					<div class="infldset">
-						<table class="aligntop" cellspacing="0">
-							<tr>
-								<th scope="row">Add a new category<div><input type="submit" name="add_cat" value="Add New" tabindex="2" /></div></th>
-								<td>
-									<input type="text" name="new_cat_name" size="35" maxlength="80" tabindex="1" />
-									<span>The name of the new category you want to add. You can edit the name of the category later (see below). Go to <a href="admin_forums.php">Forums</a> to add forums to your new category.</span>
-								</td>
-							</tr>
-<?php if ($num_cats): ?>							<tr>
-								<th scope="row">Delete a category<div><input type="submit" name="del_cat" value="Delete" tabindex="4" /></div></th>
-								<td>
-									<select name="cat_to_delete" tabindex="3">
+			<form method="post" action="admin_categories.php?action=foo">
+				<div class="inform">
+					<fieldset>
+						<legend><?php echo $lang_admin_categories['Delete categories subhead'] ?></legend>
+						<div class="infldset">
+							<table class="aligntop" cellspacing="0">
+								<tr>
+									<th scope="row"><?php echo $lang_admin_categories['Delete category label'] ?><div><input type="submit" name="del_cat" value="<?php echo $lang_admin_common['Delete'] ?>" tabindex="4" /></div></th>
+									<td>
+										<select name="cat_to_delete" tabindex="3">
 <?php
 
-	while (list(, list($cat_id, $cat_name, ,)) = @each($cat_list))
-		echo "\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cat_id.'">'.pun_htmlspecialchars($cat_name).'</option>'."\n";
+	foreach ($cat_list as $category)
+		echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$category[0].'">'.pun_htmlspecialchars($category[1]).'</option>'."\n";
 
 ?>
-									</select>
-									<span>Select the name of the category you want to delete. You will be asked to confirm your choice of category for deletion before it is deleted.</span>
-								</td>
-							</tr>
-<?php endif; ?>						</table>
-					</div>
-				</fieldset>
-			</div>
-<?php if ($num_cats): ?>			<div class="inform">
-				<fieldset>
-					<legend>Edit categories</legend>
-					<div class="infldset">
-						<table id="categoryedit" cellspacing="0" >
-						<thead>
-							<tr>
-								<th class="tcl" scope="col">Name</th>
-								<th scope="col">Position</th>
-								<th>&nbsp;</th>
-							</tr>
-						</thead>
-						<tbody>
+										</select>
+										<span><?php echo $lang_admin_categories['Delete category help'] ?></span>
+									</td>
+								</tr>
+							</table>
+						</div>
+					</fieldset>
+				</div>
+			</form>
+		</div>
+<?php endif; ?>
+
+<?php if ($num_cats): ?>		<h2 class="block2"><span><?php echo $lang_admin_categories['Edit categories head'] ?></span></h2>
+		<div class="box">
+			<form method="post" action="admin_categories.php?action=foo">
+				<div class="inform">
+					<fieldset>
+						<legend><?php echo $lang_admin_categories['Edit categories subhead'] ?></legend>
+						<div class="infldset">
+							<table id="categoryedit" cellspacing="0" >
+							<thead>
+								<tr>
+									<th class="tcl" scope="col"><?php echo $lang_admin_categories['Category name label'] ?></th>
+									<th scope="col"><?php echo $lang_admin_categories['Category position label'] ?></th>
+								</tr>
+							</thead>
+							<tbody>
 <?php
 
-	@reset($cat_list);
-	for ($i = 0; $i < $num_cats; ++$i)
+	foreach ($cat_list as $i => $category)
 	{
-		list(, list($cat_id, $cat_name, $position)) = @each($cat_list);
 
 ?>
-							<tr><td><input type="text" name="cat_name[<?php echo $i ?>]" value="<?php echo pun_htmlspecialchars($cat_name) ?>" size="35" maxlength="80" /></td><td><input type="text" name="cat_order[<?php echo $i ?>]" value="<?php echo $position ?>" size="3" maxlength="3" /></td><td>&nbsp;</td></tr>
+								<tr>
+									<td class="tcl"><input type="text" name="cat_name[<?php echo $i ?>]" value="<?php echo pun_htmlspecialchars($category[1]) ?>" size="35" maxlength="80" /></td>
+									<td><input type="text" name="cat_order[<?php echo $i ?>]" value="<?php echo $category[2] ?>" size="3" maxlength="3" /></td>
+								</tr>
 <?php
 
 	}
 
 ?>
-						</tbody>
-						</table>
-						<div class="fsetsubmit"><input type="submit" name="update" value="Update" /></div>
-					</div>
-				</fieldset>
-			</div>
-<?php endif; ?>		</form>
+							</tbody>
+							</table>
+							<div class="fsetsubmit"><input type="submit" name="update" value="<?php echo $lang_admin_common['Update'] ?>" /></div>
+						</div>
+					</fieldset>
+				</div>
+			</form>
 		</div>
-	</div>
+<?php endif; ?>	</div>
 	<div class="clearer"></div>
 </div>
 <?php
diff --git a/upload/admin_censoring.php b/upload/admin_censoring.php
index 945ad5d..de105b9 100644
--- a/upload/admin_censoring.php
+++ b/upload/admin_censoring.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,24 +17,25 @@ require PUN_ROOT.'include/common_admin.php';
 if (!$pun_user['is_admmod'])
 	message($lang_common['No permission']);
 
+// Load the admin_censoring.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_censoring.php';
 
 // Add a censor word
 if (isset($_POST['add_word']))
 {
 	confirm_referrer('admin_censoring.php');
 
-	$search_for = trim($_POST['new_search_for']);
-	$replace_with = trim($_POST['new_replace_with']);
+	$search_for = pun_trim($_POST['new_search_for']);
+	$replace_with = pun_trim($_POST['new_replace_with']);
 
 	if ($search_for == '' || $replace_with == '')
-		message('You must enter both a word to censor and text to replace it with.');
+		message($lang_admin_censoring['Must enter both message']);
 
 	$db->query('INSERT INTO '.$db->prefix.'censoring (search_for, replace_with) VALUES (\''.$db->escape($search_for).'\', \''.$db->escape($replace_with).'\')') or error('Unable to add censor word', __FILE__, __LINE__, $db->error());
 
-	redirect('admin_censoring.php', 'Censor word added. Redirecting &hellip;');
+	redirect('admin_censoring.php', $lang_admin_censoring['Word added redirect']);
 }
 
-
 // Update a censor word
 else if (isset($_POST['update']))
 {
@@ -59,18 +43,17 @@ else if (isset($_POST['update']))
 
 	$id = intval(key($_POST['update']));
 
-	$search_for = trim($_POST['search_for'][$id]);
-	$replace_with = trim($_POST['replace_with'][$id]);
+	$search_for = pun_trim($_POST['search_for'][$id]);
+	$replace_with = pun_trim($_POST['replace_with'][$id]);
 
 	if ($search_for == '' || $replace_with == '')
-		message('You must enter both text to search for and text to replace with.');
+		message($lang_admin_censoring['Must search both message']);
 
 	$db->query('UPDATE '.$db->prefix.'censoring SET search_for=\''.$db->escape($search_for).'\', replace_with=\''.$db->escape($replace_with).'\' WHERE id='.$id) or error('Unable to update censor word', __FILE__, __LINE__, $db->error());
 
-	redirect('admin_censoring.php', 'Censor word updated. Redirecting &hellip;');
+	redirect('admin_censoring.php', $lang_admin_censoring['Word updated redirect']);
 }
 
-
 // Remove a censor word
 else if (isset($_POST['remove']))
 {
@@ -80,39 +63,39 @@ else if (isset($_POST['remove']))
 
 	$db->query('DELETE FROM '.$db->prefix.'censoring WHERE id='.$id) or error('Unable to delete censor word', __FILE__, __LINE__, $db->error());
 
-	redirect('admin_censoring.php', 'Censor word removed. Redirecting &hellip;');
+	redirect('admin_censoring.php',  $lang_admin_censoring['Word removed redirect']);
 }
 
-
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Censoring';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Censoring']);
 $focus_element = array('censoring', 'new_search_for');
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('censoring');
 
 ?>
 	<div class="blockform">
-		<h2><span>Censoring</span></h2>
+		<h2><span><?php echo $lang_admin_censoring['Censoring head'] ?></span></h2>
 		<div class="box">
 			<form id="censoring" method="post" action="admin_censoring.php?action=foo">
 				<div class="inform">
 					<fieldset>
-						<legend>Add word</legend>
+						<legend><?php echo $lang_admin_censoring['Add word subhead'] ?></legend>
 						<div class="infldset">
-							<p>Enter a word that you want to censor and the replacement text for this word. Wildcards are accepted (i.e. *some* would match somewhere and lonesome). Censor words also affect usernames. New users will not be able to register with usernames containing any censored words. The search is case insensitive. <strong>Censor words must be enabled in <a href="admin_options.php#censoring">Options</a> for this to have any effect.</strong></p>
-							<table  cellspacing="0">
+							<p><?php printf($lang_admin_censoring['Add word info'], '<a href="admin_options.php#censoring">'.$lang_admin_common['Options'].'</a>') ?></p>
+							<table cellspacing="0">
 							<thead>
 								<tr>
-									<th class="tcl" scope="col">Censored&nbsp;word</th>
-									<th class="tc2" scope="col">Replacement&nbsp;text</th>
-									<th class="hidehead" scope="col">Action</th>
+									<th class="tcl" scope="col"><?php echo $lang_admin_censoring['Censored word label'] ?></th>
+									<th class="tc2" scope="col"><?php echo $lang_admin_censoring['Replacement label'] ?></th>
+									<th class="hidehead" scope="col"><?php echo $lang_admin_censoring['Action label'] ?></th>
 								</tr>
 							</thead>
 							<tbody>
 								<tr>
-									<td><input type="text" name="new_search_for" size="24" maxlength="60" tabindex="1" /></td>
-									<td><input type="text" name="new_replace_with" size="24" maxlength="60" tabindex="2" /></td>
-									<td><input type="submit" name="add_word" value=" Add " tabindex="3" /></td>
+									<td class="tcl"><input type="text" name="new_search_for" size="24" maxlength="60" tabindex="1" /></td>
+									<td class="tc2"><input type="text" name="new_replace_with" size="24" maxlength="60" tabindex="2" /></td>
+									<td><input type="submit" name="add_word" value="<?php echo $lang_admin_common['Add'] ?>" tabindex="3" /></td>
 								</tr>
 							</tbody>
 							</table>
@@ -121,7 +104,7 @@ generate_admin_menu('censoring');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Edit/remove words</legend>
+						<legend><?php echo $lang_admin_censoring['Edit remove subhead'] ?></legend>
 						<div class="infldset">
 <?php
 
@@ -133,16 +116,16 @@ if ($db->num_rows($result))
 							<table cellspacing="0" >
 							<thead>
 								<tr>
-									<th class="tcl" scope="col">Censored&nbsp;word</th>
-									<th class="tc2" scope="col">Replacement&nbsp;text</th>
-									<th class="hidehead" scope="col">Actions</th>
+									<th class="tcl" scope="col"><?php echo $lang_admin_censoring['Censored word label'] ?></th>
+									<th class="tc2" scope="col"><?php echo $lang_admin_censoring['Replacement label'] ?></th>
+									<th class="hidehead" scope="col"><?php echo $lang_admin_censoring['Action label'] ?></th>
 								</tr>
 							</thead>
 							<tbody>
 <?php
 
 	while ($cur_word = $db->fetch_assoc($result))
-		echo "\t\t\t\t\t\t\t\t".'<tr><td><input type="text" name="search_for['.$cur_word['id'].']" value="'.pun_htmlspecialchars($cur_word['search_for']).'" size="24" maxlength="60" /></td><td><input type="text" name="replace_with['.$cur_word['id'].']" value="'.pun_htmlspecialchars($cur_word['replace_with']).'" size="24" maxlength="60" /></td><td><input type="submit" name="update['.$cur_word['id'].']" value="Update" />&nbsp;<input type="submit" name="remove['.$cur_word['id'].']" value="Remove" /></td></tr>'."\n";
+		echo "\t\t\t\t\t\t\t\t".'<tr><td class="tcl"><input type="text" name="search_for['.$cur_word['id'].']" value="'.pun_htmlspecialchars($cur_word['search_for']).'" size="24" maxlength="60" /></td><td class="tc2"><input type="text" name="replace_with['.$cur_word['id'].']" value="'.pun_htmlspecialchars($cur_word['replace_with']).'" size="24" maxlength="60" /></td><td><input type="submit" name="update['.$cur_word['id'].']" value="'.$lang_admin_common['Update'].'" />&nbsp;<input type="submit" name="remove['.$cur_word['id'].']" value="'.$lang_admin_common['Remove'].'" /></td></tr>'."\n";
 
 ?>
 							</tbody>
@@ -151,7 +134,7 @@ if ($db->num_rows($result))
 
 }
 else
-	echo "\t\t\t\t\t\t\t".'<p>No censor words in list.</p>'."\n";
+	echo "\t\t\t\t\t\t\t".'<p>'.$lang_admin_censoring['No words in list'].'</p>'."\n";
 
 ?>
 						</div>
diff --git a/upload/admin_forums.php b/upload/admin_forums.php
index 158c945..6fa9a51 100644
--- a/upload/admin_forums.php
+++ b/upload/admin_forums.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,6 +17,8 @@ require PUN_ROOT.'include/common_admin.php';
 if ($pun_user['g_id'] != PUN_ADMIN)
 	message($lang_common['No permission']);
 
+// Load the admin_forums.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_forums.php';
 
 // Add a "default" forum
 if (isset($_POST['add_forum']))
@@ -46,16 +31,15 @@ if (isset($_POST['add_forum']))
 
 	$db->query('INSERT INTO '.$db->prefix.'forums (cat_id) VALUES('.$add_to_cat.')') or error('Unable to create forum', __FILE__, __LINE__, $db->error());
 
-	// Regenerate the quickjump cache
+	// Regenerate the quick jump cache
 	if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 		require PUN_ROOT.'include/cache.php';
 
 	generate_quickjump_cache();
 
-	redirect('admin_forums.php', 'Forum added. Redirecting &hellip;');
+	redirect('admin_forums.php', $lang_admin_forums['Forum added redirect']);
 }
 
-
 // Delete a forum
 else if (isset($_GET['del_forum']))
 {
@@ -65,7 +49,7 @@ else if (isset($_GET['del_forum']))
 	if ($forum_id < 1)
 		message($lang_common['Bad request']);
 
-	if (isset($_POST['del_forum_comply']))	// Delete a forum with all posts
+	if (isset($_POST['del_forum_comply'])) // Delete a forum with all posts
 	{
 		@set_time_limit(0);
 
@@ -88,40 +72,40 @@ else if (isset($_GET['del_forum']))
 		$db->query('DELETE FROM '.$db->prefix.'forums WHERE id='.$forum_id) or error('Unable to delete forum', __FILE__, __LINE__, $db->error());
 		$db->query('DELETE FROM '.$db->prefix.'forum_perms WHERE forum_id='.$forum_id) or error('Unable to delete group forum permissions', __FILE__, __LINE__, $db->error());
 
-		// Regenerate the quickjump cache
+		// Regenerate the quick jump cache
 		if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 			require PUN_ROOT.'include/cache.php';
 
 		generate_quickjump_cache();
 
-		redirect('admin_forums.php', 'Forum deleted. Redirecting &hellip;');
+		redirect('admin_forums.php', $lang_admin_forums['Forum deleted redirect']);
 	}
-	else	// If the user hasn't confirmed the delete
+	else // If the user hasn't confirmed the delete
 	{
 		$result = $db->query('SELECT forum_name FROM '.$db->prefix.'forums WHERE id='.$forum_id) or error('Unable to fetch forum info', __FILE__, __LINE__, $db->error());
 		$forum_name = pun_htmlspecialchars($db->result($result));
 
-
-		$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Forums';
+		$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Forums']);
+		define('PUN_ACTIVE_PAGE', 'admin');
 		require PUN_ROOT.'header.php';
 
 		generate_admin_menu('forums');
 
 ?>
 	<div class="blockform">
-		<h2><span>Confirm delete forum</span></h2>
+		<h2><span><?php echo $lang_admin_forums['Confirm delete head'] ?></span></h2>
 		<div class="box">
 			<form method="post" action="admin_forums.php?del_forum=<?php echo $forum_id ?>">
 				<div class="inform">
 					<fieldset>
-						<legend>Important! Read before deleting</legend>
+						<legend><?php echo $lang_admin_forums['Confirm delete subhead'] ?></legend>
 						<div class="infldset">
-							<p>Are you sure that you want to delete the forum "<?php echo $forum_name ?>"?</p>
-							<p>WARNING! Deleting a forum will delete all posts (if any) in that forum!</p>
+							<p><?php printf($lang_admin_forums['Confirm delete info'], $forum_name) ?></p>
+							<p class="warntext"><?php echo $lang_admin_forums['Confirm delete warn'] ?></p>
 						</div>
 					</fieldset>
 				</div>
-				<p><input type="submit" name="del_forum_comply" value="Delete" /><a href="javascript:history.go(-1)">Go back</a></p>
+				<p class="buttons"><input type="submit" name="del_forum_comply" value="<?php echo $lang_admin_common['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
 			</form>
 		</div>
 	</div>
@@ -133,30 +117,29 @@ else if (isset($_GET['del_forum']))
 	}
 }
 
-
 // Update forum positions
 else if (isset($_POST['update_positions']))
 {
 	confirm_referrer('admin_forums.php');
 
-	while (list($forum_id, $disp_position) = @each($_POST['position']))
+	foreach ($_POST['position'] as $forum_id => $disp_position)
 	{
-		if (!@preg_match('#^\d+$#', $disp_position))
-			message('Position must be a positive integer value.');
+		$disp_position = trim($disp_position);
+		if ($disp_position == '' || preg_match('/[^0-9]/', $disp_position))
+			message($lang_admin_forums['Must be integer message']);
 
 		$db->query('UPDATE '.$db->prefix.'forums SET disp_position='.$disp_position.' WHERE id='.intval($forum_id)) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
 	}
 
-	// Regenerate the quickjump cache
+	// Regenerate the quick jump cache
 	if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 		require PUN_ROOT.'include/cache.php';
 
 	generate_quickjump_cache();
 
-	redirect('admin_forums.php', 'Forums updated. Redirecting &hellip;');
+	redirect('admin_forums.php', $lang_admin_forums['Forums updated redirect']);
 }
 
-
 else if (isset($_GET['edit_forum']))
 {
 	$forum_id = intval($_GET['edit_forum']);
@@ -169,14 +152,14 @@ else if (isset($_GET['edit_forum']))
 		confirm_referrer('admin_forums.php');
 
 		// Start with the forum details
-		$forum_name = trim($_POST['forum_name']);
-		$forum_desc = pun_linebreaks(trim($_POST['forum_desc']));
+		$forum_name = pun_trim($_POST['forum_name']);
+		$forum_desc = pun_linebreaks(pun_trim($_POST['forum_desc']));
 		$cat_id = intval($_POST['cat_id']);
 		$sort_by = intval($_POST['sort_by']);
 		$redirect_url = isset($_POST['redirect_url']) ? trim($_POST['redirect_url']) : null;
 
 		if ($forum_name == '')
-			message('You must enter a forum name.');
+			message($lang_admin_forums['Must enter name message']);
 
 		if ($cat_id < 1)
 			message($lang_common['Bad request']);
@@ -213,13 +196,13 @@ else if (isset($_GET['edit_forum']))
 			}
 		}
 
-		// Regenerate the quickjump cache
+		// Regenerate the quick jump cache
 		if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 			require PUN_ROOT.'include/cache.php';
 
 		generate_quickjump_cache();
 
-		redirect('admin_forums.php', 'Forum updated. Redirecting &hellip;');
+		redirect('admin_forums.php', $lang_admin_forums['Forum updated redirect']);
 	}
 	else if (isset($_POST['revert_perms']))
 	{
@@ -227,16 +210,15 @@ else if (isset($_GET['edit_forum']))
 
 		$db->query('DELETE FROM '.$db->prefix.'forum_perms WHERE forum_id='.$forum_id) or error('Unable to delete group forum permissions', __FILE__, __LINE__, $db->error());
 
-		// Regenerate the quickjump cache
+		// Regenerate the quick jump cache
 		if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 			require PUN_ROOT.'include/cache.php';
 
 		generate_quickjump_cache();
 
-		redirect('admin_forums.php?edit_forum='.$forum_id, 'Permissions reverted to defaults. Redirecting &hellip;');
+		redirect('admin_forums.php?edit_forum='.$forum_id, $lang_admin_forums['Perms reverted redirect']);
 	}
 
-
 	// Fetch forum info
 	$result = $db->query('SELECT id, forum_name, forum_desc, redirect_url, num_topics, sort_by, cat_id FROM '.$db->prefix.'forums WHERE id='.$forum_id) or error('Unable to fetch forum info', __FILE__, __LINE__, $db->error());
 	if (!$db->num_rows($result))
@@ -244,33 +226,33 @@ else if (isset($_GET['edit_forum']))
 
 	$cur_forum = $db->fetch_assoc($result);
 
-
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Forums';
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Forums']);
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 	generate_admin_menu('forums');
 
 ?>
 	<div class="blockform">
-		<h2><span>Edit forum</span></h2>
+		<h2><span><?php echo $lang_admin_forums['Edit forum head'] ?></span></h2>
 		<div class="box">
 			<form id="edit_forum" method="post" action="admin_forums.php?edit_forum=<?php echo $forum_id ?>">
-				<p class="submittop"><input type="submit" name="save" value="Save changes" tabindex="6" /></p>
+				<p class="submittop"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" tabindex="6" /></p>
 				<div class="inform">
 					<fieldset>
-						<legend>Edit forum details</legend>
+						<legend><?php echo $lang_admin_forums['Edit details subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Forum name</th>
+									<th scope="row"><?php echo $lang_admin_forums['Forum name label'] ?></th>
 									<td><input type="text" name="forum_name" size="35" maxlength="80" value="<?php echo pun_htmlspecialchars($cur_forum['forum_name']) ?>" tabindex="1" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Description (HTML)</th>
+									<th scope="row"><?php echo $lang_admin_forums['Forum description label'] ?></th>
 									<td><textarea name="forum_desc" rows="3" cols="50" tabindex="2"><?php echo pun_htmlspecialchars($cur_forum['forum_desc']) ?></textarea></td>
 								</tr>
 								<tr>
-									<th scope="row">Category</th>
+									<th scope="row"><?php echo $lang_admin_forums['Category label'] ?></th>
 									<td>
 										<select name="cat_id" tabindex="3">
 <?php
@@ -287,17 +269,17 @@ else if (isset($_GET['edit_forum']))
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Sort topics by</th>
+									<th scope="row"><?php echo $lang_admin_forums['Sort by label'] ?></th>
 									<td>
 										<select name="sort_by" tabindex="4">
-											<option value="0"<?php if ($cur_forum['sort_by'] == '0') echo ' selected="selected"' ?>>Last post</option>
-											<option value="1"<?php if ($cur_forum['sort_by'] == '1') echo ' selected="selected"' ?>>Topic start</option>
+											<option value="0"<?php if ($cur_forum['sort_by'] == '0') echo ' selected="selected"' ?>><?php echo $lang_admin_forums['Last post'] ?></option>
+											<option value="1"<?php if ($cur_forum['sort_by'] == '1') echo ' selected="selected"' ?>><?php echo $lang_admin_forums['Topic start'] ?></option>
 										</select>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Redirect URL</th>
-									<td><?php echo ($cur_forum['num_topics']) ? 'Only available in empty forums' : '<input type="text" name="redirect_url" size="45" maxlength="100" value="'.pun_htmlspecialchars($cur_forum['redirect_url']).'" tabindex="5" />'; ?></td>
+									<th scope="row"><?php echo $lang_admin_forums['Redirect label'] ?></th>
+									<td><?php echo ($cur_forum['num_topics']) ? $lang_admin_forums['Redirect help'] : '<input type="text" name="redirect_url" size="45" maxlength="100" value="'.pun_htmlspecialchars($cur_forum['redirect_url']).'" tabindex="5" />'; ?></td>
 								</tr>
 							</table>
 						</div>
@@ -305,16 +287,16 @@ else if (isset($_GET['edit_forum']))
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Edit group permissions for this forum</legend>
+						<legend><?php echo $lang_admin_forums['Group permissions subhead'] ?></legend>
 						<div class="infldset">
-							<p>In this form, you can set the forum specific permissions for the different user groups. If you haven't made any changes to this forums group permissions, what you see below is the default based on settings in <a href="admin_groups.php">User groups</a>. Administrators always have full permissions and are thus excluded. Permission settings that differ from the default permissions for the user group are marked red. The "Read forum" permission checkbox will be disabled if the group in question lacks the "Read board" permission. For redirect forums, only the "Read forum" permission is editable.</p>
+							<p><?php printf($lang_admin_forums['Group permissions info'], '<a href="admin_groups.php">'.$lang_admin_common['User groups'].'</a>') ?></p>
 							<table id="forumperms" cellspacing="0">
 							<thead>
 								<tr>
 									<th class="atcl">&nbsp;</th>
-									<th>Read forum</th>
-									<th>Post replies</th>
-									<th>Post topics</th>
+									<th><?php echo $lang_admin_forums['Read forum label'] ?></th>
+									<th><?php echo $lang_admin_forums['Post replies label'] ?></th>
+									<th><?php echo $lang_admin_forums['Post topics label'] ?></th>
 								</tr>
 							</thead>
 							<tbody>
@@ -328,7 +310,7 @@ else if (isset($_GET['edit_forum']))
 		$post_replies = (($cur_perm['g_post_replies'] == '0' && $cur_perm['post_replies'] == '1') || ($cur_perm['g_post_replies'] == '1' && $cur_perm['post_replies'] != '0')) ? true : false;
 		$post_topics = (($cur_perm['g_post_topics'] == '0' && $cur_perm['post_topics'] == '1') || ($cur_perm['g_post_topics'] == '1' && $cur_perm['post_topics'] != '0')) ? true : false;
 
-		// Determine if the current sittings differ from the default or not
+		// Determine if the current settings differ from the default or not
 		$read_forum_def = ($cur_perm['read_forum'] == '0') ? false : true;
 		$post_replies_def = (($post_replies && $cur_perm['g_post_replies'] == '0') || (!$post_replies && ($cur_perm['g_post_replies'] == '' || $cur_perm['g_post_replies'] == '1'))) ? false : true;
 		$post_topics_def = (($post_topics && $cur_perm['g_post_topics'] == '0') || (!$post_topics && ($cur_perm['g_post_topics'] == '' || $cur_perm['g_post_topics'] == '1'))) ? false : true;
@@ -356,11 +338,11 @@ else if (isset($_GET['edit_forum']))
 ?>
 							</tbody>
 							</table>
-							<div class="fsetsubmit"><input type="submit" name="revert_perms" value="Revert to default" /></div>
+							<div class="fsetsubmit"><input type="submit" name="revert_perms" value="<?php echo $lang_admin_forums['Revert to default'] ?>" /></div>
 						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="save" value="Save changes" /></p>
+				<p class="submitend"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
 			</form>
 		</div>
 	</div>
@@ -372,24 +354,24 @@ else if (isset($_GET['edit_forum']))
 	require PUN_ROOT.'footer.php';
 }
 
-
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Forums';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Forums']);
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('forums');
 
 ?>
 	<div class="blockform">
-		<h2><span>Add forum</span></h2>
+		<h2><span><?php echo $lang_admin_forums['Add forum head'] ?></span></h2>
 		<div class="box">
 			<form method="post" action="admin_forums.php?action=adddel">
 				<div class="inform">
 					<fieldset>
-						<legend>Create a new forum</legend>
+						<legend><?php echo $lang_admin_forums['Create new subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Add forum to category<div><input type="submit" name="add_forum" value=" Add " tabindex="2" /></div></th>
+									<th scope="row"><?php echo $lang_admin_forums['Add forum label'] ?><div><input type="submit" name="add_forum" value="<?php echo $lang_admin_forums['Add forum'] ?>" tabindex="2" /></div></th>
 									<td>
 										<select name="add_to_cat" tabindex="1">
 <?php
@@ -398,14 +380,14 @@ generate_admin_menu('forums');
 	if ($db->num_rows($result) > 0)
 	{
 		while ($cur_cat = $db->fetch_assoc($result))
-			echo "\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_cat['id'].'">'.pun_htmlspecialchars($cur_cat['cat_name']).'</option>'."\n";
+			echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_cat['id'].'">'.pun_htmlspecialchars($cur_cat['cat_name']).'</option>'."\n";
 	}
 	else
-		echo "\t\t\t\t\t\t\t\t\t".'<option value="0" disabled="disabled">No categories exist</option>'."\n";
+		echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="0" disabled="disabled">'.$lang_admin_forums['No categories exist'].'</option>'."\n";
 
 ?>
 										</select>
-										<span>Select the category to which you wish to add a new forum.</span>
+										<span><?php echo $lang_admin_forums['Add forum help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -423,10 +405,10 @@ if ($db->num_rows($result) > 0)
 {
 
 ?>
-		<h2 class="block2"><span>Edit forums</span></h2>
+		<h2 class="block2"><span><?php echo $lang_admin_forums['Edit forums head'] ?></span></h2>
 		<div class="box">
 			<form id="edforum" method="post" action="admin_forums.php?action=edit">
-				<p class="submittop"><input type="submit" name="update_positions" value="Update positions" tabindex="3" /></p>
+				<p class="submittop"><input type="submit" name="update_positions" value="<?php echo $lang_admin_forums['Update positions'] ?>" tabindex="3" /></p>
 <?php
 
 $tabindex_count = 4;
@@ -434,17 +416,25 @@ $tabindex_count = 4;
 $cur_category = 0;
 while ($cur_forum = $db->fetch_assoc($result))
 {
-	if ($cur_forum['cid'] != $cur_category)	// A new category since last iteration?
+	if ($cur_forum['cid'] != $cur_category) // A new category since last iteration?
 	{
 		if ($cur_category != 0)
-			echo "\t\t\t\t\t\t\t".'</table>'."\n\t\t\t\t\t\t".'</div>'."\n\t\t\t\t\t".'</fieldset>'."\n\t\t\t\t".'</div>'."\n";
+			echo "\t\t\t\t\t\t\t".'</tbody>'."\n\t\t\t\t\t\t\t".'</table>'."\n\t\t\t\t\t\t".'</div>'."\n\t\t\t\t\t".'</fieldset>'."\n\t\t\t\t".'</div>'."\n";
 
 ?>
 				<div class="inform">
 					<fieldset>
-						<legend>Category: <?php echo pun_htmlspecialchars($cur_forum['cat_name']) ?></legend>
+						<legend><?php echo $lang_admin_forums['Category subhead'] ?> <?php echo pun_htmlspecialchars($cur_forum['cat_name']) ?></legend>
 						<div class="infldset">
 							<table cellspacing="0">
+							<thead>
+								<tr>
+									<th class="tcl"><?php echo $lang_admin_common['Action'] ?></th>
+									<th class="tc2"><?php echo $lang_admin_forums['Position label'] ?></th>
+									<th class="tcr"><?php echo $lang_admin_forums['Forum label'] ?></th>
+								</tr>
+							</thead>
+							<tbody>
 <?php
 
 		$cur_category = $cur_forum['cid'];
@@ -452,9 +442,9 @@ while ($cur_forum = $db->fetch_assoc($result))
 
 ?>
 								<tr>
-									<th><a href="admin_forums.php?edit_forum=<?php echo $cur_forum['fid'] ?>">Edit</a> - <a href="admin_forums.php?del_forum=<?php echo $cur_forum['fid'] ?>">Delete</a></th>
-									<td>Position&nbsp;&nbsp;<input type="text" name="position[<?php echo $cur_forum['fid'] ?>]" size="3" maxlength="3" value="<?php echo $cur_forum['disp_position'] ?>" tabindex="<?php echo $tabindex_count ?>" />
-									&nbsp;&nbsp;<strong><?php echo pun_htmlspecialchars($cur_forum['forum_name']) ?></strong></td>
+									<td class="tcl"><a href="admin_forums.php?edit_forum=<?php echo $cur_forum['fid'] ?>"><?php echo $lang_admin_forums['Edit link'] ?></a> | <a href="admin_forums.php?del_forum=<?php echo $cur_forum['fid'] ?>"><?php echo $lang_admin_forums['Delete link'] ?></a></td>
+									<td class="tc2"><input type="text" name="position[<?php echo $cur_forum['fid'] ?>]" size="3" maxlength="3" value="<?php echo $cur_forum['disp_position'] ?>" tabindex="<?php echo $tabindex_count ?>" /></td>
+									<td class="tcr"><strong><?php echo pun_htmlspecialchars($cur_forum['forum_name']) ?></strong></td>
 								</tr>
 <?php
 
@@ -462,11 +452,12 @@ while ($cur_forum = $db->fetch_assoc($result))
 }
 
 ?>
+							</tbody>
 							</table>
 						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="update_positions" value="Update positions" tabindex="<?php echo $tabindex_count ?>" /></p>
+				<p class="submitend"><input type="submit" name="update_positions" value="<?php echo $lang_admin_forums['Update positions'] ?>" tabindex="<?php echo $tabindex_count ?>" /></p>
 			</form>
 		</div>
 <?php
diff --git a/upload/admin_groups.php b/upload/admin_groups.php
index 9108c16..940dff9 100644
--- a/upload/admin_groups.php
+++ b/upload/admin_groups.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,6 +17,8 @@ require PUN_ROOT.'include/common_admin.php';
 if ($pun_user['g_id'] != PUN_ADMIN)
 	message($lang_common['No permission']);
 
+// Load the admin_censoring.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_groups.php';
 
 // Add/edit a group (stage 1)
 if (isset($_POST['add_group']) || isset($_GET['edit_group']))
@@ -47,7 +32,7 @@ if (isset($_POST['add_group']) || isset($_GET['edit_group']))
 
 		$mode = 'add';
 	}
-	else	// We are editing a group
+	else // We are editing a group
 	{
 		$group_id = intval($_GET['edit_group']);
 		if ($group_id < 1)
@@ -63,180 +48,181 @@ if (isset($_POST['add_group']) || isset($_GET['edit_group']))
 	}
 
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / User groups';
-	$required_fields = array('req_title' => 'Group title');
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['User groups']);
+	$required_fields = array('req_title' => $lang_admin_groups['Group title label']);
 	$focus_element = array('groups2', 'req_title');
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 	generate_admin_menu('groups');
 
 ?>
 	<div class="blockform">
-		<h2><span>Group settings</span></h2>
+		<h2><span><?php echo $lang_admin_groups['Group settings head'] ?></span></h2>
 		<div class="box">
 			<form id="groups2" method="post" action="admin_groups.php" onsubmit="return process_form(this)">
-				<p class="submittop"><input type="submit" name="add_edit_group" value=" Save " /></p>
+				<p class="submittop"><input type="submit" name="add_edit_group" value="<?php echo $lang_admin_common['Save'] ?>" /></p>
 				<div class="inform">
 					<input type="hidden" name="mode" value="<?php echo $mode ?>" />
-<?php if ($mode == 'edit'): ?>				<input type="hidden" name="group_id" value="<?php echo $group_id ?>" />
-<?php endif; ?><?php if ($mode == 'add'): ?>				<input type="hidden" name="base_group" value="<?php echo $base_group ?>" />
+<?php if ($mode == 'edit'): ?>					<input type="hidden" name="group_id" value="<?php echo $group_id ?>" />
+<?php endif; ?><?php if ($mode == 'add'): ?>					<input type="hidden" name="base_group" value="<?php echo $base_group ?>" />
 <?php endif; ?>					<fieldset>
-						<legend>Setup group options and permissions</legend>
+						<legend><?php echo $lang_admin_groups['Group settings subhead'] ?></legend>
 						<div class="infldset">
-							<p>Below options and permissions are the default permissions for the user group. These options apply if no forum specific permissions are in effect.</p>
+							<p><?php echo $lang_admin_groups['Group settings info'] ?></p>
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Group title</th>
+									<th scope="row"><?php echo $lang_admin_groups['Group title label'] ?></th>
 									<td>
 										<input type="text" name="req_title" size="25" maxlength="50" value="<?php if ($mode == 'edit') echo pun_htmlspecialchars($group['g_title']); ?>" tabindex="1" />
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">User title</th>
+									<th scope="row"><?php echo $lang_admin_groups['User title label'] ?></th>
 									<td>
 										<input type="text" name="user_title" size="25" maxlength="50" value="<?php echo pun_htmlspecialchars($group['g_user_title']) ?>" tabindex="2" />
-										<span>This title will override any rank users in this group have attained. Leave blank to use default title or rank.</span>
+										<span><?php echo $lang_admin_groups['User title help'] ?></span>
 									</td>
 								</tr>
 <?php if ($group['g_id'] != PUN_ADMIN): if ($group['g_id'] != PUN_GUEST): if ($mode != 'edit' || $pun_config['o_default_user_group'] != $group['g_id']): ?>								<tr>
-									<th scope="row"> Allow users moderator privileges</th>
+									<th scope="row"> <?php echo $lang_admin_groups['Mod privileges label'] ?></th>
 									<td>
-										<input type="radio" name="moderator" value="1"<?php if ($group['g_moderator'] == '1') echo ' checked="checked"' ?> tabindex="3" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="moderator" value="0"<?php if ($group['g_moderator'] == '0') echo ' checked="checked"' ?> tabindex="4" />&nbsp;<strong>No</strong>
-										<span>In order for a user in this group to have moderator abilities, he/she must be assigned to moderate one or more forums. This is done via the user administration page of the user's profile.</span>
+										<input type="radio" name="moderator" value="1"<?php if ($group['g_moderator'] == '1') echo ' checked="checked"' ?> tabindex="3" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="moderator" value="0"<?php if ($group['g_moderator'] == '0') echo ' checked="checked"' ?> tabindex="4" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Mod privileges help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Allow moderators to edit user profiles</th>
+									<th scope="row"><?php echo $lang_admin_groups['Edit profile label'] ?></th>
 									<td>
-										<input type="radio" name="mod_edit_users" value="1"<?php if ($group['g_mod_edit_users'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="mod_edit_users" value="0"<?php if ($group['g_mod_edit_users'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong>No</strong>
-										<span>If moderator privileges are enabled, allow users in this group to edit user profiles.</span>
+										<input type="radio" name="mod_edit_users" value="1"<?php if ($group['g_mod_edit_users'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="mod_edit_users" value="0"<?php if ($group['g_mod_edit_users'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Edit profile help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Allow moderators to rename users</th>
+									<th scope="row"><?php echo $lang_admin_groups['Rename users label'] ?></th>
 									<td>
-										<input type="radio" name="mod_rename_users" value="1"<?php if ($group['g_mod_rename_users'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="mod_rename_users" value="0"<?php if ($group['g_mod_rename_users'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong>No</strong>
-										<span>If moderator privileges are enabled, allow users in this group to rename users.</span>
+										<input type="radio" name="mod_rename_users" value="1"<?php if ($group['g_mod_rename_users'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="mod_rename_users" value="0"<?php if ($group['g_mod_rename_users'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Rename users help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Allow moderators to change passwords</th>
+									<th scope="row"><?php echo $lang_admin_groups['Change passwords label'] ?></th>
 									<td>
-										<input type="radio" name="mod_change_passwords" value="1"<?php if ($group['g_mod_change_passwords'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="mod_change_passwords" value="0"<?php if ($group['g_mod_change_passwords'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong>No</strong>
-										<span>If moderator privileges are enabled, allow users in this group to change user passwords.</span>
+										<input type="radio" name="mod_change_passwords" value="1"<?php if ($group['g_mod_change_passwords'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="mod_change_passwords" value="0"<?php if ($group['g_mod_change_passwords'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Change passwords help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Allow moderators to ban users</th>
+									<th scope="row"><?php echo $lang_admin_groups['Ban users label'] ?></th>
 									<td>
-										<input type="radio" name="mod_ban_users" value="1"<?php if ($group['g_mod_ban_users'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="mod_ban_users" value="0"<?php if ($group['g_mod_ban_users'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong>No</strong>
-										<span>If moderator privileges are enabled, allow users in this group to ban users.</span>
+										<input type="radio" name="mod_ban_users" value="1"<?php if ($group['g_mod_ban_users'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="mod_ban_users" value="0"<?php if ($group['g_mod_ban_users'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Ban users help'] ?></span>
 									</td>
 								</tr>
 <?php endif; endif; ?>								<tr>
-									<th scope="row">Read board</th>
+									<th scope="row"><?php echo $lang_admin_groups['Read board label'] ?></th>
 									<td>
-										<input type="radio" name="read_board" value="1"<?php if ($group['g_read_board'] == '1') echo ' checked="checked"' ?> tabindex="3" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="read_board" value="0"<?php if ($group['g_read_board'] == '0') echo ' checked="checked"' ?> tabindex="4" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to view the board. This setting applies to every aspect of the board and can therefore not be overridden by forum specific settings. If this is set to "No", users in this group will only be able to login/logout and register.</span>
+										<input type="radio" name="read_board" value="1"<?php if ($group['g_read_board'] == '1') echo ' checked="checked"' ?> tabindex="3" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="read_board" value="0"<?php if ($group['g_read_board'] == '0') echo ' checked="checked"' ?> tabindex="4" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Read board help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">View user information</th>
+									<th scope="row"><?php echo $lang_admin_groups['View user info label'] ?></th>
 									<td>
-										<input type="radio" name="view_users" value="1"<?php if ($group['g_view_users'] == '1') echo ' checked="checked"' ?> tabindex="3" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="view_users" value="0"<?php if ($group['g_view_users'] == '0') echo ' checked="checked"' ?> tabindex="4" />&nbsp;<strong>No</strong>
-										<span>Allow users to view the user list and user profiles.</span>
+										<input type="radio" name="view_users" value="1"<?php if ($group['g_view_users'] == '1') echo ' checked="checked"' ?> tabindex="3" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="view_users" value="0"<?php if ($group['g_view_users'] == '0') echo ' checked="checked"' ?> tabindex="4" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['View user info help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Post replies</th>
+									<th scope="row"><?php echo $lang_admin_groups['Post replies label'] ?></th>
 									<td>
-										<input type="radio" name="post_replies" value="1"<?php if ($group['g_post_replies'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="post_replies" value="0"<?php if ($group['g_post_replies'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to post replies in topics.</span>
+										<input type="radio" name="post_replies" value="1"<?php if ($group['g_post_replies'] == '1') echo ' checked="checked"' ?> tabindex="5" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="post_replies" value="0"<?php if ($group['g_post_replies'] == '0') echo ' checked="checked"' ?> tabindex="6" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Post replies help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Post topics</th>
+									<th scope="row"><?php echo $lang_admin_groups['Post topics label'] ?></th>
 									<td>
-										<input type="radio" name="post_topics" value="1"<?php if ($group['g_post_topics'] == '1') echo ' checked="checked"' ?> tabindex="7" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="post_topics" value="0"<?php if ($group['g_post_topics'] == '0') echo ' checked="checked"' ?> tabindex="8" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to post new topics.</span>
+										<input type="radio" name="post_topics" value="1"<?php if ($group['g_post_topics'] == '1') echo ' checked="checked"' ?> tabindex="7" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="post_topics" value="0"<?php if ($group['g_post_topics'] == '0') echo ' checked="checked"' ?> tabindex="8" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Post topics help'] ?></span>
 									</td>
 								</tr>
 <?php if ($group['g_id'] != PUN_GUEST): ?>								<tr>
-									<th scope="row">Edit posts</th>
+									<th scope="row"><?php echo $lang_admin_groups['Edit posts label'] ?></th>
 									<td>
-										<input type="radio" name="edit_posts" value="1"<?php if ($group['g_edit_posts'] == '1') echo ' checked="checked"' ?> tabindex="11" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="edit_posts" value="0"<?php if ($group['g_edit_posts'] == '0') echo ' checked="checked"' ?> tabindex="12" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to edit their own posts.</span>
+										<input type="radio" name="edit_posts" value="1"<?php if ($group['g_edit_posts'] == '1') echo ' checked="checked"' ?> tabindex="11" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="edit_posts" value="0"<?php if ($group['g_edit_posts'] == '0') echo ' checked="checked"' ?> tabindex="12" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Edit posts help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Delete posts</th>
+									<th scope="row"><?php echo $lang_admin_groups['Delete posts label'] ?></th>
 									<td>
-										<input type="radio" name="delete_posts" value="1"<?php if ($group['g_delete_posts'] == '1') echo ' checked="checked"' ?> tabindex="13" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="delete_posts" value="0"<?php if ($group['g_delete_posts'] == '0') echo ' checked="checked"' ?> tabindex="14" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to delete their own posts.</span>
+										<input type="radio" name="delete_posts" value="1"<?php if ($group['g_delete_posts'] == '1') echo ' checked="checked"' ?> tabindex="13" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="delete_posts" value="0"<?php if ($group['g_delete_posts'] == '0') echo ' checked="checked"' ?> tabindex="14" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Delete posts help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Delete topics</th>
+									<th scope="row"><?php echo $lang_admin_groups['Delete topics label'] ?></th>
 									<td>
-										<input type="radio" name="delete_topics" value="1"<?php if ($group['g_delete_topics'] == '1') echo ' checked="checked"' ?> tabindex="15" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="delete_topics" value="0"<?php if ($group['g_delete_topics'] == '0') echo ' checked="checked"' ?> tabindex="16" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to delete their own topics (including any replies).</span>
+										<input type="radio" name="delete_topics" value="1"<?php if ($group['g_delete_topics'] == '1') echo ' checked="checked"' ?> tabindex="15" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="delete_topics" value="0"<?php if ($group['g_delete_topics'] == '0') echo ' checked="checked"' ?> tabindex="16" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Delete topics help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Set user title</th>
+									<th scope="row"><?php echo $lang_admin_groups['Set own title label'] ?></th>
 									<td>
-										<input type="radio" name="set_title" value="1"<?php if ($group['g_set_title'] == '1') echo ' checked="checked"' ?> tabindex="17" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="set_title" value="0"<?php if ($group['g_set_title'] == '0') echo ' checked="checked"' ?> tabindex="18" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to set their own user title.</span>
+										<input type="radio" name="set_title" value="1"<?php if ($group['g_set_title'] == '1') echo ' checked="checked"' ?> tabindex="17" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="set_title" value="0"<?php if ($group['g_set_title'] == '0') echo ' checked="checked"' ?> tabindex="18" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Set own title help'] ?></span>
 									</td>
 								</tr>
 <?php endif; ?>								<tr>
-									<th scope="row">Use search</th>
+									<th scope="row"><?php echo $lang_admin_groups['User search label'] ?></th>
 									<td>
-										<input type="radio" name="search" value="1"<?php if ($group['g_search'] == '1') echo ' checked="checked"' ?> tabindex="19" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="search" value="0"<?php if ($group['g_search'] == '0') echo ' checked="checked"' ?> tabindex="20" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to use the search feature.</span>
+										<input type="radio" name="search" value="1"<?php if ($group['g_search'] == '1') echo ' checked="checked"' ?> tabindex="19" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="search" value="0"<?php if ($group['g_search'] == '0') echo ' checked="checked"' ?> tabindex="20" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['User search help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Search user list</th>
+									<th scope="row"><?php echo $lang_admin_groups['User list search label'] ?></th>
 									<td>
-										<input type="radio" name="search_users" value="1"<?php if ($group['g_search_users'] == '1') echo ' checked="checked"' ?> tabindex="21" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="search_users" value="0"<?php if ($group['g_search_users'] == '0') echo ' checked="checked"' ?> tabindex="22" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to freetext search for users in the user list.</span>
+										<input type="radio" name="search_users" value="1"<?php if ($group['g_search_users'] == '1') echo ' checked="checked"' ?> tabindex="21" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="search_users" value="0"<?php if ($group['g_search_users'] == '0') echo ' checked="checked"' ?> tabindex="22" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['User list search help'] ?></span>
 									</td>
 								</tr>
 <?php if ($group['g_id'] != PUN_GUEST): ?>								<tr>
-									<th scope="row">Send emails</th>
+									<th scope="row"><?php echo $lang_admin_groups['Send e-mails label'] ?></th>
 									<td>
-										<input type="radio" name="send_email" value="1"<?php if ($group['g_send_email'] == '1') echo ' checked="checked"' ?> tabindex="21" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="send_email" value="0"<?php if ($group['g_send_email'] == '0') echo ' checked="checked"' ?> tabindex="22" />&nbsp;<strong>No</strong>
-										<span>Allow users in this group to send emails to other users.</span>
+										<input type="radio" name="send_email" value="1"<?php if ($group['g_send_email'] == '1') echo ' checked="checked"' ?> tabindex="21" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="send_email" value="0"<?php if ($group['g_send_email'] == '0') echo ' checked="checked"' ?> tabindex="22" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_groups['Send e-mails help'] ?></span>
 									</td>
 								</tr>
 <?php endif; ?>								<tr>
-									<th scope="row">Post flood interval</th>
+									<th scope="row"><?php echo $lang_admin_groups['Post flood label'] ?></th>
 									<td>
 										<input type="text" name="post_flood" size="5" maxlength="4" value="<?php echo $group['g_post_flood'] ?>" tabindex="24" />
-										<span>Number of seconds that users in this group have to wait between posts. Set to 0 to disable.</span>
+										<span><?php echo $lang_admin_groups['Post flood help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Search flood interval</th>
+									<th scope="row"><?php echo $lang_admin_groups['Search flood label'] ?></th>
 									<td>
 										<input type="text" name="search_flood" size="5" maxlength="4" value="<?php echo $group['g_search_flood'] ?>" tabindex="25" />
-										<span>Number of seconds that users in this group have to wait between searches. Set to 0 to disable.</span>
+										<span><?php echo $lang_admin_groups['Search flood help'] ?></span>
 									</td>
 								</tr>
 <?php if ($group['g_id'] != PUN_GUEST): ?>								<tr>
-									<th scope="row">Email flood interval</th>
+									<th scope="row"><?php echo $lang_admin_groups['E-mail flood label'] ?></th>
 									<td>
 										<input type="text" name="email_flood" size="5" maxlength="4" value="<?php echo $group['g_email_flood'] ?>" tabindex="26" />
-										<span>Number of seconds that users in this group have to wait between e-mails. Set to 0 to disable.</span>
+										<span><?php echo $lang_admin_groups['E-mail flood help'] ?></span>
 									</td>
 								</tr>
 <?php endif; endif; ?>							</table>
-<?php if ($group['g_moderator'] == '1' ): ?>							<p class="warntext">Please note that in order for a user in this group to have moderator abilities, he/she must be assigned to moderate one or more forums. This is done via the user administration page of the user's profile.</p>
+<?php if ($group['g_moderator'] == '1' ): ?>							<p class="warntext"><?php echo $lang_admin_groups['Moderator info'] ?></p>
 <?php endif; ?>						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="add_edit_group" value=" Save " tabindex="26" /></p>
+				<p class="submitend"><input type="submit" name="add_edit_group" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="26" /></p>
 			</form>
 		</div>
 	</div>
@@ -256,8 +242,8 @@ else if (isset($_POST['add_edit_group']))
 	// Is this the admin group? (special rules apply)
 	$is_admin_group = (isset($_POST['group_id']) && $_POST['group_id'] == PUN_ADMIN) ? true : false;
 
-	$title = trim($_POST['req_title']);
-	$user_title = trim($_POST['user_title']);
+	$title = pun_trim($_POST['req_title']);
+	$user_title = pun_trim($_POST['user_title']);
 	$moderator = isset($_POST['moderator']) && $_POST['moderator'] == '1' ? '1' : '0';
 	$mod_edit_users = $moderator == '1' && isset($_POST['mod_edit_users']) && $_POST['mod_edit_users'] == '1' ? '1' : '0';
 	$mod_rename_users = $moderator == '1' && isset($_POST['mod_rename_users']) && $_POST['mod_rename_users'] == '1' ? '1' : '0';
@@ -279,7 +265,7 @@ else if (isset($_POST['add_edit_group']))
 	$email_flood = isset($_POST['email_flood']) ? intval($_POST['email_flood']) : '0';
 
 	if ($title == '')
-		message('You must enter a group title.');
+		message($lang_admin_groups['Must enter title message']);
 
 	$user_title = ($user_title != '') ? '\''.$db->escape($user_title).'\'' : 'NULL';
 
@@ -287,7 +273,7 @@ else if (isset($_POST['add_edit_group']))
 	{
 		$result = $db->query('SELECT 1 FROM '.$db->prefix.'groups WHERE g_title=\''.$db->escape($title).'\'') or error('Unable to check group title collision', __FILE__, __LINE__, $db->error());
 		if ($db->num_rows($result))
-			message('There is already a group with the title \''.pun_htmlspecialchars($title).'\'.');
+			message(sprintf($lang_admin_groups['Title already exists message'], pun_htmlspecialchars($title)));
 
 		$db->query('INSERT INTO '.$db->prefix.'groups (g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES(\''.$db->escape($title).'\', '.$user_title.', '.$moderator.', '.$mod_edit_users.', '.$mod_rename_users.', '.$mod_change_passwords.', '.$mod_ban_users.', '.$read_board.', '.$view_users.', '.$post_replies.', '.$post_topics.', '.$edit_posts.', '.$delete_posts.', '.$delete_topics.', '.$set_title.', '.$search.', '.$search_users.', '.$send_email.', '.$post_flood.', '.$search_flood.', '.$email_flood.')') or error('Unable to add group', __FILE__, __LINE__, $db->error());
 		$new_group_id = $db->insert_id();
@@ -301,18 +287,21 @@ else if (isset($_POST['add_edit_group']))
 	{
 		$result = $db->query('SELECT 1 FROM '.$db->prefix.'groups WHERE g_title=\''.$db->escape($title).'\' AND g_id!='.intval($_POST['group_id'])) or error('Unable to check group title collision', __FILE__, __LINE__, $db->error());
 		if ($db->num_rows($result))
-			message('There is already a group with the title \''.pun_htmlspecialchars($title).'\'.');
+			message(sprintf($lang_admin_groups['Title already exists message'], pun_htmlspecialchars($title)));
 
 		$db->query('UPDATE '.$db->prefix.'groups SET g_title=\''.$db->escape($title).'\', g_user_title='.$user_title.', g_moderator='.$moderator.', g_mod_edit_users='.$mod_edit_users.', g_mod_rename_users='.$mod_rename_users.', g_mod_change_passwords='.$mod_change_passwords.', g_mod_ban_users='.$mod_ban_users.', g_read_board='.$read_board.', g_view_users='.$view_users.', g_post_replies='.$post_replies.', g_post_topics='.$post_topics.', g_edit_posts='.$edit_posts.', g_delete_posts='.$delete_posts.', g_delete_topics='.$delete_topics.', g_set_title='.$set_title.', g_search='.$search.', g_search_users='.$search_users.', g_send_email='.$send_email.', g_post_flood='.$post_flood.', g_search_flood='.$search_flood.', g_email_flood='.$email_flood.' WHERE g_id='.intval($_POST['group_id'])) or error('Unable to update group', __FILE__, __LINE__, $db->error());
 	}
 
-	// Regenerate the quickjump cache
+	// Regenerate the quick jump cache
 	if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 		require PUN_ROOT.'include/cache.php';
 
 	generate_quickjump_cache();
 
-	redirect('admin_groups.php', 'Group '.(($_POST['mode'] == 'edit') ? 'edited' : 'added').'. Redirecting &hellip;');
+	if ($_POST['mode'] == 'edit')
+		redirect('admin_groups.php', $lang_admin_groups['Group edited redirect']);
+	else
+		redirect('admin_groups.php', $lang_admin_groups['Group added redirect']);
 }
 
 
@@ -340,7 +329,7 @@ else if (isset($_POST['set_default_group']))
 
 	generate_config_cache();
 
-	redirect('admin_groups.php', 'Default group set. Redirecting &hellip;');
+	redirect('admin_groups.php', $lang_admin_groups['Default group redirect']);
 }
 
 
@@ -355,7 +344,7 @@ else if (isset($_GET['del_group']))
 
 	// Make sure we don't remove the default group
 	if ($group_id == $pun_config['o_default_user_group'])
-		message('The default group cannot be removed. In order to delete this group, you must first setup a different group as the default.');
+		message($lang_admin_groups['Cannot remove default message']);
 
 	// Check if this group has any members
 	$result = $db->query('SELECT g.g_title, COUNT(u.id) FROM '.$db->prefix.'groups AS g INNER JOIN '.$db->prefix.'users AS u ON g.g_id=u.group_id WHERE g.g_id='.$group_id.' GROUP BY g.g_id, g_title') or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
@@ -375,40 +364,41 @@ else if (isset($_GET['del_group']))
 			$db->query('DELETE FROM '.$db->prefix.'groups WHERE g_id='.$group_id) or error('Unable to delete group', __FILE__, __LINE__, $db->error());
 			$db->query('DELETE FROM '.$db->prefix.'forum_perms WHERE group_id='.$group_id) or error('Unable to delete group forum permissions', __FILE__, __LINE__, $db->error());
 
-			// Regenerate the quickjump cache
+			// Regenerate the quick jump cache
 			if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 				require PUN_ROOT.'include/cache.php';
 
 			generate_quickjump_cache();
 
-			redirect('admin_groups.php', 'Group removed. Redirecting &hellip;');
+			redirect('admin_groups.php', $lang_admin_groups['Group removed redirect']);
 		}
 		else
 		{
 			$result = $db->query('SELECT g_title FROM '.$db->prefix.'groups WHERE g_id='.$group_id) or error('Unable to fetch group title', __FILE__, __LINE__, $db->error());
 			$group_title = $db->result($result);
 
-			$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / User groups';
+			$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['User groups']);
+			define('PUN_ACTIVE_PAGE', 'admin');
 			require PUN_ROOT.'header.php';
 
 			generate_admin_menu('groups');
 
 ?>
 	<div class="blockform">
-		<h2><span>Group delete</span></h2>
+		<h2><span><?php echo $lang_admin_groups['Group delete head'] ?></span></h2>
 		<div class="box">
 			<form method="post" action="admin_groups.php?del_group=<?php echo $group_id ?>">
 				<div class="inform">
 				<input type="hidden" name="group_to_delete" value="<?php echo $group_id ?>" />
 					<fieldset>
-						<legend>Confirm delete group</legend>
+						<legend><?php echo $lang_admin_groups['Confirm delete subhead'] ?></legend>
 						<div class="infldset">
-							<p>Are you sure that you want to delete the group "<?php echo pun_htmlspecialchars($group_title) ?>"?</p>
-							<p>WARNING! After you deleted a group you can not restore it.</p>
+							<p><?php printf($lang_admin_groups['Confirm delete info'], pun_htmlspecialchars($group_title)) ?></p>
+							<p class="warntext"><?php echo $lang_admin_groups['Confirm delete warn'] ?></p>
 						</div>
 					</fieldset>
 				</div>
-				<p><input type="submit" name="del_group_comply" value="Delete" /><a href="javascript:history.go(-1)">Go back</a></p>
+				<p class="buttons"><input type="submit" name="del_group_comply" value="<?php echo $lang_admin_common['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
 			</form>
 		</div>
 	</div>
@@ -422,22 +412,23 @@ else if (isset($_GET['del_group']))
 
 	list($group_title, $group_members) = $db->fetch_row($result);
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / User groups';
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['User groups']);
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 	generate_admin_menu('groups');
 
 ?>
 	<div class="blockform">
-		<h2><span>Remove group</span></h2>
+		<h2><span><?php echo $lang_admin_groups['Delete group head'] ?></span></h2>
 		<div class="box">
 			<form id="groups" method="post" action="admin_groups.php?del_group=<?php echo $group_id ?>">
 				<div class="inform">
 					<fieldset>
-						<legend>Move users currently in group</legend>
+						<legend><?php echo $lang_admin_groups['Move users subhead'] ?></legend>
 						<div class="infldset">
-							<p>The group "<?php echo pun_htmlspecialchars($group_title) ?>" currently has <?php echo $group_members ?> members. Please select a group to which these members will be assigned upon removal.</p>
-							<label>Move users to
+							<p><?php printf($lang_admin_groups['Move users info'], pun_htmlspecialchars($group_title), forum_number_format($group_members)) ?></p>
+							<label><?php echo $lang_admin_groups['Move users label'] ?>
 							<select name="move_to_group">
 <?php
 
@@ -445,7 +436,7 @@ else if (isset($_GET['del_group']))
 
 	while ($cur_group = $db->fetch_assoc($result))
 	{
-		if ($cur_group['g_id'] == PUN_MEMBER)	// Pre-select the pre-defined Members group
+		if ($cur_group['g_id'] == PUN_MEMBER) // Pre-select the pre-defined Members group
 			echo "\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'" selected="selected">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
 		else
 			echo "\t\t\t\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'">'.pun_htmlspecialchars($cur_group['g_title']).'</option>'."\n";
@@ -453,11 +444,11 @@ else if (isset($_GET['del_group']))
 
 ?>
 							</select>
-							</br></label>
+							<br /></label>
 						</div>
 					</fieldset>
 				</div>
-				<p><input type="submit" name="del_group" value="Delete group" /></p>
+				<p class="buttons"><input type="submit" name="del_group" value="<?php echo $lang_admin_groups['Delete group'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
 			</form>
 		</div>
 	</div>
@@ -469,28 +460,29 @@ else if (isset($_GET['del_group']))
 }
 
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / User groups';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['User groups']);
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('groups');
 
 ?>
 	<div class="blockform">
-		<h2><span>Add/setup groups</span></h2>
+		<h2><span><?php echo $lang_admin_groups['Add groups head'] ?></span></h2>
 		<div class="box">
 			<form id="groups" method="post" action="admin_groups.php?action=foo">
 				<div class="inform">
 					<fieldset>
-						<legend>Add new group</legend>
+						<legend><?php echo $lang_admin_groups['Add group subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Base new group on<div><input type="submit" name="add_group" value=" Add " tabindex="2" /></div></th>
+									<th scope="row"><?php echo $lang_admin_groups['New group label'] ?><div><input type="submit" name="add_group" value="<?php echo $lang_admin_common['Add'] ?>" tabindex="2" /></div></th>
 									<td>
 										<select id="base_group" name="base_group" tabindex="1">
 <?php
 
-$result = $db->query('SELECT g_id, g_title FROM '.$db->prefix.'groups WHERE g_id>'.PUN_GUEST.' ORDER BY g_title') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
+$result = $db->query('SELECT g_id, g_title FROM '.$db->prefix.'groups WHERE g_id!='.PUN_ADMIN.' AND g_id!='.PUN_GUEST.' ORDER BY g_title') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
 
 while ($cur_group = $db->fetch_assoc($result))
 {
@@ -502,7 +494,7 @@ while ($cur_group = $db->fetch_assoc($result))
 
 ?>
 										</select>
-										<span>Select a user group from which the new group will inherit its permission settings. The next page will let you fine-tune said settings.</span>
+										<span><?php echo $lang_admin_groups['New group help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -511,11 +503,11 @@ while ($cur_group = $db->fetch_assoc($result))
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Set default group</legend>
+						<legend><?php echo $lang_admin_groups['Default group subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Default group<div><input type="submit" name="set_default_group" value=" Save " tabindex="4" /></div></th>
+									<th scope="row"><?php echo $lang_admin_groups['Default group label'] ?><div><input type="submit" name="set_default_group" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="4" /></div></th>
 									<td>
 										<select id="default_group" name="default_group" tabindex="3">
 <?php
@@ -532,7 +524,7 @@ while ($cur_group = $db->fetch_assoc($result))
 
 ?>
 										</select>
-										<span>This is the default user group, e.g. the group users are placed in when they register. For security reasons, users can't be placed in either the moderator or administrator user groups by default.</span>
+										<span><?php echo $lang_admin_groups['Default group help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -542,21 +534,21 @@ while ($cur_group = $db->fetch_assoc($result))
 			</form>
 		</div>
 
-		<h2 class="block2"><span>Existing groups</span></h2>
+		<h2 class="block2"><span><?php echo $lang_admin_groups['Existing groups head'] ?></span></h2>
 		<div class="box">
 			<div class="fakeform">
 				<div class="inform">
 					<fieldset>
-						<legend>Edit/remove groups</legend>
+						<legend><?php echo $lang_admin_groups['Edit groups subhead'] ?></legend>
 						<div class="infldset">
-							<p>The pre-defined groups Guests, Administrators, Moderators and Members cannot be removed. They can however be edited. Please note though, that in some groups, some options are unavailable (e.g. the <em>edit posts</em> permission for guests). Administrators always have full permissions.</p>
+							<p><?php echo $lang_admin_groups['Edit groups info'] ?></p>
 							<table cellspacing="0">
 <?php
 
 $result = $db->query('SELECT g_id, g_title FROM '.$db->prefix.'groups ORDER BY g_id') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
 
 while ($cur_group = $db->fetch_assoc($result))
-	echo "\t\t\t\t\t\t\t\t".'<tr><th scope="row"><a href="admin_groups.php?edit_group='.$cur_group['g_id'].'">Edit</a>'.(($cur_group['g_id'] > PUN_MEMBER) ? ' - <a href="admin_groups.php?del_group='.$cur_group['g_id'].'">Remove</a>' : '').'</th><td>'.pun_htmlspecialchars($cur_group['g_title']).'</td></tr>'."\n";
+	echo "\t\t\t\t\t\t\t\t".'<tr><th scope="row"><a href="admin_groups.php?edit_group='.$cur_group['g_id'].'">'.$lang_admin_groups['Edit link'].'</a>'.(($cur_group['g_id'] > PUN_MEMBER) ? ' | <a href="admin_groups.php?del_group='.$cur_group['g_id'].'">'.$lang_admin_groups['Delete link'].'</a>' : '').'</th><td>'.pun_htmlspecialchars($cur_group['g_title']).'</td></tr>'."\n";
 
 ?>
 							</table>
diff --git a/upload/admin_index.php b/upload/admin_index.php
index bb65851..ee32df8 100644
--- a/upload/admin_index.php
+++ b/upload/admin_index.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,6 +17,8 @@ require PUN_ROOT.'include/common_admin.php';
 if (!$pun_user['is_admmod'])
 	message($lang_common['No permission']);
 
+// Load the admin_index.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_index.php';
 
 $action = isset($_GET['action']) ? $_GET['action'] : null;
 
@@ -41,25 +26,16 @@ $action = isset($_GET['action']) ? $_GET['action'] : null;
 if ($action == 'check_upgrade')
 {
 	if (!ini_get('allow_url_fopen'))
-		message('Unable to check for upgrade since \'allow_url_fopen\' is disabled on this system.');
-
-	$fp = @fopen('http://fluxbb.org/latest_version', 'r');
-	$latest_version = trim(@fread($fp, 16));
-	@fclose($fp);
-
-	if ($latest_version == '')
-		message('Check for upgrade failed for unknown reasons.');
+		message($lang_admin_index['fopen disabled message']);
 
-	$cur_version = str_replace(array('.', 'dev', 'beta', ' '), '', strtolower($pun_config['o_cur_version']));
-	$cur_version = (strlen($cur_version) == 2) ? intval($cur_version) * 10 : intval($cur_version);
+	$latest_version = trim(@file_get_contents('http://fluxbb.org/latest_version'));
+	if (empty($latest_version))
+		message($lang_admin_index['Upgrade check failed message']);
 
-	$latest_version = str_replace('.', '', strtolower($latest_version));
-	$latest_version = (strlen($latest_version) == 2) ? intval($latest_version) * 10 : intval($latest_version);
-
-	if ($cur_version >= $latest_version)
-		message('You are running the latest version of FluxBB.');
+	if (version_compare($pun_config['o_cur_version'], $latest_version, '>='))
+		message($lang_admin_index['Running latest version message']);
 	else
-		message('A new version of FluxBB has been released. You can download the latest version at <a href="http://fluxbb.org/">FluxBB.org</a>.');
+		message(sprintf($lang_admin_index['New version available message'], '<a href="http://fluxbb.org/">FluxBB.org</a>'));
 }
 
 
@@ -67,8 +43,8 @@ if ($action == 'check_upgrade')
 else if ($action == 'phpinfo' && $pun_user['g_id'] == PUN_ADMIN)
 {
 	// Is phpinfo() a disabled function?
-	if (strpos(strtolower((string)@ini_get('disable_functions')), 'phpinfo') !== false)
-		message('The PHP function phpinfo() has been disabled on this server.');
+	if (strpos(strtolower((string) ini_get('disable_functions')), 'phpinfo') !== false)
+		message($lang_admin_index['PHPinfo disabled message']);
 
 	phpinfo();
 	exit;
@@ -83,13 +59,21 @@ if (@file_exists('/proc/loadavg') && is_readable('/proc/loadavg'))
 	$load_averages = @fread($fh, 64);
 	@fclose($fh);
 
+	if (($fh = @fopen('/proc/loadavg', 'r')))
+	{
+		$load_averages = fread($fh, 64);
+		fclose($fh);
+	}
+	else
+		$load_averages = '';
+
 	$load_averages = @explode(' ', $load_averages);
-	$server_load = isset($load_averages[2]) ? $load_averages[0].' '.$load_averages[1].' '.$load_averages[2] : 'Not available';
+	$server_load = isset($load_averages[2]) ? $load_averages[0].' '.$load_averages[1].' '.$load_averages[2] : $lang_admin_index['Not available'];
 }
-else if (!in_array(PHP_OS, array('WINNT', 'WIN32')) && preg_match('/averages?: ([0-9\.]+),[\s]+([0-9\.]+),[\s]+([0-9\.]+)/i', @exec('uptime'), $load_averages))
+else if (!in_array(PHP_OS, array('WINNT', 'WIN32')) && preg_match('/averages?: ([0-9\.]+),?\s+([0-9\.]+),?\s+([0-9\.]+)/i', @exec('uptime'), $load_averages))
 	$server_load = $load_averages[1].' '.$load_averages[2].' '.$load_averages[3];
 else
-	$server_load = 'Not available';
+	$server_load = $lang_admin_index['Not available'];
 
 
 // Get number of current visitors
@@ -110,80 +94,76 @@ if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' ||
 		$total_size += $status['Data_length'] + $status['Index_length'];
 	}
 
-	$total_size = $total_size / 1024;
-
-	if ($total_size > 1024)
-		$total_size = round($total_size / 1024, 2).' MB';
-	else
-		$total_size = round($total_size, 2).' KB';
+	$total_size = file_size($total_size);
 }
 
 
-// Check for the existance of various PHP opcode caches/optimizers
+// Check for the existence of various PHP opcode caches/optimizers
 if (function_exists('mmcache'))
-	$php_accelerator = '<a href="http://turck-mmcache.sourceforge.net/">Turck MMCache</a>';
+	$php_accelerator = '<a href="http://'.$lang_admin_index['Turck MMCache link'].'">'.$lang_admin_index['Turck MMCache'].'</a>';
 else if (isset($_PHPA))
-	$php_accelerator = '<a href="http://www.php-accelerator.co.uk/">ionCube PHP Accelerator</a>';
+	$php_accelerator = '<a href="http://'.$lang_admin_index['ionCube PHP Accelerator link'].'">'.$lang_admin_index['ionCube PHP Accelerator'].'</a>';
 else if (ini_get('apc.enabled'))
-	$php_accelerator ='<a href="http://www.php.net/apc/">Alternative PHP Cache (APC)</a>';
+	$php_accelerator ='<a href="http://'.$lang_admin_index['Alternative PHP Cache (APC) link'].'">'.$lang_admin_index['Alternative PHP Cache (APC)'].'</a>';
 else if (ini_get('zend_optimizer.optimization_level'))
-	$php_accelerator = '<a href="http://www.zend.com/products/zend_optimizer/">Zend Optimizer</a>';
+	$php_accelerator = '<a href="http://'.$lang_admin_index['Zend Optimizer link'].'">'.$lang_admin_index['Zend Optimizer'].'</a>';
 else if (ini_get('eaccelerator.enable'))
-	$php_accelerator = '<a href="http://eaccelerator.net/">eAccelerator</a>';
+	$php_accelerator = '<a href="http://'.$lang_admin_index['eAccelerator link'].'">'.$lang_admin_index['eAccelerator'].'</a>';
 else if (ini_get('xcache.cacher'))
-	$php_accelerator = '<a href="http://trac.lighttpd.net/xcache/">XCache</a>';
+	$php_accelerator = '<a href="http://'.$lang_admin_index['XCache link'].'">'.$lang_admin_index['XCache'].'</a>';
 else
-	$php_accelerator = 'N/A';
+	$php_accelerator = $lang_admin_index['NA'];
 
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Index']);
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('index');
 
 ?>
 	<div class="block">
-		<h2>Forum administration</h2>
+		<h2><span><?php echo $lang_admin_index['Forum admin head'] ?></span></h2>
 		<div id="adintro" class="box">
 			<div class="inbox">
 				<p>
-					Welcome to the FluxBB administration control panel. From here you can control vital aspects of the forum. Depending on whether you are an administrator or a moderator you can<br /><br />
-					&nbsp;- organize categories and forums.<br />
-					&nbsp;- set forum-wide options and preferences.<br />
-					&nbsp;- control permissions for users and guests.<br />
-					&nbsp;- view IP statistics for users.<br />
-					&nbsp;- ban users.<br />
-					&nbsp;- censor words.<br />
-					&nbsp;- set up user ranks.<br />
-					&nbsp;- prune old posts.<br />
-					&nbsp;- handle post reports.
+					<?php echo $lang_admin_index['Welcome to admin'] ?><br /><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 1'] ?><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 2'] ?><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 3'] ?><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 4'] ?><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 5'] ?><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 6'] ?><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 7'] ?><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 8'] ?><br />
+					&nbsp;- <?php echo $lang_admin_index['Welcome 9'] ?>
 				</p>
 			</div>
 		</div>
 
-		<h2 class="block2"><span>Statistics</span></h2>
+		<h2 class="block2"><span><?php echo $lang_admin_index['Statistics head'] ?></span></h2>
 		<div id="adstats" class="box">
 			<div class="inbox">
 				<dl>
-					<dt>FluxBB version</dt>
+					<dt><?php echo $lang_admin_index['FluxBB version label'] ?></dt>
 					<dd>
-						FluxBB <?php echo $pun_config['o_cur_version'] ?> - <a href="admin_index.php?action=check_upgrade">Check for upgrade</a><br />
+						<?php printf($lang_admin_index['FluxBB version data'], $pun_config['o_cur_version'], '<a href="admin_index.php?action=check_upgrade">'.$lang_admin_index['Check for upgrade'].'</a>') ?><br />
 					</dd>
-					<dt>Server load</dt>
+					<dt><?php echo $lang_admin_index['Server load label'] ?></dt>
 					<dd>
-						<?php echo $server_load ?> (<?php echo $num_online ?> users online)
+						<?php printf($lang_admin_index['Server load data'], $server_load, $num_online) ?>
 					</dd>
-<?php if ($pun_user['g_id'] == PUN_ADMIN): ?>					<dt>Environment</dt>
+<?php if ($pun_user['g_id'] == PUN_ADMIN): ?>					<dt><?php echo $lang_admin_index['Environment label'] ?></dt>
 					<dd>
-						Operating system: <?php echo PHP_OS ?><br />
-						PHP: <?php echo phpversion() ?> - <a href="admin_index.php?action=phpinfo">Show info</a><br />
-						Accelerator: <?php echo $php_accelerator."\n" ?>
+						<?php printf($lang_admin_index['Environment data OS'], PHP_OS) ?><br />
+						<?php printf($lang_admin_index['Environment data version'], phpversion(), '<a href="admin_index.php?action=phpinfo">'.$lang_admin_index['Show info'].'</a>') ?><br />
+						<?php printf($lang_admin_index['Environment data acc'], $php_accelerator) ?>
 					</dd>
-					<dt>Database</dt>
+					<dt><?php echo $lang_admin_index['Database label'] ?></dt>
 					<dd>
 						<?php echo implode(' ', $db->get_version())."\n" ?>
-<?php if (isset($total_records) && isset($total_size)): ?>						<br />Rows: <?php echo forum_number_format($total_records)."\n" ?>
-						<br />Size: <?php echo $total_size."\n" ?>
+<?php if (isset($total_records) && isset($total_size)): ?>						<br /><?php printf($lang_admin_index['Database data rows'], forum_number_format($total_records)) ?>
+						<br /><?php printf($lang_admin_index['Database data size'], $total_size) ?>
 <?php endif; endif; ?>					</dd>
 				</dl>
 			</div>
diff --git a/upload/admin_loader.php b/upload/admin_loader.php
index 39463b8..760f967 100644
--- a/upload/admin_loader.php
+++ b/upload/admin_loader.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,10 +17,9 @@ require PUN_ROOT.'include/common_admin.php';
 if (!$pun_user['is_admmod'])
 	message($lang_common['No permission']);
 
-
 // The plugin to load should be supplied via GET
 $plugin = isset($_GET['plugin']) ? $_GET['plugin'] : '';
-if (!@preg_match('/^AM?P_(\w*?)\.php$/i', $plugin))
+if (!preg_match('/^AM?P_(\w*?)\.php$/i', $plugin))
 	message($lang_common['Bad request']);
 
 // AP_ == Admins only, AMP_ == admins and moderators
@@ -47,21 +29,22 @@ if ($pun_user['g_moderator'] == '1' && $prefix == 'AP')
 
 // Make sure the file actually exists
 if (!file_exists(PUN_ROOT.'plugins/'.$plugin))
-	message('There is no plugin called \''.$plugin.'\' in the plugin directory.');
+	message(sprintf($lang_admin_common['No plugin message'], $plugin));
 
 // Construct REQUEST_URI if it isn't set
 if (!isset($_SERVER['REQUEST_URI']))
 	$_SERVER['REQUEST_URI'] = (isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '').'?'.(isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '');
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / '.$plugin;
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Admin'], str_replace('_', ' ', substr($plugin, strpos($plugin, '_') + 1, -4)));
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 // Attempt to load the plugin. We don't use @ here to supress error messages,
 // because if we did and a parse error occurred in the plugin, we would only
-// get the "blank page of death".
+// get the "blank page of death"
 include PUN_ROOT.'plugins/'.$plugin;
 if (!defined('PUN_PLUGIN_LOADED'))
-	message('Loading of the plugin \''.$plugin.'\' failed.');
+	message(sprintf($lang_admin_common['Plugin failed message'], $plugin));
 
 // Output the clearer div
 ?>
diff --git a/upload/admin_maintenance.php b/upload/admin_maintenance.php
index 61f560f..fb36414 100644
--- a/upload/admin_maintenance.php
+++ b/upload/admin_maintenance.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -36,6 +19,8 @@ require PUN_ROOT.'include/common_admin.php';
 if ($pun_user['g_id'] != PUN_ADMIN)
 	message($lang_common['No permission']);
 
+// Load the admin_maintenance.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_maintenance.php';
 
 if (isset($_GET['i_per_page']) && isset($_GET['i_start_at']))
 {
@@ -52,9 +37,8 @@ if (isset($_GET['i_per_page']) && isset($_GET['i_start_at']))
 		// This is the only potentially "dangerous" thing we can do here, so we check the referer
 		confirm_referrer('admin_maintenance.php');
 
-		$truncate_sql = ($db_type != 'sqlite' && $db_type != 'pgsql') ? 'TRUNCATE TABLE ' : 'DELETE FROM ';
-		$db->query($truncate_sql.$db->prefix.'search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error());
-		$db->query($truncate_sql.$db->prefix.'search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error());
+		$db->truncate_table('search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error());
+		$db->truncate_table('search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error());
 
 		// Reset the sequence for the search words (not needed for SQLite)
 		switch ($db_type)
@@ -71,113 +55,116 @@ if (isset($_GET['i_per_page']) && isset($_GET['i_start_at']))
 		}
 	}
 
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_maintenance['Rebuilding search index']);
+
 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<title><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?> / Rebuilding search index &hellip;</title>
+<title><?php echo generate_page_title($page_title) ?></title>
 <style type="text/css">
 body {
-	font: 10px Verdana, Arial, Helvetica, sans-serif;
+	font: 12px Verdana, Arial, Helvetica, sans-serif;
 	color: #333333;
 	background-color: #FFFFFF
 }
+
+h1 {
+	font-size: 16px;
+	font-weight: normal;
+}
 </style>
 </head>
 <body>
 
-Rebuilding index &hellip; This might be a good time to put on some coffee :-)<br /><br />
+<h1><?php echo $lang_admin_maintenance['Rebuilding index info'] ?></h1>
+<hr />
 
 <?php
 
-	require PUN_ROOT.'include/search_idx.php';
+	$query_str = '';
 
-	// Fetch posts to process
-	$result = $db->query('SELECT id FROM '.$db->prefix.'topics WHERE id>='.$start_at.' ORDER BY id LIMIT '.$per_page) or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
-	$topics = array();
-	while ($cur_topic = $db->fetch_row($result))
-		$topics[] = $cur_topic[0];
+	require PUN_ROOT.'include/search_idx.php';
 
-	$result = $db->query('SELECT topic_id, id, message FROM '.$db->prefix.'posts WHERE topic_id IN ('.implode(',', $topics).') ORDER BY topic_id') or error('Unable to fetch topic/post info', __FILE__, __LINE__, $db->error());
+	// Fetch posts to process this cycle
+	$result = $db->query('SELECT p.id, p.message, t.subject, t.first_post_id FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id WHERE p.id >= '.$start_at.' ORDER BY p.id ASC LIMIT '.$per_page) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
 
-	$cur_topic = 0;
-	while ($cur_post = $db->fetch_row($result))
+	$end_at = 0;
+	while ($cur_item = $db->fetch_assoc($result))
 	{
-		if ($cur_post[0] <> $cur_topic)
-		{
-			// Fetch subject and ID of first post in topic
-			$result2 = $db->query('SELECT p.id, t.subject, MIN(p.posted) AS first FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id WHERE t.id='.$cur_post[0].' GROUP BY p.id, t.subject ORDER BY first LIMIT 1') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
-			list($first_post, $subject) = $db->fetch_row($result2);
-
-			$cur_topic = $cur_post[0];
-		}
+		echo '<p><span>'.sprintf($lang_admin_maintenance['Processing post'], $cur_item['id']).'</span></p>'."\n";
 
-		echo 'Processing post <strong>'.$cur_post[1].'</strong> in topic <strong>'.$cur_post[0].'</strong><br />'."\n";
-
-		if ($cur_post[1] == $first_post)	// This is the "topic post" so we have to index the subject as well
-			update_search_index('post', $cur_post[1], $cur_post[2], $subject);
+		if ($cur_item['id'] == $cur_item['first_post_id'])
+			update_search_index('post', $cur_item['id'], $cur_item['message'], $cur_item['subject']);
 		else
-			update_search_index('post', $cur_post[1], $cur_post[2]);
+			update_search_index('post', $cur_item['id'], $cur_item['message']);
+
+		$end_at = $cur_item['id'];
 	}
 
 	// Check if there is more work to do
-	$result = $db->query('SELECT id FROM '.$db->prefix.'topics WHERE id>'.$cur_topic.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
+	if ($end_at > 0)
+	{
+		$result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
 
-	$query_str = ($db->num_rows($result)) ? '?i_per_page='.$per_page.'&i_start_at='.$db->result($result) : '';
+		if ($db->num_rows($result) > 0)
+			$query_str = '?i_per_page='.$per_page.'&i_start_at='.$db->result($result);
+	}
 
 	$db->end_transaction();
 	$db->close();
 
-	exit('<script type="text/javascript">window.location="admin_maintenance.php'.$query_str.'"</script><br />JavaScript redirect unsuccessful. Click <a href="admin_maintenance.php'.$query_str.'">here</a> to continue.');
+	exit('<script type="text/javascript">window.location="admin_maintenance.php'.$query_str.'"</script><hr /><p>'.sprintf($lang_admin_maintenance['Javascript redirect failed'], '<a href="admin_maintenance.php'.$query_str.'">'.$lang_admin_maintenance['Click here'].'</a>').'</p>');
 }
 
 
 // Get the first post ID from the db
-$result = $db->query('SELECT id FROM '.$db->prefix.'topics ORDER BY id LIMIT 1') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
+$result = $db->query('SELECT id FROM '.$db->prefix.'posts ORDER BY id ASC LIMIT 1') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
 if ($db->num_rows($result))
 	$first_id = $db->result($result);
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Maintenance';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Maintenance']);
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('maintenance');
 
 ?>
 	<div class="blockform">
-		<h2><span>Forum Maintenance</span></h2>
+		<h2><span><?php echo $lang_admin_maintenance['Maintenance head'] ?></span></h2>
 		<div class="box">
 			<form method="get" action="admin_maintenance.php">
 				<div class="inform">
 					<fieldset>
-						<legend>Rebuild search index</legend>
+						<legend><?php echo $lang_admin_maintenance['Rebuild index subhead'] ?></legend>
 						<div class="infldset">
-							<p>If you've added, edited or removed posts manually in the database or if you're having problems searching, you should rebuild the search index. For best performance you should put the forum in maintenance mode during rebuilding. <strong>Rebuilding the search index can take a long time and will increase server load during the rebuild process!</strong></p>
+							<p><?php printf($lang_admin_maintenance['Rebuild index info'], '<a href="admin_options.php#maintenance">'.$lang_admin_common['Maintenance mode'].'</a>') ?></p>
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Topics per cycle</th>
+									<th scope="row"><?php echo $lang_admin_maintenance['Posts per cycle label'] ?></th>
 									<td>
-										<input type="text" name="i_per_page" size="7" maxlength="7" value="100" tabindex="1" />
-										<span>The number of topics to process per pageview. E.g. if you were to enter 100, one hundred topics would be processed and then the page would refresh. This is to prevent the script from timing out during the rebuild process.</span>
+										<input type="text" name="i_per_page" size="7" maxlength="7" value="300" tabindex="1" />
+										<span><?php echo $lang_admin_maintenance['Posts per cycle help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Starting Topic ID</th>
+									<th scope="row"><?php echo $lang_admin_maintenance['Starting post label'] ?></th>
 									<td>
 										<input type="text" name="i_start_at" size="7" maxlength="7" value="<?php echo (isset($first_id)) ? $first_id : 0 ?>" tabindex="2" />
-										<span>The topic ID to start rebuilding at. The default value is the first available ID in the database. Normally you wouldn't want to change this.</span>
+										<span><?php echo $lang_admin_maintenance['Starting post help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Empty index</th>
+									<th scope="row"><?php echo $lang_admin_maintenance['Empty index label'] ?></th>
 									<td class="inputadmin">
-										<span><input type="checkbox" name="i_empty_index" value="1" tabindex="3" checked="checked" />&nbsp;&nbsp;Select this if you want the search index to be emptied before rebuilding (see below).</span>
+										<span><input type="checkbox" name="i_empty_index" value="1" tabindex="3" checked="checked" />&nbsp;&nbsp;<?php echo $lang_admin_maintenance['Empty index help'] ?></span>
 									</td>
 								</tr>
 							</table>
-							<p class="topspace">Once the process has completed you will be redirected back to this page. It is highly recommended that you have JavaScript enabled in your browser during rebuilding (for automatic redirect when a cycle has completed). If you are forced to abort the rebuild process, make a note of the last processed topic ID and enter that ID+1 in "Starting Topic ID" when/if you want to continue ("Empty index" must not be selected).</p>
-							<div class="fsetsubmit"><input type="submit" name="rebuild_index" value="Rebuild index" tabindex="4" /></div>
+							<p class="topspace"><?php echo $lang_admin_maintenance['Rebuild completed info'] ?></p>
+							<div class="fsetsubmit"><input type="submit" name="rebuild_index" value="<?php echo $lang_admin_maintenance['Rebuild index'] ?>" tabindex="4" /></div>
 						</div>
 					</fieldset>
 				</div>
diff --git a/upload/admin_options.php b/upload/admin_options.php
index bf99676..24323e4 100644
--- a/upload/admin_options.php
+++ b/upload/admin_options.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,93 +17,162 @@ require PUN_ROOT.'include/common_admin.php';
 if ($pun_user['g_id'] != PUN_ADMIN)
 	message($lang_common['No permission']);
 
+// Load the admin_options.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_options.php';
 
 if (isset($_POST['form_sent']))
 {
 	// Custom referrer check (so we can output a custom error message)
 	if (!preg_match('#^'.preg_quote(str_replace('www.', '', $pun_config['o_base_url']).'/admin_options.php', '#').'#i', str_replace('www.', '', (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''))))
-		message('Bad HTTP_REFERER. If you have moved these forums from one location to another or switched domains, you need to update the Base URL manually in the database (look for o_base_url in the config table) and then clear the cache by deleting all .php files in the /cache directory.');
-
-	$form = array_map('trim', $_POST['form']);
+		message($lang_admin_options['Bad HTTP Referer message']);
+
+	$form = array(
+		'board_title'			=> pun_trim($_POST['form']['board_title']),
+		'board_desc'			=> pun_trim($_POST['form']['board_desc']),
+		'base_url'				=> pun_trim($_POST['form']['base_url']),
+		'default_timezone'		=> floatval($_POST['form']['default_timezone']),
+		'default_dst'			=> $_POST['form']['default_dst'] != '1' ? '0' : '1',
+		'default_lang'			=> preg_replace('#[\.\\\/]#', '', pun_trim($_POST['form']['default_lang'])),
+		'default_style'			=> preg_replace('#[\.\\\/]#', '', pun_trim($_POST['form']['default_style'])),
+		'time_format'			=> pun_trim($_POST['form']['time_format']),
+		'date_format'			=> pun_trim($_POST['form']['date_format']),
+		'timeout_visit'			=> intval($_POST['form']['timeout_visit']),
+		'timeout_online'		=> intval($_POST['form']['timeout_online']),
+		'redirect_delay'		=> intval($_POST['form']['redirect_delay']),
+		'show_version'			=> $_POST['form']['show_version'] != '1' ? '0' : '1',
+		'show_user_info'		=> $_POST['form']['show_user_info'] != '1' ? '0' : '1',
+		'show_post_count'		=> $_POST['form']['show_post_count'] != '1' ? '0' : '1',
+		'smilies'				=> $_POST['form']['smilies'] != '1' ? '0' : '1',
+		'smilies_sig'			=> $_POST['form']['smilies_sig'] != '1' ? '0' : '1',
+		'make_links'			=> $_POST['form']['make_links'] != '1' ? '0' : '1',
+		'topic_review'			=> intval($_POST['form']['topic_review']),
+		'disp_topics_default'	=> intval($_POST['form']['disp_topics_default']),
+		'disp_posts_default'	=> intval($_POST['form']['disp_posts_default']),
+		'indent_num_spaces'		=> intval($_POST['form']['indent_num_spaces']),
+		'quote_depth'			=> intval($_POST['form']['quote_depth']),
+		'quickpost'				=> $_POST['form']['quickpost'] != '1' ? '0' : '1',
+		'users_online'			=> $_POST['form']['users_online'] != '1' ? '0' : '1',
+		'censoring'				=> $_POST['form']['censoring'] != '1' ? '0' : '1',
+		'signatures'			=> $_POST['form']['signatures'] != '1' ? '0' : '1',
+		'ranks'					=> $_POST['form']['ranks'] != '1' ? '0' : '1',
+		'show_dot'				=> $_POST['form']['show_dot'] != '1' ? '0' : '1',
+		'topic_views'			=> $_POST['form']['topic_views'] != '1' ? '0' : '1',
+		'quickjump'				=> $_POST['form']['quickjump'] != '1' ? '0' : '1',
+		'gzip'					=> $_POST['form']['gzip'] != '1' ? '0' : '1',
+		'search_all_forums'		=> $_POST['form']['search_all_forums'] != '1' ? '0' : '1',
+		'additional_navlinks'	=> pun_trim($_POST['form']['additional_navlinks']),
+		'feed_type'				=> intval($_POST['form']['feed_type']),
+		'report_method'			=> intval($_POST['form']['report_method']),
+		'mailing_list'			=> pun_trim($_POST['form']['mailing_list']),
+		'avatars'				=> $_POST['form']['avatars'] != '1' ? '0' : '1',
+		'avatars_dir'			=> pun_trim($_POST['form']['avatars_dir']),
+		'avatars_width'			=> intval($_POST['form']['avatars_width']),
+		'avatars_height'		=> intval($_POST['form']['avatars_height']),
+		'avatars_size'			=> intval($_POST['form']['avatars_size']),
+		'admin_email'			=> strtolower(pun_trim($_POST['form']['admin_email'])),
+		'webmaster_email'		=> strtolower(pun_trim($_POST['form']['webmaster_email'])),
+		'subscriptions'			=> $_POST['form']['subscriptions'] != '1' ? '0' : '1',
+		'smtp_host'				=> pun_trim($_POST['form']['smtp_host']),
+		'smtp_user'				=> pun_trim($_POST['form']['smtp_user']),
+		'smtp_pass'				=> pun_trim($_POST['form']['smtp_pass']),
+		'smtp_ssl'				=> $_POST['form']['smtp_ssl'] != '1' ? '0' : '1',
+		'regs_allow'			=> $_POST['form']['regs_allow'] != '1' ? '0' : '1',
+		'regs_verify'			=> $_POST['form']['regs_verify'] != '1' ? '0' : '1',
+		'regs_report'			=> $_POST['form']['regs_report'] != '1' ? '0' : '1',
+		'rules'					=> $_POST['form']['rules'] != '1' ? '0' : '1',
+		'rules_message'			=> pun_trim($_POST['form']['rules_message']),
+		'default_email_setting'	=> intval($_POST['form']['default_email_setting']),
+		'announcement'			=> $_POST['form']['announcement'] != '1' ? '0' : '1',
+		'announcement_message'	=> pun_trim($_POST['form']['announcement_message']),
+		'maintenance'			=> $_POST['form']['maintenance'] != '1' ? '0' : '1',
+		'maintenance_message'	=> pun_trim($_POST['form']['maintenance_message']),
+	);
 
 	if ($form['board_title'] == '')
-		message('You must enter a board title.');
+		message($lang_admin_options['Must enter title message']);
+
+	// Make sure base_url doesn't end with a slash
+	if (substr($form['base_url'], -1) == '/')
+		$form['base_url'] = substr($form['base_url'], 0, -1);
+
+	if (!file_exists(PUN_ROOT.'lang/'.$form['default_lang'].'/common.php'))
+		message($lang_common['Bad request']);
+	if (!file_exists(PUN_ROOT.'style/'.$form['default_style'].'.css'))
+		message($lang_common['Bad request']);
+
+	if ($form['time_format'] == '')
+		$form['time_format'] = 'H:i:s';
+
+	if ($form['date_format'] == '')
+		$form['date_format'] = 'Y-m-d';
 
-	// Clean default_lang
-	$form['default_lang'] = preg_replace('#[\.\\\/]#', '', $form['default_lang']);
 
 	require PUN_ROOT.'include/email.php';
 
-	$form['admin_email'] = strtolower($form['admin_email']);
 	if (!is_valid_email($form['admin_email']))
-		message('The admin e-mail address you entered is invalid.');
+		message($lang_admin_options['Invalid e-mail message']);
 
-	$form['webmaster_email'] = strtolower($form['webmaster_email']);
 	if (!is_valid_email($form['webmaster_email']))
-		message('The webmaster e-mail address you entered is invalid.');
+		message($lang_admin_options['Invalid webmaster e-mail message']);
 
 	if ($form['mailing_list'] != '')
-		$form['mailing_list'] = strtolower(preg_replace('/[\s]/', '', $form['mailing_list']));
-
-	// Make sure base_url doesn't end with a slash
-	if (substr($form['base_url'], -1) == '/')
-		$form['base_url'] = substr($form['base_url'], 0, -1);
-
-	// Clean avatars_dir
-	$form['avatars_dir'] = str_replace("\0", '', $form['avatars_dir']);
+		$form['mailing_list'] = strtolower(preg_replace('/\s/S', '', $form['mailing_list']));
 
 	// Make sure avatars_dir doesn't end with a slash
 	if (substr($form['avatars_dir'], -1) == '/')
 		$form['avatars_dir'] = substr($form['avatars_dir'], 0, -1);
 
 	if ($form['additional_navlinks'] != '')
-		$form['additional_navlinks'] = trim(pun_linebreaks($form['additional_navlinks']));
+		$form['additional_navlinks'] = pun_trim(pun_linebreaks($form['additional_navlinks']));
 
 	if ($form['announcement_message'] != '')
 		$form['announcement_message'] = pun_linebreaks($form['announcement_message']);
 	else
 	{
-		$form['announcement_message'] = 'Enter your announcement here.';
-
-		if ($form['announcement'] == '1')
-			$form['announcement'] = '0';
+		$form['announcement_message'] = $lang_admin_options['Enter announcement here'];
+		$form['announcement'] = '0';
 	}
 
 	if ($form['rules_message'] != '')
 		$form['rules_message'] = pun_linebreaks($form['rules_message']);
 	else
 	{
-		$form['rules_message'] = 'Enter your rules here.';
-
-		if ($form['rules'] == '1')
-			$form['rules'] = '0';
+		$form['rules_message'] = $lang_admin_options['Enter rules here'];
+		$form['rules'] = '0';
 	}
 
 	if ($form['maintenance_message'] != '')
 		$form['maintenance_message'] = pun_linebreaks($form['maintenance_message']);
 	else
 	{
-		$form['maintenance_message'] = 'The forums are temporarily down for maintenance. Please try again in a few minutes.\n\n/Administrator';
-
-		if ($form['maintenance'] == '1')
-			$form['maintenance'] = '0';
+		$form['maintenance_message'] = $lang_admin_options['Default maintenance message'];
+		$form['maintenance'] = '0';
 	}
 
-	$form['timeout_visit'] = intval($form['timeout_visit']);
-	$form['timeout_online'] = intval($form['timeout_online']);
-	$form['redirect_delay'] = intval($form['redirect_delay']);
-	$form['topic_review'] = intval($form['topic_review']);
-	$form['disp_topics_default'] = intval($form['disp_topics_default']);
-	$form['disp_posts_default'] = intval($form['disp_posts_default']);
-	$form['indent_num_spaces'] = intval($form['indent_num_spaces']);
-	$form['avatars_width'] = intval($form['avatars_width']);
-	$form['avatars_height'] = intval($form['avatars_height']);
-	$form['avatars_size'] = intval($form['avatars_size']);
+	// Make sure the number of displayed topics and posts is between 3 and 75
+	if ($form['disp_topics_default'] < 3)
+		$form['disp_topics_default'] = 3;
+	else if ($form['disp_topics_default'] > 75)
+		$form['disp_topics_default'] = 75;
+
+	if ($form['disp_posts_default'] < 3)
+		$form['disp_posts_default'] = 3;
+	else if ($form['disp_posts_default'] > 75)
+		$form['disp_posts_default'] = 75;
+
+	if ($form['feed_type'] < 0 || $form['feed_type'] > 2)
+		message($lang_common['Bad request']);
+
+	if ($form['report_method'] < 0 || $form['report_method'] > 2)
+		message($lang_common['Bad request']);
+
+	if ($form['default_email_setting'] < 0 || $form['default_email_setting'] > 2)
+		message($lang_common['Bad request']);
 
 	if ($form['timeout_online'] >= $form['timeout_visit'])
-		message('The value of "Timeout online" must be smaller than the value of "Timeout visit".');
+		message($lang_admin_options['Timeout error message']);
 
-	while (list($key, $input) = @each($form))
+	foreach ($form as $key => $input)
 	{
 		// Only update values that have changed
 		if (array_key_exists('o_'.$key, $pun_config) && $pun_config['o_'.$key] != $input)
@@ -140,102 +192,105 @@ if (isset($_POST['form_sent']))
 
 	generate_config_cache();
 
-	redirect('admin_options.php', 'Options updated. Redirecting &hellip;');
+	redirect('admin_options.php', $lang_admin_options['Options updated redirect']);
 }
 
-
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Options';
-$form_name = 'update_options';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Options']);
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('options');
 
 ?>
 	<div class="blockform">
-		<h2><span>Options</span></h2>
+		<h2><span><?php echo $lang_admin_options['Options head'] ?></span></h2>
 		<div class="box">
 			<form method="post" action="admin_options.php?action=foo">
-				<p class="submittop"><input type="submit" name="save" value="Save changes" /></p>
+				<p class="submittop"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
 				<div class="inform">
-				<input type="hidden" name="form_sent" value="1" />
+					<input type="hidden" name="form_sent" value="1" />
 					<fieldset>
-						<legend>Essentials</legend>
+						<legend><?php echo $lang_admin_options['Essentials subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Board title</th>
+									<th scope="row"><?php echo $lang_admin_options['Board title label'] ?></th>
 									<td>
 										<input type="text" name="form[board_title]" size="50" maxlength="255" value="<?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?>" />
-										<span>The title of this bulletin board (shown at the top of every page). This field may <strong>not</strong> contain HTML.</span>
+										<span><?php echo $lang_admin_options['Board title help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Board description</th>
+									<th scope="row"><?php echo $lang_admin_options['Board desc label'] ?></th>
 									<td>
 										<input type="text" name="form[board_desc]" size="50" maxlength="255" value="<?php echo pun_htmlspecialchars($pun_config['o_board_desc']) ?>" />
-										<span>A short description of this bulletin board (shown at the top of every page). This field may contain HTML.</span>
+										<span><?php echo $lang_admin_options['Board desc help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Base URL</th>
+									<th scope="row"><?php echo $lang_admin_options['Base URL label'] ?></th>
 									<td>
 										<input type="text" name="form[base_url]" size="50" maxlength="100" value="<?php echo $pun_config['o_base_url'] ?>" />
-										<span>The complete URL of the forum without trailing slash (i.e. http://www.mydomain.com/forums). This <strong>must</strong> be correct in order for all admin and moderator features to work. If you get "Bad referer" errors, it's probably incorrect.</span>
+										<span><?php echo $lang_admin_options['Base URL help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Default timezone</th>
+									<th scope="row"><?php echo $lang_admin_options['Timezone label'] ?></th>
 									<td>
 										<select name="form[default_timezone]">
-											<option value="-12"<?php if ($pun_config['o_default_timezone'] == -12 ) echo ' selected="selected"' ?>>-12</option>
-											<option value="-11"<?php if ($pun_config['o_default_timezone'] == -11) echo ' selected="selected"' ?>>-11</option>
-											<option value="-10"<?php if ($pun_config['o_default_timezone'] == -10) echo ' selected="selected"' ?>>-10</option>
-											<option value="-9.5"<?php if ($pun_config['o_default_timezone'] == -9.5) echo ' selected="selected"' ?>>-09.5</option>
-											<option value="-9"<?php if ($pun_config['o_default_timezone'] == -9 ) echo ' selected="selected"' ?>>-09</option>
-											<option value="-8.5"<?php if ($pun_config['o_default_timezone'] == -8.5) echo ' selected="selected"' ?>>-08.5</option>
-											<option value="-8"<?php if ($pun_config['o_default_timezone'] == -8 ) echo ' selected="selected"' ?>>-08 PST</option>
-											<option value="-7"<?php if ($pun_config['o_default_timezone'] == -7 ) echo ' selected="selected"' ?>>-07 MST</option>
-											<option value="-6"<?php if ($pun_config['o_default_timezone'] == -6 ) echo ' selected="selected"' ?>>-06 CST</option>
-											<option value="-5"<?php if ($pun_config['o_default_timezone'] == -5 ) echo ' selected="selected"' ?>>-05 EST</option>
-											<option value="-4"<?php if ($pun_config['o_default_timezone'] == -4 ) echo ' selected="selected"' ?>>-04 AST</option>
-											<option value="-3.5"<?php if ($pun_config['o_default_timezone'] == -3.5) echo ' selected="selected"' ?>>-03.5</option>
-											<option value="-3"<?php if ($pun_config['o_default_timezone'] == -3 ) echo ' selected="selected"' ?>>-03 ADT</option>
-											<option value="-2"<?php if ($pun_config['o_default_timezone'] == -2 ) echo ' selected="selected"' ?>>-02</option>
-											<option value="-1"<?php if ($pun_config['o_default_timezone'] == -1) echo ' selected="selected"' ?>>-01</option>
-											<option value="0"<?php if ($pun_config['o_default_timezone'] == 0) echo ' selected="selected"' ?>>00 GMT</option>
-											<option value="1"<?php if ($pun_config['o_default_timezone'] == 1) echo ' selected="selected"' ?>>+01 CET</option>
-											<option value="2"<?php if ($pun_config['o_default_timezone'] == 2 ) echo ' selected="selected"' ?>>+02</option>
-											<option value="3"<?php if ($pun_config['o_default_timezone'] == 3 ) echo ' selected="selected"' ?>>+03</option>
-											<option value="3.5"<?php if ($pun_config['o_default_timezone'] == 3.5) echo ' selected="selected"' ?>>+03.5</option>
-											<option value="4"<?php if ($pun_config['o_default_timezone'] == 4 ) echo ' selected="selected"' ?>>+04</option>
-											<option value="4.5"<?php if ($pun_config['o_default_timezone'] == 4.5) echo ' selected="selected"' ?>>+04.5</option>
-											<option value="5"<?php if ($pun_config['o_default_timezone'] == 5 ) echo ' selected="selected"' ?>>+05</option>
-											<option value="5.5"<?php if ($pun_config['o_default_timezone'] == 5.5) echo ' selected="selected"' ?>>+05.5</option>
-											<option value="6"<?php if ($pun_config['o_default_timezone'] == 6 ) echo ' selected="selected"' ?>>+06</option>
-											<option value="6.5"<?php if ($pun_config['o_default_timezone'] == 6.5) echo ' selected="selected"' ?>>+06.5</option>
-											<option value="7"<?php if ($pun_config['o_default_timezone'] == 7 ) echo ' selected="selected"' ?>>+07</option>
-											<option value="8"<?php if ($pun_config['o_default_timezone'] == 8 ) echo ' selected="selected"' ?>>+08</option>
-											<option value="9"<?php if ($pun_config['o_default_timezone'] == 9 ) echo ' selected="selected"' ?>>+09</option>
-											<option value="9.5"<?php if ($pun_config['o_default_timezone'] == 9.5) echo ' selected="selected"' ?>>+09.5</option>
-											<option value="10"<?php if ($pun_config['o_default_timezone'] == 10) echo ' selected="selected"' ?>>+10</option>
-											<option value="10.5"<?php if ($pun_config['o_default_timezone'] == 10.5) echo ' selected="selected"' ?>>+10.5</option>
-											<option value="11"<?php if ($pun_config['o_default_timezone'] == 11) echo ' selected="selected"' ?>>+11</option>
-											<option value="11.5"<?php if ($pun_config['o_default_timezone'] == 11.5) echo ' selected="selected"' ?>>+11.5</option>
-											<option value="12"<?php if ($pun_config['o_default_timezone'] == 12 ) echo ' selected="selected"' ?>>+12</option>
-											<option value="13"<?php if ($pun_config['o_default_timezone'] == 13 ) echo ' selected="selected"' ?>>+13</option>
+											<option value="-12"<?php if ($pun_config['o_default_timezone'] == -12) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-12:00'] ?></option>
+											<option value="-11"<?php if ($pun_config['o_default_timezone'] == -11) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-11:00'] ?></option>
+											<option value="-10"<?php if ($pun_config['o_default_timezone'] == -10) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-10:00'] ?></option>
+											<option value="-9.5"<?php if ($pun_config['o_default_timezone'] == -9.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-09:30'] ?></option>
+											<option value="-9"<?php if ($pun_config['o_default_timezone'] == -9) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-09:00'] ?></option>
+											<option value="-8.5"<?php if ($pun_config['o_default_timezone'] == -8.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-08:30'] ?></option>
+											<option value="-8"<?php if ($pun_config['o_default_timezone'] == -8) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-08:00'] ?></option>
+											<option value="-7"<?php if ($pun_config['o_default_timezone'] == -7) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-07:00'] ?></option>
+											<option value="-6"<?php if ($pun_config['o_default_timezone'] == -6) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-06:00'] ?></option>
+											<option value="-5"<?php if ($pun_config['o_default_timezone'] == -5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-05:00'] ?></option>
+											<option value="-4"<?php if ($pun_config['o_default_timezone'] == -4) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-04:00'] ?></option>
+											<option value="-3.5"<?php if ($pun_config['o_default_timezone'] == -3.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-03:30'] ?></option>
+											<option value="-3"<?php if ($pun_config['o_default_timezone'] == -3) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-03:00'] ?></option>
+											<option value="-2"<?php if ($pun_config['o_default_timezone'] == -2) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-02:00'] ?></option>
+											<option value="-1"<?php if ($pun_config['o_default_timezone'] == -1) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC-01:00'] ?></option>
+											<option value="0"<?php if ($pun_config['o_default_timezone'] == 0) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC'] ?></option>
+											<option value="1"<?php if ($pun_config['o_default_timezone'] == 1) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+01:00'] ?></option>
+											<option value="2"<?php if ($pun_config['o_default_timezone'] == 2) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+02:00'] ?></option>
+											<option value="3"<?php if ($pun_config['o_default_timezone'] == 3) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+03:00'] ?></option>
+											<option value="3.5"<?php if ($pun_config['o_default_timezone'] == 3.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+03:30'] ?></option>
+											<option value="4"<?php if ($pun_config['o_default_timezone'] == 4) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+04:00'] ?></option>
+											<option value="4.5"<?php if ($pun_config['o_default_timezone'] == 4.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+04:30'] ?></option>
+											<option value="5"<?php if ($pun_config['o_default_timezone'] == 5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+05:00'] ?></option>
+											<option value="5.5"<?php if ($pun_config['o_default_timezone'] == 5.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+05:30'] ?></option>
+											<option value="5.75"<?php if ($pun_config['o_default_timezone'] == 5.75) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+05:45'] ?></option>
+											<option value="6"<?php if ($pun_config['o_default_timezone'] == 6) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+06:00'] ?></option>
+											<option value="6.5"<?php if ($pun_config['o_default_timezone'] == 6.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+06:30'] ?></option>
+											<option value="7"<?php if ($pun_config['o_default_timezone'] == 7) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+07:00'] ?></option>
+											<option value="8"<?php if ($pun_config['o_default_timezone'] == 8) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+08:00'] ?></option>
+											<option value="8.75"<?php if ($pun_config['o_default_timezone'] == 8.75) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+08:45'] ?></option>
+											<option value="9"<?php if ($pun_config['o_default_timezone'] == 9) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+09:00'] ?></option>
+											<option value="9.5"<?php if ($pun_config['o_default_timezone'] == 9.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+09:30'] ?></option>
+											<option value="10"<?php if ($pun_config['o_default_timezone'] == 10) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+10:00'] ?></option>
+											<option value="10.5"<?php if ($pun_config['o_default_timezone'] == 10.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+10:30'] ?></option>
+											<option value="11"<?php if ($pun_config['o_default_timezone'] == 11) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+11:00'] ?></option>
+											<option value="11.5"<?php if ($pun_config['o_default_timezone'] == 11.5) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+11:30'] ?></option>
+											<option value="12"<?php if ($pun_config['o_default_timezone'] == 12) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+12:00'] ?></option>
+											<option value="12.75"<?php if ($pun_config['o_default_timezone'] == 12.75) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+12:45'] ?></option>
+											<option value="13"<?php if ($pun_config['o_default_timezone'] == 13) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+13:00'] ?></option>
+											<option value="14"<?php if ($pun_config['o_default_timezone'] == 14) echo ' selected="selected"' ?>><?php echo $lang_admin_options['UTC+14:00'] ?></option>
 										</select>
-										<span>The default timezone for guests and users attempting to register for the board.</span>
+										<span><?php echo $lang_admin_options['Timezone help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Adjust for DST</th>
+									<th scope="row"><?php echo $lang_admin_options['DST label'] ?></th>
 									<td>
-										<input type="radio" name="form[default_dst]" value="1"<?php if ($pun_config['o_default_dst'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[default_dst]" value="0"<?php if ($pun_config['o_default_dst'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Check if daylight savings is in effect (advances times by 1 hour).</span>
+										<input type="radio" name="form[default_dst]" value="1"<?php if ($pun_config['o_default_dst'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[default_dst]" value="0"<?php if ($pun_config['o_default_dst'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['DST help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Default language</th>
+									<th scope="row"><?php echo $lang_admin_options['Language label'] ?></th>
 									<td>
 										<select name="form[default_lang]">
 <?php
@@ -244,14 +299,14 @@ generate_admin_menu('options');
 		$d = dir(PUN_ROOT.'lang');
 		while (($entry = $d->read()) !== false)
 		{
-			if ($entry != '.' && $entry != '..' && is_dir(PUN_ROOT.'lang/'.$entry) && file_exists(PUN_ROOT.'lang/'.$entry.'/common.php'))
+			if ($entry{0} != '.' && is_dir(PUN_ROOT.'lang/'.$entry) && file_exists(PUN_ROOT.'lang/'.$entry.'/common.php'))
 				$languages[] = $entry;
 		}
 		$d->close();
 
 		@natsort($languages);
 
-		while (list(, $temp) = @each($languages))
+		foreach ($languages as $temp)
 		{
 			if ($pun_config['o_default_lang'] == $temp)
 				echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.$temp.'</option>'."\n";
@@ -261,11 +316,11 @@ generate_admin_menu('options');
 
 ?>
 										</select>
-										<span>This is the default language style used if the visitor is a guest or a user that hasn't changed from the default in his/her profile. If you remove a language pack, this must be updated.</span>
+										<span><?php echo $lang_admin_options['Language help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Default style</th>
+									<th scope="row"><?php echo $lang_admin_options['Default style label'] ?></th>
 									<td>
 										<select name="form[default_style]">
 <?php
@@ -281,17 +336,18 @@ generate_admin_menu('options');
 
 		@natsort($styles);
 
-		while (list(, $temp) = @each($styles))
+		foreach ($styles as $temp)
 		{
 			if ($pun_config['o_default_style'] == $temp)
-				echo "\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.str_replace('_', ' ', $temp).'</option>'."\n";
+				echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.str_replace('_', ' ', $temp).'</option>'."\n";
 			else
-				echo "\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'">'.str_replace('_', ' ', $temp).'</option>'."\n";
+				echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'">'.str_replace('_', ' ', $temp).'</option>'."\n";
 		}
 
 ?>
 										</select>
-										<span>This is the default style used for guests and users who haven't changed from the default in their profile.</span></td>
+										<span><?php echo $lang_admin_options['Default style help'] ?></span>
+									</td>
 								</tr>
 							</table>
 						</div>
@@ -299,42 +355,42 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Time and timeouts</legend>
+						<legend><?php echo $lang_admin_options['Timeouts subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Time format</th>
+									<th scope="row"><?php echo $lang_admin_options['Time format label'] ?></th>
 									<td>
 										<input type="text" name="form[time_format]" size="25" maxlength="25" value="<?php echo pun_htmlspecialchars($pun_config['o_time_format']) ?>" />
-										<span>[Current format: <?php echo date($pun_config['o_time_format']) ?>]&nbsp;See <a href="http://www.php.net/manual/en/function.date.php">here</a> for formatting options.</span>
+										<span><?php printf($lang_admin_options['Time format help'], date($pun_config['o_time_format']), '<a href="http://www.php.net/manual/en/function.date.php">'.$lang_admin_options['PHP manual'].'</a>') ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Date format</th>
+									<th scope="row"><?php echo $lang_admin_options['Date format label'] ?></th>
 									<td>
 										<input type="text" name="form[date_format]" size="25" maxlength="25" value="<?php echo pun_htmlspecialchars($pun_config['o_date_format']) ?>" />
-										<span>[Current format: <?php echo date($pun_config['o_date_format']) ?>]&nbsp;See <a href="http://www.php.net/manual/en/function.date.php">here</a> for formatting options.</span>
+										<span><?php printf($lang_admin_options['Date format help'], date($pun_config['o_date_format']), '<a href="http://www.php.net/manual/en/function.date.php">'.$lang_admin_options['PHP manual'].'</a>') ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Visit timeout</th>
+									<th scope="row"><?php echo $lang_admin_options['Visit timeout label'] ?></th>
 									<td>
 										<input type="text" name="form[timeout_visit]" size="5" maxlength="5" value="<?php echo $pun_config['o_timeout_visit'] ?>" />
-										<span>Number of seconds a user must be idle before his/hers last visit data is updated (primarily affects new message indicators).</span>
+										<span><?php echo $lang_admin_options['Visit timeout help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Online timeout</th>
+									<th scope="row"><?php echo $lang_admin_options['Online timeout label'] ?></th>
 									<td>
 										<input type="text" name="form[timeout_online]" size="5" maxlength="5" value="<?php echo $pun_config['o_timeout_online'] ?>" />
-										<span>Number of seconds a user must be idle before being removed from the online users list.</span>
+										<span><?php echo $lang_admin_options['Online timeout help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Redirect time</th>
+									<th scope="row"><?php echo $lang_admin_options['Redirect time label'] ?></th>
 									<td>
 										<input type="text" name="form[redirect_delay]" size="3" maxlength="3" value="<?php echo $pun_config['o_redirect_delay'] ?>" />
-										<span>Number of seconds to wait when redirecting. If set to 0, no redirect page will be displayed (not recommended).</span>
+										<span><?php echo $lang_admin_options['Redirect time help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -343,77 +399,84 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Display</legend>
+						<legend><?php echo $lang_admin_options['Display subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Version number</th>
+									<th scope="row"><?php echo $lang_admin_options['Version number label'] ?></th>
 									<td>
-										<input type="radio" name="form[show_version]" value="1"<?php if ($pun_config['o_show_version'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[show_version]" value="0"<?php if ($pun_config['o_show_version'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Show version number in footer.</span>
+										<input type="radio" name="form[show_version]" value="1"<?php if ($pun_config['o_show_version'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[show_version]" value="0"<?php if ($pun_config['o_show_version'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Version number help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">User info in posts</th>
+									<th scope="row"><?php echo $lang_admin_options['Info in posts label'] ?></th>
 									<td>
-										<input type="radio" name="form[show_user_info]" value="1"<?php if ($pun_config['o_show_user_info'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[show_user_info]" value="0"<?php if ($pun_config['o_show_user_info'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Show information about the poster under the username in topic view. The information affected is location, register date, post count and the contact links (e-mail and URL).</span>
+										<input type="radio" name="form[show_user_info]" value="1"<?php if ($pun_config['o_show_user_info'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[show_user_info]" value="0"<?php if ($pun_config['o_show_user_info'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Info in posts help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">User post count</th>
+									<th scope="row"><?php echo $lang_admin_options['Post count label'] ?></th>
 									<td>
-										<input type="radio" name="form[show_post_count]" value="1"<?php if ($pun_config['o_show_post_count'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[show_post_count]" value="0"<?php if ($pun_config['o_show_post_count'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Show the number of posts a user has made (affects topic view, profile and userlist).</span>
+										<input type="radio" name="form[show_post_count]" value="1"<?php if ($pun_config['o_show_post_count'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[show_post_count]" value="0"<?php if ($pun_config['o_show_post_count'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Post count help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Smilies</th>
+									<th scope="row"><?php echo $lang_admin_options['Smilies label'] ?></th>
 									<td>
-										<input type="radio" name="form[smilies]" value="1"<?php if ($pun_config['o_smilies'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[smilies]" value="0"<?php if ($pun_config['o_smilies'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Convert smilies to small icons.</span>
+										<input type="radio" name="form[smilies]" value="1"<?php if ($pun_config['o_smilies'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[smilies]" value="0"<?php if ($pun_config['o_smilies'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Smilies help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Smilies in signatures</th>
+									<th scope="row"><?php echo $lang_admin_options['Smilies sigs label'] ?></th>
 									<td>
-										<input type="radio" name="form[smilies_sig]" value="1"<?php if ($pun_config['o_smilies_sig'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[smilies_sig]" value="0"<?php if ($pun_config['o_smilies_sig'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Convert smilies to small icons in user signatures.</span>
+										<input type="radio" name="form[smilies_sig]" value="1"<?php if ($pun_config['o_smilies_sig'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[smilies_sig]" value="0"<?php if ($pun_config['o_smilies_sig'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Smilies sigs help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Make clickable links</th>
+									<th scope="row"><?php echo $lang_admin_options['Clickable links label'] ?></th>
 									<td>
-										<input type="radio" name="form[make_links]" value="1"<?php if ($pun_config['o_make_links'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[make_links]" value="0"<?php if ($pun_config['o_make_links'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>When enabled, FluxBB will automatically detect any URLs in posts and make them clickable hyperlinks.</span>
+										<input type="radio" name="form[make_links]" value="1"<?php if ($pun_config['o_make_links'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[make_links]" value="0"<?php if ($pun_config['o_make_links'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Clickable links help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Topic review</th>
+									<th scope="row"><?php echo $lang_admin_options['Topic review label'] ?></th>
 									<td>
 										<input type="text" name="form[topic_review]" size="3" maxlength="3" value="<?php echo $pun_config['o_topic_review'] ?>" />
-										<span>Maximum number of posts to display when posting (newest first). 0 to disable.</span>
+										<span><?php echo $lang_admin_options['Topic review help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Topics per page default</th>
+									<th scope="row"><?php echo $lang_admin_options['Topics per page label'] ?></th>
 									<td>
 										<input type="text" name="form[disp_topics_default]" size="3" maxlength="3" value="<?php echo $pun_config['o_disp_topics_default'] ?>" />
-										<span>The default number of topics to display per page in a forum. Users can personalize this setting.</span>
+										<span><?php echo $lang_admin_options['Topics per page help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Posts per page default</th>
+									<th scope="row"><?php echo $lang_admin_options['Posts per page label'] ?></th>
 									<td>
 										<input type="text" name="form[disp_posts_default]" size="3" maxlength="3" value="<?php echo $pun_config['o_disp_posts_default'] ?>" />
-										<span>The default number of posts to display per page in a topic. Users can personalize this setting.</span>
+										<span><?php echo $lang_admin_options['Posts per page help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Indent size</th>
+									<th scope="row"><?php echo $lang_admin_options['Indent label'] ?></th>
 									<td>
 										<input type="text" name="form[indent_num_spaces]" size="3" maxlength="3" value="<?php echo $pun_config['o_indent_num_spaces'] ?>" />
-										<span>If set to 8, a regular tab will be used when displaying text within the [code][/code] tag. Otherwise this many spaces will be used to indent the text.</span>
+										<span><?php echo $lang_admin_options['Indent help'] ?></span>
+									</td>
+								</tr>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_options['Quote depth label'] ?></th>
+									<td>
+										<input type="text" name="form[quote_depth]" size="3" maxlength="3" value="<?php echo $pun_config['o_quote_depth'] ?>" />
+										<span><?php echo $lang_admin_options['Quote depth help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -422,84 +485,91 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Features</legend>
+						<legend><?php echo $lang_admin_options['Features subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Quick post</th>
+									<th scope="row"><?php echo $lang_admin_options['Quick post label'] ?></th>
 									<td>
-										<input type="radio" name="form[quickpost]" value="1"<?php if ($pun_config['o_quickpost'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[quickpost]" value="0"<?php if ($pun_config['o_quickpost'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>When enabled, FluxBB will add a quick post form at the bottom of topics. This way users can post directly from the topic view.</span>
+										<input type="radio" name="form[quickpost]" value="1"<?php if ($pun_config['o_quickpost'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[quickpost]" value="0"<?php if ($pun_config['o_quickpost'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Quick post help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Users online</th>
+									<th scope="row"><?php echo $lang_admin_options['Users online label'] ?></th>
 									<td>
-										<input type="radio" name="form[users_online]" value="1"<?php if ($pun_config['o_users_online'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[users_online]" value="0"<?php if ($pun_config['o_users_online'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Display info on the index page about guests and registered users currently browsing the forums.</span>
+										<input type="radio" name="form[users_online]" value="1"<?php if ($pun_config['o_users_online'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[users_online]" value="0"<?php if ($pun_config['o_users_online'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Users online help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row"><a name="censoring">Censor words</a></th>
+									<th scope="row"><a name="censoring"><?php echo $lang_admin_options['Censor words label'] ?></a></th>
 									<td>
-										<input type="radio" name="form[censoring]" value="1"<?php if ($pun_config['o_censoring'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[censoring]" value="0"<?php if ($pun_config['o_censoring'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Enable this to censor specific words in the forum. See <a href="admin_censoring.php">Censoring</a> for more info.</span>
+										<input type="radio" name="form[censoring]" value="1"<?php if ($pun_config['o_censoring'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[censoring]" value="0"<?php if ($pun_config['o_censoring'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php printf($lang_admin_options['Censor words help'], '<a href="admin_censoring.php">'.$lang_admin_common['Censoring'].'</a>') ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row"><a name="signatures">Signatures</a></th>
+									<th scope="row"><a name="signatures"><?php echo $lang_admin_options['Signatures label'] ?></a></th>
 									<td>
-										<input type="radio" name="form[signatures]" value="1"<?php if ($pun_config['o_signatures'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[signatures]" value="0"<?php if ($pun_config['o_signatures'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow users to attach a signature to their posts.</span>
+										<input type="radio" name="form[signatures]" value="1"<?php if ($pun_config['o_signatures'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[signatures]" value="0"<?php if ($pun_config['o_signatures'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Signatures help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row"><a name="ranks">User ranks</a></th>
+									<th scope="row"><a name="ranks"><?php echo $lang_admin_options['User ranks label'] ?></a></th>
 									<td>
-										<input type="radio" name="form[ranks]" value="1"<?php if ($pun_config['o_ranks'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[ranks]" value="0"<?php if ($pun_config['o_ranks'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Enable this to use user ranks. See <a href="admin_ranks.php">Ranks</a> for more info.</span>
+										<input type="radio" name="form[ranks]" value="1"<?php if ($pun_config['o_ranks'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[ranks]" value="0"<?php if ($pun_config['o_ranks'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php printf($lang_admin_options['User ranks help'], '<a href="admin_ranks.php">'.$lang_admin_common['Ranks'].'</a>') ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">User has posted earlier</th>
+									<th scope="row"><?php echo $lang_admin_options['User has posted label'] ?></th>
 									<td>
-										<input type="radio" name="form[show_dot]" value="1"<?php if ($pun_config['o_show_dot'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[show_dot]" value="0"<?php if ($pun_config['o_show_dot'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>This feature displays a dot in front of topics in viewforum.php in case the currently logged in user has posted in that topic earlier. Disable if you are experiencing high server load.</span>
+										<input type="radio" name="form[show_dot]" value="1"<?php if ($pun_config['o_show_dot'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[show_dot]" value="0"<?php if ($pun_config['o_show_dot'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['User has posted help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Topic views</th>
+									<th scope="row"><?php echo $lang_admin_options['Topic views label'] ?></th>
 									<td>
-										<input type="radio" name="form[topic_views]" value="1"<?php if ($pun_config['o_topic_views'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[topic_views]" value="0"<?php if ($pun_config['o_topic_views'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Keep track of the number of views a topic has. Disable if you are experiencing high server load in a busy forum.</span>
+										<input type="radio" name="form[topic_views]" value="1"<?php if ($pun_config['o_topic_views'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[topic_views]" value="0"<?php if ($pun_config['o_topic_views'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Topic views help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Quick jump</th>
+									<th scope="row"><?php echo $lang_admin_options['Quick jump label'] ?></th>
 									<td>
-										<input type="radio" name="form[quickjump]" value="1"<?php if ($pun_config['o_quickjump'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[quickjump]" value="0"<?php if ($pun_config['o_quickjump'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Enable the quick jump (jump to forum) drop list.</span>
+										<input type="radio" name="form[quickjump]" value="1"<?php if ($pun_config['o_quickjump'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[quickjump]" value="0"<?php if ($pun_config['o_quickjump'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Quick jump help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">GZip output</th>
+									<th scope="row"><?php echo $lang_admin_options['GZip label'] ?></th>
 									<td>
-										<input type="radio" name="form[gzip]" value="1"<?php if ($pun_config['o_gzip'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[gzip]" value="0"<?php if ($pun_config['o_gzip'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>If enabled, FluxBB will gzip the output sent to browsers. This will reduce bandwidth usage, but use a little more CPU. This feature requires that PHP is configured with zlib (--with-zlib). Note: If you already have one of the Apache modules mod_gzip or mod_deflate set up to compress PHP scripts, you should disable this feature.</span>
+										<input type="radio" name="form[gzip]" value="1"<?php if ($pun_config['o_gzip'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[gzip]" value="0"<?php if ($pun_config['o_gzip'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['GZip help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Search all forums</th>
+									<th scope="row"><?php echo $lang_admin_options['Search all label'] ?></th>
 									<td>
-										<input type="radio" name="form[search_all_forums]" value="1"<?php if ($pun_config['o_search_all_forums'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[search_all_forums]" value="0"<?php if ($pun_config['o_search_all_forums'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>When disabled, searches will only be allowed in one forum at a time. Disable if server load is high due to excessive searching.</span>
+										<input type="radio" name="form[search_all_forums]" value="1"<?php if ($pun_config['o_search_all_forums'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[search_all_forums]" value="0"<?php if ($pun_config['o_search_all_forums'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Search all help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Additional menu items</th>
+									<th scope="row"><?php echo $lang_admin_options['Menu items label'] ?></th>
 									<td>
 										<textarea name="form[additional_navlinks]" rows="3" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_additional_navlinks']) ?></textarea>
-										<span>By entering HTML hyperlinks into this textbox, any number of items can be added to the navigation menu at the top of all pages. The format for adding new links is X = &lt;a href="URL"&gt;LINK&lt;/a&gt; where X is the position at which the link should be inserted (e.g. 0 to insert at the beginning and 2 to insert after "User list"). Separate entries with a linebreak.</span>
+										<span><?php echo $lang_admin_options['Menu items help'] ?></span>
+									</td>
+								</tr>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_options['Default feed label'] ?></th>
+									<td>
+										<input type="radio" name="form[feed_type]" value="0"<?php if ($pun_config['o_feed_type'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_options['None'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[feed_type]" value="1"<?php if ($pun_config['o_feed_type'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_options['RSS'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[feed_type]" value="2"<?php if ($pun_config['o_feed_type'] == '2') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_options['Atom'] ?></strong>
+										<span><?php echo $lang_admin_options['Default feed help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -508,21 +578,21 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Reports</legend>
+						<legend><?php echo $lang_admin_options['Reports subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Report method</th>
+									<th scope="row"><?php echo $lang_admin_options['Reporting method label'] ?></th>
 									<td>
-										<input type="radio" name="form[report_method]" value="0"<?php if ($pun_config['o_report_method'] == '0') echo ' checked="checked"' ?> />&nbsp;Internal&nbsp;&nbsp;&nbsp;<input type="radio" name="form[report_method]" value="1"<?php if ($pun_config['o_report_method'] == '1') echo ' checked="checked"' ?> />&nbsp;E-mail&nbsp;&nbsp;&nbsp;<input type="radio" name="form[report_method]" value="2"<?php if ($pun_config['o_report_method'] == '2') echo ' checked="checked"' ?> />&nbsp;Both
-										<span>Select the method for handling topic/post reports. You can choose whether topic/post reports should be handled by the internal report system,  e-mailed to the addresses on the mailing list (see below) or both.</span>
+										<input type="radio" name="form[report_method]" value="0"<?php if ($pun_config['o_report_method'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_options['Internal'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[report_method]" value="1"<?php if ($pun_config['o_report_method'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_options['By e-mail'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[report_method]" value="2"<?php if ($pun_config['o_report_method'] == '2') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_options['Both'] ?></strong>
+										<span><?php echo $lang_admin_options['Reporting method help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Mailing list</th>
+									<th scope="row"><?php echo $lang_admin_options['Mailing list label'] ?></th>
 									<td>
 										<textarea name="form[mailing_list]" rows="5" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_mailing_list']) ?></textarea>
-										<span>A comma separated list of subscribers. The people on this list are the recipients of reports.</span>
+										<span><?php echo $lang_admin_options['Mailing list help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -531,42 +601,42 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Avatars</legend>
+						<legend><?php echo $lang_admin_options['Avatars subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Use avatars</th>
+									<th scope="row"><?php echo $lang_admin_options['Use avatars label'] ?></th>
 									<td>
-										<input type="radio" name="form[avatars]" value="1"<?php if ($pun_config['o_avatars'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[avatars]" value="0"<?php if ($pun_config['o_avatars'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>When enabled, users will be able to upload an avatar which will be displayed under their title/rank.</span>
+										<input type="radio" name="form[avatars]" value="1"<?php if ($pun_config['o_avatars'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[avatars]" value="0"<?php if ($pun_config['o_avatars'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Use avatars help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Upload directory</th>
+									<th scope="row"><?php echo $lang_admin_options['Upload directory label'] ?></th>
 									<td>
 										<input type="text" name="form[avatars_dir]" size="35" maxlength="50" value="<?php echo pun_htmlspecialchars($pun_config['o_avatars_dir']) ?>" />
-										<span>The upload directory for avatars (relative to the FluxBB root directory). PHP must have write permissions to this directory.</span>
+										<span><?php echo $lang_admin_options['Upload directory help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Max width</th>
+									<th scope="row"><?php echo $lang_admin_options['Max width label'] ?></th>
 									<td>
 										<input type="text" name="form[avatars_width]" size="5" maxlength="5" value="<?php echo $pun_config['o_avatars_width'] ?>" />
-										<span>The maximum allowed width of avatars in pixels (60 is recommended).</span>
+										<span><?php echo $lang_admin_options['Max width help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Max height</th>
+									<th scope="row"><?php echo $lang_admin_options['Max height label'] ?></th>
 									<td>
 										<input type="text" name="form[avatars_height]" size="5" maxlength="5" value="<?php echo $pun_config['o_avatars_height'] ?>" />
-										<span>The maximum allowed height of avatars in pixels (60 is recommended).</span>
+										<span><?php echo $lang_admin_options['Max height help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Max size</th>
+									<th scope="row"><?php echo $lang_admin_options['Max size label'] ?></th>
 									<td>
 										<input type="text" name="form[avatars_size]" size="6" maxlength="6" value="<?php echo $pun_config['o_avatars_size'] ?>" />
-										<span>The maximum allowed size of avatars in bytes (10240 is recommended).</span>
+										<span><?php echo $lang_admin_options['Max size help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -575,56 +645,56 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>E-mail</legend>
+						<legend><?php echo $lang_admin_options['E-mail subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Admin e-mail</th>
+									<th scope="row"><?php echo $lang_admin_options['Admin e-mail label'] ?></th>
 									<td>
-										<input type="text" name="form[admin_email]" size="50" maxlength="50" value="<?php echo $pun_config['o_admin_email'] ?>" />
-										<span>The e-mail address of the forum administrator.</span>
+										<input type="text" name="form[admin_email]" size="50" maxlength="80" value="<?php echo $pun_config['o_admin_email'] ?>" />
+										<span><?php echo $lang_admin_options['Admin e-mail help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Webmaster e-mail</th>
+									<th scope="row"><?php echo $lang_admin_options['Webmaster e-mail label'] ?></th>
 									<td>
-										<input type="text" name="form[webmaster_email]" size="50" maxlength="50" value="<?php echo $pun_config['o_webmaster_email'] ?>" />
-										<span>This is the address that all e-mails sent by the forum will be addressed from.</span>
+										<input type="text" name="form[webmaster_email]" size="50" maxlength="80" value="<?php echo $pun_config['o_webmaster_email'] ?>" />
+										<span><?php echo $lang_admin_options['Webmaster e-mail help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Subscriptions</th>
+									<th scope="row"><?php echo $lang_admin_options['Subscriptions label'] ?></th>
 									<td>
-										<input type="radio" name="form[subscriptions]" value="1"<?php if ($pun_config['o_subscriptions'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[subscriptions]" value="0"<?php if ($pun_config['o_subscriptions'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Enable users to subscribe to topics (receive e-mail when someone replies).</span>
+										<input type="radio" name="form[subscriptions]" value="1"<?php if ($pun_config['o_subscriptions'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[subscriptions]" value="0"<?php if ($pun_config['o_subscriptions'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Subscriptions help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">SMTP server address</th>
+									<th scope="row"><?php echo $lang_admin_options['SMTP address label'] ?></th>
 									<td>
 										<input type="text" name="form[smtp_host]" size="30" maxlength="100" value="<?php echo pun_htmlspecialchars($pun_config['o_smtp_host']) ?>" />
-										<span>The address of an external SMTP server to send e-mails with. You can specify a custom port number if the SMTP server doesn't run on the default port 25 (example: mail.myhost.com:3580). Leave blank to use the local mail program.</span>
+										<span><?php echo $lang_admin_options['SMTP address help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">SMTP username</th>
+									<th scope="row"><?php echo $lang_admin_options['SMTP username label'] ?></th>
 									<td>
 										<input type="text" name="form[smtp_user]" size="25" maxlength="50" value="<?php echo pun_htmlspecialchars($pun_config['o_smtp_user']) ?>" />
-										<span>Username for SMTP server. Only enter a username if it is required by the SMTP server (most servers <strong>do not</strong> require authentication).</span>
+										<span><?php echo $lang_admin_options['SMTP username help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">SMTP password</th>
+									<th scope="row"><?php echo $lang_admin_options['SMTP password label'] ?></th>
 									<td>
 										<input type="text" name="form[smtp_pass]" size="25" maxlength="50" value="<?php echo pun_htmlspecialchars($pun_config['o_smtp_pass']) ?>" />
-										<span>Password for SMTP server. Only enter a password if it is required by the SMTP server (most servers <strong>do not</strong> require authentication).</span>
+										<span><?php echo $lang_admin_options['SMTP password help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Encrypt SMTP using SSL</th>
+									<th scope="row"><?php echo $lang_admin_options['SMTP SSL label'] ?></th>
 									<td>
-										<input type="radio" name="form[smtp_ssl]" value="1"<?php if ($pun_config['o_smtp_ssl'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[smtp_ssl]" value="0"<?php if ($pun_config['o_smtp_ssl'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Encrypts the connection to the SMTP server using SSL. Should only be used if your SMTP server requires it and your version of PHP supports SSL.</span>
+										<input type="radio" name="form[smtp_ssl]" value="1"<?php if ($pun_config['o_smtp_ssl'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[smtp_ssl]" value="0"<?php if ($pun_config['o_smtp_ssl'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['SMTP SSL help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -633,51 +703,51 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Registration</legend>
+						<legend><?php echo $lang_admin_options['Registration subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Allow new registrations</th>
+									<th scope="row"><?php echo $lang_admin_options['Allow new label'] ?></th>
 									<td>
-										<input type="radio" name="form[regs_allow]" value="1"<?php if ($pun_config['o_regs_allow'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[regs_allow]" value="0"<?php if ($pun_config['o_regs_allow'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Controls whether this forum accepts new registrations. Disable only under special circumstances.</span>
+										<input type="radio" name="form[regs_allow]" value="1"<?php if ($pun_config['o_regs_allow'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[regs_allow]" value="0"<?php if ($pun_config['o_regs_allow'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Allow new help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Verify registrations</th>
+									<th scope="row"><?php echo $lang_admin_options['Verify label'] ?></th>
 									<td>
-										<input type="radio" name="form[regs_verify]" value="1"<?php if ($pun_config['o_regs_verify'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[regs_verify]" value="0"<?php if ($pun_config['o_regs_verify'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>When enabled, users are e-mailed a random password when they register. They can then log in and change the password in their profile if they see fit. This feature also requires users to verify new e-mail addresses if they choose to change from the one they registered with. This is an effective way of avoiding registration abuse and making sure that all users have "correct" e-mail addresses in their profiles.</span>
+										<input type="radio" name="form[regs_verify]" value="1"<?php if ($pun_config['o_regs_verify'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[regs_verify]" value="0"<?php if ($pun_config['o_regs_verify'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Verify help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Report new registrations</th>
+									<th scope="row"><?php echo $lang_admin_options['Report new label'] ?></th>
 									<td>
-										<input type="radio" name="form[regs_report]" value="1"<?php if ($pun_config['o_regs_report'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[regs_report]" value="0"<?php if ($pun_config['o_regs_report'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>If enabled, FluxBB will notify users on the mailing list (see below) when a new user registers in the forums.</span>
+										<input type="radio" name="form[regs_report]" value="1"<?php if ($pun_config['o_regs_report'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[regs_report]" value="0"<?php if ($pun_config['o_regs_report'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Report new help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Use forum rules</th>
+									<th scope="row"><?php echo $lang_admin_options['Use rules label'] ?></th>
 									<td>
-										<input type="radio" name="form[rules]" value="1"<?php if ($pun_config['o_rules'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[rules]" value="0"<?php if ($pun_config['o_rules'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>When enabled, users must agree to a set of rules when registering (enter text below). The rules will always be available through a link in the navigation table at the top of every page.</span>
+										<input type="radio" name="form[rules]" value="1"<?php if ($pun_config['o_rules'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[rules]" value="0"<?php if ($pun_config['o_rules'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Use rules help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Rules</th>
+									<th scope="row"><?php echo $lang_admin_options['Rules label'] ?></th>
 									<td>
 										<textarea name="form[rules_message]" rows="10" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_rules_message']) ?></textarea>
-										<span>Here you can enter any rules or other information that the user must review and accept when registering. If you enabled rules above you have to enter something here, otherwise it will be disabled. This text will not be parsed like regular posts and thus may contain HTML.</span>
+										<span><?php echo $lang_admin_options['Rules help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Default e-mail setting</th>
+									<th scope="row"><?php echo $lang_admin_options['E-mail default label'] ?></th>
 									<td>
-										<span>Choose the default privacy setting for new user registrations.</span>
-										<input type="radio" name="form[default_email_setting]" value="0"<?php if ($pun_config['o_default_email_setting'] == '0') echo ' checked="checked"' ?> />&nbsp;Display e-mail address to other users.<br />
-										<input type="radio" name="form[default_email_setting]" value="1"<?php if ($pun_config['o_default_email_setting'] == '1') echo ' checked="checked"' ?> />&nbsp;Hide e-mail address but allow form e-mail.<br />
-										<input type="radio" name="form[default_email_setting]" value="2"<?php if ($pun_config['o_default_email_setting'] == '2') echo ' checked="checked"' ?> />&nbsp;Hide e-mail address and disallow form e-mail.<br />
+										<span><?php echo $lang_admin_options['E-mail default help'] ?></span>
+										<input type="radio" name="form[default_email_setting]" value="0"<?php if ($pun_config['o_default_email_setting'] == '0') echo ' checked="checked"' ?> />&nbsp;<?php echo $lang_admin_options['Display e-mail label'] ?><br />
+										<input type="radio" name="form[default_email_setting]" value="1"<?php if ($pun_config['o_default_email_setting'] == '1') echo ' checked="checked"' ?> />&nbsp;<?php echo $lang_admin_options['Hide allow form label'] ?><br />
+										<input type="radio" name="form[default_email_setting]" value="2"<?php if ($pun_config['o_default_email_setting'] == '2') echo ' checked="checked"' ?> />&nbsp;<?php echo $lang_admin_options['Hide both label'] ?><br />
 									</td>
 								</tr>
 							</table>
@@ -686,21 +756,21 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Announcement</legend>
+						<legend><?php echo $lang_admin_options['Announcement subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Display announcement</th>
+									<th scope="row"><?php echo $lang_admin_options['Display announcement label'] ?></th>
 									<td>
-										<input type="radio" name="form[announcement]" value="1"<?php if ($pun_config['o_announcement'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[announcement]" value="0"<?php if ($pun_config['o_announcement'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Enable this to display the below message in the forums.</span>
+										<input type="radio" name="form[announcement]" value="1"<?php if ($pun_config['o_announcement'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[announcement]" value="0"<?php if ($pun_config['o_announcement'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Display announcement help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Announcement message</th>
+									<th scope="row"><?php echo $lang_admin_options['Announcement message label'] ?></th>
 									<td>
 										<textarea name="form[announcement_message]" rows="5" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_announcement_message']) ?></textarea>
-										<span>This text will not be parsed like regular posts and thus may contain HTML.</span>
+										<span><?php echo $lang_admin_options['Announcement message help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -709,28 +779,28 @@ generate_admin_menu('options');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Maintenance</legend>
+						<legend><?php echo $lang_admin_options['Maintenance subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row"><a name="maintenance">Maintenance mode</a></th>
+									<th scope="row"><a name="maintenance"><?php echo $lang_admin_options['Maintenance mode label'] ?></a></th>
 									<td>
-										<input type="radio" name="form[maintenance]" value="1"<?php if ($pun_config['o_maintenance'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[maintenance]" value="0"<?php if ($pun_config['o_maintenance'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>When enabled, the board will only be available to administrators. This should be used if the board needs to taken down temporarily for maintenance. WARNING! Do not log out when the board is in maintenance mode. You will not be able to login again.</span>
+										<input type="radio" name="form[maintenance]" value="1"<?php if ($pun_config['o_maintenance'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[maintenance]" value="0"<?php if ($pun_config['o_maintenance'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_options['Maintenance mode help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Maintenance message</th>
+									<th scope="row"><?php echo $lang_admin_options['Maintenance message label'] ?></th>
 									<td>
 										<textarea name="form[maintenance_message]" rows="5" cols="55"><?php echo pun_htmlspecialchars($pun_config['o_maintenance_message']) ?></textarea>
-										<span>The message that will be displayed to users when the board is in maintenance mode. If left blank a default message will be used. This text will not be parsed like regular posts and thus may contain HTML.</span>
+										<span><?php echo $lang_admin_options['Maintenance message help'] ?></span>
 									</td>
 								</tr>
 							</table>
 						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="save" value="Save changes" /></p>
+				<p class="submitend"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
 			</form>
 		</div>
 	</div>
diff --git a/upload/admin_permissions.php b/upload/admin_permissions.php
index 3410130..6d4ab78 100644
--- a/upload/admin_permissions.php
+++ b/upload/admin_permissions.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,6 +17,8 @@ require PUN_ROOT.'include/common_admin.php';
 if ($pun_user['g_id'] != PUN_ADMIN)
 	message($lang_common['No permission']);
 
+// Load the admin_permissions.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_permissions.php';
 
 if (isset($_POST['form_sent']))
 {
@@ -54,59 +39,60 @@ if (isset($_POST['form_sent']))
 
 	generate_config_cache();
 
-	redirect('admin_permissions.php', 'Permissions updated. Redirecting &hellip;');
+	redirect('admin_permissions.php', $lang_admin_permissions['Perms updated redirect']);
 }
 
-
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Permissions';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Permissions']);
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
+
 generate_admin_menu('permissions');
 
 ?>
 	<div class="blockform">
-		<h2><span>Permissions</span></h2>
+		<h2><span><?php echo $lang_admin_permissions['Permissions head'] ?></span></h2>
 		<div class="box">
 			<form method="post" action="admin_permissions.php">
-				<p class="submittop"><input type="submit" name="save" value="Save changes" /></p>
+				<p class="submittop"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
 				<div class="inform">
-				<input type="hidden" name="form_sent" value="1" />
+					<input type="hidden" name="form_sent" value="1" />
 					<fieldset>
-						<legend>Posting</legend>
+						<legend><?php echo $lang_admin_permissions['Posting subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">BBCode</th>
+									<th scope="row"><?php echo $lang_admin_permissions['BBCode label'] ?></th>
 									<td>
-										<input type="radio" name="form[message_bbcode]" value="1"<?php if ($pun_config['p_message_bbcode'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[message_bbcode]" value="0"<?php if ($pun_config['p_message_bbcode'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow BBCode in posts (recommended).</span>
+										<input type="radio" name="form[message_bbcode]" value="1"<?php if ($pun_config['p_message_bbcode'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[message_bbcode]" value="0"<?php if ($pun_config['p_message_bbcode'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['BBCode help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Image tag</th>
+									<th scope="row"><?php echo $lang_admin_permissions['Image tag label'] ?></th>
 									<td>
-										<input type="radio" name="form[message_img_tag]" value="1"<?php if ($pun_config['p_message_img_tag'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[message_img_tag]" value="0"<?php if ($pun_config['p_message_img_tag'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow the BBCode [img][/img] tag in posts.</span>
+										<input type="radio" name="form[message_img_tag]" value="1"<?php if ($pun_config['p_message_img_tag'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[message_img_tag]" value="0"<?php if ($pun_config['p_message_img_tag'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['Image tag help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">All caps message</th>
+									<th scope="row"><?php echo $lang_admin_permissions['All caps message label'] ?></th>
 									<td>
-										<input type="radio" name="form[message_all_caps]" value="1"<?php if ($pun_config['p_message_all_caps'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[message_all_caps]" value="0"<?php if ($pun_config['p_message_all_caps'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow a message to contain only capital letters.</span>
+										<input type="radio" name="form[message_all_caps]" value="1"<?php if ($pun_config['p_message_all_caps'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[message_all_caps]" value="0"<?php if ($pun_config['p_message_all_caps'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['All caps message help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">All caps subject</th>
+									<th scope="row"><?php echo $lang_admin_permissions['All caps subject label'] ?></th>
 									<td>
-										<input type="radio" name="form[subject_all_caps]" value="1"<?php if ($pun_config['p_subject_all_caps'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[subject_all_caps]" value="0"<?php if ($pun_config['p_subject_all_caps'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow a subject to contain only capital letters.</span>
+										<input type="radio" name="form[subject_all_caps]" value="1"<?php if ($pun_config['p_subject_all_caps'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[subject_all_caps]" value="0"<?php if ($pun_config['p_subject_all_caps'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['All caps subject help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Require guest e-mail</th>
+									<th scope="row"><?php echo $lang_admin_permissions['Require e-mail label'] ?></th>
 									<td>
-										<input type="radio" name="form[force_guest_email]" value="1"<?php if ($pun_config['p_force_guest_email'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[force_guest_email]" value="0"<?php if ($pun_config['p_force_guest_email'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Require guests to supply an e-mail address when posting.</span>
+										<input type="radio" name="form[force_guest_email]" value="1"<?php if ($pun_config['p_force_guest_email'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[force_guest_email]" value="0"<?php if ($pun_config['p_force_guest_email'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['Require e-mail help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -115,42 +101,42 @@ generate_admin_menu('permissions');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Signatures</legend>
+						<legend><?php echo $lang_admin_permissions['Signatures subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">BBCodes in signatures</th>
+									<th scope="row"><?php echo $lang_admin_permissions['BBCode sigs label'] ?></th>
 									<td>
-										<input type="radio" name="form[sig_bbcode]" value="1"<?php if ($pun_config['p_sig_bbcode'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[sig_bbcode]" value="0"<?php if ($pun_config['p_sig_bbcode'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow BBCodes in user signatures.</span>
+										<input type="radio" name="form[sig_bbcode]" value="1"<?php if ($pun_config['p_sig_bbcode'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[sig_bbcode]" value="0"<?php if ($pun_config['p_sig_bbcode'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['BBCode sigs help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Image tag in signatures</th>
+									<th scope="row"><?php echo $lang_admin_permissions['Image tag sigs label'] ?></th>
 									<td>
-										<input type="radio" name="form[sig_img_tag]" value="1"<?php if ($pun_config['p_sig_img_tag'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[sig_img_tag]" value="0"<?php if ($pun_config['p_sig_img_tag'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow the BBCode [img][/img] tag in user signatures (not recommended).</span>
+										<input type="radio" name="form[sig_img_tag]" value="1"<?php if ($pun_config['p_sig_img_tag'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[sig_img_tag]" value="0"<?php if ($pun_config['p_sig_img_tag'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['Image tag sigs help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">All caps signature</th>
+									<th scope="row"><?php echo $lang_admin_permissions['All caps sigs label'] ?></th>
 									<td>
-										<input type="radio" name="form[sig_all_caps]" value="1"<?php if ($pun_config['p_sig_all_caps'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[sig_all_caps]" value="0"<?php if ($pun_config['p_sig_all_caps'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow a signature to contain only capital letters.</span>
+										<input type="radio" name="form[sig_all_caps]" value="1"<?php if ($pun_config['p_sig_all_caps'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[sig_all_caps]" value="0"<?php if ($pun_config['p_sig_all_caps'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['All caps sigs help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Maximum signature length</th>
+									<th scope="row"><?php echo $lang_admin_permissions['Max sig length label'] ?></th>
 									<td>
 										<input type="text" name="form[sig_length]" size="5" maxlength="5" value="<?php echo $pun_config['p_sig_length'] ?>" />
-										<span>The maximum number of characters a user signature may contain.</span>
+										<span><?php echo $lang_admin_permissions['Max sig length help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Maximum signature lines</th>
+									<th scope="row"><?php echo $lang_admin_permissions['Max sig lines label'] ?></th>
 									<td>
 										<input type="text" name="form[sig_lines]" size="3" maxlength="3" value="<?php echo $pun_config['p_sig_lines'] ?>" />
-										<span>The maximum number of lines a user signature may contain.</span>
+										<span><?php echo $lang_admin_permissions['Max sig lines help'] ?></span>
 									</td>
 								</tr>
 							</table>
@@ -159,28 +145,28 @@ generate_admin_menu('permissions');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Registration</legend>
+						<legend><?php echo $lang_admin_permissions['Registration subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Allow banned e-mail addresses</th>
+									<th scope="row"><?php echo $lang_admin_permissions['Banned e-mail label'] ?></th>
 									<td>
-										<input type="radio" name="form[allow_banned_email]" value="1"<?php if ($pun_config['p_allow_banned_email'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[allow_banned_email]" value="0"<?php if ($pun_config['p_allow_banned_email'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Allow users to register with or change to a banned e-mail address/domain. If left at its default setting (yes) this action will be allowed, but an alert e-mail will be sent to the mailing list (an effective way of detecting multiple registrations).</span>
+										<input type="radio" name="form[allow_banned_email]" value="1"<?php if ($pun_config['p_allow_banned_email'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[allow_banned_email]" value="0"<?php if ($pun_config['p_allow_banned_email'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['Banned e-mail help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Allow duplicate e-mail addresses</th>
+									<th scope="row"><?php echo $lang_admin_permissions['Duplicate e-mail label'] ?></th>
 									<td>
-										<input type="radio" name="form[allow_dupe_email]" value="1"<?php if ($pun_config['p_allow_dupe_email'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[allow_dupe_email]" value="0"<?php if ($pun_config['p_allow_dupe_email'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong>No</strong>
-										<span>Controls whether users should be allowed to register with an e-mail address that another user already has. If allowed, an alert e-mail will be sent to the mailing list if a duplicate is detected.</span>
+										<input type="radio" name="form[allow_dupe_email]" value="1"<?php if ($pun_config['p_allow_dupe_email'] == '1') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="form[allow_dupe_email]" value="0"<?php if ($pun_config['p_allow_dupe_email'] == '0') echo ' checked="checked"' ?> />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_permissions['Duplicate e-mail help'] ?></span>
 									</td>
 								</tr>
 							</table>
 						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="save" value="Save changes" /></p>
+				<p class="submitend"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
 			</form>
 		</div>
 	</div>
diff --git a/upload/admin_prune.php b/upload/admin_prune.php
index ecc4224..dfb721f 100644
--- a/upload/admin_prune.php
+++ b/upload/admin_prune.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,6 +17,8 @@ require PUN_ROOT.'include/common_admin.php';
 if ($pun_user['g_id'] != PUN_ADMIN)
 	message($lang_common['No permission']);
 
+// Load the admin_prune.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_prune.php';
 
 if (isset($_GET['action']) || isset($_POST['prune']) || isset($_POST['prune_comply']))
 {
@@ -42,6 +27,7 @@ if (isset($_GET['action']) || isset($_POST['prune']) || isset($_POST['prune_comp
 		confirm_referrer('admin_prune.php');
 
 		$prune_from = $_POST['prune_from'];
+		$prune_sticky = isset($_POST['prune_sticky']) ? '1' : '0';
 		$prune_days = intval($_POST['prune_days']);
 		$prune_date = ($prune_days) ? time() - ($prune_days*86400) : -1;
 
@@ -56,14 +42,14 @@ if (isset($_GET['action']) || isset($_POST['prune']) || isset($_POST['prune_comp
 			{
 				$fid = $db->result($result, $i);
 
-				prune($fid, $_POST['prune_sticky'], $prune_date);
+				prune($fid, $prune_sticky, $prune_date);
 				update_forum($fid);
 			}
 		}
 		else
 		{
 			$prune_from = intval($prune_from);
-			prune($prune_from, $_POST['prune_sticky'], $prune_date);
+			prune($prune_from, $prune_sticky, $prune_date);
 			update_forum($prune_from);
 		}
 
@@ -79,21 +65,20 @@ if (isset($_GET['action']) || isset($_POST['prune']) || isset($_POST['prune_comp
 			$db->query('DELETE FROM '.$db->prefix.'topics WHERE id IN('.implode(',', $orphans).')') or error('Unable to delete redirect topics', __FILE__, __LINE__, $db->error());
 		}
 
-		redirect('admin_prune.php', 'Posts pruned. Redirecting &hellip;');
+		redirect('admin_prune.php', $lang_admin_prune['Posts pruned redirect']);
 	}
 
-
-	$prune_days = $_POST['req_prune_days'];
-	if (!@preg_match('#^\d+$#', $prune_days))
-		message('Days to prune must be a positive integer.');
+	$prune_days = trim($_POST['req_prune_days']);
+	if ($prune_days == '' || preg_match('/[^0-9]/', $prune_days))
+		message($lang_admin_prune['Must be integer message']);
 
 	$prune_date = time() - ($prune_days*86400);
 	$prune_from = $_POST['prune_from'];
 
-	// Concatenate together the query for counting number or topics to prune
+	// Concatenate together the query for counting number of topics to prune
 	$sql = 'SELECT COUNT(id) FROM '.$db->prefix.'topics WHERE last_post<'.$prune_date.' AND moved_to IS NULL';
 
-	if ($_POST['prune_sticky'] == '0')
+	if (!$prune_sticky)
 		$sql .= ' AND sticky=\'0\'';
 
 	if ($prune_from != 'all')
@@ -106,38 +91,39 @@ if (isset($_GET['action']) || isset($_POST['prune']) || isset($_POST['prune_comp
 		$forum = '"'.pun_htmlspecialchars($db->result($result)).'"';
 	}
 	else
-		$forum = 'all forums';
+		$forum = $lang_admin_prune['All forums'];
 
 	$result = $db->query($sql) or error('Unable to fetch topic prune count', __FILE__, __LINE__, $db->error());
 	$num_topics = $db->result($result);
 
 	if (!$num_topics)
-		message('There are no topics that are '.$prune_days.' days old. Please decrease the value of "Days old" and try again.');
+		message(sprintf($lang_admin_prune['No old topics message'], $prune_days));
 
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Prune';
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Prune']);
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 	generate_admin_menu('prune');
 
 ?>
 	<div class="blockform">
-		<h2><span>Prune</span></h2>
+		<h2><span><?php echo $lang_admin_prune['Prune head'] ?></span></h2>
 		<div class="box">
 			<form method="post" action="admin_prune.php?action=foo">
 				<div class="inform">
 					<input type="hidden" name="prune_days" value="<?php echo $prune_days ?>" />
-					<input type="hidden" name="prune_sticky" value="<?php echo $_POST['prune_sticky'] ?>" />
+					<input type="hidden" name="prune_sticky" value="<?php echo $prune_sticky ?>" />
 					<input type="hidden" name="prune_from" value="<?php echo $prune_from ?>" />
 					<fieldset>
-						<legend>Confirm prune posts</legend>
+						<legend><?php echo $lang_admin_prune['Confirm prune subhead'] ?></legend>
 						<div class="infldset">
-							<p>Are you sure that you want to prune all topics older than <?php echo $prune_days ?> days from <?php echo $forum ?>? (<?php echo $num_topics ?> topics)</p>
-							<p>WARNING! Pruning posts deletes them permanently.</p>
+							<p><?php printf($lang_admin_prune['Confirm prune info'], $prune_days, $forum, forum_number_format($num_topics)) ?></p>
+							<p class="warntext"><?php echo $lang_admin_prune['Confirm prune warn'] ?></p>
 						</div>
 					</fieldset>
 				</div>
-				<p><input type="submit" name="prune_comply" value="Prune" /><a href="javascript:history.go(-1)">Go back</a></p>
+				<p class="buttons"><input type="submit" name="prune_comply" value="<?php echo $lang_admin_common['Prune'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_admin_common['Go back'] ?></a></p>
 			</form>
 		</div>
 	</div>
@@ -151,43 +137,44 @@ if (isset($_GET['action']) || isset($_POST['prune']) || isset($_POST['prune_comp
 
 else
 {
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Prune';
-	$required_fields = array('req_prune_days' => 'Days old');
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Prune']);
+	$required_fields = array('req_prune_days' => $lang_admin_prune['Days old label']);
 	$focus_element = array('prune', 'req_prune_days');
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 	generate_admin_menu('prune');
 
 ?>
 	<div class="blockform">
-		<h2><span>Prune</span></h2>
+		<h2><span><?php echo $lang_admin_prune['Prune head'] ?></span></h2>
 		<div class="box">
 			<form id="prune" method="post" action="admin_prune.php?action=foo" onsubmit="return process_form(this)">
 				<div class="inform">
-				<input type="hidden" name="form_sent" value="1" />
+					<input type="hidden" name="form_sent" value="1" />
 					<fieldset>
-						<legend>Prune old posts</legend>
+						<legend><?php echo $lang_admin_prune['Prune subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Days old</th>
+									<th scope="row"><?php echo $lang_admin_prune['Days old label'] ?></th>
 									<td>
 										<input type="text" name="req_prune_days" size="3" maxlength="3" tabindex="1" />
-										<span>The number of days "old" a topic must be to be pruned. E.g. if you were to enter 30, every topic that didn't contain a post dated less than 30 days old would be deleted.</span>
+										<span><?php echo $lang_admin_prune['Days old help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Prune sticky topics</th>
+									<th scope="row"><?php echo $lang_admin_prune['Prune sticky label'] ?></th>
 									<td>
-										<input type="radio" name="prune_sticky" value="1" tabindex="2" checked="checked" />&nbsp;<strong>Yes</strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="prune_sticky" value="0" />&nbsp;<strong>No</strong>
-										<span>When enabled sticky topics will also be pruned.</span>
+										<input type="radio" name="prune_sticky" value="1" tabindex="2" checked="checked" />&nbsp;<strong><?php echo $lang_admin_common['Yes'] ?></strong>&nbsp;&nbsp;&nbsp;<input type="radio" name="prune_sticky" value="0" />&nbsp;<strong><?php echo $lang_admin_common['No'] ?></strong>
+										<span><?php echo $lang_admin_prune['Prune sticky help'] ?></span>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">Prune from forum</th>
+									<th scope="row"><?php echo $lang_admin_prune['Prune from label'] ?></th>
 									<td>
 										<select name="prune_from" tabindex="3">
-											<option value="all">All forums</option>
+											<option value="all"><?php echo $lang_admin_prune['All forums'] ?></option>
 <?php
 
 	$result = $db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name FROM '.$db->prefix.'categories AS c INNER JOIN '.$db->prefix.'forums AS f ON c.id=f.cat_id WHERE f.redirect_url IS NULL ORDER BY c.disp_position, c.id, f.disp_position') or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());
@@ -195,7 +182,7 @@ else
 	$cur_category = 0;
 	while ($forum = $db->fetch_assoc($result))
 	{
-		if ($forum['cid'] != $cur_category)	// Are we still in the same category?
+		if ($forum['cid'] != $cur_category) // Are we still in the same category?
 		{
 			if ($cur_category)
 				echo "\t\t\t\t\t\t\t\t\t\t\t".'</optgroup>'."\n";
@@ -210,12 +197,12 @@ else
 ?>
 											</optgroup>
 										</select>
-										<span>The forum from which you want to prune posts.</span>
+										<span><?php echo $lang_admin_prune['Prune from help'] ?></span>
 									</td>
 								</tr>
 							</table>
-							<p class="topspace">Use this feature with caution. Pruned posts can <strong>never</strong> be recovered. For best performance you should put the forum in maintenance mode during pruning.</p>
-							<div class="fsetsubmit"><input type="submit" name="prune" value="Prune" tabindex="5" /></div>
+							<p class="topspace"><?php printf($lang_admin_prune['Prune info'], '<a href="admin_options.php#maintenance">'.$lang_admin_common['Maintenance mode'].'</a>') ?></p>
+							<div class="fsetsubmit"><input type="submit" name="prune" value="<?php echo $lang_admin_common['Prune'] ?>" tabindex="5" /></div>
 						</div>
 					</fieldset>
 				</div>
diff --git a/upload/admin_ranks.php b/upload/admin_ranks.php
index 3cb5f91..1904c1e 100644
--- a/upload/admin_ranks.php
+++ b/upload/admin_ranks.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,25 +17,27 @@ require PUN_ROOT.'include/common_admin.php';
 if ($pun_user['g_id'] != PUN_ADMIN)
 	message($lang_common['No permission']);
 
+// Load the admin_ranks.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_ranks.php';
 
 // Add a rank
 if (isset($_POST['add_rank']))
 {
 	confirm_referrer('admin_ranks.php');
 
-	$rank = trim($_POST['new_rank']);
-	$min_posts = $_POST['new_min_posts'];
+	$rank = pun_trim($_POST['new_rank']);
+	$min_posts = trim($_POST['new_min_posts']);
 
 	if ($rank == '')
-		message('You must enter a rank title.');
+		message($lang_admin_ranks['Must enter title message']);
 
-	if (!@preg_match('#^\d+$#', $min_posts))
-		message('Minimum posts must be a positive integer value.');
+	if ($min_posts == '' || preg_match('/[^0-9]/', $min_posts))
+		message($lang_admin_ranks['Must be integer message']);
 
 	// Make sure there isn't already a rank with the same min_posts value
 	$result = $db->query('SELECT 1 FROM '.$db->prefix.'ranks WHERE min_posts='.$min_posts) or error('Unable to fetch rank info', __FILE__, __LINE__, $db->error());
 	if ($db->num_rows($result))
-		message('There is already a rank with a minimun posts value of '.$min_posts.'.');
+		message(sprintf($lang_admin_ranks['Dupe min posts message'], $min_posts));
 
 	$db->query('INSERT INTO '.$db->prefix.'ranks (rank, min_posts) VALUES(\''.$db->escape($rank).'\', '.$min_posts.')') or error('Unable to add rank', __FILE__, __LINE__, $db->error());
 
@@ -62,7 +47,7 @@ if (isset($_POST['add_rank']))
 
 	generate_ranks_cache();
 
-	redirect('admin_ranks.php', 'Rank added. Redirecting &hellip;');
+	redirect('admin_ranks.php', $lang_admin_ranks['Rank added redirect']);
 }
 
 
@@ -73,19 +58,19 @@ else if (isset($_POST['update']))
 
 	$id = intval(key($_POST['update']));
 
-	$rank = trim($_POST['rank'][$id]);
+	$rank = pun_trim($_POST['rank'][$id]);
 	$min_posts = trim($_POST['min_posts'][$id]);
 
 	if ($rank == '')
-		message('You must enter a rank title.');
+		message($lang_admin_ranks['Must enter title message']);
 
-	if (!@preg_match('#^\d+$#', $min_posts))
-		message('Minimum posts must be a positive integer value.');
+	if ($min_posts == '' || preg_match('/[^0-9]/', $min_posts))
+		message($lang_admin_ranks['Must be integer message']);
 
 	// Make sure there isn't already a rank with the same min_posts value
 	$result = $db->query('SELECT 1 FROM '.$db->prefix.'ranks WHERE id!='.$id.' AND min_posts='.$min_posts) or error('Unable to fetch rank info', __FILE__, __LINE__, $db->error());
 	if ($db->num_rows($result))
-		message('There is already a rank with a minimun posts value of '.$min_posts.'.');
+		message(sprintf($lang_admin_ranks['Dupe min posts message'], $min_posts));
 
 	$db->query('UPDATE '.$db->prefix.'ranks SET rank=\''.$db->escape($rank).'\', min_posts='.$min_posts.' WHERE id='.$id) or error('Unable to update rank', __FILE__, __LINE__, $db->error());
 
@@ -95,7 +80,7 @@ else if (isset($_POST['update']))
 
 	generate_ranks_cache();
 
-	redirect('admin_ranks.php', 'Rank updated. Redirecting &hellip;');
+	redirect('admin_ranks.php', $lang_admin_ranks['Rank updated redirect']);
 }
 
 
@@ -114,39 +99,39 @@ else if (isset($_POST['remove']))
 
 	generate_ranks_cache();
 
-	redirect('admin_ranks.php', 'Rank removed. Redirecting &hellip;');
+	redirect('admin_ranks.php', $lang_admin_ranks['Rank removed redirect']);
 }
 
-
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Ranks';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Ranks']);
 $focus_element = array('ranks', 'new_rank');
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('ranks');
 
 ?>
 	<div class="blockform">
-		<h2><span>Ranks</span></h2>
+		<h2><span><?php echo $lang_admin_ranks['Ranks head'] ?></span></h2>
 		<div class="box">
 			<form id="ranks" method="post" action="admin_ranks.php?action=foo">
 				<div class="inform">
 					<fieldset>
-						<legend>Add rank</legend>
+						<legend><?php echo $lang_admin_ranks['Add rank subhead'] ?></legend>
 						<div class="infldset">
-							<p>Enter a rank and the minimum number of posts that a user has to have to aquire the rank. Different ranks cannot have the same value for minimum posts. If a title is set for a user, the title will be displayed instead of any rank. <strong>User ranks must be enabled in <a href="admin_options.php#ranks">Options</a> for this to have any effect.</strong></p>
-							<table  cellspacing="0">
+							<p><?php printf($lang_admin_ranks['Add rank info'], '<a href="admin_options.php#ranks">'.$lang_admin_common['Options'].'</a>') ?></p>
+							<table cellspacing="0">
 							<thead>
 								<tr>
-									<th class="tcl" scope="col">Rank&nbsp;title</th>
-									<th class="tc2" scope="col">Minimum&nbsp;posts</th>
-									<th class="hidehead" scope="col">Action</th>
+									<th class="tcl" scope="col"><?php echo $lang_admin_ranks['Rank title label'] ?></th>
+									<th class="tc2" scope="col"><?php echo $lang_admin_ranks['Minimum posts label'] ?></th>
+									<th class="hidehead" scope="col"><?php echo $lang_admin_ranks['Actions label'] ?></th>
 								</tr>
 							</thead>
 							<tbody>
 								<tr>
-									<td><input type="text" name="new_rank" size="24" maxlength="50" tabindex="1" /></td>
-									<td><input type="text" name="new_min_posts" size="7" maxlength="7" tabindex="2" /></td>
-									<td><input type="submit" name="add_rank" value=" Add " tabindex="3" /></td>
+									<td class="tcl"><input type="text" name="new_rank" size="24" maxlength="50" tabindex="1" /></td>
+									<td class="tc2"><input type="text" name="new_min_posts" size="7" maxlength="7" tabindex="2" /></td>
+									<td><input type="submit" name="add_rank" value="<?php echo $lang_admin_common['Add'] ?>" tabindex="3" /></td>
 								</tr>
 							</tbody>
 							</table>
@@ -155,7 +140,7 @@ generate_admin_menu('ranks');
 				</div>
 				<div class="inform">
 					<fieldset>
-						<legend>Edit/remove ranks</legend>
+						<legend><?php echo $lang_admin_ranks['Edit remove subhead'] ?></legend>
 						<div class="infldset">
 <?php
 
@@ -164,19 +149,19 @@ if ($db->num_rows($result))
 {
 
 ?>
-							<table  cellspacing="0">
+							<table cellspacing="0">
 							<thead>
 								<tr>
-									<th class="tcl" scope="col"><strong>Rank&nbsp;title</strong></th>
-									<th class="tc2" scope="col"><strong>Minimum&nbsp;Posts</strong></th>
-									<th class="hidehead" scope="col">Actions</th>
+									<th class="tcl" scope="col"><?php echo $lang_admin_ranks['Rank title label'] ?></th>
+									<th class="tc2" scope="col"><?php echo $lang_admin_ranks['Minimum posts label'] ?></th>
+									<th class="hidehead" scope="col"><?php echo $lang_admin_ranks['Actions label'] ?></th>
 								</tr>
 							</thead>
 							<tbody>
 <?php
 
 	while ($cur_rank = $db->fetch_assoc($result))
-		echo "\t\t\t\t\t\t\t\t".'<tr><td><input type="text" name="rank['.$cur_rank['id'].']" value="'.pun_htmlspecialchars($cur_rank['rank']).'" size="24" maxlength="50" /></td><td><input type="text" name="min_posts['.$cur_rank['id'].']" value="'.$cur_rank['min_posts'].'" size="7" maxlength="7" /></td><td><input type="submit" name="update['.$cur_rank['id'].']" value="Update" />&nbsp;<input type="submit" name="remove['.$cur_rank['id'].']" value="Remove" /></td></tr>'."\n";
+		echo "\t\t\t\t\t\t\t\t".'<tr><td class="tcl"><input type="text" name="rank['.$cur_rank['id'].']" value="'.pun_htmlspecialchars($cur_rank['rank']).'" size="24" maxlength="50" /></td><td class="tc2"><input type="text" name="min_posts['.$cur_rank['id'].']" value="'.$cur_rank['min_posts'].'" size="7" maxlength="7" /></td><td><input type="submit" name="update['.$cur_rank['id'].']" value="'.$lang_admin_common['Update'].'" />&nbsp;<input type="submit" name="remove['.$cur_rank['id'].']" value="'.$lang_admin_common['Remove'].'" /></td></tr>'."\n";
 
 ?>
 							</tbody>
@@ -185,7 +170,7 @@ if ($db->num_rows($result))
 
 }
 else
-	echo "\t\t\t\t\t\t\t".'<p>No ranks in list.</p>'."\n";
+	echo "\t\t\t\t\t\t\t".'<p>'.$lang_admin_ranks['No ranks in list'].'</p>'."\n";
 
 ?>
 						</div>
diff --git a/upload/admin_reports.php b/upload/admin_reports.php
index ba77e89..da435ac 100644
--- a/upload/admin_reports.php
+++ b/upload/admin_reports.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,6 +17,8 @@ require PUN_ROOT.'include/common_admin.php';
 if (!$pun_user['is_admmod'])
 	message($lang_common['No permission']);
 
+// Load the admin_reports.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_reports.php';
 
 // Zap a report
 if (isset($_POST['zap_id']))
@@ -48,46 +33,48 @@ if (isset($_POST['zap_id']))
 	if ($zapped == '')
 		$db->query('UPDATE '.$db->prefix.'reports SET zapped='.time().', zapped_by='.$pun_user['id'].' WHERE id='.$zap_id) or error('Unable to zap report', __FILE__, __LINE__, $db->error());
 
-	redirect('admin_reports.php', 'Report zapped. Redirecting &hellip;');
+	redirect('admin_reports.php', $lang_admin_reports['Report zapped redirect']);
 }
 
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Reports';
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Reports']);
+define('PUN_ACTIVE_PAGE', 'admin');
 require PUN_ROOT.'header.php';
 
 generate_admin_menu('reports');
 
 ?>
 	<div class="blockform">
-		<h2><span>New reports</span></h2>
+		<h2><span><?php echo $lang_admin_reports['New reports head'] ?></span></h2>
 		<div class="box">
 			<form method="post" action="admin_reports.php?action=zap">
 <?php
 
-$result = $db->query('SELECT r.id, r.post_id, r.topic_id, r.forum_id, r.reported_by, r.created, r.message, t.subject, f.forum_name, u.username AS reporter FROM '.$db->prefix.'reports AS r LEFT JOIN '.$db->prefix.'topics AS t ON r.topic_id=t.id LEFT JOIN '.$db->prefix.'forums AS f ON r.forum_id=f.id LEFT JOIN '.$db->prefix.'users AS u ON r.reported_by=u.id WHERE r.zapped IS NULL ORDER BY created DESC') or error('Unable to fetch report list', __FILE__, __LINE__, $db->error());
+$result = $db->query('SELECT r.id, r.topic_id, r.forum_id, r.reported_by, r.created, r.message, p.id AS pid, t.subject, f.forum_name, u.username AS reporter FROM '.$db->prefix.'reports AS r LEFT JOIN '.$db->prefix.'posts AS p ON r.post_id=p.id LEFT JOIN '.$db->prefix.'topics AS t ON r.topic_id=t.id LEFT JOIN '.$db->prefix.'forums AS f ON r.forum_id=f.id LEFT JOIN '.$db->prefix.'users AS u ON r.reported_by=u.id WHERE r.zapped IS NULL ORDER BY created DESC') or error('Unable to fetch report list', __FILE__, __LINE__, $db->error());
 
 if ($db->num_rows($result))
 {
 	while ($cur_report = $db->fetch_assoc($result))
 	{
-		$reporter = ($cur_report['reporter'] != '') ? '<a href="profile.php?id='.$cur_report['reported_by'].'">'.pun_htmlspecialchars($cur_report['reporter']).'</a>' : 'Deleted user';
-		$forum = ($cur_report['forum_name'] != '') ? '<a href="viewforum.php?id='.$cur_report['forum_id'].'">'.pun_htmlspecialchars($cur_report['forum_name']).'</a>' : 'Deleted';
-		$topic = ($cur_report['subject'] != '') ? '<a href="viewtopic.php?id='.$cur_report['topic_id'].'">'.pun_htmlspecialchars($cur_report['subject']).'</a>' : 'Deleted';
-		$post = ($cur_report['post_id'] != '') ? str_replace("\n", '<br />', pun_htmlspecialchars($cur_report['message'])) : 'Deleted';
-		$postid = ($cur_report['post_id'] != '') ? '<a href="viewtopic.php?pid='.$cur_report['post_id'].'#p'.$cur_report['post_id'].'">Post #'.$cur_report['post_id'].'</a>' : 'Deleted';
+		$reporter = ($cur_report['reporter'] != '') ? '<a href="profile.php?id='.$cur_report['reported_by'].'">'.pun_htmlspecialchars($cur_report['reporter']).'</a>' : $lang_admin_reports['Deleted user'];
+		$forum = ($cur_report['forum_name'] != '') ? '<a href="viewforum.php?id='.$cur_report['forum_id'].'">'.pun_htmlspecialchars($cur_report['forum_name']).'</a>' : $lang_admin_reports['Deleted'];
+		$topic = ($cur_report['subject'] != '') ? '<a href="viewtopic.php?id='.$cur_report['topic_id'].'">'.pun_htmlspecialchars($cur_report['subject']).'</a>' : $lang_admin_reports['Deleted'];
+		$post = str_replace("\n", '<br />', pun_htmlspecialchars($cur_report['message']));
+		$postid = ($cur_report['pid'] != '') ? '<a href="viewtopic.php?pid='.$cur_report['pid'].'#p'.$cur_report['pid'].'">Post #'.$cur_report['pid'].'</a>' : $lang_admin_reports['Deleted'];
+		$report_location = array($forum, $topic, $postid);
 
 ?>
 				<div class="inform">
 					<fieldset>
-						<legend>Reported <?php echo format_time($cur_report['created']) ?></legend>
+						<legend><?php printf($lang_admin_reports['Report subhead'], format_time($cur_report['created'])) ?></legend>
 						<div class="infldset">
-							<table cellspacing="0">
+							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Forum&nbsp;&raquo;&nbsp;Topic&nbsp;&raquo;&nbsp;Post</th>
-									<td><?php echo $forum ?>&nbsp;&raquo;&nbsp;<?php echo $topic ?>&nbsp;&raquo;&nbsp;<?php echo $postid ?></td>
+									<th scope="row"><?php printf($lang_admin_reports['Reported by'], $reporter) ?></th>
+									<td><?php echo implode($lang_admin_reports['Location seperator'], $report_location) ?></td>
 								</tr>
 								<tr>
-									<th scope="row">Report by <?php echo $reporter ?><div><input type="submit" name="zap_id[<?php echo $cur_report['id'] ?>]" value=" Zap " /></div></th>
+									<th scope="row"><?php echo $lang_admin_reports['Reason'] ?><div><input type="submit" name="zap_id[<?php echo $cur_report['id'] ?>]" value="<?php echo $lang_admin_reports['Zap'] ?>" /></div></th>
 									<td><?php echo $post ?></td>
 								</tr>
 							</table>
@@ -99,7 +86,20 @@ if ($db->num_rows($result))
 	}
 }
 else
-	echo "\t\t\t\t".'<p>There are no new reports.</p>'."\n";
+{
+
+?>
+				<div class="inform">
+					<fieldset>
+						<legend><?php echo $lang_admin_common['None'] ?></legend>
+						<div class="infldset">
+							<p><?php echo $lang_admin_reports['No new reports'] ?></p>
+						</div>
+					</fieldset>
+				</div>
+<?php
+
+}
 
 ?>
 			</form>
@@ -107,36 +107,38 @@ else
 	</div>
 
 	<div class="blockform block2">
-		<h2><span>10 last zapped reports</span></h2>
+		<h2><span><?php echo $lang_admin_reports['Last 10 head'] ?></span></h2>
 		<div class="box">
 			<div class="fakeform">
 <?php
 
-$result = $db->query('SELECT r.id, r.post_id, r.topic_id, r.forum_id, r.reported_by, r.message, r.zapped, r.zapped_by AS zapped_by_id, t.subject, f.forum_name, u.username AS reporter, u2.username AS zapped_by FROM '.$db->prefix.'reports AS r LEFT JOIN '.$db->prefix.'topics AS t ON r.topic_id=t.id LEFT JOIN '.$db->prefix.'forums AS f ON r.forum_id=f.id LEFT JOIN '.$db->prefix.'users AS u ON r.reported_by=u.id LEFT JOIN '.$db->prefix.'users AS u2 ON r.zapped_by=u2.id WHERE r.zapped IS NOT NULL ORDER BY zapped DESC LIMIT 10') or error('Unable to fetch report list', __FILE__, __LINE__, $db->error());
+$result = $db->query('SELECT r.id, r.topic_id, r.forum_id, r.reported_by, r.message, r.zapped, r.zapped_by AS zapped_by_id, p.id AS pid, t.subject, f.forum_name, u.username AS reporter, u2.username AS zapped_by FROM '.$db->prefix.'reports AS r LEFT JOIN '.$db->prefix.'posts AS p ON r.post_id=p.id LEFT JOIN '.$db->prefix.'topics AS t ON r.topic_id=t.id LEFT JOIN '.$db->prefix.'forums AS f ON r.forum_id=f.id LEFT JOIN '.$db->prefix.'users AS u ON r.reported_by=u.id LEFT JOIN '.$db->prefix.'users AS u2 ON r.zapped_by=u2.id WHERE r.zapped IS NOT NULL ORDER BY zapped DESC LIMIT 10') or error('Unable to fetch report list', __FILE__, __LINE__, $db->error());
 
 if ($db->num_rows($result))
 {
 	while ($cur_report = $db->fetch_assoc($result))
 	{
-		$reporter = ($cur_report['reporter'] != '') ? '<a href="profile.php?id='.$cur_report['reported_by'].'">'.pun_htmlspecialchars($cur_report['reporter']).'</a>' : 'Deleted user';
-		$forum = ($cur_report['forum_name'] != '') ? '<a href="viewforum.php?id='.$cur_report['forum_id'].'">'.pun_htmlspecialchars($cur_report['forum_name']).'</a>' : 'Deleted';
-		$topic = ($cur_report['subject'] != '') ? '<a href="viewtopic.php?id='.$cur_report['topic_id'].'">'.pun_htmlspecialchars($cur_report['subject']).'</a>' : 'Deleted';
-		$post = ($cur_report['post_id'] != '') ? str_replace("\n", '<br />', pun_htmlspecialchars($cur_report['message'])) : 'Post deleted';
-		$post_id = ($cur_report['post_id'] != '') ? '<a href="viewtopic.php?pid='.$cur_report['post_id'].'#p'.$cur_report['post_id'].'">Post #'.$cur_report['post_id'].'</a>' : 'Deleted';
-		$zapped_by = ($cur_report['zapped_by'] != '') ? '<a href="profile.php?id='.$cur_report['zapped_by_id'].'">'.pun_htmlspecialchars($cur_report['zapped_by']).'</a>' : 'N/A';
+		$reporter = ($cur_report['reporter'] != '') ? '<a href="profile.php?id='.$cur_report['reported_by'].'">'.pun_htmlspecialchars($cur_report['reporter']).'</a>' : $lang_admin_reports['Deleted user'];
+		$forum = ($cur_report['forum_name'] != '') ? '<a href="viewforum.php?id='.$cur_report['forum_id'].'">'.pun_htmlspecialchars($cur_report['forum_name']).'</a>' : $lang_admin_reports['Deleted'];
+		$topic = ($cur_report['subject'] != '') ? '<a href="viewtopic.php?id='.$cur_report['topic_id'].'">'.pun_htmlspecialchars($cur_report['subject']).'</a>' : $lang_admin_reports['Deleted'];
+		$post = str_replace("\n", '<br />', pun_htmlspecialchars($cur_report['message']));
+		$post_id = ($cur_report['pid'] != '') ? '<a href="viewtopic.php?pid='.$cur_report['pid'].'#p'.$cur_report['pid'].'">Post #'.$cur_report['pid'].'</a>' : $lang_admin_reports['Deleted'];
+		$zapped_by = ($cur_report['zapped_by'] != '') ? '<a href="profile.php?id='.$cur_report['zapped_by_id'].'">'.pun_htmlspecialchars($cur_report['zapped_by']).'</a>' : $lang_admin_reports['NA'];
+		$zapped_by = ($cur_report['zapped_by'] != '') ? '<strong>'.pun_htmlspecialchars($cur_report['zapped_by']).'</strong>' : $lang_admin_reports['NA'];
+		$report_location = array($forum, $topic, $post_id);
 
 ?>
 				<div class="inform">
 					<fieldset>
-						<legend>Zapped <?php echo format_time($cur_report['zapped']) ?></legend>
+						<legend><?php printf($lang_admin_reports['Zapped subhead'], format_time($cur_report['zapped']), $zapped_by) ?></legend>
 						<div class="infldset">
-							<table cellspacing="0">
+							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Forum&nbsp;&raquo;&nbsp;Topic&nbsp;&raquo;&nbsp;Post</th>
-									<td><?php echo $forum ?>&nbsp;&raquo;&nbsp;<?php echo $topic ?>&nbsp;&raquo;&nbsp;<?php echo $post_id ?></td>
+									<th scope="row"><?php printf($lang_admin_reports['Reported by'], $reporter) ?></th>
+									<td><?php echo implode($lang_admin_reports['Location seperator'], $report_location) ?></td>
 								</tr>
 								<tr>
-									<th scope="row">Reported by <?php echo $reporter ?><div class="topspace">Zapped by <?php echo $zapped_by ?></div></th>
+									<th scope="row"><?php echo $lang_admin_reports['Reason'] ?></th>
 									<td><?php echo $post ?></td>
 								</tr>
 							</table>
@@ -148,7 +150,20 @@ if ($db->num_rows($result))
 	}
 }
 else
-	echo "\t\t\t\t".'<p>There are no zapped reports.</p>'."\n";
+{
+
+?>
+				<div class="inform">
+					<fieldset>
+						<legend><?php echo $lang_admin_common['None'] ?></legend>
+						<div class="infldset">
+							<p><?php echo $lang_admin_reports['No zapped reports'] ?></p>
+						</div>
+					</fieldset>
+				</div>
+<?php
+
+}
 
 ?>
 			</div>
diff --git a/upload/admin_users.php b/upload/admin_users.php
index 851ee12..d2162aa 100644
--- a/upload/admin_users.php
+++ b/upload/admin_users.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the admin template
 define('PUN_ADMIN_CONSOLE', 1);
@@ -34,6 +17,8 @@ require PUN_ROOT.'include/common_admin.php';
 if (!$pun_user['is_admmod'])
 	message($lang_common['No permission']);
 
+// Load the admin_users.php language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_users.php';
 
 // Show IP statistics for a certain user ID
 if (isset($_GET['ip_stats']))
@@ -42,34 +27,53 @@ if (isset($_GET['ip_stats']))
 	if ($ip_stats < 1)
 		message($lang_common['Bad request']);
 
+	// Fetch ip count
+	$result = $db->query('SELECT poster_ip, MAX(posted) AS last_used FROM '.$db->prefix.'posts WHERE poster_id='.$ip_stats.' GROUP BY poster_ip') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+	$num_ips = $db->num_rows($result);
+
+	// Determine the ip offset (based on $_GET['p'])
+	$num_pages = ceil($num_ips / 50);
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Users';
+	$p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
+	$start_from = 50 * ($p - 1);
+
+	// Generate paging links
+	$paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_users.php?ip_stats='.$ip_stats );
+
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Results head']);
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 ?>
 <div class="linkst">
-	<div class="inbox">
-		<div><a href="javascript:history.go(-1)">Go back</a></div>
+	<div class="inbox crumbsplus">
+		<ul class="crumbs">
+			<li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+		</ul>
+		<p class="pagelink"><?php echo $paging_links ?></p>
+		<div class="clearer"></div>
 	</div>
 </div>
 
 <div id="users1" class="blocktable">
-	<h2><span>Users</span></h2>
+	<h2><span><?php echo $lang_admin_users['Results head'] ?></span></h2>
 	<div class="box">
 		<div class="inbox">
 			<table cellspacing="0">
 			<thead>
 				<tr>
-					<th class="tcl" scope="col">IP address</th>
-					<th class="tc2" scope="col">Last used</th>
-					<th class="tc3" scope="col">Times found</th>
-					<th class="tcr" scope="col">Action</th>
+					<th class="tcl" scope="col"><?php echo $lang_admin_users['Results IP address head'] ?></th>
+					<th class="tc2" scope="col"><?php echo $lang_admin_users['Results last used head'] ?></th>
+					<th class="tc3" scope="col"><?php echo $lang_admin_users['Results times found head'] ?></th>
+					<th class="tcr" scope="col"><?php echo $lang_admin_users['Results action head'] ?></th>
 				</tr>
 			</thead>
 			<tbody>
 <?php
 
-	$result = $db->query('SELECT poster_ip, MAX(posted) AS last_used, COUNT(id) AS used_times FROM '.$db->prefix.'posts WHERE poster_id='.$ip_stats.' GROUP BY poster_ip ORDER BY last_used DESC') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+	$result = $db->query('SELECT poster_ip, MAX(posted) AS last_used, COUNT(id) AS used_times FROM '.$db->prefix.'posts WHERE poster_id='.$ip_stats.' GROUP BY poster_ip ORDER BY last_used DESC LIMIT '.$start_from.', 50') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
 	if ($db->num_rows($result))
 	{
 		while ($cur_ip = $db->fetch_assoc($result))
@@ -80,14 +84,14 @@ if (isset($_GET['ip_stats']))
 					<td class="tcl"><a href="moderate.php?get_host=<?php echo $cur_ip['poster_ip'] ?>"><?php echo $cur_ip['poster_ip'] ?></a></td>
 					<td class="tc2"><?php echo format_time($cur_ip['last_used']) ?></td>
 					<td class="tc3"><?php echo $cur_ip['used_times'] ?></td>
-					<td class="tcr"><a href="admin_users.php?show_users=<?php echo $cur_ip['poster_ip'] ?>">Find more users for this ip</a></td>
+					<td class="tcr"><a href="admin_users.php?show_users=<?php echo $cur_ip['poster_ip'] ?>"><?php echo $lang_admin_users['Results find more link'] ?></a></td>
 				</tr>
 <?php
 
 		}
 	}
 	else
-		echo "\t\t\t\t".'<tr><td class="tcl" colspan="4">There are currently no posts by that user in the forum.</td></tr>'."\n";
+		echo "\t\t\t\t".'<tr><td class="tcl" colspan="4">'.$lang_admin_users['Results no posts found'].'</td></tr>'."\n";
 
 ?>
 			</tbody>
@@ -97,8 +101,14 @@ if (isset($_GET['ip_stats']))
 </div>
 
 <div class="linksb">
-	<div class="inbox">
-		<div><a href="javascript:history.go(-1)">Go back</a></div>
+	<div class="inbox crumbsplus">
+		<p class="pagelink"><?php echo $paging_links ?></p>
+		<ul class="crumbs">
+			<li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+		</ul>
+		<div class="clearer"></div>
 	</div>
 </div>
 <?php
@@ -112,32 +122,51 @@ if (isset($_GET['show_users']))
 	$ip = $_GET['show_users'];
 
 	if (!@preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $ip) && !@preg_match('/^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/', $ip))
-		message('The supplied IP address is not correctly formatted.');
+		message($lang_admin_users['Bad IP message']);
+
+	// Fetch user count
+	$result = $db->query('SELECT DISTINCT poster_id, poster FROM '.$db->prefix.'posts WHERE poster_ip=\''.$db->escape($ip).'\'') or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+	$num_users = $db->num_rows($result);
 
+	// Determine the user offset (based on $_GET['p'])
+	$num_pages = ceil($num_users / 50);
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Users';
+	$p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
+	$start_from = 50 * ($p - 1);
+
+	// Generate paging links
+	$paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_users.php?show_users='.$ip);
+
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Results head']);
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 ?>
 <div class="linkst">
-	<div class="inbox">
-		<div><a href="javascript:history.go(-1)">Go back</a></div>
+	<div class="inbox crumbsplus">
+		<ul class="crumbs">
+			<li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+		</ul>
+		<p class="pagelink"><?php echo $paging_links ?></p>
+		<div class="clearer"></div>
 	</div>
 </div>
 
 <div id="users2" class="blocktable">
-	<h2><span>Users</span></h2>
+	<h2><span><?php echo $lang_admin_users['Results head'] ?></span></h2>
 	<div class="box">
 		<div class="inbox">
 			<table cellspacing="0">
 			<thead>
 				<tr>
-					<th class="tcl" scope="col">Username</th>
-					<th class="tc2" scope="col">E-mail</th>
-					<th class="tc3" scope="col">Title/Status</th>
-					<th class="tc4" scope="col">Posts</th>
-					<th class="tc5" scope="col">Admin note</th>
-					<th class="tcr" scope="col">Actions</th>
+					<th class="tcl" scope="col"><?php echo $lang_admin_users['Results username head'] ?></th>
+					<th class="tc2" scope="col"><?php echo $lang_admin_users['Results e-mail head'] ?></th>
+					<th class="tc3" scope="col"><?php echo $lang_admin_users['Results title head'] ?></th>
+					<th class="tc4" scope="col"><?php echo $lang_admin_users['Results posts head'] ?></th>
+					<th class="tc5" scope="col"><?php echo $lang_admin_users['Results admin note head'] ?></th>
+					<th class="tcr" scope="col"><?php echo $lang_admin_users['Results actions head'] ?></th>
 				</tr>
 			</thead>
 			<tbody>
@@ -159,7 +188,7 @@ if (isset($_GET['show_users']))
 			{
 				$user_title = get_title($user_data);
 
-				$actions = '<a href="admin_users.php?ip_stats='.$user_data['id'].'">View IP stats</a> - <a href="search.php?action=show_user&amp;user_id='.$user_data['id'].'">Show posts</a>';
+				$actions = '<a href="admin_users.php?ip_stats='.$user_data['id'].'">'.$lang_admin_users['Results view IP link'].'</a> | <a href="search.php?action=show_user&amp;user_id='.$user_data['id'].'">'.$lang_admin_users['Results show posts link'].'</a>';
 
 ?>
 				<tr>
@@ -167,7 +196,7 @@ if (isset($_GET['show_users']))
 					<td class="tc2"><a href="mailto:<?php echo $user_data['email'] ?>"><?php echo $user_data['email'] ?></a></td>
 					<td class="tc3"><?php echo $user_title ?></td>
 					<td class="tc4"><?php echo forum_number_format($user_data['num_posts']) ?></td>
-					<td class="tc5"><?php echo ($user_data['admin_note'] != '') ? $user_data['admin_note'] : '&nbsp;' ?></td>
+					<td class="tc5"><?php echo ($user_data['admin_note'] != '') ? pun_htmlspecialchars($user_data['admin_note']) : '&nbsp;' ?></td>
 					<td class="tcr"><?php echo $actions ?></td>
 				</tr>
 <?php
@@ -180,7 +209,7 @@ if (isset($_GET['show_users']))
 				<tr>
 					<td class="tcl"><?php echo pun_htmlspecialchars($poster) ?></td>
 					<td class="tc2">&nbsp;</td>
-					<td class="tc3">Guest</td>
+					<td class="tc3"><?php echo $lang_admin_users['Results guest'] ?></td>
 					<td class="tc4">&nbsp;</td>
 					<td class="tc5">&nbsp;</td>
 					<td class="tcr">&nbsp;</td>
@@ -191,7 +220,7 @@ if (isset($_GET['show_users']))
 		}
 	}
 	else
-		echo "\t\t\t\t".'<tr><td class="tcl" colspan="6">The supplied IP address could not be found in the database.</td></tr>'."\n";
+		echo "\t\t\t\t".'<tr><td class="tcl" colspan="6">'.$lang_admin_users['Results no IP found'].'</td></tr>'."\n";
 
 ?>
 			</tbody>
@@ -201,8 +230,14 @@ if (isset($_GET['show_users']))
 </div>
 
 <div class="linksb">
-	<div class="inbox">
-		<div><a href="javascript:history.go(-1)">Go back</a></div>
+	<div class="inbox crumbsplus">
+		<p class="pagelink"><?php echo $paging_links ?></p>
+		<ul class="crumbs">
+			<li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+		</ul>
+		<div class="clearer"></div>
 	</div>
 </div>
 <?php
@@ -210,98 +245,147 @@ if (isset($_GET['show_users']))
 }
 
 
-else if (isset($_POST['find_user']))
+else if (isset($_GET['find_user']))
 {
-	$form = $_POST['form'];
-	$form['username'] = $_POST['username'];
+	$form = isset($_GET['form']) ? $_GET['form'] : array();
 
 	// trim() all elements in $form
-	$form = array_map('trim', $form);
-	$conditions = array();
-
-	$posts_greater = trim($_POST['posts_greater']);
-	$posts_less = trim($_POST['posts_less']);
-	$last_post_after = trim($_POST['last_post_after']);
-	$last_post_before = trim($_POST['last_post_before']);
-	$registered_after = trim($_POST['registered_after']);
-	$registered_before = trim($_POST['registered_before']);
-	$order_by = $_POST['order_by'];
-	$direction = $_POST['direction'];
-	$user_group = $_POST['user_group'];
+	$form = array_map('pun_trim', $form);
+	$conditions = $query_str = array();
+
+	$posts_greater = isset($_GET['posts_greater']) ? trim($_GET['posts_greater']) : '';
+	$posts_less = isset($_GET['posts_less']) ? trim($_GET['posts_less']) : '';
+	$last_post_after = isset($_GET['last_post_after']) ? trim($_GET['last_post_after']) : '';
+	$last_post_before = isset($_GET['last_post_before']) ? trim($_GET['last_post_before']) : '';
+	$registered_after = isset($_GET['registered_after']) ? trim($_GET['registered_after']) : '';
+	$registered_before = isset($_GET['registered_before']) ? trim($_GET['registered_before']) : '';
+	$order_by = isset($_GET['order_by']) && in_array($_GET['order_by'], array('username', 'email', 'num_posts', 'last_post', 'registered')) ? $_GET['order_by'] : 'username';
+	$direction = isset($_GET['direction']) && $_GET['direction'] == 'DESC' ? 'DESC' : 'ASC';
+	$user_group = isset($_GET['user_group']) ? intval($_GET['user_group']) : -1;
+
+	$query_str[] = 'order_by='.$order_by;
+	$query_str[] = 'direction='.$direction;
+	$query_str[] = 'user_group='.$user_group;
 
 	if (preg_match('/[^0-9]/', $posts_greater.$posts_less))
-		message('You entered a non-numeric value into a numeric only column.');
+		message($lang_admin_users['Non numeric message']);
 
 	// Try to convert date/time to timestamps
 	if ($last_post_after != '')
-		$last_post_after = strtotime($last_post_after);
-	if ($last_post_before != '')
-		$last_post_before = strtotime($last_post_before);
-	if ($registered_after != '')
-		$registered_after = strtotime($registered_after);
-	if ($registered_before != '')
-		$registered_before = strtotime($registered_before);
+	{
+		$query_str[] = 'last_post_after='.$last_post_after;
 
-	if ($last_post_after == -1 || $last_post_before == -1 || $registered_after == -1 || $registered_before == -1)
-		message('You entered an invalid date/time.');
+		$last_post_after = strtotime($last_post_after);
+		if ($last_post_after === false || $last_post_after == -1)
+			message($lang_admin_users['Invalid date time message']);
 
-	if ($last_post_after != '')
 		$conditions[] = 'u.last_post>'.$last_post_after;
+	}
 	if ($last_post_before != '')
+	{
+		$query_str[] = 'last_post_before='.$last_post_before;
+
+		$last_post_before = strtotime($last_post_before);
+		if ($last_post_before === false || $last_post_before == -1)
+			message($lang_admin_users['Invalid date time message']);
+
 		$conditions[] = 'u.last_post<'.$last_post_before;
+	}
 	if ($registered_after != '')
+	{
+		$query_str[] = 'registered_after='.$registered_after;
+
+		$registered_after = strtotime($registered_after);
+		if ($registered_after === false || $registered_after == -1)
+			message($lang_admin_users['Invalid date time message']);
+
 		$conditions[] = 'u.registered>'.$registered_after;
+	}
 	if ($registered_before != '')
+	{
+		$query_str[] = 'registered_before='.$registered_before;
+
+		$registered_before = strtotime($registered_before);
+		if ($registered_before === false || $registered_before == -1)
+			message($lang_admin_users['Invalid date time message']);
+
 		$conditions[] = 'u.registered<'.$registered_before;
+	}
 
 	$like_command = ($db_type == 'pgsql') ? 'ILIKE' : 'LIKE';
 	while (list($key, $input) = @each($form))
 	{
 		if ($input != '' && in_array($key, array('username', 'email', 'title', 'realname', 'url', 'jabber', 'icq', 'msn', 'aim', 'yahoo', 'location', 'signature', 'admin_note')))
+		{
 			$conditions[] = 'u.'.$db->escape($key).' '.$like_command.' \''.$db->escape(str_replace('*', '%', $input)).'\'';
+			$query_str[] = 'form%5B'.$key.'%5D='.urlencode($input);
+		}
 	}
 
 	if ($posts_greater != '')
+	{
+		$query_str[] = 'posts_greater='.$posts_greater;
 		$conditions[] = 'u.num_posts>'.$posts_greater;
+	}
 	if ($posts_less != '')
+	{
+		$query_str[] = 'posts_less='.$posts_less;
 		$conditions[] = 'u.num_posts<'.$posts_less;
+	}
 
-	if ($user_group != 'all')
-		$conditions[] = 'u.group_id='.intval($user_group);
+	if ($user_group > -1)
+		$conditions[] = 'u.group_id='.$user_group;
 
-	if (empty($conditions))
-		message('You didn\'t enter any search terms.');
+	// Fetch user count
+	$result = $db->query('SELECT COUNT(id) FROM '.$db->prefix.'users AS u LEFT JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE u.id>1'.(!empty($conditions) ? ' AND '.implode(' AND ', $conditions) : '')) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+	$num_users = $db->result($result);
 
+	// Determine the user offset (based on $_GET['p'])
+	$num_pages = ceil($num_users / 50);
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Users';
+	$p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
+	$start_from = 50 * ($p - 1);
+
+	// Generate paging links
+	$paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_users.php?find_user=&amp;'.implode('&amp;', $query_str));
+
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Results head']);
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 ?>
 <div class="linkst">
-	<div class="inbox">
-		<div><a href="javascript:history.go(-1)">Go back</a></div>
+	<div class="inbox crumbsplus">
+		<ul class="crumbs">
+			<li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+		</ul>
+		<p class="pagelink"><?php echo $paging_links ?></p>
+		<div class="clearer"></div>
 	</div>
 </div>
 
+
 <div id="users2" class="blocktable">
-	<h2><span>Users</span></h2>
+	<h2><span><?php echo $lang_admin_users['Results head'] ?></span></h2>
 	<div class="box">
 		<div class="inbox">
 			<table cellspacing="0">
 			<thead>
 				<tr>
-					<th class="tcl" scope="col">Username</th>
-					<th class="tc2" scope="col">E-mail</th>
-					<th class="tc3" scope="col">Title/Status</th>
-					<th class="tc4" scope="col">Posts</th>
-					<th class="tc5" scope="col">Admin note</th>
-					<th class="tcr" scope="col">Actions</th>
+					<th class="tcl" scope="col"><?php echo $lang_admin_users['Results username head'] ?></th>
+					<th class="tc2" scope="col"><?php echo $lang_admin_users['Results e-mail head'] ?></th>
+					<th class="tc3" scope="col"><?php echo $lang_admin_users['Results title head'] ?></th>
+					<th class="tc4" scope="col"><?php echo $lang_admin_users['Results posts head'] ?></th>
+					<th class="tc5" scope="col"><?php echo $lang_admin_users['Results admin note head'] ?></th>
+					<th class="tcr" scope="col"><?php echo $lang_admin_users['Results actions head'] ?></th>
 				</tr>
 			</thead>
 			<tbody>
 <?php
 
-	$result = $db->query('SELECT u.id, u.username, u.email, u.title, u.num_posts, u.admin_note, g.g_id, g.g_user_title FROM '.$db->prefix.'users AS u LEFT JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE u.id>1 AND '.implode(' AND ', $conditions).' ORDER BY '.$db->escape($order_by).' '.$db->escape($direction)) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+	$result = $db->query('SELECT u.id, u.username, u.email, u.title, u.num_posts, u.admin_note, g.g_id, g.g_user_title FROM '.$db->prefix.'users AS u LEFT JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE u.id>1'.(!empty($conditions) ? ' AND '.implode(' AND ', $conditions) : '').' ORDER BY '.$db->escape($order_by).' '.$db->escape($direction).' LIMIT '.$start_from.', 50') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
 	if ($db->num_rows($result))
 	{
 		while ($user_data = $db->fetch_assoc($result))
@@ -310,9 +394,9 @@ else if (isset($_POST['find_user']))
 
 			// This script is a special case in that we want to display "Not verified" for non-verified users
 			if (($user_data['g_id'] == '' || $user_data['g_id'] == PUN_UNVERIFIED) && $user_title != $lang_common['Banned'])
-				$user_title = '<span class="warntext">Not verified</span>';
+				$user_title = '<span class="warntext">'.$lang_admin_users['Not verified'].'</span>';
 
-			$actions = '<a href="admin_users.php?ip_stats='.$user_data['id'].'">View IP stats</a> - <a href="search.php?action=show_user&amp;user_id='.$user_data['id'].'">Show posts</a>';
+			$actions = '<a href="admin_users.php?ip_stats='.$user_data['id'].'">'.$lang_admin_users['Results view IP link'].'</a> | <a href="search.php?action=show_user&amp;user_id='.$user_data['id'].'">'.$lang_admin_users['Results show posts link'].'</a>';
 
 ?>
 				<tr>
@@ -320,7 +404,7 @@ else if (isset($_POST['find_user']))
 					<td class="tc2"><a href="mailto:<?php echo $user_data['email'] ?>"><?php echo $user_data['email'] ?></a></td>
 					<td class="tc3"><?php echo $user_title ?></td>
 					<td class="tc4"><?php echo forum_number_format($user_data['num_posts']) ?></td>
-					<td class="tc5"><?php echo ($user_data['admin_note'] != '') ? $user_data['admin_note'] : '&nbsp;' ?></td>
+					<td class="tc5"><?php echo ($user_data['admin_note'] != '') ? pun_htmlspecialchars($user_data['admin_note']) : '&nbsp;' ?></td>
 					<td class="tcr"><?php echo $actions ?></td>
 				</tr>
 <?php
@@ -328,7 +412,7 @@ else if (isset($_POST['find_user']))
 		}
 	}
 	else
-		echo "\t\t\t\t".'<tr><td class="tcl" colspan="6">No match.</td></tr>'."\n";
+		echo "\t\t\t\t".'<tr><td class="tcl" colspan="6">'.$lang_admin_users['No match'].'</td></tr>'."\n";
 
 ?>
 			</tbody>
@@ -338,8 +422,14 @@ else if (isset($_POST['find_user']))
 </div>
 
 <div class="linksb">
-	<div class="inbox">
-		<div><a href="javascript:history.go(-1)">Go back</a></div>
+	<div class="inbox crumbsplus">
+		<p class="pagelink"><?php echo $paging_links ?></p>
+		<ul class="crumbs">
+			<li><a href="admin_index.php"><?php echo $lang_admin_common['Admin'].' '.$lang_admin_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_admin_users['Results head'] ?></strong></li>
+		</ul>
+		<div class="clearer"></div>
 	</div>
 </div>
 <?php
@@ -350,121 +440,126 @@ else if (isset($_POST['find_user']))
 
 else
 {
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Admin / Users';
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users']);
 	$focus_element = array('find_user', 'username');
+	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
 
 	generate_admin_menu('users');
 
 ?>
 	<div class="blockform">
-		<h2><span>User search</span></h2>
+		<h2><span><?php echo $lang_admin_users['User search head'] ?></span></h2>
 		<div class="box">
-			<form id="find_user" method="post" action="admin_users.php?action=find_user">
-				<p class="submittop"><input type="submit" name="find_user" value="Submit search" tabindex="1" /></p>
+			<form id="find_user" method="get" action="admin_users.php">
+				<p class="submittop"><input type="submit" name="find_user" value="<?php echo $lang_admin_users['Submit search'] ?>" tabindex="1" /></p>
 				<div class="inform">
 					<fieldset>
-						<legend>Enter search criteria</legend>
+						<legend><?php echo $lang_admin_users['User search subhead'] ?></legend>
 						<div class="infldset">
-							<p>Search for users in the database. You can enter one or more terms to search for. Wildcards in the form of asterisks (*) are accepted.</p>
-							<table  class="aligntop" cellspacing="0">
+							<p><?php echo $lang_admin_users['User search info'] ?></p>
+							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">Username</th>
-									<td><input type="text" name="username" size="25" maxlength="25" tabindex="2" /></td>
+									<th scope="row"><?php echo $lang_admin_users['Username label'] ?></th>
+									<td><input type="text" name="form[username]" size="25" maxlength="25" tabindex="2" /></td>
 								</tr>
 								<tr>
-									<th scope="row">E-mail address</th>
-									<td><input type="text" name="form[email]" size="30" maxlength="50" tabindex="3" /></td>
+									<th scope="row"><?php echo $lang_admin_users['E-mail address label'] ?></th>
+									<td><input type="text" name="form[email]" size="30" maxlength="80" tabindex="3" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Title</th>
+									<th scope="row"><?php echo $lang_admin_users['Title label'] ?></th>
 									<td><input type="text" name="form[title]" size="30" maxlength="50" tabindex="4" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Real name</th>
+									<th scope="row"><?php echo $lang_admin_users['Real name label'] ?></th>
 									<td><input type="text" name="form[realname]" size="30" maxlength="40" tabindex="5" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Website</th>
+									<th scope="row"><?php echo $lang_admin_users['Website label'] ?></th>
 									<td><input type="text" name="form[url]" size="35" maxlength="100" tabindex="6" /></td>
 								</tr>
 								<tr>
-									<th scope="row">ICQ</th>
-									<td><input type="text" name="form[icq]" size="12" maxlength="12" tabindex="7" /></td>
+									<th scope="row"><?php echo $lang_admin_users['Jabber label'] ?></th>
+									<td><input type="text" name="form[jabber]" size="30" maxlength="75" tabindex="7" /></td>
+								</tr>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_users['ICQ label'] ?></th>
+									<td><input type="text" name="form[icq]" size="12" maxlength="12" tabindex="8" /></td>
 								</tr>
 								<tr>
-									<th scope="row">MSN Messenger</th>
-									<td><input type="text" name="form[msn]" size="30" maxlength="50" tabindex="8" /></td>
+									<th scope="row"><?php echo $lang_admin_users['MSN label'] ?></th>
+									<td><input type="text" name="form[msn]" size="30" maxlength="50" tabindex="9" /></td>
 								</tr>
 								<tr>
-									<th scope="row">AOL IM</th>
-									<td><input type="text" name="form[aim]" size="20" maxlength="20" tabindex="9" /></td>
+									<th scope="row"><?php echo $lang_admin_users['AOL label'] ?></th>
+									<td><input type="text" name="form[aim]" size="20" maxlength="20" tabindex="10" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Yahoo! Messenger</th>
-									<td><input type="text" name="form[yahoo]" size="20" maxlength="20" tabindex="10" /></td>
+									<th scope="row"><?php echo $lang_admin_users['Yahoo label'] ?></th>
+									<td><input type="text" name="form[yahoo]" size="20" maxlength="20" tabindex="11" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Location</th>
-									<td><input type="text" name="form[location]" size="30" maxlength="30" tabindex="11" /></td>
+									<th scope="row"><?php echo $lang_admin_users['Location label'] ?></th>
+									<td><input type="text" name="form[location]" size="30" maxlength="30" tabindex="12" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Signature</th>
-									<td><input type="text" name="form[signature]" size="35" maxlength="512" tabindex="12" /></td>
+									<th scope="row"><?php echo $lang_admin_users['Signature label'] ?></th>
+									<td><input type="text" name="form[signature]" size="35" maxlength="512" tabindex="13" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Admin note</th>
-									<td><input type="text" name="form[admin_note]" size="30" maxlength="30" tabindex="13" /></td>
+									<th scope="row"><?php echo $lang_admin_users['Admin note label'] ?></th>
+									<td><input type="text" name="form[admin_note]" size="30" maxlength="30" tabindex="14" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Number of posts greater than</th>
-									<td><input type="text" name="posts_greater" size="5" maxlength="8" tabindex="14" /></td>
+									<th scope="row"><?php echo $lang_admin_users['Posts more than label'] ?></th>
+									<td><input type="text" name="posts_greater" size="5" maxlength="8" tabindex="15" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Number of posts less than</th>
-									<td><input type="text" name="posts_less" size="5" maxlength="8" tabindex="15" /></td>
+									<th scope="row"><?php echo $lang_admin_users['Posts less than label'] ?></th>
+									<td><input type="text" name="posts_less" size="5" maxlength="8" tabindex="16" /></td>
 								</tr>
 								<tr>
-									<th scope="row">Last post is after</th>
-									<td><input type="text" name="last_post_after" size="24" maxlength="19" tabindex="16" />
-									<span>(yyyy-mm-dd hh:mm:ss)</span></td>
+									<th scope="row"><?php echo $lang_admin_users['Last post after label'] ?></th>
+									<td><input type="text" name="last_post_after" size="24" maxlength="19" tabindex="17" />
+									<span><?php echo $lang_admin_users['Date help'] ?></span></td>
 								</tr>
 								<tr>
-									<th scope="row">Last post is before</th>
-									<td><input type="text" name="last_post_before" size="24" maxlength="19" tabindex="17" />
-									<span>(yyyy-mm-dd hh:mm:ss)</span></td>
+									<th scope="row"><?php echo $lang_admin_users['Last post before label'] ?></th>
+									<td><input type="text" name="last_post_before" size="24" maxlength="19" tabindex="18" />
+									<span><?php echo $lang_admin_users['Date help'] ?></span></td>
 								</tr>
 								<tr>
-									<th scope="row">Registered after</th>
-									<td><input type="text" name="registered_after" size="24" maxlength="19" tabindex="18" />
-									<span>(yyyy-mm-dd hh:mm:ss)</span></td>
+									<th scope="row"><?php echo $lang_admin_users['Registered after label'] ?></th>
+									<td><input type="text" name="registered_after" size="24" maxlength="19" tabindex="19" />
+									<span><?php echo $lang_admin_users['Date help'] ?></span></td>
 								</tr>
 								<tr>
-									<th scope="row">Registered before</th>
-									<td><input type="text" name="registered_before" size="24" maxlength="19" tabindex="19" />
-									<span>(yyyy-mm-dd hh:mm:ss)</span></td>
+									<th scope="row"><?php echo $lang_admin_users['Registered before label'] ?></th>
+									<td><input type="text" name="registered_before" size="24" maxlength="19" tabindex="20" />
+									<span><?php echo $lang_admin_users['Date help'] ?></span></td>
 								</tr>
 								<tr>
-									<th scope="row">Order by</th>
+									<th scope="row"><?php echo $lang_admin_users['Order by label'] ?></th>
 									<td>
-										<select name="order_by" tabindex="20">
-											<option value="username" selected="selected">username</option>
-											<option value="email">e-mail</option>
-											<option value="num_posts">posts</option>
-											<option value="last_post">last post</option>
-											<option value="registered">registered</option>
-										</select>&nbsp;&nbsp;&nbsp;<select name="direction" tabindex="21">
-											<option value="ASC" selected="selected">ascending</option>
-											<option value="DESC">descending</option>
+										<select name="order_by" tabindex="21">
+											<option value="username" selected="selected"><?php echo $lang_admin_users['Order by username'] ?></option>
+											<option value="email"><?php echo $lang_admin_users['Order by e-mail'] ?></option>
+											<option value="num_posts"><?php echo $lang_admin_users['Order by posts'] ?></option>
+											<option value="last_post"><?php echo $lang_admin_users['Order by last post'] ?></option>
+											<option value="registered"><?php echo $lang_admin_users['Order by registered'] ?></option>
+										</select>&nbsp;&nbsp;&nbsp;<select name="direction" tabindex="22">
+											<option value="ASC" selected="selected"><?php echo $lang_admin_users['Ascending'] ?></option>
+											<option value="DESC"><?php echo $lang_admin_users['Descending'] ?></option>
 										</select>
 									</td>
 								</tr>
 								<tr>
-									<th scope="row">User group</th>
+									<th scope="row"><?php echo $lang_admin_users['User group label'] ?></th>
 									<td>
-										<select name="user_group" tabindex="22">
-												<option value="all" selected="selected">All groups</option>
-												<option value="0">Unverified users</option>
+										<select name="user_group" tabindex="23">
+											<option value="-1" selected="selected"><?php echo $lang_admin_users['All groups'] ?></option>
+											<option value="0"><?php echo $lang_admin_users['Unverified users'] ?></option>
 <?php
 
 	$result = $db->query('SELECT g_id, g_title FROM '.$db->prefix.'groups WHERE g_id!='.PUN_GUEST.' ORDER BY g_title') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
@@ -480,22 +575,22 @@ else
 						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="find_user" value="Submit search" tabindex="23" /></p>
+				<p class="submitend"><input type="submit" name="find_user" value="<?php echo $lang_admin_users['Submit search'] ?>" tabindex="25" /></p>
 			</form>
 		</div>
 
-		<h2 class="block2"><span>IP search</span></h2>
+		<h2 class="block2"><span><?php echo $lang_admin_users['IP search head'] ?></span></h2>
 		<div class="box">
 			<form method="get" action="admin_users.php">
 				<div class="inform">
 					<fieldset>
-						<legend>Enter IP to search for</legend>
+						<legend><?php echo $lang_admin_users['IP search subhead'] ?></legend>
 						<div class="infldset">
 							<table class="aligntop" cellspacing="0">
 								<tr>
-									<th scope="row">IP address<div><input type="submit" value=" Find " tabindex="25" /></div></th>
+									<th scope="row"><?php echo $lang_admin_users['IP address label'] ?><div><input type="submit" value="<?php echo $lang_admin_users['Find IP address'] ?>" tabindex="26" /></div></th>
 									<td><input type="text" name="show_users" size="18" maxlength="15" tabindex="24" />
-									<span>The IP address to search for in the post database.</span></td>
+									<span><?php echo $lang_admin_users['IP address help'] ?></span></td>
 								</tr>
 							</table>
 						</div>
diff --git a/upload/cache/.htaccess b/upload/cache/.htaccess
index c391816..e67301e 100644
--- a/upload/cache/.htaccess
+++ b/upload/cache/.htaccess
@@ -1,4 +1,4 @@
 <Limit GET POST PUT>
 Order Allow,Deny
 Deny from All
-</Limit>
\ No newline at end of file
+</Limit>
diff --git a/upload/cache/index.html b/upload/cache/index.html
index 2db9a3c..89337b2 100644
--- a/upload/cache/index.html
+++ b/upload/cache/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/db_update.php b/upload/db_update.php
index c640016..6cf36eb 100644
--- a/upload/db_update.php
+++ b/upload/db_update.php
@@ -1,26 +1,28 @@
 <?php
+
 /**
- * Database updating script
- *
- * Updates the database to the latest version.
- *
- * @copyright Copyright (C) 2008 FluxBB.org, based on code copyright (C) 2002-2008 PunBB.org
- * @license http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
- * @package FluxBB
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
  */
 
+// The FluxBB version this script updates to
+define('UPDATE_TO', '1.4-rc3');
+define('UPDATE_TO_DB_REVISION', 5);
 
-define('UPDATE_TO', '1.4');
-define('UPDATE_TO_DB_REVISION', 1);
-
-// The number of items to process per pageview (lower this if the update script times out during UTF-8 conversion)
-define('PER_PAGE', 300);
+define('MIN_PHP_VERSION', '4.3.0');
+define('MIN_MYSQL_VERSION', '4.1.2');
+define('MIN_PGSQL_VERSION', '7.0.0');
+define('PUN_SEARCH_MIN_WORD', 3);
+define('PUN_SEARCH_MAX_WORD', 20);
 
 
-// Make sure we are running at least PHP 4.1.0
-if (intval(str_replace('.', '', phpversion())) < 410)
-	exit('You are running PHP version '.PHP_VERSION.'. FluxBB requires at least PHP 4.1.0 to run properly. You must upgrade your PHP installation before you can continue.');
+// The number of items to process per page view (lower this if the update script times out during UTF-8 conversion)
+define('PER_PAGE', 300);
 
+// Make sure we are running at least MIN_PHP_VERSION
+if (!function_exists('version_compare') || version_compare(PHP_VERSION, MIN_PHP_VERSION, '<'))
+	exit('You are running PHP version '.PHP_VERSION.'. FluxBB '.UPDATE_TO.' requires at least PHP '.MIN_PHP_VERSION.' to run properly. You must upgrade your PHP installation before you can continue.');
 
 define('PUN_ROOT', './');
 
@@ -28,21 +30,53 @@ define('PUN_ROOT', './');
 if (file_exists(PUN_ROOT.'config.php'))
 	include PUN_ROOT.'config.php';
 
+// If we have the 1.3-legacy constant defined, define the proper 1.4 constant so we don't get an incorrect "need to install" message
+if (defined('FORUM'))
+	define('PUN', FORUM);
+
 // If PUN isn't defined, config.php is missing or corrupt or we are outside the root directory
 if (!defined('PUN'))
 	exit('This file must be run from the forum root directory.');
 
 // Enable debug mode
-define('PUN_DEBUG', 1);
+if (!defined('PUN_DEBUG'))
+	define('PUN_DEBUG', 1);
+
+// Load the functions script
+require PUN_ROOT.'include/functions.php';
+
+// Load UTF-8 functions
+require PUN_ROOT.'include/utf8/utf8.php';
+
+// Strip out "bad" UTF-8 characters
+forum_remove_bad_characters();
+
+// Reverse the effect of register_globals
+forum_unregister_globals();
 
 // Turn on full PHP error reporting
 error_reporting(E_ALL);
 
+// Force POSIX locale (to prevent functions such as strtolower() from messing up UTF-8 strings)
+setlocale(LC_CTYPE, 'C');
+
 // Turn off magic_quotes_runtime
-set_magic_quotes_runtime(0);
+if (get_magic_quotes_runtime())
+	set_magic_quotes_runtime(0);
 
-// Turn off PHP time limit
-@set_time_limit(0);
+// Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled)
+if (get_magic_quotes_gpc())
+{
+	function stripslashes_array($array)
+	{
+		return is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array);
+	}
+
+	$_GET = stripslashes_array($_GET);
+	$_POST = stripslashes_array($_POST);
+	$_COOKIE = stripslashes_array($_COOKIE);
+	$_REQUEST = stripslashes_array($_REQUEST);
+}
 
 // If a cookie name is not specified in config.php, we use the default (forum_cookie)
 if (empty($cookie_name))
@@ -52,17 +86,8 @@ if (empty($cookie_name))
 if (!defined('FORUM_CACHE_DIR'))
 	define('FORUM_CACHE_DIR', PUN_ROOT.'cache/');
 
-// Load the functions script
-require PUN_ROOT.'include/functions.php';
-
-// Load UTF-8 functions
-require PUN_ROOT.'include/utf8/utf8.php';
-
-// Strip out "bad" UTF-8 characters
-forum_remove_bad_characters();
-
-// Instruct DB abstraction layer that we don't want it to "SET NAMES". If we need to, we'll do it ourselves below.
-define('FORUM_NO_SET_NAMES', 1);
+// Turn off PHP time limit
+@set_time_limit(0);
 
 // Load DB abstraction layer and try to connect
 require PUN_ROOT.'include/dblayer/common_db.php';
@@ -74,8 +99,28 @@ $cur_version = $db->result($result);
 if (version_compare($cur_version, '1.2', '<'))
 	exit('Version mismatch. The database \''.$db_name.'\' doesn\'t seem to be running a FluxBB database schema supported by this update script.');
 
-// If we've already done charset conversion in a previous update, we have to do SET NAMES
-$db->set_names(strpos($cur_version, '1.3') === 0 ? 'utf8' : 'latin1');
+// Do some DB type specific checks
+$mysql = false;
+switch ($db_type)
+{
+	case 'mysql':
+	case 'mysqli':
+	case 'mysql_innodb':
+	case 'mysqli_innodb':
+		$mysql_info = $db->get_version();
+		if (version_compare($mysql_info['version'], MIN_MYSQL_VERSION, '<'))
+			error('You are running MySQL version '.$mysql_version.'. FluxBB '.UPDATE_TO.' requires at least MySQL '.MIN_MYSQL_VERSION.' to run properly. You must upgrade your MySQL installation before you can continue.');
+
+		$mysql = true;
+		break;
+
+	case 'pgsql':
+		$pgsql_info = $db->get_version();
+		if (version_compare($pgsql_info['version'], MIN_PGSQL_VERSION, '<'))
+			error('You are running PostgreSQL version '.$pgsql_info.'. FluxBB '.UPDATE_TO.' requires at least PostgreSQL '.MIN_PGSQL_VERSION.' to run properly. You must upgrade your PostgreSQL installation before you can continue.');
+
+		break;
+}
 
 // Get the forum config
 $result = $db->query('SELECT * FROM '.$db->prefix.'config') or error('Unable to fetch config.', __FILE__, __LINE__, $db->error());
@@ -86,6 +131,9 @@ while ($cur_config_item = $db->fetch_row($result))
 if (isset($pun_config['o_database_revision']) && $pun_config['o_database_revision'] >= UPDATE_TO_DB_REVISION && version_compare($pun_config['o_cur_version'], UPDATE_TO, '>='))
 	exit('Your database is already as up-to-date as this script can make it.');
 
+$default_style = $pun_config['o_default_style'];
+if (!file_exists(PUN_ROOT.'style/'.$default_style.'.css'))
+	$default_style = 'Air';
 
 //
 // Determines whether $str is UTF-8 encoded or not
@@ -115,7 +163,7 @@ function seems_utf8($str)
 
 
 //
-// Translates the number from an HTML numeric entity into an UTF-8 character
+// Translates the number from a HTML numeric entity into an UTF-8 character
 //
 function dcr2utf8($src)
 {
@@ -162,11 +210,11 @@ function dcr2utf8($src)
 
 
 //
-// Attemts to convert $str from $old_charset to UTF-8. Also converts HTML entities (including numeric entities) to UTF-8 characters.
+// Attempts to convert $str from $old_charset to UTF-8. Also converts HTML entities (including numeric entities) to UTF-8 characters
 //
 function convert_to_utf8(&$str, $old_charset)
 {
-	if ($str == '')
+	if ($str === null || $str == '')
 		return false;
 
 	$save = $str;
@@ -175,14 +223,14 @@ function convert_to_utf8(&$str, $old_charset)
 	if (version_compare(PHP_VERSION, '5.0.0', '<') && $old_charset == 'ISO-8859-1' || $old_charset == 'ISO-8859-15')
 		$str = html_entity_decode($str, ENT_QUOTES, $old_charset);
 
-	if (!seems_utf8($str))
+	if ($old_charset != 'UTF-8' && !seems_utf8($str))
 	{
-		if ($old_charset == 'ISO-8859-1')
-			$str = utf8_encode($str);
-		else if (function_exists('iconv'))
-			$str = iconv($old_charset, 'UTF-8', $str);
+		if (function_exists('iconv'))
+			$str = iconv($old_charset == 'ISO-8859-1' ? 'WINDOWS-1252' : 'ISO-8859-1', 'UTF-8', $str);
 		else if (function_exists('mb_convert_encoding'))
-			$str = mb_convert_encoding($str, 'UTF-8', $old_charset);
+			$str = mb_convert_encoding($str, 'UTF-8', $old_charset == 'ISO-8859-1' ? 'WINDOWS-1252' : 'ISO-8859-1');
+		else if ($old_charset == 'ISO-8859-1')
+			$str = utf8_encode($str);
 	}
 
 	// Replace literal entities (for UTF-8 compliant html_entity_encode)
@@ -193,6 +241,9 @@ function convert_to_utf8(&$str, $old_charset)
 	$str = preg_replace_callback('/&#([0-9]+);/', 'utf8_callback_1', $str);
 	$str = preg_replace_callback('/&#x([a-f0-9]+);/i', 'utf8_callback_2', $str);
 
+	// Remove "bad" characters
+	$str = remove_bad_characters($str);
+
 	return ($save != $str);
 }
 
@@ -210,71 +261,147 @@ function utf8_callback_2($matches)
 
 
 //
-// Tries to determine whether post data in the database is UTF-8 encoded or not
+// Alter a table to be utf8. MySQL only
+// Function based on update_convert_table_utf8() from the Drupal project (http://drupal.org/)
 //
-function db_seems_utf8()
+function alter_table_utf8($table)
 {
-	global $db_type, $db;
+	global $mysql, $db;
+	static $types;
 
-	$seems_utf8 = true;
+	if (!$mysql)
+		return;
 
-	$result = $db->query('SELECT MIN(id), MAX(id) FROM '.$db->prefix.'posts') or error('Unable to fetch post IDs', __FILE__, __LINE__, $db->error());
-	list($min_id, $max_id) = $db->fetch_row($result);
-	
-	if (empty($min_id) || empty($max_id))
-		return true;
-
-	// Get a random soup of data and check if it appears to be UTF-8
-	for ($i = 0; $i < 100; ++$i)
+	if (!isset($types))
 	{
-		$id = ($i == 0) ? $min_id : (($i == 1) ? $max_id : rand($min_id, $max_id));
+		$types = array(
+			'char'			=> 'binary',
+			'varchar'		=> 'varbinary',
+			'tinytext'		=> 'tinyblob',
+			'mediumtext'	=> 'mediumblob',
+			'text'			=> 'blob',
+			'longtext'		=> 'longblob'
+		);
+	}
 
-		$result = $db->query('SELECT p.message, p.poster, t.subject, f.forum_name FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON (t.id = p.topic_id) INNER JOIN '.$db->prefix.'forums AS f ON (f.id = t.forum_id) WHERE p.id >= '.$id.' LIMIT 1') or error('Unable to fetch post information', __FILE__, __LINE__, $db->error());
-		$temp = $db->fetch_row($result);
+	// Set table default charset to utf8
+	$db->query('ALTER TABLE '.$table.' CHARACTER SET utf8') or error('Unable to set table character set', __FILE__, __LINE__, $db->error());
 
-		if (!seems_utf8($temp[0].$temp[1].$temp[2].$temp[3]))
+	// Find out which columns need converting and build SQL statements
+	$result = $db->query('SHOW FULL COLUMNS FROM '.$table) or error('Unable to fetch column information', __FILE__, __LINE__, $db->error());
+	while ($cur_column = $db->fetch_assoc($result))
+	{
+		if ($cur_column['Collation'] === null)
+			continue;
+
+		list($type) = explode('(', $cur_column['Type']);
+		if (isset($types[$type]) && strpos($cur_column['Collation'], 'utf8') === false)
 		{
-			$seems_utf8 = false;
-			break;
+			$allow_null = ($cur_column['Null'] == 'YES');
+			$collate = (substr($cur_column['Collation'], -3) == 'bin') ? 'utf8_bin' : 'utf8_general_ci';
+
+			$db->alter_field($table, $cur_column['Field'], preg_replace('/'.$type.'/i', $types[$type], $cur_column['Type']), $allow_null, $cur_column['Default'], null, true) or error('Unable to alter field to binary', __FILE__, __LINE__, $db->error());
+			$db->alter_field($table, $cur_column['Field'], $cur_column['Type'].' CHARACTER SET utf8 COLLATE '.$collate, $allow_null, $cur_column['Default'], null, true) or error('Unable to alter field to utf8', __FILE__, __LINE__, $db->error());
 		}
 	}
-
-	return $seems_utf8;
 }
 
-
 //
-// Safely converts text type columns into utf8 (MySQL only)
-// Function based on update_convert_table_utf8() from the Drupal project (http://drupal.org/)
+// Safely converts text type columns into utf8
+// If finished returns true, otherwise returns $end_at
 //
-function convert_table_utf8($table)
+function convert_table_utf8($table, $callback, $old_charset, $key = null, $start_at = null)
 {
-	global $db;
+	global $mysql, $db;
 
-	$types = array(
-		'char' 			=> 'binary',
-		'varchar'		=> 'varbinary',
-		'tinytext'		=> 'tinyblob',
-		'mediumtext'	=> 'mediumblob',
-		'text'			=> 'blob',
-		'longtext'		=> 'longblob'
-	);
+	$finished = true;
+	$end_at = 0;
+	if ($mysql)
+	{
+		// Only set up the tables if we are doing this in 1 go, or its the first go
+		if ($start_at === null || $start_at == 0)
+		{
+			// Drop any temp table that exists, in-case it's left over from a failed update
+			$db->drop_table($table.'_utf8', true) or error('Unable to drop left over temp table', __FILE__, __LINE__, $db->error());
 
-	// Set table default charset to utf8
-	$db->query('ALTER TABLE `'.$table.'` CHARACTER SET utf8') or error('Unable to set table character set', __FILE__, __LINE__, $db->error());
+			// Copy the table
+			$db->query('CREATE TABLE '.$table.'_utf8 LIKE '.$table) or error('Unable to create new table', __FILE__, __LINE__, $db->error());
 
-	// Find out which columns need converting and build SQL statements
-	$result = $db->query('SHOW FULL COLUMNS FROM `'.$table.'`') or error('Unable to fetch column information', __FILE__, __LINE__, $db->error());
-	while ($cur_column = $db->fetch_assoc($result))
+			// Set table default charset to utf8
+			alter_table_utf8($table.'_utf8');
+		}
+
+		// Change to latin1 mode so MySQL doesn't attempt to perform conversion on the data from the old table
+		$db->set_names('latin1');
+
+		// Move & Convert everything
+		$result = $db->query('SELECT * FROM '.$table.($start_at === null ? '' : ' WHERE '.$key.'>'.$start_at).' ORDER BY '.$key.' ASC'.($start_at === null ? '' : ' LIMIT '.PER_PAGE), false) or error('Unable to select from old table', __FILE__, __LINE__, $db->error());
+
+		// Change back to utf8 mode so we can insert it into the new table
+		$db->set_names('utf8');
+
+		while ($cur_item = $db->fetch_assoc($result))
+		{
+			$cur_item = call_user_func($callback, $cur_item, $old_charset);
+
+			$temp = array();
+			foreach ($cur_item as $idx => $value)
+				$temp[$idx] = $value === null ? 'NULL' : '\''.$db->escape($value).'\'';
+
+			$db->query('INSERT INTO '.$table.'_utf8('.implode(',', array_keys($temp)).') VALUES ('.implode(',', array_values($temp)).')') or error('Unable to insert data to new table', __FILE__, __LINE__, $db->error());
+
+			$end_at = $cur_item[$key];
+		}
+
+		// If we aren't doing this all in 1 go and $end_at has a value (i.e. we have processed at least 1 row), figure out if we have more to do or not
+		if ($start_at !== null && $end_at > 0)
+		{
+			$result = $db->query('SELECT 1 FROM '.$table.' WHERE '.$key.'>'.$end_at.' ORDER BY '.$key.' ASC LIMIT 1') or error('Unable to check for next row', __FILE__, __LINE__, $db->error());
+			$finished = $db->num_rows($result) == 0;
+		}
+
+		// Only swap the tables if we are doing this in 1 go, or its the last go
+		if ($finished)
+		{
+			// Delete old table
+			$db->drop_table($table, true) or error('Unable to drop old table', __FILE__, __LINE__, $db->error());
+
+			// Rename table
+			$db->query('ALTER TABLE '.$table.'_utf8 RENAME '.$table) or error('Unable to rename new table', __FILE__, __LINE__, $db->error());
+
+			return true;
+		}
+
+		return $end_at;
+	}
+	else
 	{
-		list($type) = explode('(', $cur_column['Type']);
-		if (isset($types[$type]) && strpos($cur_column['Collation'], 'utf8') === false)
+		// Convert everything
+		$result = $db->query('SELECT * FROM '.$table.($start_at === null ? '' : ' WHERE '.$key.'>'.$start_at).' ORDER BY '.$key.' ASC'.($start_at === null ? '' : ' LIMIT '.PER_PAGE)) or error('Unable to select from table', __FILE__, __LINE__, $db->error());
+		while ($cur_item = $db->fetch_assoc($result))
 		{
-			$allow_null = ($cur_column['Null'] == 'YES');
+			$cur_item = call_user_func($callback, $cur_item, $old_charset);
+
+			$temp = array();
+			foreach ($cur_item as $idx => $value)
+				$temp[] = $idx.'='.($value === null ? 'NULL' : '\''.$db->escape($value).'\'');
+
+			if (!empty($temp))
+				$db->query('UPDATE '.$table.' SET '.implode(', ', $temp).' WHERE '.$key.'=\''.$db->escape($cur_item[$key]).'\'') or error('Unable to update data', __FILE__, __LINE__, $db->error());
 
-			$db->alter_field($table, $cur_column['Field'], preg_replace('/'.$type.'/i', $types[$type], $cur_column['Type']), $allow_null, $cur_column['Default']);
-			$db->alter_field($table, $cur_column['Field'], $cur_column['Type'].' CHARACTER SET utf8', $allow_null, $cur_column['Default']);
+			$end_at = $cur_item[$key];
 		}
+
+		if ($start_at !== null && $end_at > 0)
+		{
+			$result = $db->query('SELECT 1 FROM '.$table.' WHERE '.$key.'>'.$end_at.' ORDER BY '.$key.' ASC LIMIT 1') or error('Unable to check for next row', __FILE__, __LINE__, $db->error());
+			if ($db->num_rows($result) == 0)
+				return true;
+
+			return $end_at;
+		}
+
+		return true;
 	}
 }
 
@@ -294,7 +421,6 @@ switch ($stage)
 {
 	// Show form
 	case '':
-		$db_seems_utf8 = db_seems_utf8();
 
 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
@@ -303,7 +429,7 @@ switch ($stage)
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>FluxBB Database Update</title>
-<link rel="stylesheet" type="text/css" href="style/Oxygen.css" />
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
 </head>
 <body>
 
@@ -316,11 +442,11 @@ switch ($stage)
 		<form method="get" action="<?php echo pun_htmlspecialchars($_SERVER['REQUEST_URI']) ?>" onsubmit="this.start.disabled=true">
 		<input type="hidden" name="stage" value="start" />
 			<div class="inform">
-				<p style="font-size: 1.1em">This script will update your forum database. The update procedure might take anything from a second to a few minutes depending on the speed of the server and the size of the forum database. Don't forget to make a backup of the database before continuing.</p>
+				<p style="font-size: 1.1em">This script will update your forum database. The update procedure might take anything from a second to hours depending on the speed of the server and the size of the forum database. Don't forget to make a backup of the database before continuing.</p>
 				<p style="font-size: 1.1em">Did you read the update instructions in the documentation? If not, start there.</p>
 <?php
 
-if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'])))
+if (strpos($cur_version, '1.2') === 0)
 {
 	if (!function_exists('iconv') && !function_exists('mb_convert_encoding'))
 	{
@@ -330,25 +456,12 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 <?php
 
 	}
-}
-
-if (strpos($cur_version, '1.2') === 0 && $db_seems_utf8 && !isset($_GET['force']))
-{
-
-?>
-				<p style="font-size: 1.1em"><span><strong>IMPORTANT!</strong> Based on a random selection of 100 posts, topic subjects, usernames and forum names from the database, it appears as if text in the database is currently UTF-8 encoded. This is a good thing. Based on this, the update process will not attempt to do charset conversion. If you have reason to believe that the charset conversion is required nonetheless, you can <a href="<?php echo pun_htmlspecialchars($_SERVER['REQUEST_URI']).((substr_count($_SERVER['REQUEST_URI'], '?') == 1) ? '&amp;' : '?').'force=1' ?>">force the conversion to run</a>.</p>
-<?php
-
-}
-
-if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'])))
-{
 
 ?>
 			</div>
 			<div class="inform">
-				<p style="font-size: 1.1em"><strong>Enable conversion:</strong> When enabled this update script will, after it has made the required structural changes to the database, convert all text in the database from the current character set to UTF-8. This conversion is required if you're upgrading from version 1.2 and you are not currently using an UTF-8 language pack.</p>
-				<p style="font-size: 1.1em"><strong>Current character set:</strong> If the primary language in your forum is English, you can leave this at the default value. However, if your forum is non-English, you should enter the character set of the primary language pack used in the forum.</p>
+				<p style="font-size: 1.1em"><strong>Enable conversion:</strong> When enabled this update script will, after it has made the required structural changes to the database, convert all text in the database from the current character set to UTF-8. This conversion is required if you're upgrading from version 1.2.</p>
+				<p style="font-size: 1.1em"><strong>Current character set:</strong> If the primary language in your forum is English, you can leave this at the default value. However, if your forum is non-English, you should enter the character set of the primary language pack used in the forum. <i>Getting this wrong can corrupt your database so don't just guess!</i> Note: This is required even if the old database is UTF-8.</p>
 			<fieldset>
 				<legend>Charset conversion</legend>
 				<div class="infldset">
@@ -363,8 +476,8 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 						<tr>
 							<th scope="row">Current character set:</th>
 							<td>
-								<input type="text" name="req_old_charset" size="12" maxlength="20" value="ISO-8859-1" /><br />
-								<span>Accept default for English forums otherwise the character set of the primary langauge pack.</span>
+								<input type="text" name="req_old_charset" size="12" maxlength="20" value="<?php echo $old_charset ?>" /><br />
+								<span>Accept default for English forums otherwise the character set of the primary language pack.</span>
 							</td>
 						</tr>
 					</table>
@@ -376,7 +489,7 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 
 ?>
 			</div>
-			<p><input type="submit" name="start" value="Start update" /></p>
+			<p class="buttons"><input type="submit" name="start" value="Start update" /></p>
 		</form>
 	</div>
 </div>
@@ -393,77 +506,172 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 
 	// Start by updating the database structure
 	case 'start':
-		// Make all e-mail fields VARCHAR(80)
-		$db->alter_field('bans', 'email', 'VARCHAR(80)', true);
-		$db->alter_field('posts', 'poster_email', 'VARCHAR(80)', true);
-		$db->alter_field('users', 'email', 'VARCHAR(80)', false, '');
-		$db->alter_field('users', 'jabber', 'VARCHAR(80)', true);
-		$db->alter_field('users', 'msn', 'VARCHAR(80)', true);
-		$db->alter_field('users', 'activate_string', 'VARCHAR(80)', true);
+		$query_str = '?stage=pre_finish';
+
+		// Make all email fields VARCHAR(80)
+		$db->alter_field('bans', 'email', 'VARCHAR(80)', true) or error('Unable to alter email field', __FILE__, __LINE__, $db->error());
+		$db->alter_field('posts', 'poster_email', 'VARCHAR(80)', true) or error('Unable to alter poster_email field', __FILE__, __LINE__, $db->error());
+		$db->alter_field('users', 'email', 'VARCHAR(80)', false, '') or error('Unable to alter email field', __FILE__, __LINE__, $db->error());
+		$db->alter_field('users', 'jabber', 'VARCHAR(80)', true) or error('Unable to alter jabber field', __FILE__, __LINE__, $db->error());
+		$db->alter_field('users', 'msn', 'VARCHAR(80)', true) or error('Unable to alter msn field', __FILE__, __LINE__, $db->error());
+		$db->alter_field('users', 'activate_string', 'VARCHAR(80)', true) or error('Unable to alter activate_string field', __FILE__, __LINE__, $db->error());
 
 		// Make all IP fields VARCHAR(39) to support IPv6
-		$db->alter_field('posts', 'poster_ip', 'VARCHAR(39)', true);
-		$db->alter_field('users', 'registration_ip', 'VARCHAR(39)', false, '0.0.0.0');
+		$db->alter_field('posts', 'poster_ip', 'VARCHAR(39)', true) or error('Unable to alter poster_ip field', __FILE__, __LINE__, $db->error());
+		$db->alter_field('users', 'registration_ip', 'VARCHAR(39)', false, '0.0.0.0') or error('Unable to alter registration_ip field', __FILE__, __LINE__, $db->error());
 
 		// Add the DST option to the users table
-		$db->add_field('users', 'dst', 'TINYINT(1)', false, 0, 'timezone');
+		$db->add_field('users', 'dst', 'TINYINT(1)', false, 0, 'timezone') or error('Unable to add dst field', __FILE__, __LINE__, $db->error());
 
 		// Add the last_post field to the online table
-		$db->add_field('online', 'last_post', 'INT(10) UNSIGNED', true, null, null);
+		$db->add_field('online', 'last_post', 'INT(10) UNSIGNED', true, null, null) or error('Unable to add last_post field', __FILE__, __LINE__, $db->error());
 
 		// Add the last_search field to the online table
-		$db->add_field('online', 'last_search', 'INT(10) UNSIGNED', true, null, null);
+		$db->add_field('online', 'last_search', 'INT(10) UNSIGNED', true, null, null) or error('Unable to add last_search field', __FILE__, __LINE__, $db->error());
 
 		// Add the last_search column to the users table
-		$db->add_field('users', 'last_search', 'INT(10)', true, null, 'last_post');
+		$db->add_field('users', 'last_search', 'INT(10) UNSIGNED', true, null, 'last_post') or error('Unable to add last_search field', __FILE__, __LINE__, $db->error());
 
 		// Drop use_avatar column from users table
-		$db->drop_field('users', 'use_avatar');
+		$db->drop_field('users', 'use_avatar') or error('Unable to drop use_avatar field', __FILE__, __LINE__, $db->error());
 
 		// Drop save_pass column from users table
-		$db->drop_field('users', 'save_pass');
+		$db->drop_field('users', 'save_pass') or error('Unable to drop save_pass field', __FILE__, __LINE__, $db->error());
 
 		// Drop g_edit_subjects_interval column from groups table
 		$db->drop_field('groups', 'g_edit_subjects_interval');
 
-		$new_config = array();
-
 		// Add database revision number
 		if (!array_key_exists('o_database_revision', $pun_config))
-			$new_config[] = '\'o_database_revision\', \'0\'';
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_database_revision\', \'0\')') or error('Unable to insert config value \'o_database_revision\'', __FILE__, __LINE__, $db->error());
 
 		// Add default email setting option
 		if (!array_key_exists('o_default_email_setting', $pun_config))
-			$new_config[] = '\'o_default_email_setting\', \'1\'';
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_default_email_setting\', \'1\')') or error('Unable to insert config value \'o_default_email_setting\'', __FILE__, __LINE__, $db->error());
 
 		// Make sure we have o_additional_navlinks (was added in 1.2.1)
 		if (!array_key_exists('o_additional_navlinks', $pun_config))
-			$new_config[] = '\'o_additional_navlinks\', \'\'';
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_additional_navlinks\', \'\')') or error('Unable to insert config value \'o_additional_navlinks\'', __FILE__, __LINE__, $db->error());
 
 		// Insert new config option o_topic_views
 		if (!array_key_exists('o_topic_views', $pun_config))
-			$new_config[] = '\'o_topic_views\', \'1\'';
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_topic_views\', \'1\')') or error('Unable to insert config value \'o_topic_views\'', __FILE__, __LINE__, $db->error());
 
 		// Insert new config option o_signatures
 		if (!array_key_exists('o_signatures', $pun_config))
-			$new_config[] = '\'o_signatures\', \'1\'';
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_signatures\', \'1\')') or error('Unable to insert config value \'o_signatures\'', __FILE__, __LINE__, $db->error());
 
 		// Insert new config option o_smtp_ssl
 		if (!array_key_exists('o_smtp_ssl', $pun_config))
-			$new_config[] = '\'o_smtp_ssl\', \'0\'';
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_smtp_ssl\', \'0\')') or error('Unable to insert config value \'o_smtp_ssl\'', __FILE__, __LINE__, $db->error());
 
 		// Insert new config option o_default_dst
 		if (!array_key_exists('o_default_dst', $pun_config))
-			$new_config[] = '\'o_default_dst\', \'0\'';
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_default_dst\', \'0\')') or error('Unable to insert config value \'o_default_dst\'', __FILE__, __LINE__, $db->error());
+
+		// Insert new config option o_quote_depth
+		if (!array_key_exists('o_quote_depth', $pun_config))
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_quote_depth\', \'3\')') or error('Unable to insert config value \'o_quote_depth\'', __FILE__, __LINE__, $db->error());
 
-		if (!empty($new_config))
-			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES ('.implode('), (', $new_config).')') or error('Unable to insert config values', __FILE__, __LINE__, $db->error());
+		// Insert new config option o_feed_type
+		if (!array_key_exists('o_feed_type', $pun_config))
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_feed_type\', \'2\')') or error('Unable to insert config value \'o_feed_type\'', __FILE__, __LINE__, $db->error());
+
+		// Insert config option o_base_url which was removed in 1.3
+		if (!array_key_exists('o_base_url', $pun_config))
+		{
+			// If it isn't in $pun_config['o_base_url'] it should be in $base_url, but just in-case it isn't we can make a guess at it
+			if (!isset($base_url))
+			{
+				// Make an educated guess regarding base_url
+				$base_url  = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';	// protocol
+				$base_url .= preg_replace('/:(80|443)$/', '', $_SERVER['HTTP_HOST']);							// host[:port]
+				$base_url .= str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));							// path
+			}
+
+			if (substr($base_url, -1) == '/')
+				$base_url = substr($base_url, 0, -1);
+
+			$db->query('INSERT INTO '.$db->prefix.'config (conf_name, conf_value) VALUES (\'o_base_url\', \''.$db->escape($base_url).'\')') or error('Unable to insert config value \'o_quote_depth\'', __FILE__, __LINE__, $db->error());
+		}
+
+		if (strpos($cur_version, '1.2') === 0)
+		{
+			// Groups are almost the same as 1.2:
+			// unverified:	32000 -> 0
+
+			$db->query('UPDATE '.$db->prefix.'users SET group_id = 0 WHERE group_id = 32000') or error('Unable to update unverified users', __FILE__, __LINE__, $db->error());
+		}
+		else if (strpos($cur_version, '1.3') === 0)
+		{
+			// Groups have changed quite a lot from 1.3:
+			// unverified:	0 -> 0
+			// admin:		1 -> 1
+			// mod:			? -> 2
+			// guest:		2 -> 3
+			// member:		? -> 4
 
-		unset($new_config);
+			$result = $db->query('SELECT MAX(g_id) + 1 FROM '.$db->prefix.'groups') or error('Unable to select temp group ID', __FILE__, __LINE__, $db->error());
+			$temp_id = $db->result($result);
 
-		// Server timezone is now simply the default timezone
+			$result = $db->query('SELECT g_id FROM '.$db->prefix.'groups WHERE g_moderator = 1 AND g_id > 1 LIMIT 1') or error('Unable to select moderator group', __FILE__, __LINE__, $db->error());
+			if ($db->num_rows($result))
+				$mod_gid = $db->result($result);
+			else
+			{
+				$db->query('INSERT INTO '.$db->prefix.'groups (g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('."'Moderators', 'Moderator', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
+				$mod_gid = $db->insert_id();
+			}
+
+			$member_gid = $pun_config['o_default_user_group'];
+
+			// move the mod group to a temp place
+			$db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$temp_id.' WHERE g_id = '.$mod_gid) or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'users SET group_id = '.$temp_id.' WHERE group_id = '.$mod_gid) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$temp_id.' WHERE group_id = '.$mod_gid) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+			if ($member_gid == $mod_gid) $member_gid = $temp_id;
+
+			// move whoever is in 3 to a spare slot
+			$db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$mod_gid.' WHERE g_id = 3') or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'users SET group_id = '.$mod_gid.' WHERE group_id = 3') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$mod_gid.' WHERE group_id = 3') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+			if ($member_gid == 3) $member_gid = $mod_gid;
+
+			// move guest to 3
+			$db->query('UPDATE '.$db->prefix.'groups SET g_id = 3 WHERE g_id = 2') or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'users SET group_id = 3 WHERE group_id = 2') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 3 WHERE group_id = 2') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+			if ($member_gid == 2) $member_gid = 3;
+
+			// move mod group in temp place to 2
+			$db->query('UPDATE '.$db->prefix.'groups SET g_id = 2 WHERE g_id = '.$temp_id) or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'users SET group_id = 2 WHERE group_id = '.$temp_id) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 2 WHERE group_id = '.$temp_id) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+			if ($member_gid == $temp_id) $member_gid = 2;
+
+			// Only move stuff around if it isn't already in the right place
+			if ($member_gid != $mod_gid || $member_gid != 4)
+			{
+				// move members to temp place
+				$db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$temp_id.' WHERE g_id = '.$member_gid) or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+				$db->query('UPDATE '.$db->prefix.'users SET group_id = '.$temp_id.' WHERE group_id = '.$member_gid) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+				$db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$temp_id.' WHERE group_id = '.$member_gid) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+
+				// move whoever is in 4 to members place
+				$db->query('UPDATE '.$db->prefix.'groups SET g_id = '.$member_gid.' WHERE g_id = 4') or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+				$db->query('UPDATE '.$db->prefix.'users SET group_id = '.$member_gid.' WHERE group_id = 4') or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+				$db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = '.$member_gid.' WHERE group_id = 4') or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+
+				// move members in temp place to 4
+				$db->query('UPDATE '.$db->prefix.'groups SET g_id = 4 WHERE g_id = '.$temp_id) or error('Unable to update group ID', __FILE__, __LINE__, $db->error());
+				$db->query('UPDATE '.$db->prefix.'users SET group_id = 4 WHERE group_id = '.$temp_id) or error('Unable to update users group ID', __FILE__, __LINE__, $db->error());
+				$db->query('UPDATE '.$db->prefix.'forum_perms SET group_id = 4 WHERE group_id = '.$temp_id) or error('Unable to forum_perms group ID', __FILE__, __LINE__, $db->error());
+			}
+		}
+
+		// Server time zone is now simply the default time zone
 		if (!array_key_exists('o_default_timezone', $pun_config))
-			$db->query('UPDATE '.$db->prefix.'config SET conf_name = \'o_default_timezone\' WHERE conf_name = \'o_server_timezone\'') or error('Unable to update timezone config', __FILE__, __LINE__, $db->error());
+			$db->query('UPDATE '.$db->prefix.'config SET conf_name = \'o_default_timezone\' WHERE conf_name = \'o_server_timezone\'') or error('Unable to update time zone config', __FILE__, __LINE__, $db->error());
 
 		// Increase visit timeout to 30 minutes (only if it hasn't been changed from the default)
 		if (!array_key_exists('o_database_revision', $pun_config) && $pun_config['o_timeout_visit'] == '600')
@@ -476,7 +684,7 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 		if (!$db->field_exists('groups', 'g_moderator'))
 		{
 			// Add g_moderator column to groups table
-			$db->add_field('groups', 'g_moderator', 'TINYINT(1)', false, 0, 'g_user_title');
+			$db->add_field('groups', 'g_moderator', 'TINYINT(1)', false, 0, 'g_user_title') or error('Unable to add g_moderator field', __FILE__, __LINE__, $db->error());
 
 			// Give the moderator group moderator privileges
 			$db->query('UPDATE '.$db->prefix.'groups SET g_moderator = 1 WHERE g_id = 2') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
@@ -487,7 +695,7 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 		{
 			$db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_edit_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
 
-			$db->add_field('groups', 'g_mod_edit_users', 'TINYINT(1)', false, 0, 'g_moderator');
+			$db->add_field('groups', 'g_mod_edit_users', 'TINYINT(1)', false, 0, 'g_moderator') or error('Unable to add g_mod_edit_users field', __FILE__, __LINE__, $db->error());
 
 			$db->query('UPDATE '.$db->prefix.'groups SET g_mod_edit_users = '.$pun_config['p_mod_edit_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
 		}
@@ -497,7 +705,7 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 		{
 			$db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_rename_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
 
-			$db->add_field('groups', 'g_mod_rename_users', 'TINYINT(1)', false, 0, 'g_mod_edit_users');
+			$db->add_field('groups', 'g_mod_rename_users', 'TINYINT(1)', false, 0, 'g_mod_edit_users') or error('Unable to add g_mod_rename_users field', __FILE__, __LINE__, $db->error());
 
 			$db->query('UPDATE '.$db->prefix.'groups SET g_mod_rename_users = '.$pun_config['p_mod_rename_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
 		}
@@ -507,7 +715,7 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 		{
 			$db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_change_passwords\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
 
-			$db->add_field('groups', 'g_mod_change_passwords', 'TINYINT(1)', false, 0, 'g_mod_rename_users');
+			$db->add_field('groups', 'g_mod_change_passwords', 'TINYINT(1)', false, 0, 'g_mod_rename_users') or error('Unable to add g_mod_change_passwords field', __FILE__, __LINE__, $db->error());
 
 			$db->query('UPDATE '.$db->prefix.'groups SET g_mod_change_passwords = '.$pun_config['p_mod_change_passwords'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
 		}
@@ -517,7 +725,7 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 		{
 			$db->query('DELETE FROM '.$db->prefix.'config WHERE conf_name = \'p_mod_ban_users\'') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
 
-			$db->add_field('groups', 'g_mod_ban_users', 'TINYINT(1)', false, 0, 'g_mod_change_passwords');
+			$db->add_field('groups', 'g_mod_ban_users', 'TINYINT(1)', false, 0, 'g_mod_change_passwords') or error('Unable to add g_mod_ban_users field', __FILE__, __LINE__, $db->error());
 
 			$db->query('UPDATE '.$db->prefix.'groups SET g_mod_ban_users = '.$pun_config['p_mod_ban_users'].' WHERE g_moderator = 1') or error('Unable to update moderator powers', __FILE__, __LINE__, $db->error());
 		}
@@ -525,131 +733,278 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 		// We need to add a unique index to avoid users having multiple rows in the online table
 		if (!$db->index_exists('online', 'user_id_ident_idx'))
 		{
-			$db->query('DELETE FROM '.$db->prefix.'online') or error('Unable to clear online table', __FILE__, __LINE__, $db->error());
-
-			switch ($db_type)
-			{
-				case 'mysql':
-				case 'mysqli':
-				case 'mysql_innodb':
-				case 'mysqli_innodb':
-					$db->add_index('online', 'user_id_ident_idx', array('user_id', 'ident(25)'), true);
-					break;
+			$db->truncate_table('online') or error('Unable to clear online table', __FILE__, __LINE__, $db->error());
 
-				default:
-					$db->add_index('online', 'user_id_ident_idx', array('user_id', 'ident'), true);
-					break;
-			}
+			if ($mysql)
+				$db->add_index('online', 'user_id_ident_idx', array('user_id', 'ident(25)'), true) or error('Unable to add user_id_ident_idx index', __FILE__, __LINE__, $db->error());
+			else
+				$db->add_index('online', 'user_id_ident_idx', array('user_id', 'ident'), true) or error('Unable to add user_id_ident_idx index', __FILE__, __LINE__, $db->error());
 		}
 
 		// Remove the redundant user_id_idx on the online table
-		$db->drop_index('online', 'user_id_idx');
+		$db->drop_index('online', 'user_id_idx') or error('Unable to drop user_id_idx index', __FILE__, __LINE__, $db->error());
 
 		// Add an index to ident on the online table
-		switch ($db_type)
-		{
-			case 'mysql':
-			case 'mysqli':
-			case 'mysql_innodb':
-			case 'mysqli_innodb':
-				$db->add_index('online', 'ident_idx', array('ident(25)'));
-				break;
+		if ($mysql)
+			$db->add_index('online', 'ident_idx', array('ident(25)')) or error('Unable to add ident_idx index', __FILE__, __LINE__, $db->error());
+		else
+			$db->add_index('online', 'ident_idx', array('ident')) or error('Unable to add ident_idx index', __FILE__, __LINE__, $db->error());
 
-			default:
-				$db->add_index('online', 'ident_idx', array('ident'));
-				break;
-		}
+		// Add an index to logged in the online table
+		$db->add_index('online', 'logged_idx', array('logged')) or error('Unable to add logged_idx index', __FILE__, __LINE__, $db->error());
+
+		// Add an index to last_post in the topics table
+		$db->add_index('topics', 'last_post_idx', array('last_post')) or error('Unable to add last_post_idx index', __FILE__, __LINE__, $db->error());
+
+		// Add an index to username on the bans table
+		if ($mysql)
+			$db->add_index('bans', 'username_idx', array('username(25)')) or error('Unable to add username_idx index', __FILE__, __LINE__, $db->error());
+		else
+			$db->add_index('bans', 'username_idx', array('username')) or error('Unable to add username_idx index', __FILE__, __LINE__, $db->error());
 
-		// Add an index to logged on the online table
-		$db->add_index('online', 'logged_idx', array('logged'));
+		// Change the username_idx on users to a unique index of max size 25
+		$db->drop_index('users', 'username_idx') or error('Unable to drop old username_idx index', __FILE__, __LINE__, $db->error());
+		$field = $mysql ? 'username(25)' : 'username';
 
-		// Add an index on last_post in the topics table
-		$db->add_index('topics', 'last_post_idx', array('last_post'));
+		// Attempt to add a unique index. If the user doesn't use a transactional database this can fail due to multiple matching usernames in the
+		// users table. This is bad, but just giving up if it happens is even worse! If it fails just add a regular non-unique index.
+		if (!$db->add_index('users', 'username_idx', array($field), true))
+			$db->add_index('users', 'username_idx', array($field)) or error('Unable to add username_idx field', __FILE__, __LINE__, $db->error());
 
 		// Add g_view_users field to groups table
-		$db->add_field('groups', 'g_view_users', 'TINYINT(1)', false, 1, 'g_read_board');
+		$db->add_field('groups', 'g_view_users', 'TINYINT(1)', false, 1, 'g_read_board') or error('Unable to add g_view_users field', __FILE__, __LINE__, $db->error());
 
 		// Add the last_email_sent column to the users table and the g_send_email and
 		// g_email_flood columns to the groups table
-		$db->add_field('users', 'last_email_sent', 'INT(10)', true, null, 'last_search');
-		$db->add_field('groups', 'g_send_email', 'TINYINT(1)', false, 1, 'g_search_users');
-		$db->add_field('groups', 'g_email_flood', 'INT(10)', false, 60, 'g_search_flood');
+		$db->add_field('users', 'last_email_sent', 'INT(10) UNSIGNED', true, null, 'last_search') or error('Unable to add last_email_sent field', __FILE__, __LINE__, $db->error());
+		$db->add_field('groups', 'g_send_email', 'TINYINT(1)', false, 1, 'g_search_users') or error('Unable to add g_send_email field', __FILE__, __LINE__, $db->error());
+		$db->add_field('groups', 'g_email_flood', 'SMALLINT(6)', false, 60, 'g_search_flood') or error('Unable to add g_email_flood field', __FILE__, __LINE__, $db->error());
 
 		// Set non-default g_send_email and g_flood_email values properly
 		$db->query('UPDATE '.$db->prefix.'groups SET g_send_email = 0 WHERE g_id = 3') or error('Unable to update group email permissions', __FILE__, __LINE__, $db->error());
 		$db->query('UPDATE '.$db->prefix.'groups SET g_email_flood = 0 WHERE g_id IN (1,2,3)') or error('Unable to update group email permissions', __FILE__, __LINE__, $db->error());
 
 		// Add the auto notify/subscription option to the users table
-		$db->add_field('users', 'auto_notify', 'TINYINT(1)', false, 0, 'notify_with_post');
+		$db->add_field('users', 'auto_notify', 'TINYINT(1)', false, 0, 'notify_with_post') or error('Unable to add auto_notify field', __FILE__, __LINE__, $db->error());
 
 		// Add the first_post_id column to the topics table
 		if (!$db->field_exists('topics', 'first_post_id'))
 		{
-			$db->add_field('topics', 'first_post_id', 'INT(10) UNSIGNED', false, 0, 'posted');
-			$db->add_index('topics', 'first_post_id_idx', array('first_post_id'));
+			$db->add_field('topics', 'first_post_id', 'INT(10) UNSIGNED', false, 0, 'posted') or error('Unable to add first_post_id field', __FILE__, __LINE__, $db->error());
+			$db->add_index('topics', 'first_post_id_idx', array('first_post_id')) or error('Unable to add first_post_id_idx index', __FILE__, __LINE__, $db->error());
 
-			// Now that we've added the column and indexed it, we need to give it correct data\
+			// Now that we've added the column and indexed it, we need to give it correct data
 			$result = $db->query('SELECT MIN(id) AS first_post, topic_id FROM '.$db->prefix.'posts GROUP BY topic_id') or error('Unable to fetch first_post_id', __FILE__, __LINE__, $db->error());
 
 			while ($cur_post = $db->fetch_assoc($result))
-			{
 				$db->query('UPDATE '.$db->prefix.'topics SET first_post_id = '.$cur_post['first_post'].' WHERE id = '.$cur_post['topic_id']) or error('Unable to update first_post_id', __FILE__, __LINE__, $db->error());
-			}
 		}
 
 		// Move any users with the old unverified status to their new group
 		$db->query('UPDATE '.$db->prefix.'users SET group_id=0 WHERE group_id=32000') or error('Unable to move unverified users', __FILE__, __LINE__, $db->error());
 
 		// Add the ban_creator column to the bans table
-		$db->add_field('bans', 'ban_creator', 'INT(10) UNSIGNED', false, 0);
+		$db->add_field('bans', 'ban_creator', 'INT(10) UNSIGNED', false, 0) or error('Unable to add ban_creator field', __FILE__, __LINE__, $db->error());
 
 		// Add the time/date format settings to the user table
-		$db->add_field('users', 'time_format', 'INT(10)', false, 0, 'dst');
-		$db->add_field('users', 'date_format', 'INT(10)', false, 0, 'dst');
+		$db->add_field('users', 'time_format', 'TINYINT(1)', false, 0, 'dst') or error('Unable to add time_format field', __FILE__, __LINE__, $db->error());
+		$db->add_field('users', 'date_format', 'TINYINT(1)', false, 0, 'dst') or error('Unable to add date_format field', __FILE__, __LINE__, $db->error());
 
-		// Should we do charset conversion or not?
-		if (strpos($cur_version, '1.2') === 0 && isset($_GET['convert_charset']))
-			$query_str = '?stage=conv_misc&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE;
-		else
-			$query_str = '?stage=conv_tables';
-		break;
+		// Change the search_data field to mediumtext
+		$db->alter_field('search_cache', 'search_data', 'MEDIUMTEXT', true) or error('Unable to alter search_data field', __FILE__, __LINE__, $db->error());
 
+		// Incase we had the fulltext search extension installed (1.3-legacy), remove it
+		$db->drop_index('topics', 'subject_idx') or error('Unable to drop subject_idx index', __FILE__, __LINE__, $db->error());
+		$db->drop_index('posts', 'message_idx') or error('Unable to drop message_idx index', __FILE__, __LINE__, $db->error());
 
-	// Convert config, categories, forums, groups, ranks and censor words
-	case 'conv_misc':
-		if (strpos($cur_version, '1.2') !== 0)
+		// If the search_cache table has been dropped by the fulltext search extension, recreate it
+		if (!$db->table_exists('search_cache'))
 		{
-			$query_str = '?stage=conv_tables';
-			break;
+			$schema = array(
+				'FIELDS'		=> array(
+					'id'			=> array(
+						'datatype'		=> 'INT(10) UNSIGNED',
+						'allow_null'	=> false,
+						'default'		=> '0'
+					),
+					'ident'			=> array(
+						'datatype'		=> 'VARCHAR(200)',
+						'allow_null'	=> false,
+						'default'		=> '\'\''
+					),
+					'search_data'	=> array(
+						'datatype'		=> 'MEDIUMTEXT',
+						'allow_null'	=> true
+					)
+				),
+				'PRIMARY KEY'	=> array('id'),
+				'INDEXES'		=> array(
+					'ident_idx'	=> array('ident')
+				)
+			);
+
+			if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
+				$schema['INDEXES']['ident_idx'] = array('ident(8)');
+
+			$db->create_table('search_cache', $schema);
 		}
 
-		// Convert config
-		echo 'Converting configuration …'."<br />\n";
-		foreach ($pun_config as $conf_name => $conf_value)
+		// If the search_matches table has been dropped by the fulltext search extension, recreate it
+		if (!$db->table_exists('search_matches'))
+		{
+			$schema = array(
+				'FIELDS'		=> array(
+					'post_id'		=> array(
+						'datatype'		=> 'INT(10) UNSIGNED',
+						'allow_null'	=> false,
+						'default'		=> '0'
+					),
+					'word_id'		=> array(
+						'datatype'		=> 'INT(10) UNSIGNED',
+						'allow_null'	=> false,
+						'default'		=> '0'
+					),
+					'subject_match'	=> array(
+						'datatype'		=> 'TINYINT(1)',
+						'allow_null'	=> false,
+						'default'		=> '0'
+					)
+				),
+				'INDEXES'		=> array(
+					'word_id_idx'	=> array('word_id'),
+					'post_id_idx'	=> array('post_id')
+				)
+			);
+
+			$db->create_table('search_matches', $schema);
+		}
+
+		// If the search_words table has been dropped by the fulltext search extension, recreate it
+		if (!$db->table_exists('search_words'))
 		{
-			if (convert_to_utf8($conf_value, $old_charset))
+			$schema = array(
+				'FIELDS'		=> array(
+					'id'			=> array(
+						'datatype'		=> 'SERIAL',
+						'allow_null'	=> false
+					),
+					'word'			=> array(
+						'datatype'		=> 'VARCHAR(20)',
+						'allow_null'	=> false,
+						'default'		=> '\'\'',
+						'collation'		=> 'bin'
+					)
+				),
+				'PRIMARY KEY'	=> array('word'),
+				'INDEXES'		=> array(
+					'id_idx'	=> array('id')
+				)
+			);
+
+			if ($db_type == 'sqlite')
 			{
-				$db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.$db->escape($conf_value).'\' WHERE conf_name = \''.$conf_name.'\'') or error('Unable to update config', __FILE__, __LINE__, $db->error());
+				$schema['PRIMARY KEY'] = array('id');
+				$schema['UNIQUE KEYS'] = array('word_idx'	=> array('word'));
 			}
+
+			$db->create_table('search_words', $schema);
 		}
 
-		// Convert categories
+		// Change the default style if the old doesn't exist anymore
+		if ($pun_config['o_default_style'] != $default_style)
+			$db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.$db->escape($default_style).'\' WHERE conf_name = \'o_default_style\'') or error('Unable to update default style config', __FILE__, __LINE__, $db->error());
+
+		// Should we do charset conversion or not?
+		if (strpos($cur_version, '1.2') === 0 && isset($_GET['convert_charset']))
+			$query_str = '?stage=conv_bans&req_old_charset='.$old_charset;
+
+		break;
+
+
+	// Convert bans
+	case 'conv_bans':
+		$query_str = '?stage=conv_categories&req_old_charset='.$old_charset;
+
+		function _conv_bans($cur_item, $old_charset)
+		{
+			echo 'Converting ban '.$cur_item['id'].' …<br />'."\n";
+
+			convert_to_utf8($cur_item['username'], $old_charset);
+			convert_to_utf8($cur_item['message'], $old_charset);
+
+			return $cur_item;
+		}
+
+		$end_at = convert_table_utf8($db->prefix.'bans', '_conv_bans', $old_charset, 'id', $start_at);
+
+		if ($end_at !== true)
+			$query_str = '?stage=conv_bans&req_old_charset='.$old_charset.'&start_at='.$end_at;
+
+		break;
+
+
+	// Convert categories
+	case 'conv_categories':
+		$query_str = '?stage=conv_censors&req_old_charset='.$old_charset;
+
 		echo 'Converting categories …'."<br />\n";
-		$result = $db->query('SELECT id, cat_name FROM '.$db->prefix.'categories ORDER BY id') or error('Unable to fetch categories', __FILE__, __LINE__, $db->error());
 
-		while ($cur_item = $db->fetch_assoc($result))
+		function _conv_categories($cur_item, $old_charset)
 		{
-			if (convert_to_utf8($cur_item['cat_name'], $old_charset))
-			{
-				$db->query('UPDATE '.$db->prefix.'categories SET cat_name = \''.$db->escape($cur_item['cat_name']).'\' WHERE id = '.$cur_item['id']) or error('Unable to update category', __FILE__, __LINE__, $db->error());
-			}
+			convert_to_utf8($cur_item['cat_name'], $old_charset);
+
+			return $cur_item;
+		}
+
+		convert_table_utf8($db->prefix.'categories', '_conv_categories', $old_charset, 'id');
+
+		break;
+
+
+	// Convert censor words
+	case 'conv_censors':
+		$query_str = '?stage=conv_config&req_old_charset='.$old_charset;
+
+		echo 'Converting censor words …'."<br />\n";
+
+		function _conv_censoring($cur_item, $old_charset)
+		{
+			convert_to_utf8($cur_item['search_for'], $old_charset);
+			convert_to_utf8($cur_item['replace_with'], $old_charset);
+
+			return $cur_item;
 		}
 
-		// Convert forums
+		convert_table_utf8($db->prefix.'censoring', '_conv_censoring', $old_charset, 'id');
+
+		break;
+
+
+	// Convert config
+	case 'conv_config':
+		$query_str = '?stage=conv_forums&req_old_charset='.$old_charset;
+
+		echo 'Converting configuration …'."<br />\n";
+
+		function _conv_config($cur_item, $old_charset)
+		{
+			convert_to_utf8($cur_item['conf_value'], $old_charset);
+
+			return $cur_item;
+		}
+
+		convert_table_utf8($db->prefix.'config', '_conv_config', $old_charset, 'conf_name');
+
+		break;
+
+
+	// Convert forums
+	case 'conv_forums':
+		$query_str = '?stage=conv_perms&req_old_charset='.$old_charset;
+
 		echo 'Converting forums …'."<br />\n";
-		$result = $db->query('SELECT id, forum_name, forum_desc, moderators FROM '.$db->prefix.'forums ORDER BY id') or error('Unable to fetch forums', __FILE__, __LINE__, $db->error());
 
-		while ($cur_item = $db->fetch_assoc($result))
+		function _conv_forums($cur_item, $old_charset)
 		{
 			$moderators = ($cur_item['moderators'] != '') ? unserialize($cur_item['moderators']) : array();
 			$moderators_utf8 = array();
@@ -659,313 +1014,362 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 				$moderators_utf8[$mod_username] = $mod_user_id;
 			}
 
-			if (convert_to_utf8($cur_item['forum_name'], $old_charset) | convert_to_utf8($cur_item['forum_desc'], $old_charset) || $moderators !== $moderators_utf8)
-			{
-				$cur_item['forum_desc'] = $cur_item['forum_desc'] != '' ? '\''.$db->escape($cur_item['forum_desc']).'\'' : 'NULL';
-				$cur_item['moderators'] = !empty($moderators_utf8) ? '\''.$db->escape(serialize($moderators_utf8)).'\'' : 'NULL';
+			convert_to_utf8($cur_item['forum_name'], $old_charset);
+			convert_to_utf8($cur_item['forum_desc'], $old_charset);
 
-				$db->query('UPDATE '.$db->prefix.'forums SET forum_name = \''.$db->escape($cur_item['forum_name']).'\', forum_desc = '.$cur_item['forum_desc'].', moderators = '.$cur_item['moderators'].' WHERE id = '.$cur_item['id']) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
-			}
+			if (!empty($moderators_utf8))
+				$cur_item['moderators'] = serialize($moderators_utf8);
+
+			return $cur_item;
 		}
 
-		// Convert groups
+		convert_table_utf8($db->prefix.'forums', '_conv_forums', $old_charset, 'id');
+
+		break;
+
+
+	// Convert forum permissions
+	case 'conv_perms':
+		$query_str = '?stage=conv_groups&req_old_charset='.$old_charset;
+
+		alter_table_utf8($db->prefix.'forum_perms');
+
+		break;
+
+
+	// Convert groups
+	case 'conv_groups':
+		$query_str = '?stage=conv_online&req_old_charset='.$old_charset;
+
 		echo 'Converting groups …'."<br />\n";
-		$result = $db->query('SELECT g_id, g_title, g_user_title FROM '.$db->prefix.'groups ORDER BY g_id') or error('Unable to fetch groups', __FILE__, __LINE__, $db->error());
 
-		while ($cur_item = $db->fetch_assoc($result))
+		function _conv_groups($cur_item, $old_charset)
 		{
-			if (convert_to_utf8($cur_item['g_title'], $old_charset) | convert_to_utf8($cur_item['g_user_title'], $old_charset))
-			{
-				$cur_item['g_user_title'] = $cur_item['g_user_title'] != '' ? '\''.$db->escape($cur_item['g_user_title']).'\'' : 'NULL';
+			convert_to_utf8($cur_item['g_title'], $old_charset);
+			convert_to_utf8($cur_item['g_user_title'], $old_charset);
 
-				$db->query('UPDATE '.$db->prefix.'groups SET g_title = \''.$db->escape($cur_item['g_title']).'\', g_user_title = '.$cur_item['g_user_title'].' WHERE g_id = '.$cur_item['g_id']) or error('Unable to update group', __FILE__, __LINE__, $db->error());
-			}
+			return $cur_item;
 		}
 
-		// Convert ranks
-		echo 'Converting ranks …'."<br />\n";
-		$result = $db->query('SELECT id, rank FROM '.$db->prefix.'ranks ORDER BY id') or error('Unable to fetch ranks', __FILE__, __LINE__, $db->error());
+		convert_table_utf8($db->prefix.'groups', '_conv_groups', $old_charset, 'g_id');
 
-		while ($cur_item = $db->fetch_assoc($result))
+		break;
+
+
+	// Convert online
+	case 'conv_online':
+		$query_str = '?stage=conv_posts&req_old_charset='.$old_charset;
+
+		// Truncate the table
+		$db->truncate_table('online') or error('Unable to empty online table', __FILE__, __LINE__, $db->error());
+
+		alter_table_utf8($db->prefix.'online');
+
+		break;
+
+
+	// Convert posts
+	case 'conv_posts':
+		$query_str = '?stage=conv_ranks&req_old_charset='.$old_charset;
+
+		function _conv_posts($cur_item, $old_charset)
 		{
-			if (convert_to_utf8($cur_item['rank'], $old_charset))
-			{
-				$db->query('UPDATE '.$db->prefix.'ranks SET rank = \''.$db->escape($cur_item['rank']).'\' WHERE id = '.$cur_item['id']) or error('Unable to update rank', __FILE__, __LINE__, $db->error());
-			}
+			echo 'Converting post '.$cur_item['id'].' …<br />'."\n";
+
+			convert_to_utf8($cur_item['poster'], $old_charset);
+			convert_to_utf8($cur_item['message'], $old_charset);
+			convert_to_utf8($cur_item['edited_by'], $old_charset);
+
+			return $cur_item;
 		}
 
-		// Convert censor words
-		echo 'Converting censor words …'."<br />\n";
-		$result = $db->query('SELECT id, search_for, replace_with FROM '.$db->prefix.'censoring ORDER BY id') or error('Unable to fetch censors', __FILE__, __LINE__, $db->error());
+		$end_at = convert_table_utf8($db->prefix.'posts', '_conv_posts', $old_charset, 'id', $start_at);
 
-		while ($cur_item = $db->fetch_assoc($result))
+		if ($end_at !== true)
+			$query_str = '?stage=conv_posts&req_old_charset='.$old_charset.'&start_at='.$end_at;
+
+		break;
+
+
+	// Convert ranks
+	case 'conv_ranks':
+		$query_str = '?stage=conv_reports&req_old_charset='.$old_charset;
+
+		echo 'Converting ranks …'."<br />\n";
+
+		function _conv_ranks($cur_item, $old_charset)
 		{
-			if (convert_to_utf8($cur_item['search_for'], $old_charset) | convert_to_utf8($cur_item['replace_with'], $old_charset))
-			{
-				$db->query('UPDATE '.$db->prefix.'censoring SET search_for = \''.$db->escape($cur_item['search_for']).'\', replace_with = \''.$db->escape($cur_item['replace_with']).'\' WHERE id = '.$cur_item['id']) or error('Unable to update censor', __FILE__, __LINE__, $db->error());
-			}
+			convert_to_utf8($cur_item['rank'], $old_charset);
+
+			return $cur_item;
 		}
 
-		$query_str = '?stage=conv_reports&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE;
+		convert_table_utf8($db->prefix.'ranks', '_conv_ranks', $old_charset, 'id');
+
 		break;
 
 
 	// Convert reports
 	case 'conv_reports':
-		if (strpos($cur_version, '1.2') !== 0)
-		{
-			$query_str = '?stage=conv_tables';
-			break;
-		}
+		$query_str = '?stage=conv_search_cache&req_old_charset='.$old_charset;
 
-		// Determine where to start
-		if ($start_at == 0)
+		function _conv_reports($cur_item, $old_charset)
 		{
-			$result = $db->query('SELECT id FROM '.$db->prefix.'reports ORDER BY id LIMIT 1') or error('Unable to fetch first report ID', __FILE__, __LINE__, $db->error());
+			echo 'Converting report '.$cur_item['id'].' …<br />'."\n";
 
-			if ($db->num_rows($result))
-				$start_at = $db->result($result);
+			convert_to_utf8($cur_item['message'], $old_charset);
+
+			return $cur_item;
 		}
-		$end_at = $start_at + PER_PAGE;
 
-		// Fetch reports to process this cycle
-		$result = $db->query('SELECT id, message FROM '.$db->prefix.'reports WHERE id >= '.$start_at.' AND id < '.$end_at.' ORDER BY id') or error('Unable to fetch reports', __FILE__, __LINE__, $db->error());
+		$end_at = convert_table_utf8($db->prefix.'reports', '_conv_reports', $old_charset, 'id', $start_at);
 
-		while ($cur_item = $db->fetch_assoc($result))
-		{
-			echo 'Converting report '.$cur_item['id'].' …<br />'."\n";
-			if (convert_to_utf8($cur_item['message'], $old_charset))
-			{
-				$db->query('UPDATE '.$db->prefix.'reports SET message = \''.$db->escape($cur_item['message']).'\' WHERE id = '.$cur_item['id']) or error('Unable to update report', __FILE__, __LINE__, $db->error());
-			}
-		}
+		if ($end_at !== true)
+			$query_str = '?stage=conv_reports&req_old_charset='.$old_charset.'&start_at='.$end_at;
 
-		// Check if there is more work to do
-		$result = $db->query('SELECT id FROM '.$db->prefix.'reports WHERE id >= '.$end_at.' ORDER BY id LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+		break;
+
+
+	// Convert search cache
+	case 'conv_search_cache':
+		$query_str = '?stage=conv_search_matches&req_old_charset='.$old_charset;
+
+		// Truncate the table
+		$db->truncate_table('search_cache') or error('Unable to empty search cache table', __FILE__, __LINE__, $db->error());
+
+		alter_table_utf8($db->prefix.'search_cache');
+
+		break;
+
+
+	// Convert search matches
+	case 'conv_search_matches':
+		$query_str = '?stage=conv_search_words&req_old_charset='.$old_charset;
+
+		// Truncate the table
+		$db->truncate_table('search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error());
+
+		alter_table_utf8($db->prefix.'search_matches');
 
-		if ($db->num_rows($result))
-			$query_str = '?stage=conv_reports&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE.'&start_at='.$db->result($result);
-		else
-			$query_str = '?stage=conv_search_words&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE;
 		break;
 
 
 	// Convert search words
 	case 'conv_search_words':
-		if (strpos($cur_version, '1.2') !== 0)
-		{
-			$query_str = '?stage=conv_tables';
-			break;
-		}
+		$query_str = '?stage=conv_subscriptions&req_old_charset='.$old_charset;
 
-		// Determine where to start
-		if ($start_at == 0)
+		// Truncate the table
+		$db->truncate_table('search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error());
+
+		// Reset the sequence for the search words (not needed for SQLite)
+		switch ($db_type)
 		{
-			// Get the first search word ID from the db
-			$result = $db->query('SELECT id FROM '.$db->prefix.'search_words ORDER BY id LIMIT 1') or error('Unable to fetch first search_words ID', __FILE__, __LINE__, $db->error());
+			case 'mysql':
+			case 'mysqli':
+			case 'mysql_innodb':
+			case 'mysqli_innodb':
+				$db->query('ALTER TABLE '.$db->prefix.'search_words auto_increment=1') or error('Unable to update table auto_increment', __FILE__, __LINE__, $db->error());
+				break;
 
-			if ($db->num_rows($result))
-				$start_at = $db->result($result);
+			case 'pgsql';
+				$db->query('SELECT setval(\''.$db->prefix.'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error());
+				break;
 		}
-		$end_at = $start_at + PER_PAGE;
 
-		// Fetch words to process this cycle
-		$result = $db->query('SELECT id, word FROM '.$db->prefix.'search_words WHERE id >= '.$start_at.' AND id < '.$end_at.' ORDER BY id') or error('Unable to fetch search words', __FILE__, __LINE__, $db->error());
+		alter_table_utf8($db->prefix.'search_words');
 
-		while ($cur_item = $db->fetch_assoc($result))
+		break;
+
+
+	// Convert subscriptions
+	case 'conv_subscriptions':
+		$query_str = '?stage=conv_topics&req_old_charset='.$old_charset;
+
+		alter_table_utf8($db->prefix.'subscriptions');
+
+		break;
+
+
+	// Convert topics
+	case 'conv_topics':
+		$query_str = '?stage=conv_users&req_old_charset='.$old_charset;
+
+		function _conv_topics($cur_item, $old_charset)
 		{
-			echo 'Converting search word '.$cur_item['id'].' …<br />'."\n";
-			if (convert_to_utf8($cur_item['word'], $old_charset))
-			{
-				$db->query('UPDATE '.$db->prefix.'search_words SET word = \''.$db->escape($cur_item['word']).'\' WHERE id = '.$cur_item['id']) or error('Unable to update search word', __FILE__, __LINE__, $db->error());
-			}
+			echo 'Converting topic '.$cur_item['id'].' …<br />'."\n";
+
+			convert_to_utf8($cur_item['poster'], $old_charset);
+			convert_to_utf8($cur_item['subject'], $old_charset);
+			convert_to_utf8($cur_item['last_poster'], $old_charset);
+
+			return $cur_item;
 		}
 
-		// Check if there is more work to do
-		$result = $db->query('SELECT id FROM '.$db->prefix.'search_words WHERE id >= '.$end_at.' ORDER BY id LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+		$end_at = convert_table_utf8($db->prefix.'topics', '_conv_topics', $old_charset, 'id', $start_at);
+
+		if ($end_at !== true)
+			$query_str = '?stage=conv_topics&req_old_charset='.$old_charset.'&start_at='.$end_at;
 
-		if ($db->num_rows($result))
-			$query_str = '?stage=conv_search_words&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE.'&start_at='.$db->result($result);
-		else
-			$query_str = '?stage=conv_users&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE;
 		break;
 
 
 	// Convert users
 	case 'conv_users':
-		if (strpos($cur_version, '1.2') !== 0)
+		$query_str = '?stage=preparse_posts';
+
+		function _conv_users($cur_item, $old_charset)
 		{
-			$query_str = '?stage=conv_tables';
-			break;
+			echo 'Converting user '.$cur_item['id'].' …<br />'."\n";
+
+			convert_to_utf8($cur_item['username'], $old_charset);
+			convert_to_utf8($cur_item['title'], $old_charset);
+			convert_to_utf8($cur_item['realname'], $old_charset);
+			convert_to_utf8($cur_item['location'], $old_charset);
+			convert_to_utf8($cur_item['signature'], $old_charset);
+			convert_to_utf8($cur_item['admin_note'], $old_charset);
+
+			return $cur_item;
 		}
 
-		// Determine where to start
-		if ($start_at == 0)
-			$start_at = 2;
+		$end_at = convert_table_utf8($db->prefix.'users', '_conv_users', $old_charset, 'id', $start_at);
 
-		$end_at = $start_at + PER_PAGE;
+		if ($end_at !== true)
+			$query_str = '?stage=conv_users&req_old_charset='.$old_charset.'&start_at='.$end_at;
 
-		// Fetch users to process this cycle
-		$result = $db->query('SELECT id, username, title, realname, location, signature, admin_note FROM '.$db->prefix.'users WHERE id >= '.$start_at.' AND id < '.$end_at.' ORDER BY id') or error('Unable to fetch users', __FILE__, __LINE__, $db->error());
+		break;
 
-		while ($cur_item = $db->fetch_assoc($result))
-		{
-			echo 'Converting user '.$cur_item['id'].' …<br />'."\n";
-			if (convert_to_utf8($cur_item['username'], $old_charset) | convert_to_utf8($cur_item['title'], $old_charset) | convert_to_utf8($cur_item['realname'], $old_charset) | convert_to_utf8($cur_item['location'], $old_charset) | convert_to_utf8($cur_item['signature'], $old_charset) | convert_to_utf8($cur_item['admin_note'], $old_charset))
-			{
-				$cur_item['title'] = $cur_item['title'] != '' ? '\''.$db->escape($cur_item['title']).'\'' : 'NULL';
-				$cur_item['realname'] = $cur_item['realname'] != '' ? '\''.$db->escape($cur_item['realname']).'\'' : 'NULL';
-				$cur_item['location'] = $cur_item['location'] != '' ? '\''.$db->escape($cur_item['location']).'\'' : 'NULL';
-				$cur_item['signature'] = $cur_item['signature'] != '' ? '\''.$db->escape($cur_item['signature']).'\'' : 'NULL';
-				$cur_item['admin_note'] = $cur_item['admin_note'] != '' ? '\''.$db->escape($cur_item['admin_note']).'\'' : 'NULL';
 
-				$db->query('UPDATE '.$db->prefix.'users SET username = \''.$db->escape($cur_item['username']).'\', title = '.$cur_item['title'].', realname = '.$cur_item['realname'].', location = '.$cur_item['location'].', signature = '.$cur_item['signature'].', admin_note = '.$cur_item['admin_note'].' WHERE id = '.$cur_item['id']) or error('Unable to update user', __FILE__, __LINE__, $db->error());
-			}
-		}
+	// Check if we need to do any more work
+	case 'pre_finish':
+		$query_str = '?stage=finish';
 
-		// Check if there is more work to do
-		$result = $db->query('SELECT id FROM '.$db->prefix.'users WHERE id >= '.$end_at.' ORDER BY id LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+		// If we are doing a major update we should preparse the posts and reindex everything
+		if (strpos($cur_version, substr(UPDATE_TO, 0, 3)) !== 0)
+			$query_str = '?stage=preparse_posts';
 
-		if ($db->num_rows($result))
-			$query_str = '?stage=conv_users&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE.'&start_at='.$db->result($result);
-		else
-			$query_str = '?stage=conv_topics&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE;
 		break;
 
 
-	// Convert topics
-	case 'conv_topics':
-		if (strpos($cur_version, '1.2') !== 0)
+	// Preparse posts
+	case 'preparse_posts':
+		$query_str = '?stage=preparse_sigs';
+
+		require PUN_ROOT.'include/parser.php';
+
+		// Fetch posts to process this cycle
+		$result = $db->query('SELECT id, message FROM '.$db->prefix.'posts WHERE id > '.$start_at.' ORDER BY id ASC LIMIT '.PER_PAGE) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
+
+		$temp = array();
+		$end_at = 0;
+		while ($cur_item = $db->fetch_assoc($result))
 		{
-			$query_str = '?stage=conv_tables';
-			break;
+			echo 'Preparsing post '.$cur_item['id'].' …<br />'."\n";
+			$db->query('UPDATE '.$db->prefix.'posts SET message = \''.$db->escape(preparse_bbcode($cur_item['message'], $temp)).'\' WHERE id = '.$cur_item['id']) or error('Unable to update post', __FILE__, __LINE__, $db->error());
+
+			$end_at = $cur_item['id'];
 		}
 
-		// Determine where to start
-		if ($start_at == 0)
+		// Check if there is more work to do
+		if ($end_at > 0)
 		{
-			// Get the first topic ID from the db
-			$result = $db->query('SELECT id FROM '.$db->prefix.'topics ORDER BY id LIMIT 1') or error('Unable to fetch first topic ID', __FILE__, __LINE__, $db->error());
+			$result = $db->query('SELECT 1 FROM '.$db->prefix.'posts WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
 
-			if ($db->num_rows($result))
-				$start_at = $db->result($result);
+			if ($db->num_rows($result) > 0)
+				$query_str = '?stage=preparse_posts&start_at='.$end_at;
 		}
-		$end_at = $start_at + PER_PAGE;
 
-		// Fetch topics to process this cycle
-		$result = $db->query('SELECT id, poster, subject, last_poster FROM '.$db->prefix.'topics WHERE id >= '.$start_at.' AND id < '.$end_at.' ORDER BY id') or error('Unable to fetch topics', __FILE__, __LINE__, $db->error());
+		break;
+
+
+	// Preparse signatures
+	case 'preparse_sigs':
+		$query_str = '?stage=rebuild_idx';
 
+		require PUN_ROOT.'include/parser.php';
+
+		// Fetch users to process this cycle
+		$result = $db->query('SELECT id, signature FROM '.$db->prefix.'users WHERE id > '.$start_at.' ORDER BY id ASC LIMIT '.PER_PAGE) or error('Unable to fetch users', __FILE__, __LINE__, $db->error());
+
+		$temp = array();
+		$end_at = 0;
 		while ($cur_item = $db->fetch_assoc($result))
 		{
-			echo 'Converting topic '.$cur_item['id'].' …<br />'."\n";
-			if (convert_to_utf8($cur_item['poster'], $old_charset) | convert_to_utf8($cur_item['subject'], $old_charset) | convert_to_utf8($cur_item['last_poster'], $old_charset))
-			{
-				$db->query('UPDATE '.$db->prefix.'topics SET poster = \''.$db->escape($cur_item['poster']).'\', subject = \''.$db->escape($cur_item['subject']).'\', last_poster = \''.$db->escape($cur_item['last_poster']).'\' WHERE id = '.$cur_item['id']) or error('Unable to update topic', __FILE__, __LINE__, $db->error());
-			}
+			echo 'Preparsing signature '.$cur_item['id'].' …<br />'."\n";
+			$db->query('UPDATE '.$db->prefix.'users SET signature = \''.$db->escape(preparse_bbcode($cur_item['signature'], $temp, true)).'\' WHERE id = '.$cur_item['id']) or error('Unable to update user', __FILE__, __LINE__, $db->error());
+
+			$end_at = $cur_item['id'];
 		}
 
 		// Check if there is more work to do
-		$result = $db->query('SELECT id FROM '.$db->prefix.'topics WHERE id >= '.$end_at.' ORDER BY id LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+		if ($end_at > 0)
+		{
+			$result = $db->query('SELECT 1 FROM '.$db->prefix.'users WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+			if ($db->num_rows($result) > 0)
+				$query_str = '?stage=preparse_sigs&start_at='.$end_at;
+		}
 
-		if ($db->num_rows($result))
-			$query_str = '?stage=conv_topics&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE.'&start_at='.$db->result($result);
-		else
-			$query_str = '?stage=conv_posts&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE;
 		break;
 
 
-	// Convert posts
-	case 'conv_posts':
-		if (strpos($cur_version, '1.2') !== 0)
-		{
-			$query_str = '?stage=conv_tables';
-			break;
-		}
+	// Rebuild the search index
+	case 'rebuild_idx':
+		$query_str = '?stage=finish';
 
-		// Determine where to start
 		if ($start_at == 0)
 		{
-			// Get the first post ID from the db
-			$result = $db->query('SELECT id FROM '.$db->prefix.'posts ORDER BY id LIMIT 1') or error('Unable to fetch first post ID', __FILE__, __LINE__, $db->error());
+			// Truncate the tables just in-case we didn't already (if we are coming directly here without converting the tables)
+			$db->truncate_table('search_cache') or error('Unable to empty search cache table', __FILE__, __LINE__, $db->error());
+			$db->truncate_table('search_matches') or error('Unable to empty search index match table', __FILE__, __LINE__, $db->error());
+			$db->truncate_table('search_words') or error('Unable to empty search index words table', __FILE__, __LINE__, $db->error());
 
-			if ($db->num_rows($result))
-				$start_at = $db->result($result);
+			// Reset the sequence for the search words (not needed for SQLite)
+			switch ($db_type)
+			{
+				case 'mysql':
+				case 'mysqli':
+				case 'mysql_innodb':
+				case 'mysqli_innodb':
+					$db->query('ALTER TABLE '.$db->prefix.'search_words auto_increment=1') or error('Unable to update table auto_increment', __FILE__, __LINE__, $db->error());
+					break;
+
+				case 'pgsql';
+					$db->query('SELECT setval(\''.$db->prefix.'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error());
+					break;
+			}
 		}
-		$end_at = $start_at + PER_PAGE;
+
+		require PUN_ROOT.'include/search_idx.php';
 
 		// Fetch posts to process this cycle
-		$result = $db->query('SELECT id, poster, message, edited_by FROM '.$db->prefix.'topics WHERE id >= '.$start_at.' AND id < '.$end_at.' ORDER BY id') or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
+		$result = $db->query('SELECT p.id, p.message, t.subject, t.first_post_id FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id WHERE p.id > '.$start_at.' ORDER BY p.id ASC LIMIT '.PER_PAGE) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
 
+		$end_at = 0;
 		while ($cur_item = $db->fetch_assoc($result))
 		{
-			echo 'Converting post '.$cur_item['id'].' …<br />'."\n";
-			if (convert_to_utf8($cur_item['poster'], $old_charset) | convert_to_utf8($cur_item['message'], $old_charset) | convert_to_utf8($cur_item['edited_by'], $old_charset))
-			{
-				$cur_item['edited_by'] = $cur_item['edited_by'] != '' ? '\''.$db->escape($cur_item['edited_by']).'\'' : 'NULL';
+			echo 'Rebuilding index for post '.$cur_item['id'].' …<br />'."\n";
 
-				$db->query('UPDATE '.$db->prefix.'topics SET poster = \''.$db->escape($cur_item['poster']).'\', message = \''.$db->escape($cur_item['message']).'\', edited_by = '.$cur_item['edited_by'].' WHERE id = '.$cur_item['id']) or error('Unable to update post', __FILE__, __LINE__, $db->error());
-			}
+			if ($cur_item['id'] == $cur_item['first_post_id'])
+				update_search_index('post', $cur_item['id'], $cur_item['message'], $cur_item['subject']);
+			else
+				update_search_index('post', $cur_item['id'], $cur_item['message']);
+
+			$end_at = $cur_item['id'];
 		}
 
 		// Check if there is more work to do
-		$result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE id >= '.$end_at.' ORDER BY id LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
-
-		if ($db->num_rows($result))
-			$query_str = '?stage=conv_posts&req_old_charset='.$old_charset.'&req_per_page='.PER_PAGE.'&start_at='.$db->result($result);
-		else
-			$query_str = '?stage=conv_tables';
-		break;
-
-
-	// Convert table columns to utf8 (MySQL only)
-	case 'conv_tables':
-		// Do the cumbersome charset conversion of MySQL tables/columns
-		if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
+		if ($end_at > 0)
 		{
-			echo 'Converting table '.$db->prefix.'bans …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'bans');
-			echo 'Converting table '.$db->prefix.'categories …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'categories');
-			echo 'Converting table '.$db->prefix.'censoring …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'censoring');
-			echo 'Converting table '.$db->prefix.'config …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'config');
-			echo 'Converting table '.$db->prefix.'forum_perms …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'forum_perms');
-			echo 'Converting table '.$db->prefix.'forums …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'forums');
-			echo 'Converting table '.$db->prefix.'groups …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'groups');
-			echo 'Converting table '.$db->prefix.'online …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'online');
-			echo 'Converting table '.$db->prefix.'posts …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'posts');
-			echo 'Converting table '.$db->prefix.'ranks …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'ranks');
-			echo 'Converting table '.$db->prefix.'reports …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'reports');
-			echo 'Converting table '.$db->prefix.'search_cache …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'search_cache');
-			echo 'Converting table '.$db->prefix.'search_matches …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'search_matches');
-			echo 'Converting table '.$db->prefix.'search_words …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'search_words');
-			echo 'Converting table '.$db->prefix.'subscriptions …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'subscriptions');
-			echo 'Converting table '.$db->prefix.'topics …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'topics');
-			echo 'Converting table '.$db->prefix.'users …<br />'."\n"; flush();
-			convert_table_utf8($db->prefix.'users');
+			$result = $db->query('SELECT 1 FROM '.$db->prefix.'posts WHERE id > '.$end_at.' ORDER BY id ASC LIMIT 1') or error('Unable to fetch next ID', __FILE__, __LINE__, $db->error());
+
+			if ($db->num_rows($result) > 0)
+				$query_str = '?stage=rebuild_idx&start_at='.$end_at;
 		}
 
-		$query_str = '?stage=finish';
 		break;
 
+
 	// Show results page
 	case 'finish':
-		// Now we're definitely using UTF-8, so we convert the output properly
-		$db->set_names('utf8');
-
 		// We update the version number
 		$db->query('UPDATE '.$db->prefix.'config SET conf_value = \''.UPDATE_TO.'\' WHERE conf_name = \'o_cur_version\'') or error('Unable to update version', __FILE__, __LINE__, $db->error());
 
@@ -978,9 +1382,6 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 		while ($row = $db->fetch_row($result))
 			update_forum($row[0]);
 
-		// We'll empty the search cache table as well (using DELETE FROM since SQLite does not support TRUNCATE TABLE)
-		$db->query('DELETE FROM '.$db->prefix.'search_cache') or error('Unable to clear search cache', __FILE__, __LINE__, $db->error());
-
 		// Empty the PHP cache
 		forum_clear_cache();
 
@@ -991,7 +1392,7 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>FluxBB Database Update</title>
-<link rel="stylesheet" type="text/css" href="style/Oxygen.css" />
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
 </head>
 <body>
 
@@ -1003,7 +1404,7 @@ if (strpos($cur_version, '1.2') === 0 && (!$db_seems_utf8 || isset($_GET['force'
 	<div class="box">
 		<div class="fakeform">
 			<div class="inform">
-				<p style="font-size: 1.1em">Your forum database was successfully updated.</p>
+				<p style="font-size: 1.1em">Your forum database was successfully updated. You may now <a href="<?php echo PUN_ROOT ?>index.php">go to the forum index</a>.</p>
 			</div>
 		</div>
 	</div>
diff --git a/upload/delete.php b/upload/delete.php
index 36767d4..69868ac 100644
--- a/upload/delete.php
+++ b/upload/delete.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 define('PUN_ROOT', './');
 require PUN_ROOT.'include/common.php';
@@ -86,7 +69,8 @@ if (isset($_POST['delete']))
 }
 
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_delete['Delete post'];
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_delete['Delete post']);
+define ('PUN_ACTIVE_PAGE', 'index');
 require PUN_ROOT.'header.php';
 
 require PUN_ROOT.'include/parser.php';
@@ -95,7 +79,12 @@ $cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smili
 ?>
 <div class="linkst">
 	<div class="inbox">
-		<ul><li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li><li>&nbsp;&raquo;&nbsp;<a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li><li>&nbsp;&raquo;&nbsp;<?php echo pun_htmlspecialchars($cur_post['subject']) ?></li></ul>
+		<ul class="crumbs">
+			<li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewtopic.php?pid=<?php echo $id ?>#p<?php echo $id ?>"><?php echo pun_htmlspecialchars($cur_post['subject']) ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_delete['Delete post'] ?></strong></li>
+		</ul>
 	</div>
 </div>
 
@@ -104,17 +93,16 @@ $cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smili
 	<div class="box">
 		<form method="post" action="delete.php?id=<?php echo $id ?>">
 			<div class="inform">
-				<fieldset>
-					<legend class="warntext"><?php echo $lang_delete['Warning'] ?></legend>
-					<div class="infldset">
-						<div class="postmsg">
-							<p><?php echo $lang_common['Author'] ?>: <strong><?php echo pun_htmlspecialchars($cur_post['poster']) ?></strong></p>
-							<?php echo $cur_post['message'] ?>
-						</div>
+				<p><strong><?php echo $lang_delete['Warning'] ?></strong></p>
+				<p><strong><?php printf($lang_delete['Author'], '</strong>'.pun_htmlspecialchars($cur_post['poster'])) ?></p>
+				<p><strong><?php echo $lang_common['Message'] ?></strong></p>
+				<div class="deletemsg">
+					<div class="postmsg">
+						<?php echo $cur_post['message']."\n" ?>
 					</div>
-				</fieldset>
+				</div>
 			</div>
-			<p><input type="submit" name="delete" value="<?php echo $lang_delete['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="delete" value="<?php echo $lang_delete['Delete'] ?>" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
diff --git a/upload/edit.php b/upload/edit.php
index a61bfab..e08e402 100644
--- a/upload/edit.php
+++ b/upload/edit.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 define('PUN_ROOT', './');
 require PUN_ROOT.'include/common.php';
@@ -67,7 +50,7 @@ if (isset($_POST['form_sent']))
 	if ($is_admmod)
 		confirm_referrer('edit.php');
 
-	// If it is a topic it must contain a subject
+	// If it's a topic it must contain a subject
 	if ($can_edit_subject)
 	{
 		$subject = pun_trim($_POST['req_subject']);
@@ -76,30 +59,29 @@ if (isset($_POST['form_sent']))
 			$errors[] = $lang_post['No subject'];
 		else if (pun_strlen($subject) > 70)
 			$errors[] = $lang_post['Too long subject'];
-		else if ($pun_config['p_subject_all_caps'] == '0' && strtoupper($subject) == $subject && !$pun_user['is_admmod'])
-			$subject = ucwords(strtolower($subject));
+		else if ($pun_config['p_subject_all_caps'] == '0' && is_all_uppercase($subject) && !$pun_user['is_admmod'])
+			$errors[] = $lang_post['All caps subject'];
 	}
 
 	// Clean up message from POST
 	$message = pun_linebreaks(pun_trim($_POST['req_message']));
 
-	if ($message == '')
-		$errors[] = $lang_post['No message'];
-	else if (strlen($message) > 65535)
+	if (pun_strlen($message) > PUN_MAX_POSTSIZE)
 		$errors[] = $lang_post['Too long message'];
-	else if ($pun_config['p_message_all_caps'] == '0' && strtoupper($message) == $message && !$pun_user['is_admmod'])
-		$message = ucwords(strtolower($message));
+	else if ($pun_config['p_message_all_caps'] == '0' && is_all_uppercase($message) && !$pun_user['is_admmod'])
+		$errors[] = $lang_post['All caps message'];
 
 	// Validate BBCode syntax
-	if ($pun_config['p_message_bbcode'] == '1' && strpos($message, '[') !== false && strpos($message, ']') !== false)
+	if ($pun_config['p_message_bbcode'] == '1')
 	{
 		require PUN_ROOT.'include/parser.php';
 		$message = preparse_bbcode($message, $errors);
 	}
 
+	if ($message == '')
+		$errors[] = $lang_post['No message'];
 
-	$hide_smilies = isset($_POST['hide_smilies']) ? intval($_POST['hide_smilies']) : 0;
-	if ($hide_smilies != '1') $hide_smilies = '0';
+	$hide_smilies = isset($_POST['hide_smilies']) ? '1' : '0';
 
 	// Did everything go according to plan?
 	if (empty($errors) && !isset($_POST['preview']))
@@ -120,7 +102,7 @@ if (isset($_POST['form_sent']))
 			update_search_index('edit', $id, $message);
 
 		// Update the post
-		$db->query('UPDATE '.$db->prefix.'posts SET message=\''.$db->escape($message).'\', hide_smilies=\''.$hide_smilies.'\''.$edited_sql.' WHERE id='.$id) or error('Unable to update post', __FILE__, __LINE__, $db->error());
+		$db->query('UPDATE '.$db->prefix.'posts SET message=\''.$db->escape($message).'\', hide_smilies='.$hide_smilies.$edited_sql.' WHERE id='.$id) or error('Unable to update post', __FILE__, __LINE__, $db->error());
 
 		redirect('viewtopic.php?pid='.$id.'#p'.$id, $lang_post['Edit redirect']);
 	}
@@ -128,9 +110,10 @@ if (isset($_POST['form_sent']))
 
 
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_post['Edit post'];
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_post['Edit post']);
 $required_fields = array('req_subject' => $lang_common['Subject'], 'req_message' => $lang_common['Message']);
 $focus_element = array('edit', 'req_message');
+define('PUN_ACTIVE_PAGE', 'index');
 require PUN_ROOT.'header.php';
 
 $cur_index = 1;
@@ -138,7 +121,12 @@ $cur_index = 1;
 ?>
 <div class="linkst">
 	<div class="inbox">
-		<ul><li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li><li>&nbsp;&raquo;&nbsp;<a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li><li>&nbsp;&raquo;&nbsp;<?php echo pun_htmlspecialchars($cur_post['subject']) ?></li></ul>
+		<ul class="crumbs">
+			<li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewtopic.php?id=<?php echo $cur_post['tid'] ?>"><?php echo pun_htmlspecialchars($cur_post['subject']) ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_post['Edit post'] ?></strong></li>
+		</ul>
 	</div>
 </div>
 
@@ -152,12 +140,12 @@ if (!empty($errors))
 <div id="posterror" class="block">
 	<h2><span><?php echo $lang_post['Post errors'] ?></span></h2>
 	<div class="box">
-		<div class="inbox">
+		<div class="inbox error-info">
 			<p><?php echo $lang_post['Post errors info'] ?></p>
-			<ul>
+			<ul class="error-list">
 <?php
 
-	while (list(, $cur_error) = each($errors))
+	foreach ($errors as $cur_error)
 		echo "\t\t\t\t".'<li><strong>'.$cur_error.'</strong></li>'."\n";
 ?>
 			</ul>
@@ -178,9 +166,11 @@ else if (isset($_POST['preview']))
 	<h2><span><?php echo $lang_post['Post preview'] ?></span></h2>
 	<div class="box">
 		<div class="inbox">
-			<div class="postright">
-				<div class="postmsg">
-					<?php echo $preview_message."\n" ?>
+			<div class="postbody">
+				<div class="postright">
+					<div class="postmsg">
+						<?php echo $preview_message."\n" ?>
+					</div>
 				</div>
 			</div>
 		</div>
@@ -201,14 +191,14 @@ else if (isset($_POST['preview']))
 					<legend><?php echo $lang_post['Edit post legend'] ?></legend>
 					<input type="hidden" name="form_sent" value="1" />
 					<div class="infldset txtarea">
-<?php if ($can_edit_subject): ?>						<label><?php echo $lang_common['Subject'] ?><br />
+<?php if ($can_edit_subject): ?>						<label class="required"><strong><?php echo $lang_common['Subject'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br />
 						<input class="longinput" type="text" name="req_subject" size="80" maxlength="70" tabindex="<?php echo $cur_index++ ?>" value="<?php echo pun_htmlspecialchars(isset($_POST['req_subject']) ? $_POST['req_subject'] : $cur_post['subject']) ?>" /><br /></label>
-<?php endif; ?>						<label><?php echo $lang_common['Message'] ?><br />
+<?php endif; ?>						<label class="required"><strong><?php echo $lang_common['Message'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br />
 						<textarea name="req_message" rows="20" cols="95" tabindex="<?php echo $cur_index++ ?>"><?php echo pun_htmlspecialchars(isset($_POST['req_message']) ? $message : $cur_post['message']) ?></textarea><br /></label>
 						<ul class="bblinks">
-							<li><a href="help.php#bbcode" onclick="window.open(this.href); return false;"><?php echo $lang_common['BBCode'] ?></a>: <?php echo ($pun_config['p_message_bbcode'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></li>
-							<li><a href="help.php#img" onclick="window.open(this.href); return false;"><?php echo $lang_common['img tag'] ?></a>: <?php echo ($pun_config['p_message_img_tag'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></li>
-							<li><a href="help.php#smilies" onclick="window.open(this.href); return false;"><?php echo $lang_common['Smilies'] ?></a>: <?php echo ($pun_config['o_smilies'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></li>
+							<li><a href="help.php#bbcode" onclick="window.open(this.href); return false;"><?php echo $lang_common['BBCode'] ?></a> <?php echo ($pun_config['p_message_bbcode'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></li>
+							<li><a href="help.php#img" onclick="window.open(this.href); return false;"><?php echo $lang_common['img tag'] ?></a> <?php echo ($pun_config['p_message_img_tag'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></li>
+							<li><a href="help.php#smilies" onclick="window.open(this.href); return false;"><?php echo $lang_common['Smilies'] ?></a> <?php echo ($pun_config['o_smilies'] == '1') ? $lang_common['on'] : $lang_common['off']; ?></li>
 						</ul>
 					</div>
 				</fieldset>
@@ -218,17 +208,17 @@ $checkboxes = array();
 if ($pun_config['o_smilies'] == '1')
 {
 	if (isset($_POST['hide_smilies']) || $cur_post['hide_smilies'] == '1')
-		$checkboxes[] = '<label><input type="checkbox" name="hide_smilies" value="1" checked="checked" tabindex="'.($cur_index++).'" />&nbsp;'.$lang_post['Hide smilies'];
+		$checkboxes[] = '<label><input type="checkbox" name="hide_smilies" value="1" checked="checked" tabindex="'.($cur_index++).'" />'.$lang_post['Hide smilies'].'<br /></label>';
 	else
-		$checkboxes[] = '<label><input type="checkbox" name="hide_smilies" value="1" tabindex="'.($cur_index++).'" />&nbsp;'.$lang_post['Hide smilies'];
+		$checkboxes[] = '<label><input type="checkbox" name="hide_smilies" value="1" tabindex="'.($cur_index++).'" />'.$lang_post['Hide smilies'].'<br /></label>';
 }
 
 if ($is_admmod)
 {
 	if ((isset($_POST['form_sent']) && isset($_POST['silent'])) || !isset($_POST['form_sent']))
-		$checkboxes[] = '<label><input type="checkbox" name="silent" value="1" tabindex="'.($cur_index++).'" checked="checked" />&nbsp;'.$lang_post['Silent edit'];
+		$checkboxes[] = '<label><input type="checkbox" name="silent" value="1" tabindex="'.($cur_index++).'" checked="checked" />'.$lang_post['Silent edit'].'<br /></label>';
 	else
-		$checkboxes[] = '<label><input type="checkbox" name="silent" value="1" tabindex="'.($cur_index++).'" />&nbsp;'.$lang_post['Silent edit'];
+		$checkboxes[] = '<label><input type="checkbox" name="silent" value="1" tabindex="'.($cur_index++).'" />'.$lang_post['Silent edit'].'<br /></label>';
 }
 
 if (!empty($checkboxes))
@@ -241,7 +231,7 @@ if (!empty($checkboxes))
 					<legend><?php echo $lang_common['Options'] ?></legend>
 					<div class="infldset">
 						<div class="rbox">
-							<?php echo implode('</label>'."\n\t\t\t\t\t\t\t", $checkboxes).'</label>'."\n" ?>
+							<?php echo implode("\n\t\t\t\t\t\t\t", $checkboxes)."\n" ?>
 						</div>
 					</div>
 				</fieldset>
@@ -251,7 +241,7 @@ if (!empty($checkboxes))
 
 ?>
 			</div>
-			<p><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" tabindex="<?php echo $cur_index++ ?>" accesskey="s" /><input type="submit" name="preview" value="<?php echo $lang_post['Preview'] ?>" tabindex="<?php echo $cur_index++ ?>" accesskey="p" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" tabindex="<?php echo $cur_index++ ?>" accesskey="s" /> <input type="submit" name="preview" value="<?php echo $lang_post['Preview'] ?>" tabindex="<?php echo $cur_index++ ?>" accesskey="p" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
diff --git a/upload/extern.php b/upload/extern.php
index 87996e6..ee92eab 100644
--- a/upload/extern.php
+++ b/upload/extern.php
@@ -1,337 +1,488 @@
 <?php
-/***********************************************************************
 
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
+/*-----------------------------------------------------------------------------
 
   INSTRUCTIONS
 
   This script is used to include information about your board from
   pages outside the forums and to syndicate news about recent
-  discussions via RSS. The script can display a list of recent
-  discussions (sorted by post time or last post time), a list of
-  active users or a collection of general board statistics. The
-  script can be called directly via an URL (for RSS), from a PHP
-  include command or through the use of Server Side Includes (SSI).
+  discussions via RSS/Atom/XML. The script can display a list of
+  recent discussions, a list of active users or a collection of
+  general board statistics. The script can be called directly via
+  an URL, from a PHP include command or through the use of Server
+  Side Includes (SSI).
 
   The scripts behaviour is controlled via variables supplied in the
   URL to the script. The different variables are: action (what to
-  output), show (how many topics to display), fid (the ID or ID's of
-  the forum(s) to poll for topics), nfid (the ID or ID's of forums
-  that should be excluded) and type (output as HTML or RSS). The
-  only mandatory variable is action. Possible/default values are:
-
-    action: active (show most recently active topics) (HTML or RSS)
-            new (show newest topics) (HTML or RSS)
-            online (show users online) (HTML)
-            online_full (as above, but includes a full list) (HTML)
-            stats (show board statistics) (HTML)
+  do), show (how many items to display), fid (the ID or IDs of
+  the forum(s) to poll for topics), nfid (the ID or IDs of forums
+  that should be excluded), tid (the ID of the topic from which to
+  display posts) and type (output as HTML or RSS). The only
+  mandatory variable is action. Possible/default values are:
+
+    action: feed - show most recent topics/posts (HTML or RSS)
+            online - show users online (HTML)
+            online_full - as above, but includes a full list (HTML)
+            stats - show board statistics (HTML)
+
+    type:   rss - output as RSS 2.0
+            atom - output as Atom 1.0
+            xml - output as XML
+            html - output as HTML (<li>'s)
+
+    fid:    One or more forum IDs (comma-separated). If ignored,
+            topics from all readable forums will be pulled.
+
+    nfid:   One or more forum IDs (comma-separated) that are to be
+            excluded. E.g. the ID of a a test forum.
 
-    show:   Any integer value between 1 and 50. This variables is
-            ignored for RSS output. The default is 15.
+    tid:    A topic ID from which to show posts. If a tid is supplied,
+            fid and nfid are ignored.
 
-    fid:    One or more forum ID's (comma-separated). If ignored,
-            topics from all guest-readable forums will be polled.
+    show:   Any integer value between 1 and 50. The default is 15.
 
-    nfid:   One or more forum ID's (comma-separated) that are to be
-            excluded. E.g. the ID of a a test forum.
+    order:  last_post - show topics ordered by when they were last
+                        posted in, giving information about the reply.
+            posted - show topics ordered by when they were first
+                     posted, giving information about the original post.
 
-    type:   RSS. Anything else means HTML output.
+-----------------------------------------------------------------------------*/
 
-  Here are some examples using PHP include().
+define('PUN_QUIET_VISIT', 1);
 
-    Show the 15 most recently active topics from all forums:
-    include('http://host.com/forums/extern.php?action=active');
+if (!defined('PUN_ROOT'))
+	define('PUN_ROOT', './');
+require PUN_ROOT.'include/common.php';
 
-    Show the 10 newest topics from forums with ID 5, 6 and 7:
-    include('http://host.com/forums/extern.php?action=new&show=10&fid=5,6,7');
+// The length at which topic subjects will be truncated (for HTML output)
+if (!defined('FORUM_EXTERN_MAX_SUBJECT_LENGTH'))
+	define('FORUM_EXTERN_MAX_SUBJECT_LENGTH', 30);
 
-    Show users online:
-    include('http://host.com/forums/extern.php?action=online');
+// If we're a guest and we've sent a username/pass, we can try to authenticate using those details
+if ($pun_user['is_guest'] && isset($_SERVER['PHP_AUTH_USER']))
+	authenticate_user($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
 
-    Show users online with full listing of users:
-    include('http://host.com/forums/extern.php?action=online_full');
+if ($pun_user['g_read_board'] == '0')
+{
+	http_authenticate_user();
+	exit($lang_common['No view']);
+}
 
-    Show board statistics:
-    include('http://host.com/forums/extern.php?action=stats');
+$action = isset($_GET['action']) ? $_GET['action'] : 'feed';
 
-  Here are some examples using SSI.
 
-    Show the 5 newest topics from forums with ID 11 and 22:
-    <!--#include virtual="forums/extern.php?action=new&show=5&fid=11,22" -->
+//
+// Sends the proper headers for Basic HTTP Authentication
+//
+function http_authenticate_user()
+{
+	global $pun_config, $pun_user;
 
-    Show board statistics:
-    <!--#include virtual="forums/extern.php?action=stats" -->
+	if (!$pun_user['is_guest'])
+		return;
 
-  And finally some examples using extern.php to output an RSS 0.91
-  feed.
+	header('WWW-Authenticate: Basic realm="'.$pun_config['o_board_title'].' External Syndication"');
+	header('HTTP/1.0 401 Unauthorized');
+}
 
-    Output the 15 most recently active topics:
-    http://host.com/extern.php?action=active&type=RSS
 
-    Output the 15 newest topics from forum with ID=2:
-    http://host.com/extern.php?action=active&type=RSS&fid=2
+//
+// Output $feed as RSS 2.0
+//
+function output_rss($feed)
+{
+	global $lang_common, $pun_config;
+
+	// Send XML/no cache headers
+	header('Content-Type: text/xml; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
+
+	echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
+	echo '<rss version="2.0">'."\n";
+	echo "\t".'<channel>'."\n";
+	echo "\t\t".'<title><![CDATA['.escape_cdata($feed['title']).']]></title>'."\n";
+	echo "\t\t".'<link>'.$feed['link'].'</link>'."\n";
+	echo "\t\t".'<description><![CDATA['.escape_cdata($feed['description']).']]></description>'."\n";
+	echo "\t\t".'<lastBuildDate>'.gmdate('r', count($feed['items']) ? $feed['items'][0]['pubdate'] : time()).'</lastBuildDate>'."\n";
+
+	if ($pun_config['o_show_version'] == '1')
+		echo "\t\t".'<generator>FluxBB '.$pun_config['o_cur_version'].'</generator>'."\n";
+	else
+		echo "\t\t".'<generator>FluxBB</generator>'."\n";
 
-  Below you will find some variables you can edit to tailor the
-  scripts behaviour to your needs.
+	foreach ($feed['items'] as $item)
+	{
+		echo "\t\t".'<item>'."\n";
+		echo "\t\t\t".'<title><![CDATA['.escape_cdata($item['title']).']]></title>'."\n";
+		echo "\t\t\t".'<link>'.$item['link'].'</link>'."\n";
+		echo "\t\t\t".'<description><![CDATA['.escape_cdata($item['description']).']]></description>'."\n";
+		echo "\t\t\t".'<author><![CDATA['.(isset($item['author']['email']) ? escape_cdata($item['author']['email']) : 'dummy@example.com').' ('.escape_cdata($item['author']['name']).')]]></author>'."\n";
+		echo "\t\t\t".'<pubDate>'.gmdate('r', $item['pubdate']).'</pubDate>'."\n";
+		echo "\t\t\t".'<guid>'.$item['link'].'</guid>'."\n";
+
+		echo "\t\t".'</item>'."\n";
+	}
 
+	echo "\t".'</channel>'."\n";
+	echo '</rss>'."\n";
+}
 
-/***********************************************************************/
 
-// The maximum number of topics that will be displayed
-$show_max_topics = 60;
+//
+// Output $feed as Atom 1.0
+//
+function output_atom($feed)
+{
+	global $lang_common, $pun_config;
 
-// The length at which topic subjects will be truncated (for HTML output)
-$max_subject_length = 30;
+	// Send XML/no cache headers
+	header('Content-Type: text/xml; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
 
-/***********************************************************************/
+	echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
+	echo '<feed xmlns="http://www.w3.org/2005/Atom">'."\n";
 
-// DO NOT EDIT ANYTHING BELOW THIS LINE! (unless you know what you are doing)
+	echo "\t".'<title type="html"><![CDATA['.escape_cdata($feed['title']).']]></title>'."\n";
+	echo "\t".'<link rel="self" href="'.pun_htmlspecialchars(get_current_url()).'"/>'."\n";
+	echo "\t".'<link href="'.$feed['link'].'"/>'."\n";
+	echo "\t".'<updated>'.gmdate('Y-m-d\TH:i:s\Z', count($feed['items']) ? $feed['items'][0]['pubdate'] : time()).'</updated>'."\n";
 
+	if ($pun_config['o_show_version'] == '1')
+		echo "\t".'<generator version="'.$pun_config['o_cur_version'].'">FluxBB</generator>'."\n";
+	else
+		echo "\t".'<generator>FluxBB</generator>'."\n";
 
-define('PUN_ROOT', './');
-@include PUN_ROOT.'config.php';
+	echo "\t".'<id>'.$feed['link'].'</id>'."\n";
 
-// If PUN isn't defined, config.php is missing or corrupt
-if (!defined('PUN'))
-	exit('The file \'config.php\' doesn\'t exist or is corrupt. Please run install.php to install FluxBB first.');
+	$content_tag = ($feed['type'] == 'posts') ? 'content' : 'summary';
 
+	foreach ($feed['items'] as $item)
+	{
+		echo "\t".'<entry>'."\n";
+		echo "\t\t".'<title type="html"><![CDATA['.escape_cdata($item['title']).']]></title>'."\n";
+		echo "\t\t".'<link rel="alternate" href="'.$item['link'].'"/>'."\n";
+		echo "\t\t".'<'.$content_tag.' type="html"><![CDATA['.escape_cdata($item['description']).']]></'.$content_tag.'>'."\n";
+		echo "\t\t".'<author>'."\n";
+		echo "\t\t\t".'<name><![CDATA['.escape_cdata($item['author']['name']).']]></name>'."\n";
 
-// Make sure PHP reports all errors except E_NOTICE
-error_reporting(E_ALL ^ E_NOTICE);
+		if (isset($item['author']['email']))
+			echo "\t\t\t".'<email><![CDATA['.escape_cdata($item['author']['email']).']]></email>'."\n";
 
-// Turn off magic_quotes_runtime
-set_magic_quotes_runtime(0);
+		if (isset($item['author']['uri']))
+			echo "\t\t\t".'<uri>'.$item['author']['uri'].'</uri>'."\n";
 
-// If the cache directory is not specified, we use the default setting
-if (!defined('FORUM_CACHE_DIR'))
-	define('FORUM_CACHE_DIR', PUN_ROOT.'cache/');
+		echo "\t\t".'</author>'."\n";
+		echo "\t\t".'<updated>'.gmdate('Y-m-d\TH:i:s\Z', $item['pubdate']).'</updated>'."\n";
 
-// Load the functions script
-require PUN_ROOT.'include/functions.php';
+		echo "\t\t".'<id>'.$item['link'].'</id>'."\n";
+		echo "\t".'</entry>'."\n";
+	}
 
-// Load DB abstraction layer and try to connect
-require PUN_ROOT.'include/dblayer/common_db.php';
+	echo '</feed>'."\n";
+}
 
-// Load cached config
-if (file_exists(FORUM_CACHE_DIR.'cache_config.php'))
-	include FORUM_CACHE_DIR.'cache_config.php';
 
-if (!defined('PUN_CONFIG_LOADED'))
+//
+// Output $feed as XML
+//
+function output_xml($feed)
 {
-	if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
-		require PUN_ROOT.'include/cache.php';
+	global $lang_common, $pun_config;
 
-	generate_config_cache();
-	require FORUM_CACHE_DIR.'cache_config.php';
-}
+	// Send XML/no cache headers
+	header('Content-Type: text/xml; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
 
-// Make sure we (guests) have permission to read the forums
-$result = $db->query('SELECT g_read_board FROM '.$db->prefix.'groups WHERE g_id=3') or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
-if ($db->result($result) == '0')
-	exit('No permission');
+	echo '<?xml version="1.0" encoding="utf-8"?>'."\n";
+	echo '<source>'."\n";
+	echo "\t".'<url>'.$feed['link'].'</url>'."\n";
 
+	$forum_tag = ($feed['type'] == 'posts') ? 'post' : 'topic';
 
-// Attempt to load the common language file
-@include PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/common.php';
-if (!isset($lang_common))
-	exit('There is no valid language pack \''.$pun_config['o_default_lang'].'\' installed. Please reinstall a language of that name.');
+	foreach ($feed['items'] as $item)
+	{
+		echo "\t".'<'.$forum_tag.' id="'.$item['id'].'">'."\n";
 
-// Check if we are to display a maintenance message
-if ($pun_config['o_maintenance'] && !defined('PUN_TURN_OFF_MAINT'))
-	maintenance_message();
+		echo "\t\t".'<title><![CDATA['.escape_cdata($item['title']).']]></title>'."\n";
+		echo "\t\t".'<link>'.$item['link'].'</link>'."\n";
+		echo "\t\t".'<content><![CDATA['.escape_cdata($item['description']).']]></content>'."\n";
+		echo "\t\t".'<author>'."\n";
+		echo "\t\t\t".'<name><![CDATA['.escape_cdata($item['author']['name']).']]></name>'."\n";
 
-if (!isset($_GET['action']))
-	exit('No parameters supplied. See extern.php for instructions.');
+		if (isset($item['author']['email']))
+			echo "\t\t\t".'<email><![CDATA['.escape_cdata($item['author']['email']).']]></email>'."\n";
 
+		if (isset($item['author']['uri']))
+			echo "\t\t\t".'<uri>'.$item['author']['uri'].'</uri>'."\n";
 
-//
-// Converts the CDATA end sequence ]]> into ]]&gt;
-//
-function escape_cdata($str)
-{
-	return str_replace(']]>', ']]&gt;', $str);
+		echo "\t\t".'</author>'."\n";
+		echo "\t\t".'<posted>'.gmdate('r', $item['pubdate']).'</posted>'."\n";
+
+		echo "\t".'</'.$forum_tag.'>'."\n";
+	}
+
+	echo '</source>'."\n";
 }
 
 
 //
-// Show recent discussions
+// Output $feed as HTML (using <li> tags)
 //
-if ($_GET['action'] == 'active' || $_GET['action'] == 'new')
+function output_html($feed)
 {
-	$order_by = ($_GET['action'] == 'active') ? 't.last_post' : 't.posted';
-	$forum_sql = '';
 
-	// Was any specific forum ID's supplied?
-	if (isset($_GET['fid']) && $_GET['fid'] != '')
+	// Send the Content-type header in case the web server is setup to send something else
+	header('Content-type: text/html; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
+
+	foreach ($feed['items'] as $item)
 	{
-		$fids = explode(',', trim($_GET['fid']));
-		$fids = array_map('intval', $fids);
+		if (utf8_strlen($item['title']) > FORUM_EXTERN_MAX_SUBJECT_LENGTH)
+			$subject_truncated = pun_htmlspecialchars(pun_trim(utf8_substr($item['title'], 0, (FORUM_EXTERN_MAX_SUBJECT_LENGTH - 5)))).' &hellip;';
+		else
+			$subject_truncated = pun_htmlspecialchars($item['title']);
 
-		if (!empty($fids))
-			$forum_sql = ' AND f.id IN('.implode(',', $fids).')';
+		echo '<li><a href="'.$item['link'].'" title="'.pun_htmlspecialchars($item['title']).'">'.$subject_truncated.'</a></li>'."\n";
 	}
+}
 
-	// Any forum ID's to exclude?
-	if (isset($_GET['nfid']) && $_GET['nfid'] != '')
-	{
-		$nfids = explode(',', trim($_GET['nfid']));
-		$nfids = array_map('intval', $nfids);
+// Show recent discussions
+if ($action == 'feed')
+{
+	require PUN_ROOT.'include/parser.php';
 
-		if (!empty($nfids))
-			$forum_sql = ' AND f.id NOT IN('.implode(',', $nfids).')';
-	}
+	// Determine what type of feed to output
+	$type = isset($_GET['type']) && in_array($_GET['type'], array('html', 'rss', 'atom', 'xml')) ? $_GET['type'] : 'html';
+
+	$show = isset($_GET['show']) ? intval($_GET['show']) : 15;
+	if ($show < 1 || $show > 50)
+		$show = 15;
 
-	// Should we output this as RSS?
-	if (isset($_GET['type']) && strtoupper($_GET['type']) == 'RSS')
+	// Was a topic ID supplied?
+	if (isset($_GET['tid']))
 	{
-		$rss_description = ($_GET['action'] == 'active') ? $lang_common['RSS Desc Active'] : $lang_common['RSS Desc New'];
-		$url_action = ($_GET['action'] == 'active') ? '&amp;action=new' : '';
-
-		// Send XML/no cache headers
-		header('Content-Type: text/xml');
-		header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
-		header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
-		header('Pragma: public');
-
-		// It's time for some syndication!
-		echo '<?xml version="1.0" encoding="utf-8"?>'."\r\n";
-		echo '<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN" "http://my.netscape.com/publish/formats/rss-0.91.dtd">'."\r\n";
-		echo '<rss version="0.91">'."\r\n";
-		echo '<channel>'."\r\n";
-		echo "\t".'<title>'.pun_htmlspecialchars($pun_config['o_board_title']).'</title>'."\r\n";
-		echo "\t".'<link>'.$pun_config['o_base_url'].'/</link>'."\r\n";
-		echo "\t".'<description>'.pun_htmlspecialchars($rss_description.' '.$pun_config['o_board_title']).'</description>'."\r\n";
-		echo "\t".'<language>en-us</language>'."\r\n";
-
-		// Fetch 15 topics
-		$result = $db->query('SELECT t.id, t.poster, t.subject, t.posted, t.last_post, f.id AS fid, f.forum_name FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=3) WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.moved_to IS NULL'.$forum_sql.' ORDER BY '.$order_by.' DESC LIMIT 15') or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
+		$tid = intval($_GET['tid']);
 
-		while ($cur_topic = $db->fetch_assoc($result))
+		// Fetch topic subject
+		$result = $db->query('SELECT t.subject, t.first_post_id FROM '.$db->prefix.'topics AS t LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=t.forum_id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.moved_to IS NULL AND t.id='.$tid) or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
+		if (!$db->num_rows($result))
 		{
-			if ($pun_config['o_censoring'] == '1')
-				$cur_topic['subject'] = censor_words($cur_topic['subject']);
-
-			echo "\t".'<item>'."\r\n";
-			echo "\t\t".'<title>'.pun_htmlspecialchars($cur_topic['subject']).'</title>'."\r\n";
-			echo "\t\t".'<link>'.$pun_config['o_base_url'].'/viewtopic.php?id='.$cur_topic['id'].$url_action.'</link>'."\r\n";
-			echo "\t\t".'<description><![CDATA['.escape_cdata($lang_common['Forum'].': <a href="'.$pun_config['o_base_url'].'/viewforum.php?id='.$cur_topic['fid'].'">'.$cur_topic['forum_name'].'</a><br />'."\r\n".$lang_common['Author'].': '.$cur_topic['poster'].'<br />'."\r\n".$lang_common['Posted'].': '.date('r', $cur_topic['posted']).'<br />'."\r\n".$lang_common['Last post'].': '.date('r', $cur_topic['last_post'])).']]></description>'."\r\n";
-			echo "\t".'</item>'."\r\n";
+			http_authenticate_user();
+			exit($lang_common['Bad request']);
 		}
 
-		echo '</channel>'."\r\n";
-		echo '</rss>';
-	}
+		$cur_topic = $db->fetch_assoc($result);
+
+		if ($pun_config['o_censoring'] == '1')
+			$cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+		// Setup the feed
+		$feed = array(
+			'title' 		=>	$pun_config['o_board_title'].$lang_common['Title separator'].$cur_topic['subject'],
+			'link'			=>	$pun_config['o_base_url'].'/viewtopic.php?id='.$tid,
+			'description'		=>	sprintf($lang_common['RSS description topic'], $cur_topic['subject']),
+			'items'			=>	array(),
+			'type'			=>	'posts'
+		);
 
+		// Fetch $show posts
+		$result = $db->query('SELECT p.id, p.poster, p.message, p.hide_smilies, p.posted, p.poster_id, u.email_setting, u.email, p.poster_email FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'users AS u ON u.id=p.poster_id WHERE p.topic_id='.$tid.' ORDER BY p.posted DESC LIMIT '.$show) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+		while ($cur_post = $db->fetch_assoc($result))
+		{
+			$cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
+
+			$item = array(
+				'id'			=>	$cur_post['id'],
+				'title'			=>	$cur_topic['first_post_id'] == $cur_post['id'] ? $cur_topic['subject'] : $lang_common['RSS reply'].$cur_topic['subject'],
+				'link'			=>	$pun_config['o_base_url'].'/viewtopic.php?pid='.$cur_post['id'].'#p'.$cur_post['id'],
+				'description'		=>	$cur_post['message'],
+				'author'		=>	array(
+					'name'	=> $cur_post['poster'],
+				),
+				'pubdate'		=>	$cur_post['posted']
+			);
+
+			if ($cur_post['poster_id'] > 1)
+			{
+				if ($cur_post['email_setting'] == '0' && !$pun_user['is_guest'])
+					$item['author']['email'] = $cur_post['email'];
+
+				$item['author']['uri'] = $pun_config['o_base_url'].'/profile.php?id='.$cur_post['poster_id'];
+			}
+			else if ($cur_post['poster_email'] != '' && !$pun_user['is_guest'])
+				$item['author']['email'] = $cur_post['poster_email'];
+
+			$feed['items'][] = $item;
+		}
 
-	// Output regular HTML
+		$output_func = 'output_'.$type;
+		$output_func($feed);
+	}
 	else
 	{
-		$show = isset($_GET['show']) ? intval($_GET['show']) : 15;
-		if ($show < 1 || $show > 50)
-			$show = 15;
+		$order_posted = isset($_GET['order']) && $_GET['order'] == 'posted';
+		$forum_name = '';
+		$forum_sql = '';
 
-		// Fetch $show topics
-		$result = $db->query('SELECT t.id, t.subject FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id=3) WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.moved_to IS NULL'.$forum_sql.' ORDER BY '.$order_by.' DESC LIMIT '.$show) or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
+		// Were any forum IDs supplied?
+		if (isset($_GET['fid']) && is_scalar($_GET['fid']) && $_GET['fid'] != '')
+		{
+			$fids = explode(',', pun_trim($_GET['fid']));
+			$fids = array_map('intval', $fids);
+
+			if (!empty($fids))
+				$forum_sql = ' AND t.forum_id IN('.implode(',', $fids).')';
+
+			if (count($fids) == 1)
+			{
+				// Fetch forum name
+				$result = $db->query('SELECT f.forum_name FROM '.$db->prefix.'forums AS f LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$fids[0]) or error('Unable to fetch forum name', __FILE__, __LINE__, $db->error());
+				if ($db->num_rows($result))
+					$forum_name = $lang_common['Title separator'].$db->result($result);
+			}
+		}
+
+		// Any forum IDs to exclude?
+		if (isset($_GET['nfid']) && is_scalar($_GET['nfid']) && $_GET['nfid'] != '')
+		{
+			$nfids = explode(',', pun_trim($_GET['nfid']));
+			$nfids = array_map('intval', $nfids);
+
+			if (!empty($nfids))
+				$forum_sql = ' AND t.forum_id NOT IN('.implode(',', $nfids).')';
+		}
 
+		// Setup the feed
+		$feed = array(
+			'title' 		=>	$pun_config['o_board_title'].$forum_name,
+			'link'			=>	$pun_config['o_base_url'].'/index.php',
+			'description'	=>	sprintf($lang_common['RSS description'], $pun_config['o_board_title']),
+			'items'			=>	array(),
+			'type'			=>	'topics'
+		);
+
+		// Fetch $show topics
+		$result = $db->query('SELECT t.id, t.poster, t.subject, t.posted, t.last_post, t.last_poster, p.message, p.hide_smilies, u.email_setting, u.email, p.poster_id, p.poster_email FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'posts AS p ON p.id='.($order_posted ? 't.first_post_id' : 't.last_post_id').' INNER JOIN '.$db->prefix.'users AS u ON u.id=p.poster_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=t.forum_id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.moved_to IS NULL'.$forum_sql.' ORDER BY '.($order_posted ? 't.posted' : 't.last_post').' DESC LIMIT '.$show) or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
 		while ($cur_topic = $db->fetch_assoc($result))
 		{
 			if ($pun_config['o_censoring'] == '1')
 				$cur_topic['subject'] = censor_words($cur_topic['subject']);
 
-			if (pun_strlen($cur_topic['subject']) > $max_subject_length)
-				$subject_truncated = pun_htmlspecialchars(trim(substr($cur_topic['subject'], 0, ($max_subject_length-5)))).' &hellip;';
-			else
-				$subject_truncated = pun_htmlspecialchars($cur_topic['subject']);
-
-			echo '<li><a href="'.$pun_config['o_base_url'].'/viewtopic.php?id='.$cur_topic['id'].'&amp;action=new" title="'.pun_htmlspecialchars($cur_topic['subject']).'">'.$subject_truncated.'</a></li>'."\n";
+			$cur_topic['message'] = parse_message($cur_topic['message'], $cur_topic['hide_smilies']);
+
+			$item = array(
+				'id'			=>	$cur_topic['id'],
+				'title'			=>	$cur_topic['subject'],
+				'link'			=>	$pun_config['o_base_url'].($order_posted ? '/viewtopic.php?id='.$cur_topic['id'] : '/viewtopic.php?id='.$cur_topic['id'].'&amp;action=new'),
+				'description'	=>	$cur_topic['message'],
+				'author'		=>	array(
+					'name'	=> $order_posted ? $cur_topic['poster'] : $cur_topic['last_poster']
+				),
+				'pubdate'		=>	$order_posted ? $cur_topic['posted'] : $cur_topic['last_post']
+			);
+
+			if ($cur_topic['poster_id'] > 1)
+			{
+				if ($cur_topic['email_setting'] == '0' && !$pun_user['is_guest'])
+					$item['author']['email'] = $cur_topic['email'];
+
+				$item['author']['uri'] = $pun_config['o_base_url'].'/profile.php?id='.$cur_topic['poster_id'];
+			}
+			else if ($cur_topic['poster_email'] != '' && !$pun_user['is_guest'])
+				$item['author']['email'] = $cur_topic['poster_email'];
+
+			$feed['items'][] = $item;
 		}
+
+		$output_func = 'output_'.$type;
+		$output_func($feed);
 	}
 
-	return;
+	exit;
 }
 
-
-//
 // Show users online
-//
-else if ($_GET['action'] == 'online' || $_GET['action'] == 'online_full')
+else if ($action == 'online' || $action == 'online_full')
 {
 	// Load the index.php language file
 	require PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/index.php';
-	
+
 	// Fetch users online info and generate strings for output
 	$num_guests = $num_users = 0;
 	$users = array();
+
 	$result = $db->query('SELECT user_id, ident FROM '.$db->prefix.'online WHERE idle=0 ORDER BY ident', true) or error('Unable to fetch online list', __FILE__, __LINE__, $db->error());
 
 	while ($pun_user_online = $db->fetch_assoc($result))
 	{
 		if ($pun_user_online['user_id'] > 1)
 		{
-			$users[] = '<a href="'.$pun_config['o_base_url'].'/profile.php?id='.$pun_user_online['user_id'].'">'.pun_htmlspecialchars($pun_user_online['ident']).'</a>';
+			$users[] = ($pun_user['g_view_users'] == '1') ? '<a href="'.$pun_config['o_base_url'].'/profile.php?id='.$pun_user_online['user_id'].'">'.pun_htmlspecialchars($pun_user_online['ident']).'</a>' : pun_htmlspecialchars($pun_user_online['ident']);
 			++$num_users;
 		}
 		else
 			++$num_guests;
 	}
 
-	echo $lang_index['Guests online'].': '.forum_number_format($num_guests).'<br />';
+	// Send the Content-type header in case the web server is setup to send something else
+	header('Content-type: text/html; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
+
+	echo $lang_index['Guests online'].': '.forum_number_format($num_guests).'<br />'."\n";
 
-	if ($_GET['action'] == 'online_full')
-		echo $lang_index['Users online'].': '.implode(', ', $users).'<br />';
+	if ($action == 'online_full' && !empty($users))
+		echo $lang_index['Users online'].': '.implode(', ', $users).'<br />'."\n";
 	else
-		echo $lang_index['Users online'].': '.forum_number_format($num_users).'<br />';
+		echo $lang_index['Users online'].': '.forum_number_format($num_users).'<br />'."\n";
 
-	return;
+	exit;
 }
 
-
-//
 // Show board statistics
-//
-else if ($_GET['action'] == 'stats')
+else if ($action == 'stats')
 {
 	// Load the index.php language file
 	require PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/index.php';
 
 	// Collect some statistics from the database
-	$result = $db->query('SELECT COUNT(id)-1 FROM '.$db->prefix.'users') or error('Unable to fetch total user count', __FILE__, __LINE__, $db->error());
+	$result = $db->query('SELECT COUNT(id)-1 FROM '.$db->prefix.'users WHERE group_id!='.PUN_UNVERIFIED) or error('Unable to fetch total user count', __FILE__, __LINE__, $db->error());
 	$stats['total_users'] = $db->result($result);
 
-	$result = $db->query('SELECT id, username FROM '.$db->prefix.'users ORDER BY registered DESC LIMIT 1') or error('Unable to fetch newest registered user', __FILE__, __LINE__, $db->error());
+	$result = $db->query('SELECT id, username FROM '.$db->prefix.'users WHERE group_id!='.PUN_UNVERIFIED.' ORDER BY registered DESC LIMIT 1') or error('Unable to fetch newest registered user', __FILE__, __LINE__, $db->error());
 	$stats['last_user'] = $db->fetch_assoc($result);
 
 	$result = $db->query('SELECT SUM(num_topics), SUM(num_posts) FROM '.$db->prefix.'forums') or error('Unable to fetch topic/post count', __FILE__, __LINE__, $db->error());
 	list($stats['total_topics'], $stats['total_posts']) = $db->fetch_row($result);
 
-	echo $lang_index['No of users'].': '.forum_number_format($stats['total_users']).'<br />';
-	echo $lang_index['Newest user'].': <a href="'.$pun_config['o_base_url'].'/profile.php?id='.$stats['last_user']['id'].'">'.pun_htmlspecialchars($stats['last_user']['username']).'</a><br />';
-	echo $lang_index['No of topics'].': '.forum_number_format($stats['total_topics']).'<br />';
-	echo $lang_index['No of posts'].': '.forum_number_format($stats['total_posts']);
+	// Send the Content-type header in case the web server is setup to send something else
+	header('Content-type: text/html; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
 
-	return;
-}
+	echo $lang_index['No of users'].': '.forum_number_format($stats['total_users']).'<br />'."\n";
+	echo $lang_index['Newest user'].': '.(($pun_user['g_view_users'] == '1') ? '<a href="'.$pun_config['o_base_url'].'/profile.php?id='.$stats['last_user']['id'].'">'.pun_htmlspecialchars($stats['last_user']['username']).'</a>' : pun_htmlspecialchars($stats['last_user']['username'])).'<br />'."\n";
+	echo $lang_index['No of topics'].': '.forum_number_format($stats['total_topics']).'<br />'."\n";
+	echo $lang_index['No of posts'].': '.forum_number_format($stats['total_posts']).'<br />'."\n";
 
+	exit;
+}
 
-else
-	exit('Bad request');
+// If we end up here, the script was called with some wacky parameters
+exit($lang_common['Bad request']);
diff --git a/upload/footer.php b/upload/footer.php
index acc78f0..4575702 100644
--- a/upload/footer.php
+++ b/upload/footer.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure no one attempts to run this script "directly"
 if (!defined('PUN'))
@@ -48,33 +31,55 @@ $footer_style = isset($footer_style) ? $footer_style : NULL;
 
 if ($footer_style == 'index' || $footer_style == 'search')
 {
-	if (!$pun_user['is_guest'])
+	echo "\t\t\t".'<div class="conl">'."\n";
+
+	if (!$pun_user['is_guest'] && $pun_user['g_search'] == '1')
 	{
-		echo "\n\t\t\t".'<dl id="searchlinks" class="conl">'."\n\t\t\t\t".'<dt><strong>'.$lang_common['Search links'].'</strong></dt>'."\n\t\t\t\t".'<dd><a href="search.php?action=show_24h">'.$lang_common['Show recent posts'].'</a></dd>'."\n";
-		echo "\t\t\t\t".'<dd><a href="search.php?action=show_unanswered">'.$lang_common['Show unanswered posts'].'</a></dd>'."\n";
+		echo "\t\t\t\t".'<dl id="searchlinks">'."\n";
+		echo "\t\t\t\t\t".'<dt><strong>'.$lang_common['Search links'].'</strong></dt>'."\n";
+
+		echo "\t\t\t\t\t".'<dd><a href="search.php?action=show_24h">'.$lang_common['Show recent posts'].'</a></dd>'."\n";
+		echo "\t\t\t\t\t".'<dd><a href="search.php?action=show_unanswered">'.$lang_common['Show unanswered posts'].'</a></dd>'."\n";
 
 		if ($pun_config['o_subscriptions'] == '1')
-			echo "\t\t\t\t".'<dd><a href="search.php?action=show_subscriptions">'.$lang_common['Show subscriptions'].'</a></dd>'."\n";
+			echo "\t\t\t\t\t".'<dd><a href="search.php?action=show_subscriptions">'.$lang_common['Show subscriptions'].'</a></dd>'."\n";
 
-		echo "\t\t\t\t".'<dd><a href="search.php?action=show_user&amp;user_id='.$pun_user['id'].'">'.$lang_common['Show your posts'].'</a></dd>'."\n\t\t\t".'</dl>'."\n";
+		echo "\t\t\t\t\t".'<dd><a href="search.php?action=show_user&amp;user_id='.$pun_user['id'].'">'.$lang_common['Show your posts'].'</a></dd>'."\n";
+
+		echo "\t\t\t\t".'</dl>'."\n";
 	}
 	else
 	{
 		if ($pun_user['g_search'] == '1')
 		{
-			echo "\n\t\t\t".'<dl id="searchlinks" class="conl">'."\n\t\t\t\t".'<dt><strong>'.$lang_common['Search links'].'</strong></dt><dd><a href="search.php?action=show_24h">'.$lang_common['Show recent posts'].'</a></dd>'."\n";
-			echo "\t\t\t\t".'<dd><a href="search.php?action=show_unanswered">'.$lang_common['Show unanswered posts'].'</a></dd>'."\n\t\t\t".'</dl>'."\n";
+			echo "\t\t\t\t".'<dl id="searchlinks">'."\n";
+			echo "\t\t\t\t\t".'<dt><strong>'.$lang_common['Search links'].'</strong></dt>'."\n";
+
+			echo "\t\t\t\t\t".'<dd><a href="search.php?action=show_24h">'.$lang_common['Show recent posts'].'</a></dd>'."\n";
+			echo "\t\t\t\t\t".'<dd><a href="search.php?action=show_unanswered">'.$lang_common['Show unanswered posts'].'</a></dd>'."\n";
+
+			echo "\t\t\t\t".'</dl>'."\n";
 		}
 	}
+
+	if ($footer_style == 'index')
+	{
+		if ($pun_config['o_feed_type'] == '1')
+			echo "\t\t\t\t".'<p id="feedlinks"><span class="rss"><a href="extern.php?action=feed&amp;type=rss">'.$lang_common['RSS active topics feed'].'</a></span></p>'."\n";
+		else if ($pun_config['o_feed_type'] == '2')
+			echo "\t\t\t\t".'<p id="feedlinks"><span class="atom"><a href="extern.php?action=feed&amp;type=atom">'.$lang_common['Atom active topics feed'].'</a></span></p>'."\n";
+	}
+
+	echo "\t\t\t".'</div>'."\n";
 }
 else if ($footer_style == 'viewforum' || $footer_style == 'viewtopic')
 {
-	echo "\n\t\t\t".'<div class="conl">'."\n";
+	echo "\t\t\t".'<div class="conl">'."\n";
 
 	// Display the "Jump to" drop list
 	if ($pun_config['o_quickjump'] == '1')
 	{
-		// Load cached quickjump
+		// Load cached quick jump
 		if (file_exists(FORUM_CACHE_DIR.'cache_quickjump_'.$pun_user['g_id'].'.php'))
 			include FORUM_CACHE_DIR.'cache_quickjump_'.$pun_user['g_id'].'.php';
 
@@ -88,47 +93,65 @@ else if ($footer_style == 'viewforum' || $footer_style == 'viewtopic')
 		}
 	}
 
-	if ($footer_style == 'viewforum' && $is_admmod)
-		echo "\t\t\t".'<p id="modcontrols"><a href="moderate.php?fid='.$forum_id.'&amp;p='.$p.'">'.$lang_common['Moderate forum'].'</a></p>'."\n";
-	else if ($footer_style == 'viewtopic' && $is_admmod)
+	if ($footer_style == 'viewforum')
 	{
-		echo "\t\t\t".'<dl id="modcontrols"><dt><strong>'.$lang_topic['Mod controls'].'</strong></dt><dd><a href="moderate.php?fid='.$forum_id.'&amp;tid='.$id.'&amp;p='.$p.'">'.$lang_common['Moderate topic'].'</a></dd>'."\n";
-		echo "\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;move_topics='.$id.'">'.$lang_common['Move topic'].'</a></dd>'."\n";
-
-		if ($cur_topic['closed'] == '1')
-			echo "\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;open='.$id.'">'.$lang_common['Open topic'].'</a></dd>'."\n";
-		else
-			echo "\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;close='.$id.'">'.$lang_common['Close topic'].'</a></dd>'."\n";
-
-		if ($cur_topic['sticky'] == '1')
-			echo "\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;unstick='.$id.'">'.$lang_common['Unstick topic'].'</a></dd></dl>'."\n";
-		else
-			echo "\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;stick='.$id.'">'.$lang_common['Stick topic'].'</a></dd></dl>'."\n";
+		if ($is_admmod)
+			echo "\t\t\t\t".'<p id="modcontrols"><a href="moderate.php?fid='.$forum_id.'&amp;p='.$p.'">'.$lang_common['Moderate forum'].'</a></p>'."\n";
+
+		if ($pun_config['o_feed_type'] == '1')
+			echo "\t\t\t\t".'<p id="feedlinks"><span class="rss"><a href="extern.php?action=feed&amp;fid='.$forum_id.'&amp;type=rss">'.$lang_common['RSS forum feed'].'</a></span></p>'."\n";
+		else if ($pun_config['o_feed_type'] == '2')
+			echo "\t\t\t\t".'<p id="feedlinks"><span class="atom"><a href="extern.php?action=feed&amp;fid='.$forum_id.'&amp;type=atom">'.$lang_common['Atom forum feed'].'</a></span></p>'."\n";
+	}
+	else if ($footer_style == 'viewtopic')
+	{
+		if ($is_admmod)
+		{
+			echo "\t\t\t\t".'<dl id="modcontrols">'."\n";
+			echo "\t\t\t\t\t".'<dt><strong>'.$lang_topic['Mod controls'].'</strong></dt>'."\n";
+
+			echo "\t\t\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;tid='.$id.'&amp;p='.$p.'">'.$lang_common['Moderate topic'].'</a></dd>'."\n";
+			echo "\t\t\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;move_topics='.$id.'">'.$lang_common['Move topic'].'</a></dd>'."\n";
+
+			if ($cur_topic['closed'] == '1')
+				echo "\t\t\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;open='.$id.'">'.$lang_common['Open topic'].'</a></dd>'."\n";
+			else
+				echo "\t\t\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;close='.$id.'">'.$lang_common['Close topic'].'</a></dd>'."\n";
+
+			if ($cur_topic['sticky'] == '1')
+				echo "\t\t\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;unstick='.$id.'">'.$lang_common['Unstick topic'].'</a></dd>'."\n";
+			else
+				echo "\t\t\t\t\t".'<dd><a href="moderate.php?fid='.$forum_id.'&amp;stick='.$id.'">'.$lang_common['Stick topic'].'</a></dd>'."\n";
+
+			echo "\t\t\t\t".'</dl>'."\n";
+		}
+
+		if ($pun_config['o_feed_type'] == '1')
+			echo "\t\t\t\t".'<p id="feedlinks"><span class="rss"><a href="extern.php?action=feed&amp;tid='.$id.'&amp;type=rss">'.$lang_common['RSS topic feed'].'</a></span></p>'."\n";
+		else if ($pun_config['o_feed_type'] == '2')
+			echo "\t\t\t\t".'<p id="feedlinks"><span class="atom"><a href="extern.php?action=feed&amp;tid='.$id.'&amp;type=atom">'.$lang_common['Atom topic feed'].'</a></span></p>'."\n";
 	}
 
 	echo "\t\t\t".'</div>'."\n";
 }
 
 ?>
-			<p class="conr">Powered by <a href="http://fluxbb.org/">FluxBB</a><?php if ($pun_config['o_show_version'] == '1') echo ' '.$pun_config['o_cur_version']; ?></p>
+			<p id="poweredby" class="conr"><?php printf($lang_common['Powered by'], '<a href="http://fluxbb.org/">FluxBB</a>'.(($pun_config['o_show_version'] == '1') ? ' '.$pun_config['o_cur_version'] : '')) ?></p>
+			<div class="clearer"></div>
+		</div>
+	</div>
+</div>
 <?php
 
 // Display debug info (if enabled/defined)
 if (defined('PUN_DEBUG'))
 {
 	// Calculate script generation time
-	list($usec, $sec) = explode(' ', microtime());
-	$time_diff = sprintf('%.3f', ((float)$usec + (float)$sec) - $pun_start);
-	echo "\t\t\t".'<p class="conr">[ Generated in '.$time_diff.' seconds, '.$db->get_num_queries().' queries executed ]</p>'."\n";
+	$time_diff = sprintf('%.3f', get_microtime() - $pun_start);
+	echo '<p id="debugtime">[ '.sprintf($lang_common['Querytime'], $time_diff, $db->get_num_queries()).' - Memory usage: '.
+		 file_size(memory_get_usage()).', Peak: '.file_size(memory_get_peak_usage()).' ]</p>'."\n";
 }
 
-?>
-			<div class="clearer"></div>
-		</div>
-	</div>
-</div>
-<?php
-
 
 // End the transaction
 $db->end_transaction();
diff --git a/upload/header.php b/upload/header.php
index fac37b5..258b588 100644
--- a/upload/header.php
+++ b/upload/header.php
@@ -1,63 +1,69 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure no one attempts to run this script "directly"
 if (!defined('PUN'))
 	exit;
 
 // Send no-cache headers
-header('Expires: Thu, 21 Jul 1977 07:30:00 GMT');	// When yours truly first set eyes on this world! :)
+header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
 header('Cache-Control: post-check=0, pre-check=0', false);
-header('Pragma: no-cache');		// For HTTP/1.0 compability
+header('Pragma: no-cache'); // For HTTP/1.0 compatibility
 
+// Send the Content-type header in case the web server is setup to send something else
+header('Content-type: text/html; charset=utf-8');
 
 // Load the template
 if (defined('PUN_ADMIN_CONSOLE'))
-	$tpl_main = file_get_contents(PUN_ROOT.'include/template/admin.tpl');
+	$tpl_file = 'admin.tpl';
 else if (defined('PUN_HELP'))
-	$tpl_main = file_get_contents(PUN_ROOT.'include/template/help.tpl');
+	$tpl_file = 'help.tpl';
 else
-	$tpl_main = file_get_contents(PUN_ROOT.'include/template/main.tpl');
+	$tpl_file = 'main.tpl';
 
+if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/'.$tpl_file))
+{
+	$tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/'.$tpl_file;
+	$tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/';
+}
+else
+{
+	$tpl_file = PUN_ROOT.'include/template/'.$tpl_file;
+	$tpl_inc_dir = PUN_ROOT.'include/user/';
+}
+
+$tpl_main = file_get_contents($tpl_file);
 
 // START SUBST - <pun_include "*">
-while (preg_match('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_main, $cur_include))
+preg_match_all('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_main, $pun_includes, PREG_SET_ORDER);
+
+foreach ($pun_includes as $cur_include)
 {
-	if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
-		error('Unable to process user include '.htmlspecialchars($cur_include[0]).' from template main.tpl. There is no such file in folder /include/user/');
+	if (!file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]))
+		error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file), $tpl_inc_dir));
 
 	ob_start();
-	include PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
+
+	require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2];
+
 	$tpl_temp = ob_get_contents();
 	$tpl_main = str_replace($cur_include[0], $tpl_temp, $tpl_main);
-    ob_end_clean();
+	ob_end_clean();
 }
 // END SUBST - <pun_include "*">
 
 
+// START SUBST - <pun_language>
+$tpl_main = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_main);
+// END SUBST - <pun_language>
+
+
 // START SUBST - <pun_content_direction>
 $tpl_main = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_main);
 // END SUBST - <pun_content_direction>
@@ -66,17 +72,25 @@ $tpl_main = str_replace('<pun_content_direction>', $lang_common['lang_direction'
 // START SUBST - <pun_head>
 ob_start();
 
+// Define $p if its not set to avoid a PHP notice
+$p = isset($p) ? $p : null;
+
 // Is this a page that we want search index spiders to index?
 if (!defined('PUN_ALLOW_INDEX'))
 	echo '<meta name="ROBOTS" content="NOINDEX, FOLLOW" />'."\n";
 
 ?>
-<title><?php echo $page_title ?></title>
+<title><?php echo generate_page_title($page_title, $p) ?></title>
 <link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
 <?php
 
 if (defined('PUN_ADMIN_CONSOLE'))
-	echo '<link rel="stylesheet" type="text/css" href="style/imports/base_admin.css" />'."\n";
+{
+	if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/base_admin.css'))
+		echo '<link rel="stylesheet" type="text/css" href="style/'.$pun_user['style'].'/base_admin.css" />'."\n";
+	else
+		echo '<link rel="stylesheet" type="text/css" href="style/imports/base_admin.css" />'."\n";
+}
 
 if (isset($required_fields))
 {
@@ -84,21 +98,21 @@ if (isset($required_fields))
 
 ?>
 <script type="text/javascript">
-<!--
+/* <![CDATA[ */
 function process_form(the_form)
 {
 	var element_names = new Object()
 <?php
 
 	// Output a JavaScript array with localised field names
-	while (list($elem_orig, $elem_trans) = @each($required_fields))
+	foreach ($required_fields as $elem_orig => $elem_trans)
 		echo "\t".'element_names["'.$elem_orig.'"] = "'.addslashes(str_replace('&nbsp;', ' ', $elem_trans)).'"'."\n";
 
 ?>
 
 	if (document.all || document.getElementById)
 	{
-		for (i = 0; i < the_form.length; ++i)
+		for (var i = 0; i < the_form.length; ++i)
 		{
 			var elem = the_form.elements[i]
 			if (elem.name && elem.name.substring(0, 4) == "req_")
@@ -115,15 +129,17 @@ function process_form(the_form)
 
 	return true
 }
-// -->
+/* ]]> */
 </script>
 <?php
 
 }
 
-$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : '';
-if (strpos($user_agent, 'msie') !== false && strpos($user_agent, 'windows') !== false && strpos($user_agent, 'opera') === false)
-	echo '<script type="text/javascript" src="style/imports/minmax.js"></script>';
+// JavaScript tricks for IE6 and older
+echo '<!--[if lte IE 6]><script type="text/javascript" src="style/imports/minmax.js"></script><![endif]-->'."\n";
+
+if (isset($page_head))
+	echo implode("\n", $page_head)."\n";
 
 $tpl_temp = trim(ob_get_contents());
 $tpl_main = str_replace('<pun_head>', $tpl_temp, $tpl_main);
@@ -151,7 +167,7 @@ $tpl_main = str_replace('<pun_title>', '<h1><span>'.pun_htmlspecialchars($pun_co
 
 
 // START SUBST - <pun_desc>
-$tpl_main = str_replace('<pun_desc>', '<p><span>'.$pun_config['o_board_desc'].'</span></p>', $tpl_main);
+$tpl_main = str_replace('<pun_desc>', '<div id="brddesc">'.$pun_config['o_board_desc'].'</div>', $tpl_main);
 // END SUBST - <pun_desc>
 
 
@@ -165,21 +181,26 @@ if ($pun_user['is_guest'])
 	$tpl_temp = '<div id="brdwelcome" class="inbox">'."\n\t\t\t".'<p>'.$lang_common['Not logged in'].'</p>'."\n\t\t".'</div>';
 else
 {
-	$tpl_temp = '<div id="brdwelcome" class="inbox">'."\n\t\t\t".'<ul class="conl">'."\n\t\t\t\t".'<li>'.$lang_common['Logged in as'].' <strong>'.pun_htmlspecialchars($pun_user['username']).'</strong></li>'."\n\t\t\t\t".'<li>'.$lang_common['Last visit'].': '.format_time($pun_user['last_visit']).'</li>';
+	$tpl_temp = '<div id="brdwelcome" class="inbox">'."\n\t\t\t".'<ul class="conl">'."\n\t\t\t\t".'<li>'.$lang_common['Logged in as'].' <strong>'.pun_htmlspecialchars($pun_user['username']).'</strong></li>'."\n\t\t\t\t".'<li>'.sprintf($lang_common['Last visit'], format_time($pun_user['last_visit'])).'</li>';
 
 	if ($pun_user['is_admmod'])
 	{
-		$result_header = $db->query('SELECT COUNT(id) FROM '.$db->prefix.'reports WHERE zapped IS NULL') or error('Unable to fetch reports info', __FILE__, __LINE__, $db->error());
+		if ($pun_config['o_report_method'] == '0' || $pun_config['o_report_method'] == '2')
+		{
+			$result_header = $db->query('SELECT 1 FROM '.$db->prefix.'reports WHERE zapped IS NULL') or error('Unable to fetch reports info', __FILE__, __LINE__, $db->error());
 
-		if ($db->result($result_header))
-			$tpl_temp .= "\n\t\t\t\t".'<li class="reportlink"><strong><a href="admin_reports.php">There are new reports</a></strong></li>';
+			if ($db->result($result_header))
+				$tpl_temp .= "\n\t\t\t\t".'<li class="reportlink"><strong><a href="admin_reports.php">'.$lang_common['New reports'].'</a></strong></li>';
+		}
 
 		if ($pun_config['o_maintenance'] == '1')
-			$tpl_temp .= "\n\t\t\t\t".'<li class="maintenancelink"><strong><a href="admin_options.php#maintenance">Maintenance mode is enabled!</a></strong></li>';
+			$tpl_temp .= "\n\t\t\t\t".'<li class="maintenancelink"><strong><a href="admin_options.php#maintenance">'.$lang_common['Maintenance mode enabled'].'</a></strong></li>';
 	}
 
 	if (in_array(basename($_SERVER['PHP_SELF']), array('index.php', 'search.php')))
-		$tpl_temp .= "\n\t\t\t".'</ul>'."\n\t\t\t".'<ul class="conr">'."\n\t\t\t\t".'<li><a href="search.php?action=show_new">'.$lang_common['Show new posts'].'</a></li>'."\n\t\t\t\t".'<li><a href="misc.php?action=markread">'.$lang_common['Mark all as read'].'</a></li>'."\n\t\t\t".'</ul>'."\n\t\t\t".'<div class="clearer"></div>'."\n\t\t".'</div>';
+		$tpl_temp .= "\n\t\t\t".'</ul>'."\n\t\t\t".'<ul class="conr">'.($pun_user['g_search'] == '1' ? "\n\t\t\t\t".'<li><a href="search.php?action=show_new">'.$lang_common['Show new posts'].'</a></li>' : '')."\n\t\t\t\t".'<li><a href="misc.php?action=markread">'.$lang_common['Mark all as read'].'</a></li>'."\n\t\t\t".'</ul>'."\n\t\t\t".'<div class="clearer"></div>'."\n\t\t".'</div>';
+	else if (basename($_SERVER['PHP_SELF']) == 'viewforum.php')
+		$tpl_temp .= "\n\t\t\t".'</ul>'."\n\t\t\t".'<ul class="conr">'."\n\t\t\t\t".'<li><a href="misc.php?action=markforumread&amp;fid='.$id.'">'.$lang_common['Mark forum read'].'</a></li>'."\n\t\t\t".'</ul>'."\n\t\t\t".'<div class="clearer"></div>'."\n\t\t".'</div>';
 	else
 		$tpl_temp .= "\n\t\t\t".'</ul>'."\n\t\t\t".'<div class="clearer"></div>'."\n\t\t".'</div>';
 }
@@ -195,10 +216,10 @@ if ($pun_config['o_announcement'] == '1')
 
 ?>
 <div id="announce" class="block">
-	<h2><span><?php echo $lang_common['Announcement'] ?></span></h2>
+	<div class="hd"><h2><span><?php echo $lang_common['Announcement'] ?></span></h2></div>
 	<div class="box">
-		<div class="inbox">
-			<div><?php echo $pun_config['o_announcement_message'] ?></div>
+		<div id="announce-block" class="inbox">
+			<div class="usercontent"><?php echo $pun_config['o_announcement_message'] ?></div>
 		</div>
 	</div>
 </div>
diff --git a/upload/help.php b/upload/help.php
index ba754d2..765e20f 100644
--- a/upload/help.php
+++ b/upload/help.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Tell header.php to use the help template
 define('PUN_HELP', 1);
@@ -38,118 +21,118 @@ if ($pun_user['g_read_board'] == '0')
 require PUN_ROOT.'lang/'.$pun_user['language'].'/help.php';
 
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_help['Help'];
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_help['Help']);
+define('PUN_ACTIVE_PAGE', 'help');
 require PUN_ROOT.'header.php';
 
 ?>
-<h2><?php echo $lang_common['BBCode'] ?></h2>
+<h2><span><?php echo $lang_help['BBCode'] ?></span></h2>
 <div class="box">
 	<div class="inbox">
-		<p><a name="bbcode"></a><?php echo $lang_help['BBCode info 1'] ?></p><br />
+		<p><a name="bbcode"></a><?php echo $lang_help['BBCode info 1'] ?></p>
 		<p><?php echo $lang_help['BBCode info 2'] ?></p>
 	</div>
 </div>
-<h2><?php echo $lang_help['Text style'] ?></h2>
+<h2><span><?php echo $lang_help['Text style'] ?></span></h2>
 <div class="box">
-	<p><?php echo $lang_help['Text style info'] ?></p><br />
-	<div style="padding-left: 4px">
-		[b]<?php echo $lang_help['Bold text'] ?>[/b] <?php echo $lang_help['produces'] ?> <b><?php echo $lang_help['Bold text'] ?></b><br />
-		[u]<?php echo $lang_help['Underlined text'] ?>[/u] <?php echo $lang_help['produces'] ?> <span class="bbu"><?php echo $lang_help['Underlined text'] ?></span><br />
-		[i]<?php echo $lang_help['Italic text'] ?>[/i] <?php echo $lang_help['produces'] ?> <i><?php echo $lang_help['Italic text'] ?></i><br />
-		[color=#FF0000]<?php echo $lang_help['Red text'] ?>[/color] <?php echo $lang_help['produces'] ?> <span style="color: #ff0000"><?php echo $lang_help['Red text'] ?></span><br />
-		[color=blue]<?php echo $lang_help['Blue text'] ?>[/color] <?php echo $lang_help['produces'] ?> <span style="color: blue"><?php echo $lang_help['Blue text'] ?></span>
+	<div class="inbox">
+		<p><?php echo $lang_help['Text style info'] ?></p>
+		<p><code>[b]<?php echo $lang_help['Bold text'] ?>[/b]</code> <?php echo $lang_help['produces'] ?> <strong><?php echo $lang_help['Bold text'] ?></strong></p>
+		<p><code>[u]<?php echo $lang_help['Underlined text'] ?>[/u]</code> <?php echo $lang_help['produces'] ?> <span class="bbu"><?php echo $lang_help['Underlined text'] ?></span></p>
+		<p><code>[i]<?php echo $lang_help['Italic text'] ?>[/i]</code> <?php echo $lang_help['produces'] ?> <i><?php echo $lang_help['Italic text'] ?></i></p>
+		<p><code>[color=#FF0000]<?php echo $lang_help['Red text'] ?>[/color]</code> <?php echo $lang_help['produces'] ?> <span style="color: #ff0000"><?php echo $lang_help['Red text'] ?></span></p>
+		<p><code>[color=blue]<?php echo $lang_help['Blue text'] ?>[/color]</code> <?php echo $lang_help['produces'] ?> <span style="color: blue"><?php echo $lang_help['Blue text'] ?></span></p>
+		<p><code>[h]<?php echo $lang_help['Heading text'] ?>[/h]</code> <?php echo $lang_help['produces'] ?></p><h5><?php echo $lang_help['Heading text'] ?></h5>
 	</div>
 </div>
-<h2><?php echo $lang_help['Links and images'] ?></h2>
+<h2><span><?php echo $lang_help['Links and images'] ?></span></h2>
 <div class="box">
-	<p><?php echo $lang_help['Links info'] ?></p><br />
-	<div style="padding-left: 4px">
-		[url=<?php echo $pun_config['o_base_url'].'/' ?>]<?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?>[/url] <?php echo $lang_help['produces'] ?> <a href="<?php echo $pun_config['o_base_url'].'/' ?>"><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?></a><br />
-		[url]<?php echo $pun_config['o_base_url'].'/' ?>[/url] <?php echo $lang_help['produces'] ?> <a href="<?php echo $pun_config['o_base_url'] ?>"><?php echo $pun_config['o_base_url'].'/' ?></a><br />
-		[email]myname@mydomain.com[/email] <?php echo $lang_help['produces'] ?> <a href="mailto:myname@mydomain.com">myname@mydomain.com</a><br />
-		[email=myname@mydomain.com]<?php echo $lang_help['My e-mail address'] ?>[/email] <?php echo $lang_help['produces'] ?> <a href="mailto:myname@mydomain.com"><?php echo $lang_help['My e-mail address'] ?></a><br /><br />
+	<div class="inbox">
+		<p><?php echo $lang_help['Links info'] ?></p>
+		<p><code>[url=<?php echo $pun_config['o_base_url'].'/' ?>]<?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?>[/url]</code> <?php echo $lang_help['produces'] ?> <a href="<?php echo $pun_config['o_base_url'].'/' ?>"><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?></a></p>
+		<p><code>[url]<?php echo $pun_config['o_base_url'].'/' ?>[/url]</code> <?php echo $lang_help['produces'] ?> <a href="<?php echo $pun_config['o_base_url'] ?>"><?php echo $pun_config['o_base_url'].'/' ?></a></p>
+		<p><code>[email]myname@mydomain.com[/email]</code> <?php echo $lang_help['produces'] ?> <a href="mailto:myname@mydomain.com">myname@mydomain.com</a></p>
+		<p><code>[email=myname@mydomain.com]<?php echo $lang_help['My email address'] ?>[/email]</code> <?php echo $lang_help['produces'] ?> <a href="mailto:myname@mydomain.com"><?php echo $lang_help['My email address'] ?></a></p>
+	</div>
+	<div class="inbox">
+		<p><a name="img"></a><?php echo $lang_help['Images info'] ?></p>
+		<p><code>[img=FluxBB bbcode test]<?php echo $pun_config['o_base_url'].'/' ?>img/test.png[/img]</code> <?php echo $lang_help['produces'] ?> <img src="<?php echo $pun_config['o_base_url'].'/' ?>img/test.png" alt="FluxBB bbcode test" /></p>
 	</div>
-	<p><a name="img"></a><?php echo $lang_help['Images info'] ?></p>
-	<div>[img]<?php echo $pun_config['o_base_url'].'/' ?>img/test.png[/img] <?php echo $lang_help['produces'] ?> <img src="<?php echo $pun_config['o_base_url'].'/' ?>img/test.png" /></div>
 </div>
-<h2><?php echo $lang_help['Quotes'] ?></h2>
+<h2><span><?php echo $lang_help['Quotes'] ?></span></h2>
 <div class="box">
-	<div style="padding-left: 4px">
-		<?php echo $lang_help['Quotes info'] ?><br /><br />
-		&nbsp;&nbsp;&nbsp;&nbsp;[quote=James]<?php echo $lang_help['Quote text'] ?>[/quote]<br /><br />
-		<?php echo $lang_help['produces quote box'] ?><br /><br />
+	<div class="inbox">
+		<p><?php echo $lang_help['Quotes info'] ?></p>
+		<p><code>[quote=James]<?php echo $lang_help['Quote text'] ?>[/quote]</code></p>
+		<p><?php echo $lang_help['produces quote box'] ?></p>
 		<div class="postmsg">
-			<blockquote><div class="incqbox"><h4>James <?php echo $lang_common['wrote'] ?>:</h4><p><?php echo $lang_help['Quote text'] ?></p></div></blockquote>
+			<div class="quotebox"><cite>James <?php echo $lang_common['wrote'] ?></cite><blockquote><div><p><?php echo $lang_help['Quote text'] ?></p></div></blockquote></div>
 		</div>
-		<br />
-		<?php echo $lang_help['Quotes info 2'] ?><br /><br />
-		&nbsp;&nbsp;&nbsp;&nbsp;[quote]<?php echo $lang_help['Quote text'] ?>[/quote]<br /><br />
-		<?php echo $lang_help['produces quote box'] ?><br /><br />
+		<p><?php echo $lang_help['Quotes info 2'] ?></p>
+		<p><code>[quote]<?php echo $lang_help['Quote text'] ?>[/quote]</code></p>
+		<p><?php echo $lang_help['produces quote box'] ?></p>
+		<div class="postmsg">
+			<div class="quotebox"><blockquote><div><p><?php echo $lang_help['Quote text'] ?></p></div></blockquote></div>
+		</div>
+		<p><?php echo $lang_help['quote note'] ?></p>
+	</div>
+</div>
+<h2><span><?php echo $lang_help['Code'] ?></span></h2>
+<div class="box">
+	<div class="inbox">
+		<p><?php echo $lang_help['Code info'] ?></p>
+		<p><code>[code]<?php echo $lang_help['Code text'] ?>[/code]</code></p>
+		<p><?php echo $lang_help['produces code box'] ?></p>
 		<div class="postmsg">
-			<blockquote><div class="incqbox"><p><?php echo $lang_help['Quote text'] ?></p></div></blockquote>
+			<div class="codebox"><pre><code><?php echo $lang_help['Code text'] ?></code></pre></div>
 		</div>
 	</div>
 </div>
-<h2><?php echo $lang_help['Code'] ?></h2>
+<h2><span><?php echo $lang_help['Lists'] ?></span></h2>
 <div class="box">
-	<div style="padding-left: 4px">
-		<?php echo $lang_help['Code info'] ?><br /><br />
-		&nbsp;&nbsp;&nbsp;&nbsp;[code]<?php echo $lang_help['Code text'] ?>[/code]<br /><br />
-		<?php echo $lang_help['produces code box'] ?><br /><br />
+	<div class="inbox">
+		<p><a name="lists"></a><?php echo $lang_help['List info'] ?></p>
+		<p><code>[list][*]<?php echo $lang_help['List text 1'] ?>[/*][*]<?php echo $lang_help['List text 2'] ?>[/*][*]<?php echo $lang_help['List text 3'] ?>[/*][/list]</code> <span><?php echo $lang_help['produces list'] ?></span></p>
+		<div class="postmsg">
+			<ul><li><?php echo $lang_help['List text 1'] ?></li><li><?php echo $lang_help['List text 2'] ?></li><li><?php echo $lang_help['List text 3'] ?></li></ul>
+		</div>
+		<p><code>[list=1][*]<?php echo $lang_help['List text 1'] ?>[/*][*]<?php echo $lang_help['List text 2'] ?>[/*][*]<?php echo $lang_help['List text 3'] ?>[/*][/list]</code> <span><?php echo $lang_help['produces decimal list'] ?></span></p>
+		<div class="postmsg">
+			<ol class="decimal"><li><?php echo $lang_help['List text 1'] ?></li><li><?php echo $lang_help['List text 2'] ?></li><li><?php echo $lang_help['List text 3'] ?></li></ol>
+		</div>
+		<p><code>[list=a][*]<?php echo $lang_help['List text 1'] ?>[/*][*]<?php echo $lang_help['List text 2'] ?>[/*][*]<?php echo $lang_help['List text 3'] ?>[/*][/list]</code> <span><?php echo $lang_help['produces alpha list'] ?></span></p>
 		<div class="postmsg">
-			<div class="codebox"><div class="incqbox"><h4><?php echo $lang_common['Code'] ?>:</h4><div class="scrollbox" style="height: 4.5em"><pre><?php echo $lang_help['Code text'] ?></pre></div></div></div>
+			<ol class="alpha"><li><?php echo $lang_help['List text 1'] ?></li><li><?php echo $lang_help['List text 2'] ?></li><li><?php echo $lang_help['List text 3'] ?></li></ol>
 		</div>
 	</div>
 </div>
-<h2><?php echo $lang_help['Nested tags'] ?></h2>
+<h2><span><?php echo $lang_help['Nested tags'] ?></span></h2>
 <div class="box">
-	<div style="padding-left: 4px">
-		<?php echo $lang_help['Nested tags info'] ?><br /><br />
-		&nbsp;&nbsp;&nbsp;&nbsp;[b][u]<?php echo $lang_help['Bold, underlined text'] ?>[/u][/b] <?php echo $lang_help['produces'] ?> <span class="bbu"><b><?php echo $lang_help['Bold, underlined text'] ?></b></span><br /><br />
+	<div class="inbox">
+		<p><?php echo $lang_help['Nested tags info'] ?></p>
+		<p><code>[b][u]<?php echo $lang_help['Bold, underlined text'] ?>[/u][/b]</code> <?php echo $lang_help['produces'] ?> <strong><span class="bbu"><?php echo $lang_help['Bold, underlined text'] ?></span></strong></p>
 	</div>
 </div>
-<h2><?php echo $lang_common['Smilies'] ?></h2>
+<h2><span><?php echo $lang_help['Smilies'] ?></span></h2>
 <div class="box">
-	<div style="padding-left: 4px">
-		<a name="smilies"></a><?php echo $lang_help['Smilies info'] ?><br /><br />
+	<div class="inbox">
+		<p><a name="smilies"></a><?php echo $lang_help['Smilies info'] ?></p>
+		<div class="postmsg">
 <?php
 
 // Display the smiley set
 require PUN_ROOT.'include/parser.php';
 
-$num_smilies = count($smiley_text);
-for ($i = 0; $i < $num_smilies; ++$i)
-{
-	// Is there a smiley at the current index?
-	if (!isset($smiley_text[$i]))
-		continue;
-
-	echo "\t\t".'&nbsp;&nbsp;&nbsp;&nbsp;'.$smiley_text[$i];
-
-	// Save the current text and image
-	$cur_img = $smiley_img[$i];
-	$cur_text = $smiley_text[$i];
-
-	// Loop through the rest of the array and see if there are any duplicate images
-	// (more than one text representation for one image)
-	for ($next = $i + 1; $next < $num_smilies; ++$next)
-	{
-		// Did we find a dupe?
-		if (isset($smiley_img[$next]) && $smiley_img[$i] == $smiley_img[$next])
-		{
-			echo ' '.$lang_common['and'].' '.$smiley_text[$next];
-
-			// Remove the dupe so we won't display it twice
-			unset($smiley_text[$next]);
-			unset($smiley_img[$next]);
-		}
-	}
-
-	echo ' '.$lang_help['produces'].' <img src="img/smilies/'.$cur_img.'" width="15" height="15" alt="'.$cur_text.'" /><br />'."\n";
-}
+$smiley_groups = array();
+
+foreach ($smilies as $smiley_text => $smiley_img)
+	$smiley_groups[$smiley_img][] = $smiley_text;
+
+foreach ($smiley_groups as $smiley_img => $smiley_texts)
+	echo "\t\t\t".'<p><code>'.implode('</code> '.$lang_common['and'].' <code>', $smiley_texts).'</code> <span>'.$lang_help['produces'].'</span> <img src="'.$pun_config['o_base_url'].'/img/smilies/'.$smiley_img.'" width="15" height="15" alt="'.$smiley_texts[0].'" /></p>'."\n";
 
 ?>
-		<br />
+		</div>
 	</div>
 </div>
 <?php
diff --git a/upload/img/avatars/index.html b/upload/img/avatars/index.html
index 2db9a3c..89337b2 100644
--- a/upload/img/avatars/index.html
+++ b/upload/img/avatars/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/img/index.html b/upload/img/index.html
index 2db9a3c..89337b2 100644
--- a/upload/img/index.html
+++ b/upload/img/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/img/smilies/index.html b/upload/img/smilies/index.html
index 2db9a3c..89337b2 100644
--- a/upload/img/smilies/index.html
+++ b/upload/img/smilies/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/include/cache.php b/upload/include/cache.php
index 9e22cd1..fba95e3 100644
--- a/upload/include/cache.php
+++ b/upload/include/cache.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure no one attempts to run this script "directly"
 if (!defined('PUN'))
@@ -29,51 +12,6 @@ if (!defined('PUN'))
 
 
 //
-// If we are running pre PHP 4.2.0, we add our own implementation of var_export
-//
-if (!function_exists('var_export'))
-{
-	function var_export()
-	{
-		$args = func_get_args();
-		$indent = (isset($args[2])) ? $args[2] : '';
-
-		if (is_array($args[0]))
-		{
-			$output = 'array ('."\n";
-
-			foreach ($args[0] as $k => $v)
-			{
-				if (is_numeric($k))
-					$output .= $indent.'  '.$k.' => ';
-				else
-					$output .= $indent.'  \''.str_replace('\'', '\\\'', str_replace('\\', '\\\\', $k)).'\' => ';
-
-				if (is_array($v))
-					$output .= var_export($v, true, $indent.'  ');
-				else
-				{
-					if (gettype($v) != 'string' && !empty($v))
-						$output .= $v.','."\n";
-					else
-						$output .= '\''.str_replace('\'', '\\\'', str_replace('\\', '\\\\', $v)).'\','."\n";
-				}
-			}
-
-			$output .= ($indent != '') ? $indent.'),'."\n" : ')';
-		}
-		else
-			$output = $args[0];
-
-		if ($args[1] == true)
-			return $output;
-		else
-			echo $output;
-	}
-}
-
-
-//
 // Generate the config cache PHP script
 //
 function generate_config_cache()
@@ -147,18 +85,18 @@ function generate_ranks_cache()
 
 
 //
-// Generate quickjump cache PHP scripts
+// Generate quick jump cache PHP scripts
 //
 function generate_quickjump_cache($group_id = false)
 {
 	global $db, $lang_common, $pun_user;
 
-	// If a group_id was supplied, we generate the quickjump cache for that group only
+	// If a group_id was supplied, we generate the quick jump cache for that group only
 	if ($group_id !== false)
 		$groups[0] = $group_id;
 	else
 	{
-		// A group_id was now supplied, so we generate the quickjump cache for all groups
+		// A group_id was now supplied, so we generate the quick jump cache for all groups
 		$result = $db->query('SELECT g_id FROM '.$db->prefix.'groups') or error('Unable to fetch user group list', __FILE__, __LINE__, $db->error());
 		$num_groups = $db->num_rows($result);
 
@@ -169,13 +107,13 @@ function generate_quickjump_cache($group_id = false)
 	// Loop through the groups in $groups and output the cache for each of them
 	while (list(, $group_id) = @each($groups))
 	{
-		// Output quickjump as PHP code
+		// Output quick jump as PHP code
 		$fh = @fopen(FORUM_CACHE_DIR.'cache_quickjump_'.$group_id.'.php', 'wb');
 		if (!$fh)
-			error('Unable to write quickjump cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'', __FILE__, __LINE__);
+			error('Unable to write quick jump cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'', __FILE__, __LINE__);
 
 		$output = '<?php'."\n\n".'if (!defined(\'PUN\')) exit;'."\n".'define(\'PUN_QJ_LOADED\', 1);'."\n\n".'?>';
-		$output .= "\t\t\t\t".'<form id="qjump" method="get" action="viewforum.php">'."\n\t\t\t\t\t".'<div><label><?php echo $lang_common[\'Jump to\'] ?>'."\n\n\t\t\t\t\t".'<br /><select name="id" onchange="window.location=(\'viewforum.php?id=\'+this.options[this.selectedIndex].value)">'."\n";
+		$output .= "\t\t\t\t".'<form id="qjump" method="get" action="viewforum.php">'."\n\t\t\t\t\t".'<div><label><span><?php echo $lang_common[\'Jump to\'] ?>'.'<br /></span>'."\n\t\t\t\t\t".'<select name="id" onchange="window.location=(\'viewforum.php?id=\'+this.options[this.selectedIndex].value)">'."\n";
 
 
 		$result = $db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url FROM '.$db->prefix.'categories AS c INNER JOIN '.$db->prefix.'forums AS f ON c.id=f.cat_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$group_id.') WHERE fp.read_forum IS NULL OR fp.read_forum=1 ORDER BY c.disp_position, c.id, f.disp_position', true) or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());
@@ -183,7 +121,7 @@ function generate_quickjump_cache($group_id = false)
 		$cur_category = 0;
 		while ($cur_forum = $db->fetch_assoc($result))
 		{
-			if ($cur_forum['cid'] != $cur_category)	// A new category since last iteration?
+			if ($cur_forum['cid'] != $cur_category) // A new category since last iteration?
 			{
 				if ($cur_category)
 					$output .= "\t\t\t\t\t\t".'</optgroup>'."\n";
@@ -196,7 +134,7 @@ function generate_quickjump_cache($group_id = false)
 			$output .= "\t\t\t\t\t\t\t".'<option value="'.$cur_forum['fid'].'"<?php echo ($forum_id == '.$cur_forum['fid'].') ? \' selected="selected"\' : \'\' ?>>'.pun_htmlspecialchars($cur_forum['forum_name']).$redirect_tag.'</option>'."\n";
 		}
 
-		$output .= "\t\t\t\t\t".'</optgroup>'."\n\t\t\t\t\t".'</select>'."\n\t\t\t\t\t".'<input type="submit" value="<?php echo $lang_common[\'Go\'] ?>" accesskey="g" />'."\n\t\t\t\t\t".'</label></div>'."\n\t\t\t\t".'</form>'."\n";
+		$output .= "\t\t\t\t\t\t".'</optgroup>'."\n\t\t\t\t\t".'</select>'."\n\t\t\t\t\t".'<input type="submit" value="<?php echo $lang_common[\'Go\'] ?>" accesskey="g" />'."\n\t\t\t\t\t".'</label></div>'."\n\t\t\t\t".'</form>'."\n";
 
 		fwrite($fh, $output);
 
diff --git a/upload/include/common.php b/upload/include/common.php
index a85d26e..46d990f 100644
--- a/upload/include/common.php
+++ b/upload/include/common.php
@@ -1,83 +1,69 @@
 <?php
-/***********************************************************************
 
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 if (!defined('PUN_ROOT'))
 	exit('The constant PUN_ROOT must be defined and point to a valid FluxBB installation root directory.');
 
-
 // Define the version and database revision that this code was written for
-define('FORUM_VERSION', '1.4');
-define('FORUM_DB_REVISION', 0);
+define('FORUM_VERSION', '1.4-rc3');
+define('FORUM_DB_REVISION', 5);
+
+// Block prefetch requests
+if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch')
+{
+	header('HTTP/1.1 403 Prefetching Forbidden');
+
+	// Send no-cache headers
+	header('Expires: Thu, 21 Jul 1977 07:30:00 GMT'); // When yours truly first set eyes on this world! :)
+	header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: post-check=0, pre-check=0', false);
+	header('Pragma: no-cache'); // For HTTP/1.0 compatibility
 
+	exit;
+}
 
 // Attempt to load the configuration file config.php
 if (file_exists(PUN_ROOT.'config.php'))
-	include PUN_ROOT.'config.php';
+	require PUN_ROOT.'config.php';
+
+// If we have the 1.3-legacy constant defined, define the proper 1.4 constant so we don't get an incorrect "need to install" message
+if (defined('FORUM'))
+	define('PUN', FORUM);
 
 // If PUN isn't defined, config.php is missing or corrupt
 if (!defined('PUN'))
 	exit('The file \'config.php\' doesn\'t exist or is corrupt. Please run <a href="install.php">install.php</a> to install FluxBB first.');
 
-
 // Load the functions script
 require PUN_ROOT.'include/functions.php';
 
 // Load UTF-8 functions
 require PUN_ROOT.'include/utf8/utf8.php';
 
-// Block prefetch requests
-if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch')
-{
-	header('HTTP/1.1 403 Prefetching Forbidden');
-
-	// Send no-cache headers
-	header('Expires: Thu, 21 Jul 1977 07:30:00 GMT');	// When yours truly first set eyes on this world! :)
-	header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
-	header('Cache-Control: post-check=0, pre-check=0', false);
-	header('Pragma: no-cache');		// For HTTP/1.0 compability
-
-	exit;
-}
+// Strip out "bad" UTF-8 characters
+forum_remove_bad_characters();
 
 // Reverse the effect of register_globals
 forum_unregister_globals();
 
-
 // Record the start time (will be used to calculate the generation time for the page)
-list($usec, $sec) = explode(' ', microtime());
-$pun_start = ((float)$usec + (float)$sec);
+$pun_start = get_microtime();
 
-// Make sure PHP reports all errors except E_NOTICE. FluxBB supports E_ALL, but a lot of scripts it may interact with, do not.
+// Make sure PHP reports all errors except E_NOTICE. FluxBB supports E_ALL, but a lot of scripts it may interact with, do not
 error_reporting(E_ALL ^ E_NOTICE);
 
+// Force POSIX locale (to prevent functions such as strtolower() from messing up UTF-8 strings)
+setlocale(LC_CTYPE, 'C');
+
 // Turn off magic_quotes_runtime
 if (get_magic_quotes_runtime())
 	set_magic_quotes_runtime(0);
 
-// Force POSIX locale (to prevent functions such as strtolower() from messing up UTF-8 strings)
-setlocale(LC_CTYPE, 'C');
-
 // Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled)
 if (get_magic_quotes_gpc())
 {
@@ -89,6 +75,7 @@ if (get_magic_quotes_gpc())
 	$_GET = stripslashes_array($_GET);
 	$_POST = stripslashes_array($_POST);
 	$_COOKIE = stripslashes_array($_COOKIE);
+	$_REQUEST = stripslashes_array($_REQUEST);
 }
 
 // If a cookie name is not specified in config.php, we use the default (pun_cookie)
@@ -106,7 +93,6 @@ define('PUN_MOD', 2);
 define('PUN_GUEST', 3);
 define('PUN_MEMBER', 4);
 
-
 // Load DB abstraction layer and connect
 require PUN_ROOT.'include/dblayer/common_db.php';
 
@@ -152,7 +138,7 @@ check_cookie($pun_user);
 if (file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/common.php'))
 	include PUN_ROOT.'lang/'.$pun_user['language'].'/common.php';
 else
-	error('There is no valid language pack \''.pun_htmlspecialchars($pun_user['language']).'\' installed. Please reinstall a language of that name.');
+	error('There is no valid language pack \''.pun_htmlspecialchars($pun_user['language']).'\' installed. Please reinstall a language of that name');
 
 // Check if we are to display a maintenance message
 if ($pun_config['o_maintenance'] && $pun_user['g_id'] > PUN_ADMIN && !defined('PUN_TURN_OFF_MAINT'))
@@ -180,3 +166,11 @@ update_users_online();
 // Check to see if we logged in without a cookie being set
 if ($pun_user['is_guest'] && isset($_GET['login']))
 	message($lang_common['No cookie']);
+
+if (!defined('PUN_MAX_POSTSIZE'))
+	define('PUN_MAX_POSTSIZE', 65535);
+
+if (!defined('PUN_SEARCH_MIN_WORD'))
+	define('PUN_SEARCH_MIN_WORD', 3);
+if (!defined('PUN_SEARCH_MAX_WORD'))
+	define('PUN_SEARCH_MAX_WORD', 20);
diff --git a/upload/include/common_admin.php b/upload/include/common_admin.php
index b1276d0..023b7f3 100644
--- a/upload/include/common_admin.php
+++ b/upload/include/common_admin.php
@@ -1,60 +1,55 @@
 <?php
-/***********************************************************************
 
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure no one attempts to run this script "directly"
 if (!defined('PUN'))
 	exit;
 
+// Make sure we have a usable language pack for admin.
+if (file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/admin_common.php'))
+	$admin_language = $pun_user['language'];
+else if (file_exists(PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/admin_common.php'))
+	$admin_language = $pun_config['language'];
+else
+	$admin_language = 'English';
+
+// Attempt to load the admin_common language file
+require PUN_ROOT.'lang/'.$admin_language.'/admin_common.php';
+
 //
 // Display the admin navigation menu
 //
 function generate_admin_menu($page = '')
 {
-	global $pun_config, $pun_user;
+	global $pun_config, $pun_user, $lang_admin_common;
 
 	$is_admin = $pun_user['g_id'] == PUN_ADMIN ? true : false;
 
 ?>
 <div id="adminconsole" class="block2col">
 	<div id="adminmenu" class="blockmenu">
-		<h2><span><?php echo ($is_admin) ? 'Admin' : 'Moderator' ?> menu</span></h2>
+		<h2><span><?php echo ($is_admin) ? $lang_admin_common['Admin menu'] : $lang_admin_common['Moderator menu'] ?></span></h2>
 		<div class="box">
 			<div class="inbox">
 				<ul>
-					<li<?php if ($page == 'index') echo ' class="isactive"'; ?>><a href="admin_index.php">Index</a></li>
-<?php if ($is_admin): ?>					<li<?php if ($page == 'categories') echo ' class="isactive"'; ?>><a href="admin_categories.php">Categories</a></li>
-<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'forums') echo ' class="isactive"'; ?>><a href="admin_forums.php">Forums</a></li>
-<?php endif; ?>					<li<?php if ($page == 'users') echo ' class="isactive"'; ?>><a href="admin_users.php">Users</a></li>
-<?php if ($is_admin): ?>					<li<?php if ($page == 'groups') echo ' class="isactive"'; ?>><a href="admin_groups.php">User groups</a></li>
-<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'options') echo ' class="isactive"'; ?>><a href="admin_options.php">Options</a></li>
-<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'permissions') echo ' class="isactive"'; ?>><a href="admin_permissions.php">Permissions</a></li>
-<?php endif; ?>					<li<?php if ($page == 'censoring') echo ' class="isactive"'; ?>><a href="admin_censoring.php">Censoring</a></li>
-<?php if ($is_admin): ?>					<li<?php if ($page == 'ranks') echo ' class="isactive"'; ?>><a href="admin_ranks.php">Ranks</a></li>
-<?php endif; ?><?php if ($is_admin || $pun_user['g_mod_ban_users'] == '1'): ?>					<li<?php if ($page == 'bans') echo ' class="isactive"'; ?>><a href="admin_bans.php">Bans</a></li>
-<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'prune') echo ' class="isactive"'; ?>><a href="admin_prune.php">Prune</a></li>
-<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'maintenance') echo ' class="isactive"'; ?>><a href="admin_maintenance.php">Maintenance</a></li>
-<?php endif; ?>					<li<?php if ($page == 'reports') echo ' class="isactive"'; ?>><a href="admin_reports.php">Reports</a></li>
+					<li<?php if ($page == 'index') echo ' class="isactive"'; ?>><a href="admin_index.php"><?php echo $lang_admin_common['Index'] ?></a></li>
+<?php if ($is_admin): ?>					<li<?php if ($page == 'categories') echo ' class="isactive"'; ?>><a href="admin_categories.php"><?php echo $lang_admin_common['Categories'] ?></a></li>
+<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'forums') echo ' class="isactive"'; ?>><a href="admin_forums.php"><?php echo $lang_admin_common['Forums'] ?></a></li>
+<?php endif; ?>					<li<?php if ($page == 'users') echo ' class="isactive"'; ?>><a href="admin_users.php"><?php echo $lang_admin_common['Users'] ?></a></li>
+<?php if ($is_admin): ?>					<li<?php if ($page == 'groups') echo ' class="isactive"'; ?>><a href="admin_groups.php"><?php echo $lang_admin_common['User groups'] ?></a></li>
+<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'options') echo ' class="isactive"'; ?>><a href="admin_options.php"><?php echo $lang_admin_common['Options'] ?></a></li>
+<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'permissions') echo ' class="isactive"'; ?>><a href="admin_permissions.php"><?php echo $lang_admin_common['Permissions'] ?></a></li>
+<?php endif; ?>					<li<?php if ($page == 'censoring') echo ' class="isactive"'; ?>><a href="admin_censoring.php"><?php echo $lang_admin_common['Censoring'] ?></a></li>
+<?php if ($is_admin): ?>					<li<?php if ($page == 'ranks') echo ' class="isactive"'; ?>><a href="admin_ranks.php"><?php echo $lang_admin_common['Ranks'] ?></a></li>
+<?php endif; ?><?php if ($is_admin || $pun_user['g_mod_ban_users'] == '1'): ?>					<li<?php if ($page == 'bans') echo ' class="isactive"'; ?>><a href="admin_bans.php"><?php echo $lang_admin_common['Bans'] ?></a></li>
+<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'prune') echo ' class="isactive"'; ?>><a href="admin_prune.php"><?php echo $lang_admin_common['Prune'] ?></a></li>
+<?php endif; ?><?php if ($is_admin): ?>					<li<?php if ($page == 'maintenance') echo ' class="isactive"'; ?>><a href="admin_maintenance.php"><?php echo $lang_admin_common['Maintenance'] ?></a></li>
+<?php endif; ?>					<li<?php if ($page == 'reports') echo ' class="isactive"'; ?>><a href="admin_reports.php"><?php echo $lang_admin_common['Reports'] ?></a></li>
 				</ul>
 			</div>
 		</div>
@@ -69,7 +64,7 @@ function generate_admin_menu($page = '')
 		$suffix = substr($entry, strlen($entry) - 4);
 
 		if ($suffix == '.php' && ((!$is_admin && $prefix == 'AMP') || ($is_admin && ($prefix == 'AP' || $prefix == 'AMP'))))
-			$plugins[] = array(substr(substr($entry, strpos($entry, '_') + 1), 0, -4), $entry);
+			$plugins[] = array(substr($entry, strpos($entry, '_') + 1, -4), $entry);
 	}
 	$d->close();
 
@@ -78,7 +73,7 @@ function generate_admin_menu($page = '')
 	{
 
 ?>
-		<h2 class="block2"><span>Plugins</span></h2>
+		<h2 class="block2"><span><?php echo $lang_admin_common['Plugins menu'] ?></span></h2>
 		<div class="box">
 			<div class="inbox">
 				<ul>
diff --git a/upload/include/dblayer/common_db.php b/upload/include/dblayer/common_db.php
index f47f06e..121d895 100644
--- a/upload/include/dblayer/common_db.php
+++ b/upload/include/dblayer/common_db.php
@@ -1,53 +1,23 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure no one attempts to run this script "directly"
 if (!defined('PUN'))
 	exit;
 
 
-//
-// Return current timestamp (with microseconds) as a float (used in dblayer)
-//
-if (defined('PUN_SHOW_QUERIES'))
-{
-	function get_microtime()
-	{
-		list($usec, $sec) = explode(' ', microtime());
-		return ((float)$usec + (float)$sec);
-	}
-}
-
-
 // Load the appropriate DB layer class
 switch ($db_type)
 {
 	case 'mysql':
 		require PUN_ROOT.'include/dblayer/mysql.php';
 		break;
-	
+
 	case 'mysql_innodb':
 		require PUN_ROOT.'include/dblayer/mysql_innodb.php';
 		break;
@@ -55,7 +25,7 @@ switch ($db_type)
 	case 'mysqli':
 		require PUN_ROOT.'include/dblayer/mysqli.php';
 		break;
-	
+
 	case 'mysqli_innodb':
 		require PUN_ROOT.'include/dblayer/mysqli_innodb.php';
 		break;
diff --git a/upload/include/dblayer/index.html b/upload/include/dblayer/index.html
index 2db9a3c..89337b2 100644
--- a/upload/include/dblayer/index.html
+++ b/upload/include/dblayer/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/include/dblayer/mysql.php b/upload/include/dblayer/mysql.php
index f3458c5..c595da4 100644
--- a/upload/include/dblayer/mysql.php
+++ b/upload/include/dblayer/mysql.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure we have built in support for MySQL
 if (!function_exists('mysql_connect'))
@@ -81,9 +64,6 @@ class DBLayer
 
 	function query($sql, $unbuffered = false)
 	{
-		if (strlen($sql) > 140000)
-			exit('Insane query. Aborting.');
-
 		if (defined('PUN_SHOW_QUERIES'))
 			$q_start = get_microtime();
 
@@ -249,7 +229,7 @@ class DBLayer
 	function create_table($table_name, $schema, $no_prefix = false)
 	{
 		if ($this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
 		$query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
 
@@ -293,70 +273,75 @@ class DBLayer
 		// We remove the last two characters (a newline and a comma) and add on the ending
 		$query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'MyISAM').' CHARACTER SET utf8';
 
-		$this->query($query) or error('Unable to create table '.($no_prefix ? '' : $this->prefix).$table_name, __FILE__, __LINE__, $this->error());
+		return $this->query($query) ? true : false;
 	}
 
 
 	function drop_table($table_name, $no_prefix = false)
 	{
 		if (!$this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) or $this->query($query) or error('Unable to drop table '.($no_prefix ? '' : $this->prefix).$table_name, __FILE__, __LINE__, $this->error());
+		return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 
 
 	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if ($this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
 		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
 			$default_value = '\''.$this->escape($default_value).'\'';
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error('Unable to add field', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) ? true : false;
 	}
 
 
 	function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
 		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
 			$default_value = '\''.$this->escape($default_value).'\'';
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error('Unable to alter field', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) ? true : false;
 	}
 
 
 	function drop_field($table_name, $field_name, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) or error('Unable to drop field', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
 	}
 
 
 	function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
 	{
 		if ($this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') or error('Unable to add index', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
 	}
 
 
 	function drop_index($table_name, $index_name, $no_prefix = false)
 	{
 		if (!$this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) or error('Unable to drop index', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+	}
+
+	function truncate_table($table_name, $no_prefix = false)
+	{
+		return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 }
diff --git a/upload/include/dblayer/mysql_innodb.php b/upload/include/dblayer/mysql_innodb.php
index fbee574..b78c63c 100644
--- a/upload/include/dblayer/mysql_innodb.php
+++ b/upload/include/dblayer/mysql_innodb.php
@@ -1,13 +1,11 @@
 <?php
+
 /**
- * A database layer class supporting transactions that relies on the MySQL PHP extension.
- *
- * @copyright Copyright (C) 2009 FluxBB.org, based on code copyright (C) 2002-2008 PunBB.org
- * @license http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
- * @package FluxBB
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
  */
 
-
 // Make sure we have built in support for MySQL
 if (!function_exists('mysql_connect'))
 	exit('This PHP environment doesn\'t have MySQL support built in. MySQL support is required if you want to use a MySQL database to run this forum. Consult the PHP documentation for further assistance.');
@@ -57,7 +55,7 @@ class DBLayer
 	{
 		++$this->in_transaction;
 
-		$this->query('START TRANSACTION');
+		mysql_query('START TRANSACTION', $this->link_id);
 		return;
 	}
 
@@ -66,16 +64,13 @@ class DBLayer
 	{
 		--$this->in_transaction;
 
-		$this->query('COMMIT');
+		mysql_query('COMMIT', $this->link_id);
 		return;
 	}
 
 
 	function query($sql, $unbuffered = false)
 	{
-		if (strlen($sql) > 140000)
-			exit('Insane query. Aborting.');
-
 		if (defined('PUN_SHOW_QUERIES'))
 			$q_start = get_microtime();
 
@@ -100,7 +95,7 @@ class DBLayer
 
 			// Rollback transaction
 			if ($this->in_transaction)
-				$this->query('ROLLBACK');
+				mysql_query('ROLLBACK', $this->link_id);
 
 			--$this->in_transaction;
 
@@ -250,7 +245,7 @@ class DBLayer
 	function create_table($table_name, $schema, $no_prefix = false)
 	{
 		if ($this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
 		$query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
 
@@ -294,70 +289,75 @@ class DBLayer
 		// We remove the last two characters (a newline and a comma) and add on the ending
 		$query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'InnoDB').' CHARACTER SET utf8';
 
-		$this->query($query) or error(__FILE__, __LINE__);
+		return $this->query($query) ? true : false;
 	}
 
 
 	function drop_table($table_name, $no_prefix = false)
 	{
 		if (!$this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) or error(__FILE__, __LINE__);
+		return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 
 
 	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if ($this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
 		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
 			$default_value = '\''.$this->escape($default_value).'\'';
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) ? true : false;
 	}
 
 
 	function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
 		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
 			$default_value = '\''.$this->escape($default_value).'\'';
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) ? true : false;
 	}
 
 
 	function drop_field($table_name, $field_name, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
 	}
 
 
 	function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
 	{
 		if ($this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
 	}
 
 
 	function drop_index($table_name, $index_name, $no_prefix = false)
 	{
 		if (!$this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+	}
+
+	function truncate_table($table_name, $no_prefix = false)
+	{
+		return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 }
diff --git a/upload/include/dblayer/mysqli.php b/upload/include/dblayer/mysqli.php
index ff18826..9b81bdd 100644
--- a/upload/include/dblayer/mysqli.php
+++ b/upload/include/dblayer/mysqli.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure we have built in support for MySQL
 if (!function_exists('mysqli_connect'))
@@ -42,7 +25,7 @@ class DBLayer
 	);
 
 
-	function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $foo)
+	function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
 	{
 		$this->prefix = $db_prefix;
 
@@ -50,10 +33,13 @@ class DBLayer
 		if (strpos($db_host, ':') !== false)
 			list($db_host, $db_port) = explode(':', $db_host);
 
+		// Persistent connection in MySQLi are only available in PHP 5.3 and later releases
+		$p_connect = $p_connect && version_compare(PHP_VERSION, '5.3.0', '>=') ? 'p:' : '';
+
 		if (isset($db_port))
-			$this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name, $db_port);
+			$this->link_id = @mysqli_connect($p_connect.$db_host, $db_username, $db_password, $db_name, $db_port);
 		else
-			$this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name);
+			$this->link_id = @mysqli_connect($p_connect.$db_host, $db_username, $db_password, $db_name);
 
 		if (!$this->link_id)
 			error('Unable to connect to MySQL and select database. MySQL reported: '.mysqli_connect_error(), __FILE__, __LINE__);
@@ -80,9 +66,6 @@ class DBLayer
 
 	function query($sql, $unbuffered = false)
 	{
-		if (strlen($sql) > 140000)
-			exit('Insane query. Aborting.');
-
 		if (defined('PUN_SHOW_QUERIES'))
 			$q_start = get_microtime();
 
@@ -251,7 +234,7 @@ class DBLayer
 	function create_table($table_name, $schema, $no_prefix = false)
 	{
 		if ($this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
 		$query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
 
@@ -295,70 +278,75 @@ class DBLayer
 		// We remove the last two characters (a newline and a comma) and add on the ending
 		$query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'MyISAM').' CHARACTER SET utf8';
 
-		$this->query($query) or error('Unable to create table '.($no_prefix ? '' : $this->prefix).$table_name, __FILE__, __LINE__, $this->error());
+		return $this->query($query) ? true : false;
 	}
 
 
 	function drop_table($table_name, $no_prefix = false)
 	{
 		if (!$this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) or error('Unable to drop table '.($no_prefix ? '' : $this->prefix).$table_name, __FILE__, __LINE__, $this->error());
+		return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 
 
 	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if ($this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
 		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
 			$default_value = '\''.$this->escape($default_value).'\'';
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error('Unable to add field', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) ? true : false;
 	}
 
 
 	function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
 		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
 			$default_value = '\''.$this->escape($default_value).'\'';
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error('Unable to alter field', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) ? true : false;
 	}
 
 
 	function drop_field($table_name, $field_name, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) or error('Unable to drop field', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
 	}
 
 
 	function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
 	{
 		if ($this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') or error('Unable to add index', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
 	}
 
 
 	function drop_index($table_name, $index_name, $no_prefix = false)
 	{
 		if (!$this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) or error('Unable to drop index', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+	}
+
+	function truncate_table($table_name, $no_prefix = false)
+	{
+		return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 }
diff --git a/upload/include/dblayer/mysqli_innodb.php b/upload/include/dblayer/mysqli_innodb.php
index a298191..2b591cd 100644
--- a/upload/include/dblayer/mysqli_innodb.php
+++ b/upload/include/dblayer/mysqli_innodb.php
@@ -1,13 +1,11 @@
 <?php
+
 /**
- * A database layer class supporting transactions that relies on the MySQLi PHP extension.
- *
- * @copyright Copyright (C) 2009 FluxBB.org, based on code copyright (C) 2002-2008 PunBB.org
- * @license http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
- * @package FluxBB
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
  */
 
-
 // Make sure we have built in support for MySQL
 if (!function_exists('mysqli_connect'))
 	exit('This PHP environment doesn\'t have Improved MySQL (mysqli) support built in. Improved MySQL support is required if you want to use a MySQL 4.1 (or later) database to run this forum. Consult the PHP documentation for further assistance.');
@@ -28,7 +26,7 @@ class DBLayer
 	);
 
 
-	function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $foo)
+	function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
 	{
 		$this->prefix = $db_prefix;
 
@@ -36,10 +34,13 @@ class DBLayer
 		if (strpos($db_host, ':') !== false)
 			list($db_host, $db_port) = explode(':', $db_host);
 
+		// Persistent connection in MySQLi are only available in PHP 5.3 and later releases
+		$p_connect = $p_connect && version_compare(PHP_VERSION, '5.3.0', '>=') ? 'p:' : '';
+
 		if (isset($db_port))
-			$this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name, $db_port);
+			$this->link_id = @mysqli_connect($p_connect.$db_host, $db_username, $db_password, $db_name, $db_port);
 		else
-			$this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name);
+			$this->link_id = @mysqli_connect($p_connect.$db_host, $db_username, $db_password, $db_name);
 
 		if (!$this->link_id)
 			error('Unable to connect to MySQL and select database. MySQL reported: '.mysqli_connect_error(), __FILE__, __LINE__);
@@ -56,7 +57,7 @@ class DBLayer
 	{
 		++$this->in_transaction;
 
-		$this->query('START TRANSACTION');
+		mysqli_query($this->link_id, 'START TRANSACTION');
 		return;
 	}
 
@@ -65,16 +66,13 @@ class DBLayer
 	{
 		--$this->in_transaction;
 
-		$this->query('COMMIT');
+		mysqli_query($this->link_id, 'COMMIT');
 		return;
 	}
 
 
 	function query($sql, $unbuffered = false)
 	{
-		if (strlen($sql) > 140000)
-			exit('Insane query. Aborting.');
-
 		if (defined('PUN_SHOW_QUERIES'))
 			$q_start = get_microtime();
 
@@ -96,7 +94,7 @@ class DBLayer
 
 			// Rollback transaction
 			if ($this->in_transaction)
-				$this->query('ROLLBACK');
+				mysqli_query($this->link_id, 'ROLLBACK');
 
 			--$this->in_transaction;
 
@@ -105,73 +103,6 @@ class DBLayer
 	}
 
 
-	function query_build($query, $return_query_string = false, $unbuffered = false)
-	{
-		$sql = '';
-
-		if (isset($query['SELECT']))
-		{
-			$sql = 'SELECT '.$query['SELECT'].' FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['FROM'];
-
-			if (isset($query['JOINS']))
-			{
-				foreach ($query['JOINS'] as $cur_join)
-					$sql .= ' '.key($cur_join).' '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).current($cur_join).' ON '.$cur_join['ON'];
-			}
-
-			if (!empty($query['WHERE']))
-				$sql .= ' WHERE '.$query['WHERE'];
-			if (!empty($query['GROUP BY']))
-				$sql .= ' GROUP BY '.$query['GROUP BY'];
-			if (!empty($query['HAVING']))
-				$sql .= ' HAVING '.$query['HAVING'];
-			if (!empty($query['ORDER BY']))
-				$sql .= ' ORDER BY '.$query['ORDER BY'];
-			if (!empty($query['LIMIT']))
-				$sql .= ' LIMIT '.$query['LIMIT'];
-		}
-		else if (isset($query['INSERT']))
-		{
-			$sql = 'INSERT INTO '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['INTO'];
-
-			if (!empty($query['INSERT']))
-				$sql .= ' ('.$query['INSERT'].')';
-
-			if (is_array($query['VALUES']))
-				$sql .= ' VALUES('.implode('),(', $query['VALUES']).')';
-			else
-				$sql .= ' VALUES('.$query['VALUES'].')';
-		}
-		else if (isset($query['UPDATE']))
-		{
-			$query['UPDATE'] = (isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['UPDATE'];
-
-			$sql = 'UPDATE '.$query['UPDATE'].' SET '.$query['SET'];
-
-			if (!empty($query['WHERE']))
-				$sql .= ' WHERE '.$query['WHERE'];
-		}
-		else if (isset($query['DELETE']))
-		{
-			$sql = 'DELETE FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['DELETE'];
-
-			if (!empty($query['WHERE']))
-				$sql .= ' WHERE '.$query['WHERE'];
-		}
-		else if (isset($query['REPLACE']))
-		{
-			$sql = 'REPLACE INTO '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['INTO'];
-
-			if (!empty($query['REPLACE']))
-				$sql .= ' ('.$query['REPLACE'].')';
-
-			$sql .= ' VALUES('.$query['VALUES'].')';
-		}
-
-		return ($return_query_string) ? $sql : $this->query($sql, $unbuffered);
-	}
-
-
 	function result($query_id = 0, $row = 0, $col = 0)
 	{
 		if ($query_id)
@@ -317,7 +248,7 @@ class DBLayer
 	function create_table($table_name, $schema, $no_prefix = false)
 	{
 		if ($this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
 		$query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
 
@@ -361,70 +292,75 @@ class DBLayer
 		// We remove the last two characters (a newline and a comma) and add on the ending
 		$query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'InnoDB').' CHARACTER SET utf8';
 
-		$this->query($query) or error(__FILE__, __LINE__);
+		return $this->query($query) ? true : false;
 	}
 
 
 	function drop_table($table_name, $no_prefix = false)
 	{
 		if (!$this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) or error(__FILE__, __LINE__);
+		return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 
 
 	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if ($this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
 		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
 			$default_value = '\''.$this->escape($default_value).'\'';
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) ? true : false;
 	}
 
 
 	function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
 		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
 			$default_value = '\''.$this->escape($default_value).'\'';
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) ? true : false;
 	}
 
 
 	function drop_field($table_name, $field_name, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
 	}
 
 
 	function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
 	{
 		if ($this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') or error(__FILE__, __LINE__);
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') ? true : false;
 	}
 
 
 	function drop_index($table_name, $index_name, $no_prefix = false)
 	{
 		if (!$this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
+
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+	}
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) or error(__FILE__, __LINE__);
+	function truncate_table($table_name, $no_prefix = false)
+	{
+		return $this->query('TRUNCATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 }
diff --git a/upload/include/dblayer/pgsql.php b/upload/include/dblayer/pgsql.php
index 271320a..05d8cf0 100644
--- a/upload/include/dblayer/pgsql.php
+++ b/upload/include/dblayer/pgsql.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure we have built in support for PostgreSQL
 if (!function_exists('pg_connect'))
@@ -114,11 +97,8 @@ class DBLayer
 	}
 
 
-	function query($sql, $unbuffered = false)	// $unbuffered is ignored since there is no pgsql_unbuffered_query()
+	function query($sql, $unbuffered = false) // $unbuffered is ignored since there is no pgsql_unbuffered_query()
 	{
-		if (strlen($sql) > 140000)
-			exit('Insane query. Aborting.');
-		
 		if (strrpos($sql, 'LIMIT') !== false)
 			$sql = preg_replace('#LIMIT ([0-9]+),([ 0-9]+)#', 'LIMIT \\2 OFFSET \\1', $sql);
 
@@ -316,7 +296,7 @@ class DBLayer
 	function create_table($table_name, $schema, $no_prefix = false)
 	{
 		if ($this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
 		$query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
 
@@ -351,86 +331,97 @@ class DBLayer
 		// We remove the last two characters (a newline and a comma) and add on the ending
 		$query = substr($query, 0, strlen($query) - 2)."\n".')';
 
-		$this->query($query) or error('Unable to create table '.($no_prefix ? '' : $this->prefix).$table_name, __FILE__, __LINE__, $this->error());
+		$result = $this->query($query) ? true : false;
 
 		// Add indexes
 		if (isset($schema['INDEXES']))
 		{
 			foreach ($schema['INDEXES'] as $index_name => $index_fields)
-				$this->add_index($table_name, $index_name, $index_fields, false, $no_prefix);
+				$result &= $this->add_index($table_name, $index_name, $index_fields, false, $no_prefix);
 		}
+
+		return $result;
 	}
 
 
 	function drop_table($table_name, $no_prefix = false)
 	{
 		if (!$this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) or error('Unable to drop table '.($no_prefix ? '' : $this->prefix).$table_name, __FILE__, __LINE__, $this->error());
+		return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 
 
 	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if ($this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type) or error('Unable to add field', __FILE__, __LINE__, $this->error());
+		$result = $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type) ? true : false;
 
 		if ($default_value !== null)
 		{
 			if (!is_int($default_value) && !is_float($default_value))
 				$default_value = '\''.$this->escape($default_value).'\'';
 
-			$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ALTER '.$field_name.' SET DEFAULT '.$default_value) or error('Unable to set field default value', __FILE__, __LINE__, $this->error());
-			$this->query('UPDATE '.($no_prefix ? '' : $this->prefix).$table_name.' SET '.$field_name.'='.$default_value) or error('Unable to update field to default value', __FILE__, __LINE__, $this->error());
+			$result &= $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ALTER '.$field_name.' SET DEFAULT '.$default_value) ? true : false;
+			$result &= $this->query('UPDATE '.($no_prefix ? '' : $this->prefix).$table_name.' SET '.$field_name.'='.$default_value) ? true : false;
 		}
 
 		if (!$allow_null)
-			$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ALTER '.$field_name.' SET NOT NULL') or error('Unable to set field not null', __FILE__, __LINE__, $this->error());
+			$result &= $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ALTER '.$field_name.' SET NOT NULL') ? true : false;
+
+		return $result;
 	}
 
 
 	function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
 
-		$this->add_field($table_name, 'tmp_'.$field_name, $field_type, $allow_null, $default_value, $after_field, $no_prefix);
-		$this->query('UPDATE '.($no_prefix ? '' : $this->prefix).$table_name.' SET tmp_'.$field_name.' = '.$field_name) or error('Unable to copy altered field data', __FILE__, __LINE__, $this->error());
-		$this->drop_field($table_name, $field_name, $no_prefix);
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' RENAME COLUMN tmp_'.$field_name.' TO '.$field_name) or error('Unable to rename altered field', __FILE__, __LINE__, $this->error());
+		$result = $this->add_field($table_name, 'tmp_'.$field_name, $field_type, $allow_null, $default_value, $after_field, $no_prefix);
+		$result &= $this->query('UPDATE '.($no_prefix ? '' : $this->prefix).$table_name.' SET tmp_'.$field_name.' = '.$field_name) ? true : false;
+		$result &= $this->drop_field($table_name, $field_name, $no_prefix);
+		$result &= $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' RENAME COLUMN tmp_'.$field_name.' TO '.$field_name) ? true : false;
+
+		return $result;
 	}
 
 
 	function drop_field($table_name, $field_name, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) or error('Unable to drop field', __FILE__, __LINE__, $this->error());
+		return $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) ? true : false;
 	}
 
 
 	function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
 	{
 		if ($this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('CREATE '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ON '.($no_prefix ? '' : $this->prefix).$table_name.'('.implode(',', $index_fields).')') or error('Unable to add index', __FILE__, __LINE__, $this->error());
+		return $this->query('CREATE '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ON '.($no_prefix ? '' : $this->prefix).$table_name.'('.implode(',', $index_fields).')') ? true : false;
 	}
 
 
 	function drop_index($table_name, $index_name, $no_prefix = false)
 	{
 		if (!$this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) or error('Unable to drop index', __FILE__, __LINE__, $this->error());
+		return $this->query('DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+	}
+
+	function truncate_table($table_name, $no_prefix = false)
+	{
+		return $this->query('DELETE FROM '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 }
diff --git a/upload/include/dblayer/sqlite.php b/upload/include/dblayer/sqlite.php
index 509ae1d..49ffeb8 100644
--- a/upload/include/dblayer/sqlite.php
+++ b/upload/include/dblayer/sqlite.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure we have built in support for SQLite
 if (!function_exists('sqlite_open'))
@@ -105,9 +88,6 @@ class DBLayer
 
 	function query($sql, $unbuffered = false)
 	{
-		if (strlen($sql) > 140000)
-			exit('Insane query. Aborting.');
-
 		if (defined('PUN_SHOW_QUERIES'))
 			$q_start = get_microtime();
 
@@ -166,15 +146,15 @@ class DBLayer
 			if ($cur_row)
 			{
 				// Horrible hack to get rid of table names and table aliases from the array keys
-				while (list($key, $value) = @each($cur_row))
+				foreach ($cur_row as $key => $value)
 				{
-				    $dot_spot = strpos($key, '.');
-				    if ($dot_spot !== false)
-				    {
-				        unset($cur_row[$key]);
-				        $key = substr($key, $dot_spot+1);
-				        $cur_row[$key] = $value;
-				    }
+					$dot_spot = strpos($key, '.');
+					if ($dot_spot !== false)
+					{
+						unset($cur_row[$key]);
+						$key = substr($key, $dot_spot+1);
+						$cur_row[$key] = $value;
+					}
 				}
 			}
 
@@ -303,7 +283,7 @@ class DBLayer
 	function create_table($table_name, $schema, $no_prefix = false)
 	{
 		if ($this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
 		$query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
 
@@ -337,23 +317,25 @@ class DBLayer
 		// We remove the last two characters (a newline and a comma) and add on the ending
 		$query = substr($query, 0, strlen($query) - 2)."\n".')';
 
-		$this->query($query) or error('Unable to create table '.($no_prefix ? '' : $this->prefix).$table_name, __FILE__, __LINE__, $this->error());
+		$result = $this->query($query) ? true : false;
 
 		// Add indexes
 		if (isset($schema['INDEXES']))
 		{
 			foreach ($schema['INDEXES'] as $index_name => $index_fields)
-				$this->add_index($table_name, $index_name, $index_fields, false, $no_prefix);
+				$result &= $this->add_index($table_name, $index_name, $index_fields, false, $no_prefix);
 		}
+
+		return $result;
 	}
 
 
 	function drop_table($table_name, $no_prefix = false)
 	{
 		if (!$this->table_exists($table_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) or error('Unable to drop table '.($no_prefix ? '' : $this->prefix).$table_name, __FILE__, __LINE__, $this->error());
+		return $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 
 
@@ -370,6 +352,9 @@ class DBLayer
 		$table['indices'] = array();
 		while ($cur_index = $this->fetch_assoc($result))
 		{
+			if (empty($cur_index['sql']))
+				continue;
+
 			if (!isset($table['sql']))
 				$table['sql'] = $cur_index['sql'];
 			else
@@ -382,7 +367,7 @@ class DBLayer
 		foreach ($table_lines as $table_line)
 		{
 			$table_line = pun_trim($table_line);
-			if (substr($table_line, 0, 12) == 'CREATE TABLE') 
+			if (substr($table_line, 0, 12) == 'CREATE TABLE')
 				continue;
 			else if (substr($table_line, 0, 11) == 'PRIMARY KEY')
 				$table['primary_key'] = $table_line;
@@ -399,15 +384,15 @@ class DBLayer
 	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = 0, $no_prefix = false)
 	{
 		if ($this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$table = $this->get_table_info($table_name, $no_prefix);
 
 		// Create temp table
 		$now = time();
 		$tmptable = str_replace('CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (', 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' (', $table['sql']);
-		$this->query($tmptable) or error('Unable to create temporary table', __FILE__, __LINE__, $this->error());
-		$this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) or error('Unable to insert data into temporary table', __FILE__, __LINE__, $this->error());
+		$result = $this->query($tmptable) ? true : false;
+		$result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) ? true : false;
 
 		// Create new table sql
 		$field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
@@ -426,54 +411,57 @@ class DBLayer
 
 		foreach ($table['columns'] as $cur_column => $column_details)
 			$new_table .= "\n".$cur_column.' '.$column_details;
-			
+
 		if (isset($table['unique']))
 			$new_table .= "\n".$table['unique'].',';
-			
+
 		if (isset($table['primary_key']))
 			$new_table .= "\n".$table['primary_key'];
-			
+
 		$new_table = trim($new_table, ',')."\n".');';
 
 		// Drop old table
-		$this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name));
+		$result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name));
 
 		// Create new table
-		$this->query($new_table) or error('Unable to recreate table', __FILE__, __LINE__, $this->error());
+		$result &= $this->query($new_table) ? true : false;
 
 		// Recreate indexes
 		if (!empty($table['indices']))
 		{
 			foreach ($table['indices'] as $cur_index)
-				$this->query($cur_index) or error('Unable to add index', __FILE__, __LINE__, $this->error());
+				$result &= $this->query($cur_index) ? true : false;
 		}
 
 		// Copy content back
-		$this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' ('.implode(', ', $old_columns).') SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now) or error('Unable to insert data into recreated table', __FILE__, __LINE__, $this->error());
+		$result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' ('.implode(', ', $old_columns).') SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now) ? true : false;
 
 		// Drop temp table
-		$this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now);
+		$result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now);
+
+		return $result;
 	}
 
 
 	function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = 0, $no_prefix = false)
 	{
-		return;
+		// Unneeded for SQLite
+		return true;
 	}
 
 
 	function drop_field($table_name, $field_name, $no_prefix = false)
 	{
 		if (!$this->field_exists($table_name, $field_name, $no_prefix))
-			return;
+			return true;
 
 		$table = $this->get_table_info($table_name, $no_prefix);
 
 		// Create temp table
 		$now = time();
 		$tmptable = str_replace('CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (', 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' (', $table['sql']);
-		$this->query($tmptable) or error('Unable to create temporary table', __FILE__, __LINE__, $this->error());
-		$this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) or error('Unable to insert data into temporary table', __FILE__, __LINE__, $this->error());
+		$result = $this->query($tmptable) ? true : false;
+		$result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now.' SELECT * FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name)) ? true : false;
 
 		// Work out the columns we need to keep and the sql for the new table
 		unset($table['columns'][$field_name]);
@@ -483,50 +471,58 @@ class DBLayer
 
 		foreach ($table['columns'] as $cur_column => $column_details)
 			$new_table .= "\n".$cur_column.' '.$column_details;
-			
+
 		if (isset($table['unique']))
 			$new_table .= "\n".$table['unique'].',';
-			
+
 		if (isset($table['primary_key']))
 			$new_table .= "\n".$table['primary_key'];
-			
+
 		$new_table = trim($new_table, ',')."\n".');';
 
 		// Drop old table
-		$this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name));
+		$result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name));
 
 		// Create new table
-		$this->query($new_table) or error('Unable to recreate table', __FILE__, __LINE__, $this->error());
+		$result &= $this->query($new_table) ? true : false;
 
 		// Recreate indexes
 		if (!empty($table['indices']))
 		{
 			foreach ($table['indices'] as $cur_index)
-				$this->query($cur_index) or error('Unable to add index', __FILE__, __LINE__, $this->error());
+				if (!preg_match('%\('.preg_quote($field_name, '%').'\)%', $cur_index))
+					$result &= $this->query($cur_index) ? true : false;
 		}
 
 		// Copy content back
-		$this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' SELECT '.implode(', ', $new_columns).' FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now) or error('Unable to reinsert data', __FILE__, __LINE__, $this->error());
+		$result &= $this->query('INSERT INTO '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' SELECT '.implode(', ', $new_columns).' FROM '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now) ? true : false;
 
 		// Drop temp table
-		$this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now);
+		$result &= $this->drop_table(($no_prefix ? '' : $this->prefix).$this->escape($table_name).'_t'.$now);
+
+		return $result;
 	}
 
 
 	function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
 	{
 		if ($this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
 
-		$this->query('CREATE '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ON '.($no_prefix ? '' : $this->prefix).$table_name.'('.implode(',', $index_fields).')') or error('Unable to add index', __FILE__, __LINE__, $this->error());
+		return $this->query('CREATE '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ON '.($no_prefix ? '' : $this->prefix).$table_name.'('.implode(',', $index_fields).')') ? true : false;
 	}
 
 
 	function drop_index($table_name, $index_name, $no_prefix = false)
 	{
 		if (!$this->index_exists($table_name, $index_name, $no_prefix))
-			return;
+			return true;
+
+		return $this->query('DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) ? true : false;
+	}
 
-		$this->query('DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) or error('Unable to drop index', __FILE__, __LINE__, $this->error());
+	function truncate_table($table_name, $no_prefix = false)
+	{
+		return $this->query('DELETE FROM '.($no_prefix ? '' : $this->prefix).$table_name) ? true : false;
 	}
 }
diff --git a/upload/include/email.php b/upload/include/email.php
index 565c7e8..5df0ef0 100644
--- a/upload/include/email.php
+++ b/upload/include/email.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure no one attempts to run this script "directly"
 if (!defined('PUN'))
@@ -29,14 +12,14 @@ if (!defined('PUN'))
 
 
 //
-// Validate an e-mail address
+// Validate an email address
 //
 function is_valid_email($email)
 {
 	if (strlen($email) > 80)
 		return false;
 
-	return preg_match('/^(([^<>()[\]\\.,;:\s@"\']+(\.[^<>()[\]\\.,;:\s@"\']+)*)|("[^"\']+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\d\-]+\.)+[a-zA-Z]{2,}))$/', $email);
+	return preg_match('/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|("[^"]+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\d\-]+\.)+[a-zA-Z]{2,}))$/', $email);
 }
 
 
@@ -111,8 +94,8 @@ function pun_mail($to, $subject, $message, $reply_to_email = '', $reply_to_name
 
 
 //
-// This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com).
-// They deserve all the credit for writing it. I made small modifications for it to suit PunBB and it's coding standards.
+// This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com)
+// They deserve all the credit for writing it. I made small modifications for it to suit PunBB and it's coding standards
 //
 function server_parse($socket, $expected_response)
 {
@@ -124,12 +107,12 @@ function server_parse($socket, $expected_response)
 	}
 
 	if (!(substr($server_response, 0, 3) == $expected_response))
-		error('Unable to send e-mail. Please contact the forum administrator with the following error message reported by the SMTP server: "'.$server_response.'"', __FILE__, __LINE__);
+		error('Unable to send email. Please contact the forum administrator with the following error message reported by the SMTP server: "'.$server_response.'"', __FILE__, __LINE__);
 }
 
 
 //
-// This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com).
+// This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com)
 // They deserve all the credit for writing it. I made small modifications for it to suit PunBB and it's coding standards.
 //
 function smtp_mail($to, $subject, $message, $headers = '')
@@ -182,7 +165,7 @@ function smtp_mail($to, $subject, $message, $headers = '')
 	fwrite($socket, 'MAIL FROM: <'.$pun_config['o_webmaster_email'].'>'."\r\n");
 	server_parse($socket, '250');
 
-	while (list(, $email) = @each($recipients))
+	foreach ($recipients as $email)
 	{
 		fwrite($socket, 'RCPT TO: <'.$email.'>'."\r\n");
 		server_parse($socket, '250');
diff --git a/upload/include/functions.php b/upload/include/functions.php
index ac100de..d66298e 100644
--- a/upload/include/functions.php
+++ b/upload/include/functions.php
@@ -1,26 +1,20 @@
 <?php
-/***********************************************************************
 
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
-  This file is part of PunBB.
 
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
+//
+// Return current timestamp (with microseconds) as a float
+//
+function get_microtime()
+{
+	list($usec, $sec) = explode(' ', microtime());
+	return ((float)$usec + (float)$sec);
+}
 
 //
 // Cookie stuff!
@@ -30,14 +24,13 @@ function check_cookie(&$pun_user)
 	global $db, $db_type, $pun_config, $cookie_name, $cookie_seed;
 
 	$now = time();
-	$expire = $now + 31536000;	// The cookie expires after a year
 
 	// We assume it's a guest
 	$cookie = array('user_id' => 1, 'password_hash' => 'Guest');
 
 	// If a cookie is set, we get the user_id and password hash from it
 	if (isset($_COOKIE[$cookie_name]))
-		list($cookie['user_id'], $cookie['password_hash']) = @unserialize($_COOKIE[$cookie_name]);
+		list($cookie['user_id'], $cookie['password_hash'], $cookie['expiration_time']) = @unserialize($_COOKIE[$cookie_name]);
 
 	if ($cookie['user_id'] > 1)
 	{
@@ -48,18 +41,23 @@ function check_cookie(&$pun_user)
 		// If user authorisation failed
 		if (!isset($pun_user['id']) || md5($cookie_seed.$pun_user['password']) !== $cookie['password_hash'])
 		{
+			$expire = $now + 31536000; // The cookie expires after a year
 			pun_setcookie(1, md5(uniqid(rand(), true)), $expire);
 			set_default_user();
 
 			return;
 		}
 
+		// Send a new, updated cookie with a new expiration timestamp
+		$expire = (intval($cookie['expiration_time']) > $now + $pun_config['o_timeout_visit']) ? $now + 1209600 : $now + $pun_config['o_timeout_visit'];
+		pun_setcookie($pun_user['id'], $pun_user['password'], $expire);
+
 		// Set a default language if the user selected language no longer exists
-		if (!@file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
+		if (!file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
 			$pun_user['language'] = $pun_config['o_default_lang'];
 
 		// Set a default style if the user selected style no longer exists
-		if (!@file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))
+		if (!file_exists(PUN_ROOT.'style/'.$pun_user['style'].'.css'))
 			$pun_user['style'] = $pun_config['o_default_style'];
 
 		if (!$pun_user['disp_topics'])
@@ -75,18 +73,19 @@ function check_cookie(&$pun_user)
 			{
 				$pun_user['logged'] = $now;
 
-				// With MySQL/MySQLi, REPLACE INTO avoids a user having two rows in the online table
+				// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
 				switch ($db_type)
 				{
 					case 'mysql':
 					case 'mysqli':
 					case 'mysql_innodb':
 					case 'mysqli_innodb':
+					case 'sqlite':
 						$db->query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
 						break;
 
 					default:
-						$db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
+						$db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) SELECT '.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$pun_user['logged'].' WHERE NOT EXISTS (SELECT 1 FROM '.$db->prefix.'online WHERE user_id='.$pun_user['id'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
 						break;
 				}
 
@@ -121,6 +120,55 @@ function check_cookie(&$pun_user)
 
 
 //
+// Converts the CDATA end sequence ]]> into ]]&gt;
+//
+function escape_cdata($str)
+{
+	return str_replace(']]>', ']]&gt;', $str);
+}
+
+
+//
+// Authenticates the provided username and password against the user database
+// $user can be either a user ID (integer) or a username (string)
+// $password can be either a plaintext password or a password hash including salt ($password_is_hash must be set accordingly)
+//
+function authenticate_user($user, $password, $password_is_hash = false)
+{
+	global $db, $pun_user;
+
+	// Check if there's a user matching $user and $password
+	$result = $db->query('SELECT u.*, g.*, o.logged, o.idle FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id LEFT JOIN '.$db->prefix.'online AS o ON o.user_id=u.id WHERE '.(is_int($user) ? 'u.id='.intval($user) : 'u.username=\''.$db->escape($user).'\'')) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+	$pun_user = $db->fetch_assoc($result);
+
+	if (!isset($pun_user['id']) ||
+		($password_is_hash && $password != $pun_user['password']) ||
+		(!$password_is_hash && pun_hash($password) != $pun_user['password']))
+		set_default_user();
+	else
+		$pun_user['is_guest'] = false;
+}
+
+
+//
+// Try to determine the current URL
+//
+function get_current_url($max_length = 0)
+{
+	$protocol = (!isset($_SERVER['HTTPS']) || strtolower($_SERVER['HTTPS']) == 'off') ? 'http://' : 'https://';
+	$port = (isset($_SERVER['SERVER_PORT']) && (($_SERVER['SERVER_PORT'] != '80' && $protocol == 'http://') || ($_SERVER['SERVER_PORT'] != '443' && $protocol == 'https://')) && strpos($_SERVER['HTTP_HOST'], ':') === false) ? ':'.$_SERVER['SERVER_PORT'] : '';
+
+	$url = urldecode($protocol.$_SERVER['HTTP_HOST'].$port.$_SERVER['REQUEST_URI']);
+
+	if (strlen($url) <= $max_length || $max_length == 0)
+		return $url;
+
+	// We can't find a short enough url
+	return null;
+}
+
+
+//
 // Fill $pun_user with default values (for guests)
 //
 function set_default_user()
@@ -141,18 +189,19 @@ function set_default_user()
 	{
 		$pun_user['logged'] = time();
 
-		// With MySQL/MySQLi, REPLACE INTO avoids a user having two rows in the online table
+		// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
 		switch ($db_type)
 		{
 			case 'mysql':
 			case 'mysqli':
 			case 'mysql_innodb':
 			case 'mysqli_innodb':
+			case 'sqlite':
 				$db->query('REPLACE INTO '.$db->prefix.'online (user_id, ident, logged) VALUES(1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
 				break;
 
 			default:
-				$db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) VALUES(1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
+				$db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) SELECT 1, \''.$db->escape($remote_addr).'\', '.$pun_user['logged'].' WHERE NOT EXISTS (SELECT 1 FROM '.$db->prefix.'online WHERE ident=\''.$db->escape($remote_addr).'\')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
 				break;
 		}
 	}
@@ -178,7 +227,7 @@ function pun_setcookie($user_id, $password_hash, $expire)
 {
 	global $cookie_name, $cookie_seed;
 
-	forum_setcookie($cookie_name, serialize(array($user_id, md5($cookie_seed.$password_hash))), $expire);
+	forum_setcookie($cookie_name, serialize(array($user_id, md5($cookie_seed.$password_hash), $expire)), $expire);
 }
 
 
@@ -190,7 +239,7 @@ function forum_setcookie($name, $value, $expire)
 	global $cookie_path, $cookie_domain, $cookie_secure;
 
 	// Enable sending of a P3P header
-	@header('P3P: CP="CUR ADM"');
+	header('P3P: CP="CUR ADM"');
 
 	if (version_compare(PHP_VERSION, '5.2.0', '>='))
 		setcookie($name, $value, $expire, $cookie_path, $cookie_domain, $cookie_secure, true);
@@ -271,16 +320,67 @@ function check_bans()
 
 
 //
+// Check username
+//
+function check_username($username, $exclude_id = null)
+{
+	global $db, $pun_config, $errors, $lang_prof_reg, $lang_register, $lang_common, $pun_bans;
+
+	// Convert multiple whitespace characters into one (to prevent people from registering with indistinguishable usernames)
+	$username = preg_replace('#\s+#s', ' ', $username);
+
+	// Validate username
+	if (pun_strlen($username) < 2)
+		$errors[] = $lang_prof_reg['Username too short'];
+	else if (pun_strlen($username) > 25) // This usually doesn't happen since the form element only accepts 25 characters
+		$errors[] = $lang_prof_reg['Username too long'];
+	else if (!strcasecmp($username, 'Guest') || !strcasecmp($username, $lang_common['Guest']))
+		$errors[] = $lang_prof_reg['Username guest'];
+	else if (preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $username) || preg_match('/((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))/', $username))
+		$errors[] = $lang_prof_reg['Username IP'];
+	else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false)
+		$errors[] = $lang_prof_reg['Username reserved chars'];
+	else if (preg_match('/(?:\[\/?(?:b|u|i|h|colou?r|quote|code|img|url|email|list|\*)\]|\[(?:img|url|quote|list)=)/i', $username))
+		$errors[] = $lang_prof_reg['Username BBCode'];
+
+	// Check username for any censored words
+	if ($pun_config['o_censoring'] == '1' && censor_words($username) != $username)
+		$errors[] = $lang_register['Username censor'];
+
+	// Check that the username (or a too similar username) is not already registered
+	$query = ($exclude_id) ? ' AND id!='.$exclude_id : '';
+
+	$result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$db->escape($username).'\') OR UPPER(username)=UPPER(\''.$db->escape(preg_replace('/[^\w]/', '', $username)).'\')) AND id>1'.$query) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+
+	if ($db->num_rows($result))
+	{
+		$busy = $db->result($result);
+		$errors[] = $lang_register['Username dupe 1'].' '.pun_htmlspecialchars($busy).'. '.$lang_register['Username dupe 2'];
+	}
+
+	// Check username for any banned usernames
+	foreach ($pun_bans as $cur_ban)
+	{
+		if ($cur_ban['username'] != '' && utf8_strtolower($username) == utf8_strtolower($cur_ban['username']))
+		{
+			$errors[] = $lang_prof_reg['Banned username'];
+			break;
+		}
+	}
+}
+
+
+//
 // Update "Users online"
 //
 function update_users_online()
 {
-	global $db, $pun_config, $pun_user;
+	global $db, $pun_config;
 
 	$now = time();
 
 	// Fetch all online list entries that are older than "o_timeout_online"
-	$result = $db->query('SELECT * FROM '.$db->prefix.'online WHERE logged<'.($now-$pun_config['o_timeout_online'])) or error('Unable to fetch old entries from online list', __FILE__, __LINE__, $db->error());
+	$result = $db->query('SELECT user_id, ident, logged, idle FROM '.$db->prefix.'online WHERE logged<'.($now-$pun_config['o_timeout_online'])) or error('Unable to fetch old entries from online list', __FILE__, __LINE__, $db->error());
 	while ($cur_user = $db->fetch_assoc($result))
 	{
 		// If the entry is a guest, delete it
@@ -309,21 +409,21 @@ function generate_navlinks()
 	global $pun_config, $lang_common, $pun_user;
 
 	// Index and Userlist should always be displayed
-	$links[] = '<li id="navindex"><a href="index.php">'.$lang_common['Index'].'</a>';
+	$links[] = '<li id="navindex"'.((PUN_ACTIVE_PAGE == 'index') ? ' class="isactive"' : '').'><a href="index.php">'.$lang_common['Index'].'</a></li>';
 
 	if ($pun_user['g_read_board'] == '1' && $pun_user['g_view_users'] == '1')
-		$links[] = '<li id="navuserlist"><a href="userlist.php">'.$lang_common['User list'].'</a>';
+		$links[] = '<li id="navuserlist"'.((PUN_ACTIVE_PAGE == 'userlist') ? ' class="isactive"' : '').'><a href="userlist.php">'.$lang_common['User list'].'</a></li>';
 
 	if ($pun_config['o_rules'] == '1' && (!$pun_user['is_guest'] || $pun_user['g_read_board'] == '1' || $pun_config['o_regs_allow'] == '1'))
-		$links[] = '<li id="navrules"><a href="misc.php?action=rules">'.$lang_common['Rules'].'</a>';
+		$links[] = '<li id="navrules"'.((PUN_ACTIVE_PAGE == 'rules') ? ' class="isactive"' : '').'><a href="misc.php?action=rules">'.$lang_common['Rules'].'</a></li>';
 
 	if ($pun_user['is_guest'])
 	{
 		if ($pun_user['g_read_board'] == '1' && $pun_user['g_search'] == '1')
-			$links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>';
+			$links[] = '<li id="navsearch"'.((PUN_ACTIVE_PAGE == 'search') ? ' class="isactive"' : '').'><a href="search.php">'.$lang_common['Search'].'</a></li>';
 
-		$links[] = '<li id="navregister"><a href="register.php">'.$lang_common['Register'].'</a>';
-		$links[] = '<li id="navlogin"><a href="login.php">'.$lang_common['Login'].'</a>';
+		$links[] = '<li id="navregister"'.((PUN_ACTIVE_PAGE == 'register') ? ' class="isactive"' : '').'><a href="register.php">'.$lang_common['Register'].'</a></li>';
+		$links[] = '<li id="navlogin"'.((PUN_ACTIVE_PAGE == 'login') ? ' class="isactive"' : '').'><a href="login.php">'.$lang_common['Login'].'</a></li>';
 
 		$info = $lang_common['Not logged in'];
 	}
@@ -332,17 +432,17 @@ function generate_navlinks()
 		if (!$pun_user['is_admmod'])
 		{
 			if ($pun_user['g_read_board'] == '1' && $pun_user['g_search'] == '1')
-				$links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>';
+				$links[] = '<li id="navsearch"'.((PUN_ACTIVE_PAGE == 'search') ? ' class="isactive"' : '').'><a href="search.php">'.$lang_common['Search'].'</a></li>';
 
-			$links[] = '<li id="navprofile"><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a>';
-			$links[] = '<li id="navlogout"><a href="login.php?action=out&amp;id='.$pun_user['id'].'&amp;csrf_token='.pun_hash($pun_user['id'].pun_hash(get_remote_address())).'">'.$lang_common['Logout'].'</a>';
+			$links[] = '<li id="navprofile"'.((PUN_ACTIVE_PAGE == 'profile') ? ' class="isactive"' : '').'><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a></li>';
+			$links[] = '<li id="navlogout"><a href="login.php?action=out&amp;id='.$pun_user['id'].'&amp;csrf_token='.pun_hash($pun_user['id'].pun_hash(get_remote_address())).'">'.$lang_common['Logout'].'</a></li>';
 		}
 		else
 		{
-			$links[] = '<li id="navsearch"><a href="search.php">'.$lang_common['Search'].'</a>';
-			$links[] = '<li id="navprofile"><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a>';
-			$links[] = '<li id="navadmin"><a href="admin_index.php">'.$lang_common['Admin'].'</a>';
-			$links[] = '<li id="navlogout"><a href="login.php?action=out&amp;id='.$pun_user['id'].'&amp;csrf_token='.pun_hash($pun_user['id'].pun_hash(get_remote_address())).'">'.$lang_common['Logout'].'</a>';
+			$links[] = '<li id="navsearch"'.((PUN_ACTIVE_PAGE == 'search') ? ' class="isactive"' : '').'><a href="search.php">'.$lang_common['Search'].'</a></li>';
+			$links[] = '<li id="navprofile"'.((PUN_ACTIVE_PAGE == 'profile') ? ' class="isactive"' : '').'><a href="profile.php?id='.$pun_user['id'].'">'.$lang_common['Profile'].'</a></li>';
+			$links[] = '<li id="navadmin"'.((PUN_ACTIVE_PAGE == 'admin') ? ' class="isactive"' : '').'><a href="admin_index.php">'.$lang_common['Admin'].'</a></li>';
+			$links[] = '<li id="navlogout"><a href="login.php?action=out&amp;id='.$pun_user['id'].'&amp;csrf_token='.pun_hash($pun_user['id'].pun_hash(get_remote_address())).'">'.$lang_common['Logout'].'</a></li>';
 		}
 	}
 
@@ -354,11 +454,11 @@ function generate_navlinks()
 			// Insert any additional links into the $links array (at the correct index)
 			$num_links = count($extra_links[1]);
 			for ($i = 0; $i < $num_links; ++$i)
-				array_splice($links, $extra_links[1][$i], 0, array('<li id="navextra'.($i + 1).'">'.$extra_links[2][$i]));
+				array_splice($links, $extra_links[1][$i], 0, array('<li id="navextra'.($i + 1).'">'.$extra_links[2][$i].'</li>'));
 		}
 	}
 
-	return '<ul>'."\n\t\t\t\t".implode($lang_common['Link separator'].'</li>'."\n\t\t\t\t", $links).'</li>'."\n\t\t\t".'</ul>';
+	return '<ul>'."\n\t\t\t\t".implode("\n\t\t\t\t", $links)."\n\t\t\t".'</ul>';
 }
 
 
@@ -406,7 +506,7 @@ function generate_avatar_markup($user_id)
 	{
 		$path = $pun_config['o_avatars_dir'].'/'.$user_id.'.'.$cur_type;
 
-		if (file_exists(PUN_ROOT.$path) && $img_size = @getimagesize(PUN_ROOT.$path))
+		if (file_exists(PUN_ROOT.$path) && $img_size = getimagesize(PUN_ROOT.$path))
 		{
 			$avatar_markup = '<img src="'.$pun_config['o_base_url'].'/'.$path.'?m='.filemtime(PUN_ROOT.$path).'" '.$img_size[3].' alt="" />';
 			break;
@@ -418,6 +518,24 @@ function generate_avatar_markup($user_id)
 
 
 //
+// Generate browser's title
+//
+function generate_page_title($page_title, $p = null)
+{
+	global $pun_config, $lang_common;
+
+	$page_title = array_reverse($page_title);
+
+	if ($p != null)
+		$page_title[0] .= ' ('.sprintf($lang_common['Page'], forum_number_format($p)).')';
+
+	$crumbs = implode($lang_common['Title separator'], $page_title);
+
+	return $crumbs;
+}
+
+
+//
 // Save array of tracked topics in cookie
 //
 function set_tracked_topics($tracked_topics)
@@ -446,7 +564,7 @@ function set_tracked_topics($tracked_topics)
 	}
 
 	forum_setcookie($cookie_name.'_track', $cookie_data, time() + $pun_config['o_timeout_visit']);
-	$_COOKIE[$cookie_name.'_track'] = $cookie_data;	// Set it directly in $_COOKIE as well
+	$_COOKIE[$cookie_name.'_track'] = $cookie_data; // Set it directly in $_COOKIE as well
 }
 
 
@@ -471,7 +589,7 @@ function get_tracked_topics()
 	{
 		$type = substr($t, 0, 1) == 'f' ? 'forums' : 'topics';
 		$id = intval(substr($t, 1));
-		$timestamp = intval(@substr($t, strpos($t, '=') + 1));
+		$timestamp = intval(substr($t, strpos($t, '=') + 1));
 		if ($id > 0 && $timestamp > 0)
 			$tracked_topics[$type][$id] = $timestamp;
 	}
@@ -490,16 +608,16 @@ function update_forum($forum_id)
 	$result = $db->query('SELECT COUNT(id), SUM(num_replies) FROM '.$db->prefix.'topics WHERE forum_id='.$forum_id) or error('Unable to fetch forum topic count', __FILE__, __LINE__, $db->error());
 	list($num_topics, $num_posts) = $db->fetch_row($result);
 
-	$num_posts = $num_posts + $num_topics;		// $num_posts is only the sum of all replies (we have to add the topic posts)
+	$num_posts = $num_posts + $num_topics; // $num_posts is only the sum of all replies (we have to add the topic posts)
 
 	$result = $db->query('SELECT last_post, last_post_id, last_poster FROM '.$db->prefix.'topics WHERE forum_id='.$forum_id.' AND moved_to IS NULL ORDER BY last_post DESC LIMIT 1') or error('Unable to fetch last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());
-	if ($db->num_rows($result))		// There are topics in the forum
+	if ($db->num_rows($result)) // There are topics in the forum
 	{
 		list($last_post, $last_post_id, $last_poster) = $db->fetch_row($result);
 
 		$db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$db->escape($last_poster).'\' WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());
 	}
-	else	// There are no topics
+	else // There are no topics
 		$db->query('UPDATE '.$db->prefix.'forums SET num_topics='.$num_topics.', num_posts='.$num_posts.', last_post=NULL, last_post_id=NULL, last_poster=NULL WHERE id='.$forum_id) or error('Unable to update last_post/last_post_id/last_poster', __FILE__, __LINE__, $db->error());
 }
 
@@ -532,13 +650,13 @@ function delete_topic($topic_id)
 	// Delete the topic and any redirect topics
 	$db->query('DELETE FROM '.$db->prefix.'topics WHERE id='.$topic_id.' OR moved_to='.$topic_id) or error('Unable to delete topic', __FILE__, __LINE__, $db->error());
 
-	// Create a list of the post ID's in this topic
+	// Create a list of the post IDs in this topic
 	$post_ids = '';
 	$result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id='.$topic_id) or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
 	while ($row = $db->fetch_row($result))
 		$post_ids .= ($post_ids != '') ? ','.$row[0] : $row[0];
 
-	// Make sure we have a list of post ID's
+	// Make sure we have a list of post IDs
 	if ($post_ids != '')
 	{
 		strip_search_index($post_ids);
@@ -683,8 +801,7 @@ function get_title($user)
 		// Are there any ranks?
 		if ($pun_config['o_ranks'] == '1' && !empty($pun_ranks))
 		{
-			@reset($pun_ranks);
-			while (list(, $cur_rank) = @each($pun_ranks))
+			foreach ($pun_ranks as $cur_rank)
 			{
 				if (intval($user['num_posts']) >= $cur_rank['min_posts'])
 					$user_title = pun_htmlspecialchars($cur_rank['rank']);
@@ -703,8 +820,10 @@ function get_title($user)
 //
 // Generate a string with numbered links (for multipage scripts)
 //
-function paginate($num_pages, $cur_page, $link_to)
+function paginate($num_pages, $cur_page, $link)
 {
+	global $lang_common;
+
 	$pages = array();
 	$link_to_all = false;
 
@@ -716,38 +835,46 @@ function paginate($num_pages, $cur_page, $link_to)
 	}
 
 	if ($num_pages <= 1)
-		$pages = array('<strong>1</strong>');
+		$pages = array('<strong class="item1">1</strong>');
 	else
 	{
+		// Add a previous page link
+		if ($num_pages > 1 && $cur_page > 1)
+			$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&amp;p='.($cur_page - 1).'">'.$lang_common['Previous'].'</a>';
+
 		if ($cur_page > 3)
 		{
-			$pages[] = '<a href="'.$link_to.'&amp;p=1">1</a>';
+			$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&amp;p=1">1</a>';
 
-			if ($cur_page != 4)
-				$pages[] = '&hellip;';
+			if ($cur_page > 5)
+				$pages[] = '<span>'.$lang_common['Spacer'].'</span>';
 		}
 
 		// Don't ask me how the following works. It just does, OK? :-)
-		for ($current = $cur_page - 2, $stop = $cur_page + 3; $current < $stop; ++$current)
+		for ($current = ($cur_page == 5) ? $cur_page - 3 : $cur_page - 2, $stop = ($cur_page + 4 == $num_pages) ? $cur_page + 4 : $cur_page + 3; $current < $stop; ++$current)
 		{
 			if ($current < 1 || $current > $num_pages)
 				continue;
 			else if ($current != $cur_page || $link_to_all)
-				$pages[] = '<a href="'.$link_to.'&amp;p='.$current.'">'.forum_number_format($current).'</a>';
+				$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&amp;p='.$current.'">'.forum_number_format($current).'</a>';
 			else
-				$pages[] = '<strong>'.forum_number_format($current).'</strong>';
+				$pages[] = '<strong'.(empty($pages) ? ' class="item1"' : '').'>'.forum_number_format($current).'</strong>';
 		}
 
 		if ($cur_page <= ($num_pages-3))
 		{
-			if ($cur_page != ($num_pages-3))
-				$pages[] = '&hellip;';
+			if ($cur_page != ($num_pages-3) && $cur_page != ($num_pages-4))
+				$pages[] = '<span>'.$lang_common['Spacer'].'</span>';
 
-			$pages[] = '<a href="'.$link_to.'&amp;p='.$num_pages.'">'.forum_number_format($num_pages).'</a>';
+			$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&amp;p='.$num_pages.'">'.forum_number_format($num_pages).'</a>';
 		}
+
+		// Add a next page link
+		if ($num_pages > 1 && !$link_to_all && $cur_page < $num_pages)
+			$pages[] = '<a'.(empty($pages) ? ' class="item1"' : '').' href="'.$link.'&amp;p='.($cur_page +1).'">'.$lang_common['Next'].'</a>';
 	}
 
-	return implode('&nbsp;', $pages);
+	return implode(' ', $pages);
 }
 
 
@@ -762,7 +889,8 @@ function message($message, $no_back_link = false)
 	{
 		global $pun_user;
 
-		$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Info'];
+		$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Info']);
+		define('PUN_ACTIVE_PAGE', 'index');
 		require PUN_ROOT.'header.php';
 	}
 
@@ -772,8 +900,8 @@ function message($message, $no_back_link = false)
 	<h2><span><?php echo $lang_common['Info'] ?></span></h2>
 	<div class="box">
 		<div class="inbox">
-		<p><?php echo $message ?></p>
-<?php if (!$no_back_link): ?>		<p><a href="javascript: history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p><?php echo $message ?></p>
+<?php if (!$no_back_link): ?>			<p><a href="javascript: history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 <?php endif; ?>		</div>
 	</div>
 </div>
@@ -784,7 +912,7 @@ function message($message, $no_back_link = false)
 
 
 //
-// Format a time string according to $time_format and timezones
+// Format a time string according to $time_format and time zones
 //
 function format_time($timestamp, $date_only = false, $date_format = null, $time_format = null, $time_only = false, $no_text = false)
 {
@@ -831,7 +959,7 @@ function forum_number_format($number, $decimals = 0)
 {
 	global $lang_common;
 
-	return number_format($number, $decimals, $lang_common['lang_decimal_point'], $lang_common['lang_thousands_sep']);
+	return is_numeric($number) ? number_format($number, $decimals, $lang_common['lang_decimal_point'], $lang_common['lang_thousands_sep']) : $number;
 }
 
 
@@ -905,16 +1033,10 @@ function random_pass($len)
 
 //
 // Compute a hash of $str
-// Uses sha1() if available. If not, SHA1 through mhash() if available. If not, fall back on md5().
 //
 function pun_hash($str)
 {
-	if (function_exists('sha1'))	// Only in PHP 4.3.0+
-		return sha1($str);
-	else if (function_exists('mhash'))	// Only if Mhash library is loaded
-		return bin2hex(mhash(MHASH_SHA1, $str));
-	else
-		return md5($str);
+	return sha1($str);
 }
 
 
@@ -962,6 +1084,39 @@ function pun_trim($str)
 	return utf8_trim($str);
 }
 
+//
+// Checks if a string is in all uppercase
+//
+function is_all_uppercase($string)
+{
+	return utf8_strtoupper($string) == $string && utf8_strtolower($string) != $string;
+}
+
+
+//
+// Inserts $element into $input at $offset
+// $offset can be either a numerical offset to insert at (eg: 0 inserts at the beginning of the array)
+// or a string, which is the key that the new element should be inserted before
+// $key is optional: it's used when inserting a new key/value pair into an associative array
+//
+function array_insert(&$input, $offset, $element, $key = null)
+{
+	if ($key == null)
+		$key = $offset;
+
+	// Determine the proper offset if we're using a string
+	if (!is_int($offset))
+		$offset = array_search($offset, array_keys($input), true);
+
+	// Out of bounds checks
+	if ($offset > count($input))
+		$offset = count($input);
+	else if ($offset < 0)
+		$offset = 0;
+
+	$input = array_merge(array_slice($input, 0, $offset), array($key => $element), array_slice($input, $offset));
+}
+
 
 //
 // Display a message when board is in maintenance mode
@@ -976,25 +1131,43 @@ function maintenance_message()
 	$message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']);
 
 
-	// Load the maintenance template
-	$tpl_maint = trim(file_get_contents(PUN_ROOT.'include/template/maintenance.tpl'));
+	if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/maintenance.tpl'))
+	{
+		$tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/maintenance.tpl';
+		$tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/';
+	}
+	else
+	{
+		$tpl_file = PUN_ROOT.'include/template/maintenance.tpl';
+		$tpl_inc_dir = PUN_ROOT.'include/user/';
+	}
 
+	$tpl_maint = file_get_contents($tpl_file);
 
 	// START SUBST - <pun_include "*">
-	while (preg_match('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_maint, $cur_include))
+	preg_match_all('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_maint, $pun_includes, PREG_SET_ORDER);
+
+	foreach ($pun_includes as $cur_include)
 	{
-		if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
-			error('Unable to process user include '.htmlspecialchars($cur_include[0]).' from template maintenance.tpl. There is no such file in folder /include/user/');
+		if (!file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]))
+			error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file), $tpl_inc_dir));
 
 		ob_start();
-		include PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
+
+		require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2];
+
 		$tpl_temp = ob_get_contents();
 		$tpl_maint = str_replace($cur_include[0], $tpl_temp, $tpl_maint);
-	    ob_end_clean();
+		ob_end_clean();
 	}
 	// END SUBST - <pun_include "*">
 
 
+	// START SUBST - <pun_language>
+	$tpl_maint = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_maint);
+	// END SUBST - <pun_language>
+
+
 	// START SUBST - <pun_content_direction>
 	$tpl_maint = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_maint);
 	// END SUBST - <pun_content_direction>
@@ -1003,8 +1176,10 @@ function maintenance_message()
 	// START SUBST - <pun_head>
 	ob_start();
 
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Maintenance']);
+
 ?>
-<title><?php echo pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Maintenance'] ?></title>
+<title><?php echo generate_page_title($page_title) ?></title>
 <link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
 <?php
 
@@ -1014,14 +1189,24 @@ function maintenance_message()
 	// END SUBST - <pun_head>
 
 
-	// START SUBST - <pun_maint_heading>
-	$tpl_maint = str_replace('<pun_maint_heading>', $lang_common['Maintenance'], $tpl_maint);
-	// END SUBST - <pun_maint_heading>
+	// START SUBST - <pun_maint_main>
+	ob_start();
 
+?>
+<div class="block">
+	<h2><?php echo $lang_common['Maintenance'] ?></h2>
+	<div class="box">
+		<div class="inbox">
+			<p><?php echo $message ?></p>
+		</div>
+	</div>
+</div>
+<?php
 
-	// START SUBST - <pun_maint_message>
-	$tpl_maint = str_replace('<pun_maint_message>', $message, $tpl_maint);
-	// END SUBST - <pun_maint_message>
+	$tpl_temp = trim(ob_get_contents());
+	$tpl_redir = str_replace('<pun_maint_main>', $tpl_temp, $tpl_main);
+	ob_end_clean();
+	// END SUBST - <pun_maint_main>
 
 
 	// End the transaction
@@ -1047,32 +1232,50 @@ function redirect($destination_url, $message)
 		$destination_url = $pun_config['o_base_url'].'/'.$destination_url;
 
 	// Do a little spring cleaning
-	$destination_url = preg_replace('/([\r\n])|(%0[ad])|(;[\s]*data[\s]*:)/i', '', $destination_url);
+	$destination_url = preg_replace('/([\r\n])|(%0[ad])|(;\s*data\s*:)/i', '', $destination_url);
 
 	// If the delay is 0 seconds, we might as well skip the redirect all together
 	if ($pun_config['o_redirect_delay'] == '0')
 		header('Location: '.str_replace('&amp;', '&', $destination_url));
 
 
-	// Load the redirect template
-	$tpl_redir = trim(file_get_contents(PUN_ROOT.'include/template/redirect.tpl'));
+	if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/redirect.tpl'))
+	{
+		$tpl_file = PUN_ROOT.'style/'.$pun_user['style'].'/redirect.tpl';
+		$tpl_inc_dir = PUN_ROOT.'style/'.$pun_user['style'].'/';
+	}
+	else
+	{
+		$tpl_file = PUN_ROOT.'include/template/redirect.tpl';
+		$tpl_inc_dir = PUN_ROOT.'include/user/';
+	}
 
+	$tpl_redir = file_get_contents($tpl_file);
 
 	// START SUBST - <pun_include "*">
-	while (preg_match('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_redir, $cur_include))
+	preg_match_all('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_redir, $pun_includes, PREG_SET_ORDER);
+
+	foreach ($pun_includes as $cur_include)
 	{
-		if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2]))
-			error('Unable to process user include '.htmlspecialchars($cur_include[0]).' from template redirect.tpl. There is no such file in folder /include/user/');
+		if (!file_exists($tpl_inc_dir.$cur_include[1].'.'.$cur_include[2]))
+			error(sprintf($lang_common['Pun include error'], htmlspecialchars($cur_include[0]), basename($tpl_file), $tpl_inc_dir));
 
 		ob_start();
-		include PUN_ROOT.'include/user/'.$cur_include[1].'.'.$cur_include[2];
+
+		require $tpl_inc_dir.$cur_include[1].'.'.$cur_include[2];
+
 		$tpl_temp = ob_get_contents();
 		$tpl_redir = str_replace($cur_include[0], $tpl_temp, $tpl_redir);
-	    ob_end_clean();
+		ob_end_clean();
 	}
 	// END SUBST - <pun_include "*">
 
 
+	// START SUBST - <pun_language>
+	$tpl_redir = str_replace('<pun_language>', $lang_common['lang_identifier'], $tpl_redir);
+	// END SUBST - <pun_language>
+
+
 	// START SUBST - <pun_content_direction>
 	$tpl_redir = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_redir);
 	// END SUBST - <pun_content_direction>
@@ -1081,9 +1284,11 @@ function redirect($destination_url, $message)
 	// START SUBST - <pun_head>
 	ob_start();
 
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Redirecting']);
+
 ?>
 <meta http-equiv="refresh" content="<?php echo $pun_config['o_redirect_delay'] ?>;URL=<?php echo str_replace(array('<', '>', '"'), array('&lt;', '&gt;', '&quot;'), $destination_url) ?>" />
-<title><?php echo pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Redirecting'] ?></title>
+<title><?php echo generate_page_title($page_title) ?></title>
 <link rel="stylesheet" type="text/css" href="style/<?php echo $pun_user['style'].'.css' ?>" />
 <?php
 
@@ -1093,15 +1298,24 @@ function redirect($destination_url, $message)
 	// END SUBST - <pun_head>
 
 
-	// START SUBST - <pun_redir_heading>
-	$tpl_redir = str_replace('<pun_redir_heading>', $lang_common['Redirecting'], $tpl_redir);
-	// END SUBST - <pun_redir_heading>
+	// START SUBST - <pun_redir_main>
+	ob_start();
 
+?>
+<div class="block">
+	<h2><?php echo $lang_common['Redirecting'] ?></h2>
+	<div class="box">
+		<div class="inbox">
+			<p><?php echo $message.'<br /><br /><a href="'.$destination_url.'">'.$lang_common['Click redirect'].'</a>' ?></p>
+		</div>
+	</div>
+</div>
+<?php
 
-	// START SUBST - <pun_redir_text>
-	$tpl_temp = $message.'<br /><br />'.'<a href="'.$destination_url.'">'.$lang_common['Click redirect'].'</a>';
-	$tpl_redir = str_replace('<pun_redir_text>', $tpl_temp, $tpl_redir);
-	// END SUBST - <pun_redir_text>
+	$tpl_temp = trim(ob_get_contents());
+	$tpl_redir = str_replace('<pun_redir_main>', $tpl_temp, $tpl_redir);
+	ob_end_clean();
+	// END SUBST - <pun_redir_main>
 
 
 	// START SUBST - <pun_footer>
@@ -1130,13 +1344,27 @@ function redirect($destination_url, $message)
 //
 // Display a simple error message
 //
-function error($message, $file, $line, $db_error = false)
+function error($message, $file = null, $line = null, $db_error = false)
 {
-	global $pun_config;
+	global $pun_config, $lang_common;
 
-	// Set a default title if the script failed before $pun_config could be populated
+	// Set some default settings if the script failed before $pun_config could be populated
 	if (empty($pun_config))
-		$pun_config['o_board_title'] = 'FluxBB';
+	{
+		$pun_config = array(
+			'o_board_title'	=> 'FluxBB',
+			'o_gzip'		=> '0'
+		);
+	}
+
+	// Set some default translations if the script failed before $lang_common could be populated
+	if (empty($lang_common))
+	{
+		$lang_common = array(
+			'Title separator'	=> ' / ',
+			'Page'				=> 'Page %s'
+		);
+	}
 
 	// Empty all output buffers and stop buffering
 	while (@ob_end_clean());
@@ -1150,7 +1378,8 @@ function error($message, $file, $line, $db_error = false)
 <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<title><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?> / Error</title>
+<?php $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), 'Error') ?>
+<title><?php echo generate_page_title($page_title) ?></title>
 <style type="text/css">
 <!--
 BODY {MARGIN: 10% 20% auto 20%; font: 10px Verdana, Arial, Helvetica, sans-serif}
@@ -1167,7 +1396,7 @@ H2 {MARGIN: 0; COLOR: #FFFFFF; BACKGROUND-COLOR: #B84623; FONT-SIZE: 1.1em; PADD
 	<div>
 <?php
 
-	if (defined('PUN_DEBUG'))
+	if (defined('PUN_DEBUG') && $file !== null && $line !== null)
 	{
 		echo "\t\t".'<strong>File:</strong> '.$file.'<br />'."\n\t\t".'<strong>Line:</strong> '.$line.'<br /><br />'."\n\t\t".'<strong>FluxBB reported</strong>: '.$message."\n";
 
@@ -1203,14 +1432,14 @@ H2 {MARGIN: 0; COLOR: #FFFFFF; BACKGROUND-COLOR: #B84623; FONT-SIZE: 1.1em; PADD
 //
 function forum_unregister_globals()
 {
-	$register_globals = @ini_get('register_globals');
+	$register_globals = ini_get('register_globals');
 	if ($register_globals === "" || $register_globals === "0" || strtolower($register_globals) === "off")
 		return;
 
 	// Prevent script.php?GLOBALS[foo]=bar
 	if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS']))
 		exit('I\'ll have a steak sandwich and... a steak sandwich.');
-	
+
 	// Variables that shouldn't be unset
 	$no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');
 
@@ -1221,7 +1450,7 @@ function forum_unregister_globals()
 		if (!in_array($k, $no_unset) && isset($GLOBALS[$k]))
 		{
 			unset($GLOBALS[$k]);
-			unset($GLOBALS[$k]);	// Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4
+			unset($GLOBALS[$k]); // Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4
 		}
 	}
 }
@@ -1232,20 +1461,93 @@ function forum_unregister_globals()
 //
 function forum_remove_bad_characters()
 {
-	global $bad_utf8_chars;
+	$_GET = remove_bad_characters($_GET);
+	$_POST = remove_bad_characters($_POST);
+	$_COOKIE = remove_bad_characters($_COOKIE);
+	$_REQUEST = remove_bad_characters($_REQUEST);
+}
 
-	$bad_utf8_chars = array("\0", "\xc2\xad", "\xcc\xb7", "\xcc\xb8", "\xe1\x85\x9F", "\xe1\x85\xA0", "\xe2\x80\x80", "\xe2\x80\x81", "\xe2\x80\x82", "\xe2\x80\x83", "\xe2\x80\x84", "\xe2\x80\x85", "\xe2\x80\x86", "\xe2\x80\x87", "\xe2\x80\x88", "\xe2\x80\x89", "\xe2\x80\x8a", "\xe2\x80\x8b", "\xe2\x80\x8e", "\xe2\x80\x8f", "\xe2\x80\xaa", "\xe2\x80\xab", "\xe2\x80\xac", "\xe2\x80\xad", "\xe2\x80\xae", "\xe2\x80\xaf", "\xe2\x81\x9f", "\xe3\x80\x80", "\xe3\x85\xa4", "\xef\xbb\xbf", "\xef\xbe\xa0", "\xef\xbf\xb9", "\xef\xbf\xba", "\xef\xbf\xbb", "\xE2\x80\x8D");
+//
+// Removes any "bad" characters (characters which mess with the display of a page, are invisible, etc) from the given string
+// See: http://kb.mozillazine.org/Network.IDN.blacklist_chars
+//
+function remove_bad_characters($array)
+{
+	static $bad_utf8_chars;
 
-	function _forum_remove_bad_characters($array)
+	if (!isset($bad_utf8_chars))
 	{
-		global $bad_utf8_chars;
-		return is_array($array) ? array_map('_forum_remove_bad_characters', $array) : str_replace($bad_utf8_chars, '', $array);
+		$bad_utf8_chars = array(
+			"\0"			=> '',		// NULL									0000	*
+			"\xcc\xb7"		=> '',		// COMBINING SHORT SOLIDUS OVERLAY		0337	*
+			"\xcc\xb8"		=> '',		// COMBINING LONG SOLIDUS OVERLAY		0338	*
+			"\xe1\x85\x9F"	=> '',		// HANGUL CHOSEONG FILLER				115F	*
+			"\xe1\x85\xA0"	=> '',		// HANGUL JUNGSEONG FILLER				1160	*
+			"\xe2\x80\x8b"	=> '',		// ZERO WIDTH SPACE						200B	*
+			"\xe2\x80\x8c"	=> '',		// ZERO WIDTH NON-JOINER				200C
+			"\xe2\x80\x8d"	=> '',		// ZERO WIDTH JOINER					200D
+			"\xe2\x80\x8e"	=> '',		// LEFT-TO-RIGHT MARK					200E
+			"\xe2\x80\x8f"	=> '',		// RIGHT-TO-LEFT MARK					200F
+			"\xe2\x80\xaa"	=> '',		// LEFT-TO-RIGHT EMBEDDING				202A
+			"\xe2\x80\xab"	=> '',		// RIGHT-TO-LEFT EMBEDDING				202B
+			"\xe2\x80\xac"	=> '', 		// POP DIRECTIONAL FORMATTING			202C
+			"\xe2\x80\xad"	=> '',		// LEFT-TO-RIGHT OVERRIDE				202D
+			"\xe2\x80\xae"	=> '',		// RIGHT-TO-LEFT OVERRIDE				202E
+			"\xe2\x80\xaf"	=> '',		// NARROW NO-BREAK SPACE				202F	*
+			"\xe2\x81\x9f"	=> '',		// MEDIUM MATHEMATICAL SPACE			205F	*
+			"\xe2\x81\xa0"	=> '',		// WORD JOINER							2060
+			"\xe3\x85\xa4"	=> '',		// HANGUL FILLER						3164	*
+			"\xef\xbb\xbf"	=> '',		// ZERO WIDTH NO-BREAK SPACE			FEFF
+			"\xef\xbe\xa0"	=> '',		// HALFWIDTH HANGUL FILLER				FFA0	*
+			"\xef\xbf\xb9"	=> '',		// INTERLINEAR ANNOTATION ANCHOR		FFF9	*
+			"\xef\xbf\xba"	=> '',		// INTERLINEAR ANNOTATION SEPARATOR		FFFA	*
+			"\xef\xbf\xbb"	=> '',		// INTERLINEAR ANNOTATION TERMINATOR	FFFB	*
+			"\xef\xbf\xbc"	=> '',		// OBJECT REPLACEMENT CHARACTER			FFFC	*
+			"\xef\xbf\xbd"	=> '',		// REPLACEMENT CHARACTER				FFFD	*
+			"\xc2\xad"		=> '-',		// SOFT HYPHEN							00AD
+			"\xE2\x80\x9C"	=> '"',		// LEFT DOUBLE QUOTATION MARK			201C
+			"\xE2\x80\x9D"	=> '"',		// RIGHT DOUBLE QUOTATION MARK			201D
+			"\xE2\x80\x98"	=> '\'',	// LEFT SINGLE QUOTATION MARK			2018
+			"\xE2\x80\x99"	=> '\'',	// RIGHT SINGLE QUOTATION MARK			2019
+			"\xe2\x80\x80"	=> ' ',		// EN QUAD								2000	*
+			"\xe2\x80\x81"	=> ' ',		// EM QUAD								2001	*
+			"\xe2\x80\x82"	=> ' ',		// EN SPACE								2002	*
+			"\xe2\x80\x83"	=> ' ',		// EM SPACE								2003	*
+			"\xe2\x80\x84"	=> ' ',		// THREE-PER-EM SPACE					2004	*
+			"\xe2\x80\x85"	=> ' ',		// FOUR-PER-EM SPACE					2005	*
+			"\xe2\x80\x86"	=> ' ',		// SIX-PER-EM SPACE						2006	*
+			"\xe2\x80\x87"	=> ' ',		// FIGURE SPACE							2007	*
+			"\xe2\x80\x88"	=> ' ',		// PUNCTUATION SPACE					2008	*
+			"\xe2\x80\x89"	=> ' ',		// THIN SPACE							2009	*
+			"\xe2\x80\x8a"	=> ' ',		// HAIR SPACE							200A	*
+			"\xE3\x80\x80"	=> ' ',		// IDEOGRAPHIC SPACE					3000	*
+		);
 	}
 
-	$_GET = _forum_remove_bad_characters($_GET);
-	$_POST = _forum_remove_bad_characters($_POST);
-	$_COOKIE = _forum_remove_bad_characters($_COOKIE);
-	$_REQUEST = _forum_remove_bad_characters($_REQUEST);
+	if (is_array($array))
+		return array_map('remove_bad_characters', $array);
+
+	// Strip out any invalid characters
+	$array = utf8_bad_strip($array);
+
+	// Replace some "bad" characters
+	$array = str_replace(array_keys($bad_utf8_chars), array_values($bad_utf8_chars), $array);
+
+	return $array;
+}
+
+
+//
+// Converts the file size in bytes to a human readable file size
+//
+function file_size($size)
+{
+	$units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB');
+
+	for ($i = 0; $size > 1024; $i++)
+		$size /= 1024;
+
+	return round($size, 2).' '.$units[$i];
 }
 
 
@@ -1270,15 +1572,15 @@ function display_saved_queries()
 			<table cellspacing="0">
 			<thead>
 				<tr>
-					<th class="tcl" scope="col">Time (s)</th>
-					<th class="tcr" scope="col">Query</th>
+					<th class="tcl" scope="col"><?php echo $lang_common['Query times'] ?></th>
+					<th class="tcr" scope="col"><?php echo $lang_common['Query'] ?></th>
 				</tr>
 			</thead>
 			<tbody>
 <?php
 
 	$query_time_total = 0.0;
-	while (list(, $cur_query) = @each($saved_queries))
+	foreach ($saved_queries as $cur_query)
 	{
 		$query_time_total += $cur_query[1];
 
@@ -1293,7 +1595,7 @@ function display_saved_queries()
 
 ?>
 				<tr>
-					<td class="tcl" colspan="2">Total query time: <?php echo $query_time_total ?> s</td>
+					<td class="tcl" colspan="2"><?php printf($lang_common['Total query time'], $query_time_total.' s') ?></td>
 				</tr>
 			</tbody>
 			</table>
diff --git a/upload/include/index.html b/upload/include/index.html
new file mode 100644
index 0000000..89337b2
--- /dev/null
+++ b/upload/include/index.html
@@ -0,0 +1 @@
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/include/parser.php b/upload/include/parser.php
index df10ef8..9397e8a 100644
--- a/upload/include/parser.php
+++ b/upload/include/parser.php
@@ -1,239 +1,569 @@
 <?php
-/***********************************************************************
 
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // Make sure no one attempts to run this script "directly"
 if (!defined('PUN'))
 	exit;
 
-
-// Here you can add additional smilies if you like (please note that you must escape singlequote and backslash)
-$smiley_text = array(':)', '=)', ':|', '=|', ':(', '=(', ':D', '=D', ':o', ':O', ';)', ':/', ':P', ':lol:', ':mad:', ':rolleyes:', ':cool:');
-$smiley_img = array('smile.png', 'smile.png', 'neutral.png', 'neutral.png', 'sad.png', 'sad.png', 'big_smile.png', 'big_smile.png', 'yikes.png', 'yikes.png', 'wink.png', 'hmm.png', 'tongue.png', 'lol.png', 'mad.png', 'roll.png', 'cool.png');
-
-// Uncomment the next row if you add smilies that contain any of the characters &"'<>
-//$smiley_text = array_map('pun_htmlspecialchars', $smiley_text);
-
+// Global variables
+/* regular expression to match nested BBCode LIST tags
+'%
+\[list                # match opening bracket and tag name of outermost LIST tag
+(?:=([1a*]))?+        # optional attribute capture in group 1
+\]                    # closing bracket of outermost opening LIST tag
+(                     # capture contents of LIST tag in group 2
+  (?:                 # non capture group for either contents or whole nested LIST
+    [^\[]*+           # unroll the loop! consume everything up to next [ (normal *)
+    (?:               # (See "Mastering Regular Expressions" chapter 6 for details)
+      (?!             # negative lookahead ensures we are NOT on [LIST*] or [/LIST]
+        \[list        # opening LIST tag
+        (?:=[1a*])?+  # with optional attribute
+        \]            # closing bracket of opening LIST tag
+        |             # or...
+        \[/list\]     # a closing LIST tag
+      )               # end negative lookahead assertion (we are not on a LIST tag)
+      \[              # match the [ which is NOT the start of LIST tag (special)
+      [^\[]*+         # consume everything up to next [ (normal *)
+    )*+               # finish up "unrolling the loop" technique (special (normal*))*
+  |                   # or...
+    (?R)              # recursively match a whole nested LIST element
+  )*                  # as many times as necessary until deepest nested LIST tag grabbed
+)                     # end capturing contents of LIST tag into group 2
+\[/list\]             # match outermost closing LIST tag
+%iex' */
+$re_list = '%\[list(?:=([1a*]))?+\]((?:[^\[]*+(?:(?!\[list(?:=[1a*])?+\]|\[/list\])\[[^\[]*+)*+|(?R))*)\[/list\]%ie';
+
+// Here you can add additional smilies if you like (please note that you must escape single quote and backslash)
+$smilies = array(
+	':)' => 'smile.png',
+	'=)' => 'smile.png',
+	':|' => 'neutral.png',
+	'=|' => 'neutral.png',
+	':(' => 'sad.png',
+	'=(' => 'sad.png',
+	':D' => 'big_smile.png',
+	'=D' => 'big_smile.png',
+	':o' => 'yikes.png',
+	':O' => 'yikes.png',
+	';)' => 'wink.png',
+	':/' => 'hmm.png',
+	':P' => 'tongue.png',
+	':p' => 'tongue.png',
+	':lol:' => 'lol.png',
+	':mad:' => 'mad.png',
+	':rolleyes:' => 'roll.png',
+	':cool:' => 'cool.png');
 
 //
 // Make sure all BBCodes are lower case and do a little cleanup
 //
 function preparse_bbcode($text, &$errors, $is_signature = false)
 {
-	// Change all simple BBCodes to lower case
-	$a = array('[B]', '[I]', '[U]', '[/B]', '[/I]', '[/U]');
-	$b = array('[b]', '[i]', '[u]', '[/b]', '[/i]', '[/u]');
-	$text = str_replace($a, $b, $text);
-
-	// Do the more complex BBCodes (also strip excessive whitespace and useless quotes)
-	$a = array( '#\[url=("|\'|)(.*?)\\1\]\s*#i',
-				'#\[url\]\s*#i',
-				'#\s*\[/url\]#i',
-				'#\[email=("|\'|)(.*?)\\1\]\s*#i',
-				'#\[email\]\s*#i',
-				'#\s*\[/email\]#i',
-				'#\[img\]\s*(.*?)\s*\[/img\]#is',
-				'#\[colou?r=("|\'|)(.*?)\\1\](.*?)\[/colou?r\]#is');
-
-	$b = array(	'[url=$2]',
-				'[url]',
-				'[/url]',
-				'[email=$2]',
-				'[email]',
-				'[/email]',
-				'[img]$1[/img]',
-				'[color=$2]$3[/color]');
+	global $pun_config, $lang_common, $re_list;
 
-	if (!$is_signature)
+	if ($is_signature)
 	{
-		// For non-signatures, we have to do the quote and code tags as well
-		$a[] = '#\[quote=(&quot;|"|\'|)(.*?)\\1\]\s*#i';
-		$a[] = '#\[quote\]\s*#i';
-		$a[] = '#\s*\[/quote\]\s*#i';
-		$a[] = '#\[code\][\r\n]*(.*?)\s*\[/code\]\s*#is';
-
-		$b[] = '[quote=$1$2$1]';
-		$b[] = '[quote]';
-		$b[] = '[/quote]'."\n";
-		$b[] = '[code]$1[/code]'."\n";
-	}
+		global $lang_profile;
 
-	// Run this baby!
-	$text = preg_replace($a, $b, $text);
+		if (preg_match('%\[/?(?:quote|code|list|h)\b[^\]]*\]%i', $text))
+			$errors[] = $lang_profile['Signature quote/code/list/h'];
+	}
 
-	if (!$is_signature)
+	// If the message contains a code tag we have to split it up (text within [code][/code] shouldn't be touched)
+	if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
 	{
-		$overflow = check_tag_order($text, $error);
-
-		if ($error)
-			// A BBCode error was spotted in check_tag_order()
-			$errors[] = $error;
-		else if ($overflow)
-			// The quote depth level was too high, so we strip out the inner most quote(s)
-			$text = substr($text, 0, $overflow[0]).substr($text, $overflow[1], (strlen($text) - $overflow[0]));
+		list($inside, $outside) = split_text($text, '[code]', '[/code]', $errors);
+		$text = implode("\0", $outside);
 	}
+
+	// Tidy up lists
+	$temp = preg_replace($re_list, 'preparse_list_tag(\'$2\', \'$1\', $errors)', $text);
+
+	// If the regex failed
+	if ($temp === null)
+		$errors[] = $lang_common['BBCode list size error'];
 	else
+		$text = str_replace('*'."\0".']', '*]', $temp);
+
+	if ($pun_config['o_make_links'] == '1')
+		$text = do_clickable($text);
+
+	// If we split up the message before we have to concatenate it together again (code tags)
+	if (isset($inside))
 	{
-		global $lang_prof_reg;
+		$outside = explode("\0", $text);
+		$text = '';
 
-		if (preg_match('#\[quote=(&quot;|"|\'|)(.*)\\1\]|\[quote\]|\[/quote\]|\[code\]|\[/code\]#i', $text))
-			message($lang_prof_reg['Signature quote/code']);
+		$num_tokens = count($outside);
+
+		for ($i = 0; $i < $num_tokens; ++$i)
+		{
+			$text .= $outside[$i];
+			if (isset($inside[$i]))
+				$text .= '[code]'.$inside[$i].'[/code]';
+		}
 	}
 
-	return trim($text);
+	$temp_text = false;
+	if (empty($errors))
+		$temp_text = preparse_tags($text, $errors, $is_signature);
+
+	if ($temp_text !== false)
+		$text = $temp_text;
+
+	// Remove empty tags
+	while (($new_text = preg_replace('/\[(b|u|i|h|colou?r|quote|code|img|url|email|list)(?:\=[^\]]*)?\]\[\/\1\]/', '', $text)) !== false)
+	{
+		if ($new_text != $text)
+			$text = $new_text;
+		else
+			break;
+	}
+
+	return pun_trim($text);
 }
 
 
 //
-// Parse text and make sure that [code] and [quote] syntax is correct
+// Check the structure of bbcode tags and fix simple mistakes where possible
 //
-function check_tag_order($text, &$error)
+function preparse_tags($text, &$errors, $is_signature = false)
 {
-	global $lang_common;
+	global $lang_common, $pun_config;
+
+	// Start off by making some arrays of bbcode tags and what we need to do with each one
+
+	// List of all the tags
+	$tags = array('quote', 'code', 'b', 'i', 'u', 'color', 'colour', 'url', 'email', 'img', 'list', '*', 'h');
+	// List of tags that we need to check are open (You could not put b,i,u in here then illegal nesting like [b][i][/b][/i] would be allowed)
+	$tags_opened = $tags;
+	// and tags we need to check are closed (the same as above, added it just in case)
+	$tags_closed = $tags;
+	// Tags we can nest and the depth they can be nested to (only quotes)
+	$tags_nested = array('quote' => $pun_config['o_quote_depth'], 'list' => 5, '*' => 5);
+	// Tags to ignore the contents of completely (just code)
+	$tags_ignore = array('code');
+	// Block tags, block tags can only go within another block tag, they cannot be in a normal tag
+	$tags_block = array('quote', 'code', 'list', 'h', '*');
+	// Inline tags, we do not allow new lines in these
+	$tags_inline = array('b', 'i', 'u', 'color', 'colour', 'h');
+	// Tags we trim interior space
+	$tags_trim = array('img');
+	// Tags we remove quotes from the argument
+	$tags_quotes = array('url', 'email', 'img');
+	// Tags we limit bbcode in
+	$tags_limit_bbcode = array(
+		'*' 	=> array('b', 'i', 'u', 'color', 'colour', 'url', 'email', 'list', 'img'),
+		'list' 	=> array('*'),
+		'url' 	=> array('b', 'i', 'u', 'color', 'colour', 'img'),
+		'email' => array('b', 'i', 'u', 'color', 'colour', 'img'),
+		'img' 	=> array()
+	);
+	// Tags we can automatically fix bad nesting
+	$tags_fix = array('quote', 'b', 'i', 'u', 'color', 'colour', 'url', 'email', 'h');
+
+	$split_text = preg_split("/(\[[\*a-zA-Z0-9-\/]*?(?:=.*?)?\])/", $text, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
+
+	$open_tags = array('post');
+	$open_args = array('');
+	$opened_tag = 0;
+	$new_text = '';
+	$current_ignore = '';
+	$current_nest = '';
+	$current_depth = array();
+	$limit_bbcode = $tags;
+
+	foreach ($split_text as $current)
+	{
+		if ($current == '')
+			continue;
 
-	// The maximum allowed quote depth
-	$max_depth = 3;
+		// Are we dealing with a tag?
+		if (substr($current, 0, 1) != '[' || substr($current, -1, 1) != ']')
+		{
+			// It's not a bbcode tag so we put it on the end and continue
 
-	$cur_index = 0;
-	$q_depth = 0;
+			// If we are nested too deeply don't add to the end
+			if ($current_nest)
+				continue;
 
-	while (true)
-	{
-		// Look for regular code and quote tags
-		$c_start = strpos($text, '[code]');
-		$c_end = strpos($text, '[/code]');
-		$q_start = strpos($text, '[quote]');
-		$q_end = strpos($text, '[/quote]');
-
-		// Look for [quote=username] style quote tags
-		if (preg_match('#\[quote=(&quot;|"|\'|)(.*)\\1\]#sU', $text, $matches))
-			$q2_start = strpos($text, $matches[0]);
-		else
-			$q2_start = 65536;
+			$current = str_replace("\r\n", "\n", $current);
+			$current = str_replace("\r", "\n", $current);
+			if (in_array($open_tags[$opened_tag], $tags_inline) && strpos($current, "\n") !== false)
+			{
+				// Deal with new lines
+				$split_current = preg_split("/(\n\n+)/", $current, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
+				$current = '';
+
+				if (!pun_trim($split_current[0], "\n")) // The first part is a linebreak so we need to handle any open tags first
+					array_unshift($split_current, '');
+
+				for ($i = 1; $i < count($split_current); $i += 2)
+				{
+					$temp_opened = array();
+					$temp_opened_arg = array();
+					$temp = $split_current[$i - 1];
+					while (!empty($open_tags))
+					{
+						$temp_tag = array_pop($open_tags);
+						$temp_arg = array_pop($open_args);
+
+						if (in_array($temp_tag , $tags_inline))
+						{
+							array_push($temp_opened, $temp_tag);
+							array_push($temp_opened_arg, $temp_arg);
+							$temp .= '[/'.$temp_tag.']';
+						}
+						else
+						{
+							array_push($open_tags, $temp_tag);
+							array_push($open_args, $temp_arg);
+							break;
+						}
+					}
+					$current .= $temp.$split_current[$i];
+					$temp = '';
+					while (!empty($temp_opened))
+					{
+						$temp_tag = array_pop($temp_opened);
+						$temp_arg = array_pop($temp_opened_arg);
+						if (empty($temp_arg))
+							$temp .= '['.$temp_tag.']';
+						else
+							$temp .= '['.$temp_tag.'='.$temp_arg.']';
+						array_push($open_tags, $temp_tag);
+						array_push($open_args, $temp_arg);
+					}
+					$current .= $temp;
+				}
+
+				if (array_key_exists($i - 1, $split_current))
+					$current .= $split_current[$i - 1];
+			}
 
-		// Deal with strpos() returning false when the string is not found
-		// (65536 is one byte longer than the maximum post length)
-		if ($c_start === false) $c_start = 65536;
-		if ($c_end === false) $c_end = 65536;
-		if ($q_start === false) $q_start = 65536;
-		if ($q_end === false) $q_end = 65536;
+			if (in_array($open_tags[$opened_tag], $tags_trim))
+				$new_text .= pun_trim($current);
+			else
+				$new_text .= $current;
 
-		// If none of the strings were found
-		if (min($c_start, $c_end, $q_start, $q_end, $q2_start) == 65536)
-			break;
+			continue;
+		}
 
-		// We are interested in the first quote (regardless of the type of quote)
-		$q3_start = ($q_start < $q2_start) ? $q_start : $q2_start;
+		// Get the name of the tag
+		$current_arg = '';
+		if (strpos($current, '/') === 1)
+		{
+			$current_tag = substr($current, 2, -1);
+		}
+		else if (strpos($current, '=') === false)
+		{
+			$current_tag = substr($current, 1, -1);
+		}
+		else
+		{
+			$current_tag = substr($current, 1, strpos($current, '=')-1);
+			$current_arg = substr($current, strpos($current, '=')+1, -1);
+		}
+		$current_tag = strtolower($current_tag);
 
-		// We found a [quote] or a [quote=username]
-		if ($q3_start < min($q_end, $c_start, $c_end))
+		// Is the tag defined?
+		if (!in_array($current_tag, $tags))
 		{
-			$step = ($q_start < $q2_start) ? 7 : strlen($matches[0]);
+			// It's not a bbcode tag so we put it on the end and continue
+			if (!$current_nest)
+				$new_text .= $current;
 
-			$cur_index += $q3_start + $step;
+			continue;
+		}
 
-			// Did we reach $max_depth?
-			if ($q_depth == $max_depth)
-				$overflow_begin = $cur_index - $step;
+		// We definitely have a bbcode tag
 
-			++$q_depth;
-			$text = substr($text, $q3_start + $step);
+		// Make the tag string lower case
+		if ($equalpos = strpos($current,'='))
+		{
+			// We have an argument for the tag which we don't want to make lowercase
+			if (strlen(substr($current, $equalpos)) == 2)
+			{
+				// Empty tag argument
+				$errors[] = sprintf($lang_common['BBCode error empty attribute'], $current_tag);
+				return false;
+			}
+			$current = strtolower(substr($current, 0, $equalpos)).substr($current, $equalpos);
 		}
+		else
+			$current = strtolower($current);
 
-		// We found a [/quote]
-		else if ($q_end < min($q_start, $c_start, $c_end))
+		// This is if we are currently in a tag which escapes other bbcode such as code
+		if ($current_ignore)
 		{
-			if ($q_depth == 0)
+			if ('[/'.$current_ignore.']' == $current)
 			{
-				$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 1'];
-				return;
+				// We've finished the ignored section
+				$current = '[/'.$current_tag.']';
+				$current_ignore = '';
 			}
 
-			$q_depth--;
-			$cur_index += $q_end+8;
+			$new_text .= $current;
 
-			// Did we reach $max_depth?
-			if ($q_depth == $max_depth)
-				$overflow_end = $cur_index;
+			continue;
+		}
+
+		if ($current_nest)
+		{
+			// We are currently too deeply nested so lets see if we are closing the tag or not
+			if ($current_tag != $current_nest)
+				continue;
+
+			if (substr($current, 1, 1) == '/')
+				$current_depth[$current_nest]--;
+			else
+				$current_depth[$current_nest]++;
+
+			if ($current_depth[$current_nest] <= $tags_nested[$current_nest])
+				$current_nest = '';
 
-			$text = substr($text, $q_end+8);
+			continue;
 		}
 
-		// We found a [code]
-		else if ($c_start < min($c_end, $q_start, $q_end))
+		// Check the current tag is allowed here
+		if (!in_array($current_tag, $limit_bbcode) && $current_tag != $open_tags[$opened_tag])
 		{
-			// Make sure there's a [/code] and that any new [code] doesn't occur before the end tag
-			$tmp = strpos($text, '[/code]');
-			$tmp2 = strpos(substr($text, $c_start+6), '[code]');
-			if ($tmp2 !== false)
-				$tmp2 += $c_start+6;
+			$errors[] = sprintf($lang_common['BBCode error invalid nesting'], $current_tag, $open_tags[$opened_tag]);
+			return false;
+		}
+
+		if (substr($current, 1, 1) == '/')
+		{
+			// This is if we are closing a tag
 
-			if ($tmp === false || ($tmp2 !== false && $tmp2 < $tmp))
+			if ($opened_tag == 0 || !in_array($current_tag, $open_tags))
 			{
-				$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 2'];
-				return;
+				// We tried to close a tag which is not open
+				if (in_array($current_tag, $tags_opened))
+				{
+					$errors[] = sprintf($lang_common['BBCode error no opening tag'], $current_tag);
+					return false;
+				}
 			}
 			else
-				$text = substr($text, $tmp+7);
+			{
+				// Check nesting
+				while (true)
+				{
+					// Nesting is ok
+					if ($open_tags[$opened_tag] == $current_tag)
+					{
+						array_pop($open_tags);
+						array_pop($open_args);
+						$opened_tag--;
+						break;
+					}
+
+					// Nesting isn't ok, try to fix it
+					if (in_array($open_tags[$opened_tag], $tags_closed) && in_array($current_tag, $tags_closed))
+					{
+						if (in_array($current_tag, $open_tags))
+						{
+							$temp_opened = array();
+							$temp_opened_arg = array();
+							$temp = '';
+							while (!empty($open_tags))
+							{
+								$temp_tag = array_pop($open_tags);
+								$temp_arg = array_pop($open_args);
+
+								if (!in_array($temp_tag, $tags_fix))
+								{
+									// We couldn't fix nesting
+									$errors[] = sprintf($lang_common['BBCode error no closing tag'], array_pop($temp_opened));
+									return false;
+								}
+								array_push($temp_opened, $temp_tag);
+								array_push($temp_opened_arg, $temp_arg);
+
+								if ($temp_tag == $current_tag)
+									break;
+								else
+									$temp .= '[/'.$temp_tag.']';
+							}
+							$current = $temp.$current;
+							$temp = '';
+							array_pop($temp_opened);
+							array_pop($temp_opened_arg);
+
+							while (!empty($temp_opened))
+							{
+								$temp_tag = array_pop($temp_opened);
+								$temp_arg = array_pop($temp_opened_arg);
+								if (empty($temp_arg))
+									$temp .= '['.$temp_tag.']';
+								else
+									$temp .= '['.$temp_tag.'='.$temp_arg.']';
+								array_push($open_tags, $temp_tag);
+								array_push($open_args, $temp_arg);
+							}
+							$current .= $temp;
+							$opened_tag--;
+							break;
+						}
+						else
+						{
+							// We couldn't fix nesting
+							$errors[] = sprintf($lang_common['BBCode error no opening tag'], $current_tag);
+							return false;
+						}
+					}
+					else if (in_array($open_tags[$opened_tag], $tags_closed))
+						break;
+					else
+					{
+						array_pop($open_tags);
+						array_pop($open_args);
+						$opened_tag--;
+					}
+				}
+			}
 
-			$cur_index += $tmp+7;
+			if (in_array($current_tag, array_keys($tags_nested)))
+			{
+				if (isset($current_depth[$current_tag]))
+					$current_depth[$current_tag]--;
+			}
+
+			if (in_array($open_tags[$opened_tag], array_keys($tags_limit_bbcode)))
+				$limit_bbcode = $tags_limit_bbcode[$open_tags[$opened_tag]];
+			else
+				$limit_bbcode = $tags;
+
+			$new_text .= $current;
+
+			continue;
 		}
+		else
+		{
+			// We are opening a tag
+			if (in_array($current_tag, array_keys($tags_limit_bbcode)))
+				$limit_bbcode = $tags_limit_bbcode[$current_tag];
+			else
+				$limit_bbcode = $tags;
+
+			if (in_array($current_tag, $tags_block) && !in_array($open_tags[$opened_tag], $tags_block) && $opened_tag != 0)
+			{
+				// We tried to open a block tag within a non-block tag
+				$errors[] = sprintf($lang_common['BBCode error invalid nesting'], $current_tag, $open_tags[$opened_tag]);
+				return false;
+			}
+
+			if (in_array($current_tag, $tags_ignore))
+			{
+				// It's an ignore tag so we don't need to worry about what's inside it
+				$current_ignore = $current_tag;
+				$new_text .= $current;
+				continue;
+			}
 
-		// We found a [/code] (this shouldn't happen since we handle both start and end tag in the if clause above)
-		else if ($c_end < min($c_start, $q_start, $q_end))
+			// Deal with nested tags
+			if (in_array($current_tag, $open_tags) && !in_array($current_tag, array_keys($tags_nested)))
+			{
+				// We nested a tag we shouldn't
+				$errors[] = sprintf($lang_common['BBCode error invalid self-nesting'], $current_tag);
+				return false;
+			}
+			else if (in_array($current_tag, array_keys($tags_nested)))
+			{
+				// We are allowed to nest this tag
+
+				if (isset($current_depth[$current_tag]))
+					$current_depth[$current_tag]++;
+				else
+					$current_depth[$current_tag] = 1;
+
+				// See if we are nested too deep
+				if ($current_depth[$current_tag] > $tags_nested[$current_tag])
+				{
+					$current_nest = $current_tag;
+					continue;
+				}
+			}
+
+			// Remove quotes from arguments for certain tags
+			if (strpos($current, '=') !== false && in_array($current_tag, $tags_quotes))
+			{
+				$current = preg_replace('#\['.$current_tag.'=("|\'|)(.*?)\\1\]\s*#i', '['.$current_tag.'=$2]', $current);
+			}
+
+			if (in_array($current_tag, array_keys($tags_limit_bbcode)))
+				$limit_bbcode = $tags_limit_bbcode[$current_tag];
+
+			$open_tags[] = $current_tag;
+			$open_args[] = $current_arg;
+			$opened_tag++;
+			$new_text .= $current;
+			continue;
+		}
+	}
+
+	// Check we closed all the tags we needed to
+	foreach ($tags_closed as $check)
+	{
+		if (in_array($check, $open_tags))
 		{
-			$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 3'];
-			return;
+			// We left an important tag open
+			$errors[] = sprintf($lang_common['BBCode error no closing tag'], $check);
+			return false;
 		}
 	}
 
-	// If $q_depth <> 0 something is wrong with the quote syntax
-	if ($q_depth)
+	if ($current_ignore)
 	{
-		$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 4'];
-		return;
+		// We left an ignore tag open
+		$errors[] = sprintf($lang_common['BBCode error no closing tag'], $current_ignore);
+		return false;
 	}
-	else if ($q_depth < 0)
+
+	return $new_text;
+}
+
+
+//
+// Preparse the contents of [list] bbcode
+//
+function preparse_list_tag($content, $type = '*', &$errors)
+{
+	global $lang_common, $re_list;
+
+	if (strlen($type) != 1)
+		$type = '*';
+
+	if (strpos($content,'[list') !== false)
 	{
-		$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 5'];
-		return;
+		$content = preg_replace($re_list, 'preparse_list_tag(\'$2\', \'$1\', $errors)', $content);
 	}
 
-	// If the quote depth level was higher than $max_depth we return the index for the
-	// beginning and end of the part we should strip out
-	if (isset($overflow_begin))
-		return array($overflow_begin, $overflow_end);
-	else
-		return null;
+	$items = explode('[*]', str_replace('\"', '"', $content));
+
+	$content = '';
+	foreach ($items as $item)
+	{
+		if (pun_trim($item) != '')
+			$content .= '[*'."\0".']'.str_replace('[/*]', '', pun_trim($item)).'[/*'."\0".']'."\n";
+	}
+
+	return '[list='.$type.']'."\n".$content.'[/list]';
 }
 
 
 //
 // Split text into chunks ($inside contains all text inside $start and $end, and $outside contains all text outside)
 //
-function split_text($text, $start, $end)
+function split_text($text, $start, $end, &$errors, $retab = true)
 {
-	global $pun_config;
+	global $pun_config, $lang_common;
 
 	$tokens = explode($start, $text);
 
@@ -243,11 +573,17 @@ function split_text($text, $start, $end)
 	for ($i = 1; $i < $num_tokens; ++$i)
 	{
 		$temp = explode($end, $tokens[$i]);
+
+		if (count($temp) != 2)
+		{
+			$errors[] = $lang_common['BBCode code problem'];
+			return array(null, array($text));
+		}
 		$inside[] = $temp[0];
 		$outside[] = $temp[1];
 	}
 
-	if ($pun_config['o_indent_num_spaces'] != 8 && $start == '[code]')
+	if ($pun_config['o_indent_num_spaces'] != 8 && $retab)
 	{
 		$spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
 		$inside = str_replace("\t", $spaces, $inside);
@@ -260,74 +596,140 @@ function split_text($text, $start, $end)
 //
 // Truncate URL if longer than 55 characters (add http:// or ftp:// if missing)
 //
-function handle_url_tag($url, $link = '')
+function handle_url_tag($url, $link = '', $bbcode = false)
 {
-	global $pun_user;
-
+	$url = pun_trim($url);
 	$full_url = str_replace(array(' ', '\'', '`', '"'), array('%20', '', '', ''), $url);
-	if (strpos($url, 'www.') === 0)			// If it starts with www, we add http://
+	if (strpos($url, 'www.') === 0) // If it starts with www, we add http://
 		$full_url = 'http://'.$full_url;
-	else if (strpos($url, 'ftp.') === 0)	// Else if it starts with ftp, we add ftp://
+	else if (strpos($url, 'ftp.') === 0) // Else if it starts with ftp, we add ftp://
 		$full_url = 'ftp://'.$full_url;
-	else if (!preg_match('#^([a-z0-9]{3,6})://#', $url, $bah)) 	// Else if it doesn't start with abcdef://, we add http://
+	else if (!preg_match('#^([a-z0-9]{3,6})://#', $url)) // Else if it doesn't start with abcdef://, we add http://
 		$full_url = 'http://'.$full_url;
 
 	// Ok, not very pretty :-)
-	$link = ($link == '' || $link == $url) ? ((strlen($url) > 55) ? substr($url, 0 , 39).' &hellip; '.substr($url, -10) : $url) : stripslashes($link);
+	if (!$bbcode)
+		$link = ($link == '' || $link == $url) ? ((utf8_strlen($url) > 55) ? utf8_substr($url, 0 , 39).' &#133; '.utf8_substr($url, -10) : $url) : stripslashes($link);
 
-	return '<a href="'.$full_url.'">'.$link.'</a>';
+	if ($bbcode)
+	{
+		if ($full_url == $link)
+			return '[url]'.$link.'[/url]';
+		else
+			return '[url='.$full_url.']'.$link.'[/url]';
+	}
+	else
+		return '<a href="'.$full_url.'">'.$link.'</a>';
 }
 
 
 //
 // Turns an URL from the [img] tag into an <img> tag or a <a href...> tag
 //
-function handle_img_tag($url, $is_signature = false)
+function handle_img_tag($url, $is_signature = false, $alt = null)
 {
-	global $lang_common, $pun_config, $pun_user;
+	global $lang_common, $pun_user;
+
+	if ($alt == null)
+		$alt = $url;
 
 	$img_tag = '<a href="'.$url.'">&lt;'.$lang_common['Image link'].'&gt;</a>';
 
 	if ($is_signature && $pun_user['show_img_sig'] != '0')
-		$img_tag = '<img class="sigimage" src="'.$url.'" alt="'.htmlspecialchars($url).'" />';
+		$img_tag = '<img class="sigimage" src="'.$url.'" alt="'.pun_htmlspecialchars($alt).'" />';
 	else if (!$is_signature && $pun_user['show_img'] != '0')
-		$img_tag = '<img class="postimg" src="'.$url.'" alt="'.htmlspecialchars($url).'" />';
+		$img_tag = '<span class="postimg"><img src="'.$url.'" alt="'.pun_htmlspecialchars($alt).'" /></span>';
 
 	return $img_tag;
 }
 
 
 //
+// Parse the contents of [list] bbcode
+//
+function handle_list_tag($content, $type = '*')
+{
+	global $re_list;
+
+	if (strlen($type) != 1)
+		$type = '*';
+
+	if (strpos($content,'[list') !== false)
+	{
+		$content = preg_replace($re_list, 'handle_list_tag(\'$2\', \'$1\')', $content);
+	}
+
+	$content = preg_replace('#\s*\[\*\](.*?)\[/\*\]\s*#s', '<li><p>$1</p></li>', pun_trim($content));
+
+	if ($type == '*')
+		$content = '<ul>'.$content.'</ul>';
+	else
+		if ($type == 'a')
+			$content = '<ol class="alpha">'.$content.'</ol>';
+		else
+			$content = '<ol class="decimal">'.$content.'</ol>';
+
+	return '</p>'.$content.'<p>';
+}
+
+
+//
 // Convert BBCodes to their HTML equivalent
 //
-function do_bbcode($text)
+function do_bbcode($text, $is_signature = false)
 {
-	global $lang_common, $pun_user;
+	global $lang_common, $pun_user, $pun_config, $re_list;
+
+	if (strpos($text, '[quote') !== false)
+	{
+		$text = preg_replace('#\[quote\]\s*#', '</p><div class="quotebox"><blockquote><div><p>', $text);
+		$text = preg_replace('#\[quote=(&quot;|"|\'|)(.*?)\\1\]#se', '"</p><div class=\"quotebox\"><cite>".str_replace(array(\'[\', \'\\"\'), array(\'&#91;\', \'"\'), \'$2\')." ".$lang_common[\'wrote\']."</cite><blockquote><div><p>"', $text);
+		$text = preg_replace('#\s*\[\/quote\]#S', '</p></div></blockquote></div><p>', $text);
+	}
 
-	if (strpos($text, 'quote') !== false)
+	if (!$is_signature)
 	{
-		$text = str_replace('[quote]', '</p><blockquote><div class="incqbox"><p>', $text);
-		$text = preg_replace('#\[quote=(&quot;|"|\'|)(.*)\\1\]#seU', '"</p><blockquote><div class=\"incqbox\"><h4>".str_replace(array(\'[\', \'\\"\'), array(\'&#91;\', \'"\'), \'$2\')." ".$lang_common[\'wrote\'].":</h4><p>"', $text);
-		$text = preg_replace('#\[\/quote\]\s*#', '</p></div></blockquote><p>', $text);
+		$pattern[] = $re_list;
+		$replace[] = 'handle_list_tag(\'$2\', \'$1\')';
 	}
 
-	$pattern = array('#\[b\](.*?)\[/b\]#s',
-					 '#\[i\](.*?)\[/i\]#s',
-					 '#\[u\](.*?)\[/u\]#s',
-					 '#\[url\]([^\[<]*?)\[/url\]#e',
-					 '#\[url=([^\[<]*?)\](.*?)\[/url\]#e',
-					 '#\[email\]([^\[<]*?)\[/email\]#',
-					 '#\[email=([^\[<]*?)\](.*?)\[/email\]#',
-					 '#\[color=([a-zA-Z]*|\#?[0-9a-fA-F]{6})](.*?)\[/color\]#s');
-
-	$replace = array('<strong>$1</strong>',
-					 '<em>$1</em>',
-					 '<span class="bbu">$1</span>',
-					 'handle_url_tag(\'$1\')',
-					 'handle_url_tag(\'$1\', \'$2\')',
-					 '<a href="mailto:$1">$1</a>',
-					 '<a href="mailto:$1">$2</a>',
-					 '<span style="color: $1">$2</span>');
+	$pattern[] = '#\[b\](.*?)\[/b\]#ms';
+	$pattern[] = '#\[i\](.*?)\[/i\]#ms';
+	$pattern[] = '#\[u\](.*?)\[/u\]#ms';
+	$pattern[] = '#\[colou?r=([a-zA-Z]{3,20}|\#[0-9a-fA-F]{6}|\#[0-9a-fA-F]{3})](.*?)\[/colou?r\]#ms';
+	$pattern[] = '#\[h\](.*?)\[/h\]#ms';
+
+	$replace[] = '<strong>$1</strong>';
+	$replace[] = '<em>$1</em>';
+	$replace[] = '<span class="bbu">$1</span>';
+	$replace[] = '<span style="color: $1">$2</span>';
+	$replace[] = '</p><h5>$1</h5><p>';
+
+	if (($is_signature && $pun_config['p_sig_img_tag'] == '1') || (!$is_signature && $pun_config['p_message_img_tag'] == '1'))
+	{
+		$pattern[] = '#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e';
+		$pattern[] = '#\[img=([^\[]*?)\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e';
+		if ($is_signature)
+		{
+			$replace[] = 'handle_img_tag(\'$1$3\', true)';
+			$replace[] = 'handle_img_tag(\'$2$4\', true, \'$1\')';
+		}
+		else
+		{
+			$replace[] = 'handle_img_tag(\'$1$3\', false)';
+			$replace[] = 'handle_img_tag(\'$2$4\', false, \'$1\')';
+		}
+	}
+
+	$pattern[] = '#\[url\]([^\[]*?)\[/url\]#e';
+	$pattern[] = '#\[url=([^\[]+?)\](.*?)\[/url\]#e';
+	$pattern[] = '#\[email\]([^\[]*?)\[/email\]#';
+	$pattern[] = '#\[email=([^\[]+?)\](.*?)\[/email\]#';
+
+	$replace[] = 'handle_url_tag(\'$1\')';
+	$replace[] = 'handle_url_tag(\'$1\', \'$2\')';
+	$replace[] = '<a href="mailto:$1">$1</a>';
+	$replace[] = '<a href="mailto:$1">$2</a>';
 
 	// This thing takes a while! :)
 	$text = preg_replace($pattern, $replace, $text);
@@ -341,12 +743,10 @@ function do_bbcode($text)
 //
 function do_clickable($text)
 {
-	global $pun_user;
-
 	$text = ' '.$text;
 
-	$text = preg_replace('#([\s\(\)])(https?|ftp|news){1}://([\w\-]+\.([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^"\s\(\)<\[]*)?)#ie', '\'$1\'.handle_url_tag(\'$2://$3\')', $text);
-	$text = preg_replace('#([\s\(\)])(www|ftp)\.(([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^"\s\(\)<\[]*)?)#ie', '\'$1\'.handle_url_tag(\'$2.$3\', \'$2.$3\')', $text);
+	$text = preg_replace('#(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(https?|ftp|news){1}://([\w\-]+\.([\w\-]+\.)*\w+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])#ie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5://$6\', \'$5://$6\', true).stripslashes(\'$4$10$11$12\')', $text);
+	$text = preg_replace('#(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(www|ftp)\.(([\w\-]+\.)*\w+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])#ie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5.$6\', \'$5.$6\', true).stripslashes(\'$4$10$11$12\')', $text);
 
 	return substr($text, 1);
 }
@@ -357,13 +757,15 @@ function do_clickable($text)
 //
 function do_smilies($text)
 {
-	global $smiley_text, $smiley_img;
+	global $pun_config, $smilies;
 
 	$text = ' '.$text.' ';
 
-	$num_smilies = count($smiley_text);
-	for ($i = 0; $i < $num_smilies; ++$i)
-		$text = preg_replace("#(?<=.\W|\W.|^\W)".preg_quote($smiley_text[$i], '#')."(?=.\W|\W.|\W$)#m", '$1<img src="img/smilies/'.$smiley_img[$i].'" width="15" height="15" alt="'.substr($smiley_img[$i], 0, strrpos($smiley_img[$i], '.')).'" />$2', $text);
+	foreach ($smilies as $smiley_text => $smiley_img)
+	{
+		if (strpos($text, $smiley_text) !== false)
+			$text = preg_replace("#(?<=[>\s])".preg_quote($smiley_text, '#')."(?=\W)#m", '<img src="'.$pun_config['o_base_url'].'/img/smilies/'.$smiley_img.'" width="15" height="15" alt="'.substr($smiley_img, 0, strrpos($smiley_img, '.')).'" />', $text);
+	}
 
 	return substr($text, 1, -1);
 }
@@ -385,27 +787,15 @@ function parse_message($text, $hide_smilies)
 	// If the message contains a code tag we have to split it up (text within [code][/code] shouldn't be touched)
 	if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
 	{
-		list($inside, $outside) = split_text($text, '[code]', '[/code]');
-		$outside = array_map('ltrim', $outside);
-		$text = implode('<">', $outside);
+		list($inside, $outside) = split_text($text, '[code]', '[/code]', $errors);
+		$text = implode("\0", $outside);
 	}
 
-	if ($pun_config['o_make_links'] == '1')
-		$text = do_clickable($text);
-
-	if ($pun_config['o_smilies'] == '1' && $pun_user['show_smilies'] == '1' && $hide_smilies == '0')
-		$text = do_smilies($text);
-
 	if ($pun_config['p_message_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
-	{
 		$text = do_bbcode($text);
 
-		if ($pun_config['p_message_img_tag'] == '1')
-		{
-//			$text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\.(jpg|jpeg|png|gif)\[/img\]#e', 'handle_img_tag(\'$1$3.$4\')', $text);
-			$text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e', 'handle_img_tag(\'$1$3\')', $text);
-		}
-	}
+	if ($pun_config['o_smilies'] == '1' && $pun_user['show_smilies'] == '1' && $hide_smilies == '0')
+		$text = do_smilies($text);
 
 	// Deal with newlines, tabs and multiple spaces
 	$pattern = array("\n", "\t", '  ', '  ');
@@ -415,7 +805,7 @@ function parse_message($text, $hide_smilies)
 	// If we split up the message before we have to concatenate it together again (code tags)
 	if (isset($inside))
 	{
-		$outside = explode('<">', $text);
+		$outside = explode("\0", $text);
 		$text = '';
 
 		$num_tokens = count($outside);
@@ -424,15 +814,17 @@ function parse_message($text, $hide_smilies)
 		{
 			$text .= $outside[$i];
 			if (isset($inside[$i]))
+			//	$text .= '</p><div class="codebox"><pre><code>'.pun_trim($inside[$i], "\n\r").'</code></pre></div><p>';
 			{
-				$num_lines = ((substr_count($inside[$i], "\n")) + 3) * 1.5;
-				$height_str = ($num_lines > 35) ? '35em' : $num_lines.'em';
-				$text .= '</p><div class="codebox"><div class="incqbox"><h4>'.$lang_common['Code'].':</h4><div class="scrollbox" style="height: '.$height_str.'"><pre>'.$inside[$i].'</pre></div></div></div><p>';
+				$num_lines = (substr_count($inside[$i], "\n"));
+				$text .= '</p><div class="codebox"><pre'.(($num_lines > 28) ? ' class="vscroll"' : '').'><code>'.pun_trim($inside[$i], "\n\r").'</code></pre></div><p>';
 			}
 		}
 	}
 
 	// Add paragraph tag around post, but make sure there are no empty paragraphs
+	$text = preg_replace('#<br />\s*?<br />((\s*<br />)*)#i', "</p>$1<p>", $text);
+	$text = str_replace('<p><br />', '<p>', $text);
 	$text = str_replace('<p></p>', '', '<p>'.$text.'</p>');
 
 	return $text;
@@ -449,29 +841,25 @@ function parse_signature($text)
 	if ($pun_config['o_censoring'] == '1')
 		$text = censor_words($text);
 
+	// Convert applicable characters to HTML entities
 	$text = pun_htmlspecialchars($text);
 
-	if ($pun_config['o_make_links'] == '1')
-		$text = do_clickable($text);
+	if ($pun_config['p_sig_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
+		$text = do_bbcode($text, true);
 
-	if ($pun_config['o_smilies_sig'] == '1' && $pun_user['show_smilies'] != '0')
+	if ($pun_config['o_smilies_sig'] == '1' && $pun_user['show_smilies'] == '1')
 		$text = do_smilies($text);
 
-	if ($pun_config['p_sig_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
-	{
-		$text = do_bbcode($text);
-
-		if ($pun_config['p_sig_img_tag'] == '1')
-		{
-//			$text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\.(jpg|jpeg|png|gif)\[/img\]#e', 'handle_img_tag(\'$1$3.$4\', true)', $text);
-			$text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e', 'handle_img_tag(\'$1$3\', true)', $text);
-		}
-	}
 
 	// Deal with newlines, tabs and multiple spaces
 	$pattern = array("\n", "\t", '  ', '  ');
 	$replace = array('<br />', '&nbsp; &nbsp; ', '&nbsp; ', ' &nbsp;');
 	$text = str_replace($pattern, $replace, $text);
 
+	// Add paragraph tag around post, but make sure there are no empty paragraphs
+	$text = preg_replace('#<br />\s*?<br />((\s*<br />)*)#i', "</p>$1<p>", $text);
+	$text = str_replace('<p><br />', '<p>', $text);
+	$text = str_replace('<p></p>', '', '<p>'.$text.'</p>');
+
 	return $text;
 }
diff --git a/upload/include/search_idx.php b/upload/include/search_idx.php
index 1a9a24f..1214676 100644
--- a/upload/include/search_idx.php
+++ b/upload/include/search_idx.php
@@ -1,83 +1,153 @@
 <?php
-/***********************************************************************
 
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
-  This file is part of PunBB.
-
-  PunBB 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.
+// The contents of this file are very much inspired by the file functions_search.php
+// from the phpBB Group forum software phpBB2 (http://www.phpbb.com)
 
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
 
-************************************************************************/
 
+// Make a regex that will match CJK or Hangul characters
+define('PUN_CJK_HANGUL_REGEX', '['.
+	'\x{1100}-\x{11FF}'.		// Hangul Jamo							1100-11FF		(http://www.fileformat.info/info/unicode/block/hangul_jamo/index.htm)
+	'\x{3130}-\x{318F}'.		// Hangul Compatibility Jamo			3130-318F		(http://www.fileformat.info/info/unicode/block/hangul_compatibility_jamo/index.htm)
+	'\x{AC00}-\x{D7AF}'.		// Hangul Syllables						AC00-D7AF		(http://www.fileformat.info/info/unicode/block/hangul_syllables/index.htm)
 
-// The contents of this file are very much inspired by the file functions_search.php
-// from the phpBB Group forum software phpBB2 (http://www.phpbb.com). 
+	// Hiragana
+	'\x{3040}-\x{309F}'.		// Hiragana								3040-309F		(http://www.fileformat.info/info/unicode/block/hiragana/index.htm)
 
+	// Katakana
+	'\x{30A0}-\x{30FF}'.		// Katakana								30A0-30FF		(http://www.fileformat.info/info/unicode/block/katakana/index.htm)
+	'\x{31F0}-\x{31FF}'.		// Katakana Phonetic Extensions			31F0-31FF		(http://www.fileformat.info/info/unicode/block/katakana_phonetic_extensions/index.htm)
 
-// Make sure no one attempts to run this script "directly"
-if (!defined('PUN'))
-	exit;
+	// CJK Unified Ideographs	(http://en.wikipedia.org/wiki/CJK_Unified_Ideographs)
+	'\x{2E80}-\x{2EFF}'.		// CJK Radicals Supplement				2E80-2EFF		(http://www.fileformat.info/info/unicode/block/cjk_radicals_supplement/index.htm)
+	'\x{2F00}-\x{2FDF}'.		// Kangxi Radicals						2F00-2FDF		(http://www.fileformat.info/info/unicode/block/kangxi_radicals/index.htm)
+	'\x{2FF0}-\x{2FFF}'.		// Ideographic Description Characters	2FF0-2FFF		(http://www.fileformat.info/info/unicode/block/ideographic_description_characters/index.htm)
+	'\x{3000}-\x{303F}'.		// CJK Symbols and Punctuation			3000-303F		(http://www.fileformat.info/info/unicode/block/cjk_symbols_and_punctuation/index.htm)
+	'\x{31C0}-\x{31EF}'.		// CJK Strokes							31C0-31EF		(http://www.fileformat.info/info/unicode/block/cjk_strokes/index.htm)
+	'\x{3200}-\x{32FF}'.		// Enclosed CJK Letters and Months		3200-32FF		(http://www.fileformat.info/info/unicode/block/enclosed_cjk_letters_and_months/index.htm)
+	'\x{3400}-\x{4DBF}'.		// CJK Unified Ideographs Extension A	3400-4DBF		(http://www.fileformat.info/info/unicode/block/cjk_unified_ideographs_extension_a/index.htm)
+	'\x{4E00}-\x{9FFF}'.		// CJK Unified Ideographs				4E00-9FFF		(http://www.fileformat.info/info/unicode/block/cjk_unified_ideographs/index.htm)
+	'\x{20000}-\x{2A6DF}'.		// CJK Unified Ideographs Extension B	20000-2A6DF		(http://www.fileformat.info/info/unicode/block/cjk_unified_ideographs_extension_b/index.htm)
+']');
 
 
 //
 // "Cleans up" a text string and returns an array of unique words
 // This function depends on the current locale setting
 //
-function split_words($text)
+function split_words($text, $idx)
 {
-	global $pun_user;
-	static $noise_match, $noise_replace, $stopwords;
+	// Remove BBCode
+	$text = preg_replace('/\[\/?(b|u|i|h|colou?r|quote|code|img|url|email|list)(?:\=[^\]]*)?\]/', ' ', $text);
 
-	if (empty($noise_match))
-	{
-		$noise_match = 		array('[quote', '[code', '[url', '[img', '[email', '[color', '[colour', 'quote]', 'code]', 'url]', 'img]', 'email]', 'color]', 'colour]', '^', '$', '&', '(', ')', '<', '>', '`', '\'', '"', '|', ',', '@', '_', '?', '%', '~', '+', '[', ']', '{', '}', ':', '\\', '/', '=', '#', ';', '!', '*');
-		$noise_replace =	array('',       '',      '',     '',     '',       '',       '',        '',       '',      '',     '',     '',       '',       '',        ' ', ' ', ' ', ' ', ' ', ' ', ' ', '',  '',   ' ', ' ', ' ', ' ', '',  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '' ,  ' ', ' ', ' ', ' ', ' ', ' ');
+	// Remove any apostrophes or dashes which aren't part of words
+	$text = substr(preg_replace('/((?<=\W)[\'\-]|[\'\-](?=\W))/', '', ' '.$text.' '), 1, -1);
+
+	// Remove symbols and multiple whitespace
+	$text = preg_replace('/[\^\$&\(\)<>`"„\|,@_\?%~\+\[\]{}:=\/#\\\\;!\*\.…\s•]+/u', ' ', $text);
+
+	// Replace multiple dashes with just one
+	$text = preg_replace('/-{2,}/', '-', $text);
 
-		$stopwords = (array)@file(PUN_ROOT.'lang/'.$pun_user['language'].'/stopwords.txt');
-		$stopwords = array_map('trim', $stopwords);
+	// Fill an array with all the words
+	$words = array_unique(explode(' ', $text));
+
+	// Remove any words that should not be indexed
+	foreach ($words as $key => $value)
+	{
+		// If the word shouldn't be indexed, remove it
+		if (!validate_search_word($value, $idx))
+			unset($words[$key]);
 	}
 
-	// Clean up
-	$patterns[] = '#&[\#a-z0-9]+?;#i';
-	$patterns[] = '#\b[\w]+:\/\/[a-z0-9\.\-]+(\/[a-z0-9\?\.%_\-\+=&\/~]+)?#';
-	$patterns[] = '#\[\/?[a-z\*=\+\-]+(\:?[0-9a-z]+)?:[a-z0-9]{10,}(\:[a-z0-9]+)?=?.*?\]#';
-	$text = preg_replace($patterns, ' ', ' '.strtolower($text).' ');
+	return $words;
+}
 
-	// Filter out junk
-	$text = str_replace($noise_match, $noise_replace, $text);
 
-	// Strip out extra whitespace between words
-	$text = trim(preg_replace('#\s+#', ' ', $text));
+//
+// Checks if a word is a valid searchable word
+//
+function validate_search_word($word, $idx)
+{
+	global $pun_user, $pun_config;
+	static $stopwords;
 
-	// Fill an array with all the words
-	$words = explode(' ', $text);
+	// If the word is a keyword we don't want to index it, but we do want to be allowed to search it
+	if (is_keyword($word))
+		return !$idx;
 
-	if (!empty($words))
+	$language = isset($pun_user['language']) ? $pun_user['language'] : $pun_config['o_default_lang'];
+	if (!isset($stopwords))
 	{
-		while (list($i, $word) = @each($words))
+		if (file_exists(PUN_ROOT.'lang/'.$language.'/stopwords.txt'))
 		{
-			$words[$i] = trim($word, '.');
-			$num_chars = pun_strlen($word);
-
-			if ($num_chars < 3 || $num_chars > 20 || in_array($word, $stopwords))
-				unset($words[$i]);
+			$stopwords = file(PUN_ROOT.'lang/'.$language.'/stopwords.txt');
+			$stopwords = array_map('pun_trim', $stopwords);
+			$stopwords = array_filter($stopwords);
 		}
+		else
+			$stopwords = array();
 	}
 
-	return array_unique($words);
+	// If it is a stopword it isn't valid
+	if (in_array($word, $stopwords))
+		return false;
+
+	// If the word if CJK we don't want to index it, but we do want to be allowed to search it
+	if (is_cjk($word))
+		return !$idx;
+
+	// Check the word is within the min/max length
+	$num_chars = pun_strlen($word);
+	return $num_chars >= PUN_SEARCH_MIN_WORD && $num_chars <= PUN_SEARCH_MAX_WORD;
+}
+
+
+//
+// Check a given word is a search keyword.
+//
+function is_keyword($word)
+{
+	return $word == 'and' || $word == 'or' || $word == 'not';
+}
+
+
+//
+// Check if a given word is CJK or Hangul.
+//
+function is_cjk($word)
+{
+	return preg_match('/^'.PUN_CJK_HANGUL_REGEX.'+$/u', $word) ? true : false;
+}
+
+
+//
+// Strip [img] [url] and [email] out of the message so we don't index their contents
+//
+function strip_bbcode($text)
+{
+	static $patterns;
+
+	if (!isset($patterns))
+	{
+		$patterns = array(
+			'%\[img=([^\]]*+)\][^[]*+\[/img\]%'									=>	'$1',	// Keep the alt description
+			'%\[(url|email)=[^\]]*+\]([^[]*+(?:(?!\[/\1\])\[[^[]*+)*)\[/\1\]%' =>	'$2',	// Keep the text
+			'%\[(img|url|email)\]([^[]*+(?:(?!\[/\1\])\[[^[]*+)*)\[/\1\]%'		=>	'',		// Remove the whole thing
+		);
+	}
+
+	return preg_replace(array_keys($patterns), array_values($patterns), $text);
 }
 
 
@@ -88,9 +158,15 @@ function update_search_index($mode, $post_id, $message, $subject = null)
 {
 	global $db_type, $db;
 
+	$message = utf8_strtolower($message);
+	$subject = utf8_strtolower($subject);
+
+	// Remove any bbcode that we shouldn't index
+	$message = strip_bbcode($message);
+
 	// Split old and new post/subject to obtain array of 'words'
-	$words_message = split_words($message);
-	$words_subject = ($subject) ? split_words($subject) : array();
+	$words_message = split_words($message, true);
+	$words_subject = ($subject) ? split_words($subject, true) : array();
 
 	if ($mode == 'edit')
 	{
@@ -129,7 +205,7 @@ function update_search_index($mode, $post_id, $message, $subject = null)
 
 	if (!empty($unique_words))
 	{
-		$result = $db->query('SELECT id, word FROM '.$db->prefix.'search_words WHERE word IN('.implode(',', preg_replace('#^(.*)$#', '\'\1\'', $unique_words)).')', true) or error('Unable to fetch search index words', __FILE__, __LINE__, $db->error());
+		$result = $db->query('SELECT id, word FROM '.$db->prefix.'search_words WHERE word IN(\''.implode('\',\'', array_map(array($db, 'escape'), $unique_words)).'\')', true) or error('Unable to fetch search index words', __FILE__, __LINE__, $db->error());
 
 		$word_ids = array();
 		while ($row = $db->fetch_row($result))
@@ -148,12 +224,12 @@ function update_search_index($mode, $post_id, $message, $subject = null)
 				case 'mysqli':
 				case 'mysql_innodb':
 				case 'mysqli_innodb':
-					$db->query('INSERT INTO '.$db->prefix.'search_words (word) VALUES'.implode(',', preg_replace('#^(.*)$#', '(\'\1\')', $new_words))) or error('Unable to insert search index words', __FILE__, __LINE__, $db->error());
+					$db->query('INSERT INTO '.$db->prefix.'search_words (word) VALUES(\''.implode('\'),(\'', array_map(array($db, 'escape'), $new_words)).'\')');
 					break;
 
 				default:
-					while (list(, $word) = @each($new_words))
-						$db->query('INSERT INTO '.$db->prefix.'search_words (word) VALUES(\''.$word.'\')') or error('Unable to insert search index words', __FILE__, __LINE__, $db->error());
+					foreach ($new_words as $word)
+						$db->query('INSERT INTO '.$db->prefix.'search_words (word) VALUES(\''.$db->escape($word).'\')');
 					break;
 			}
 		}
@@ -162,14 +238,14 @@ function update_search_index($mode, $post_id, $message, $subject = null)
 	}
 
 	// Delete matches (only if editing a post)
-	while (list($match_in, $wordlist) = @each($words['del']))
+	foreach ($words['del'] as $match_in => $wordlist)
 	{
 		$subject_match = ($match_in == 'subject') ? 1 : 0;
 
 		if (!empty($wordlist))
 		{
 			$sql = '';
-			while (list(, $word) = @each($wordlist))
+			foreach ($wordlist as $word)
 				$sql .= (($sql != '') ? ',' : '').$cur_words[$match_in][$word];
 
 			$db->query('DELETE FROM '.$db->prefix.'search_matches WHERE word_id IN('.$sql.') AND post_id='.$post_id.' AND subject_match='.$subject_match) or error('Unable to delete search index word matches', __FILE__, __LINE__, $db->error());
@@ -177,12 +253,12 @@ function update_search_index($mode, $post_id, $message, $subject = null)
 	}
 
 	// Add new matches
-	while (list($match_in, $wordlist) = @each($words['add']))
+	foreach ($words['add'] as $match_in => $wordlist)
 	{
 		$subject_match = ($match_in == 'subject') ? 1 : 0;
 
 		if (!empty($wordlist))
-			$db->query('INSERT INTO '.$db->prefix.'search_matches (post_id, word_id, subject_match) SELECT '.$post_id.', id, '.$subject_match.' FROM '.$db->prefix.'search_words WHERE word IN('.implode(',', preg_replace('#^(.*)$#', '\'\1\'', $wordlist)).')') or error('Unable to insert search index word matches', __FILE__, __LINE__, $db->error());
+			$db->query('INSERT INTO '.$db->prefix.'search_matches (post_id, word_id, subject_match) SELECT '.$post_id.', id, '.$subject_match.' FROM '.$db->prefix.'search_words WHERE word IN(\''.implode('\',\'', array_map(array($db, 'escape'), $wordlist)).'\')') or error('Unable to insert search index word matches', __FILE__, __LINE__, $db->error());
 	}
 
 	unset($words);
diff --git a/upload/include/template/admin.tpl b/upload/include/template/admin.tpl
index 4233bf2..1f6e007 100644
--- a/upload/include/template/admin.tpl
+++ b/upload/include/template/admin.tpl
@@ -1,15 +1,17 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<pun_language>" lang="<pun_language>" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <pun_head>
 </head>
+
 <body>
 
 <div id="punwrap">
 <div id="punadmin" class="pun">
 
+<div class="top-box"><div><!-- Top Corners --></div></div>
+
 <div id="brdheader" class="block">
 	<div class="box">
 		<div id="brdtitle" class="inbox">
@@ -23,10 +25,14 @@
 
 <pun_announcement>
 
+<div id="brdmain">
 <pun_main>
+</div>
 
 <pun_footer>
 
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+
 </div>
 </div>
 
diff --git a/upload/include/template/help.tpl b/upload/include/template/help.tpl
index c059979..533d0a0 100644
--- a/upload/include/template/help.tpl
+++ b/upload/include/template/help.tpl
@@ -1,16 +1,22 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<pun_language>" lang="<pun_language>" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <pun_head>
 </head>
+
 <body>
 
 <div id="punwrap">
 <div id="helpfile" class="pun">
 
+<div class="top-box"><div><!-- Top Corners --></div></div>
+
+<div id="brdmain">
 <pun_main>
+</div>
+
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
 
 </div>
 </div>
diff --git a/upload/include/template/index.html b/upload/include/template/index.html
index 2db9a3c..89337b2 100644
--- a/upload/include/template/index.html
+++ b/upload/include/template/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/include/template/main.tpl b/upload/include/template/main.tpl
index 33f25c9..f069193 100644
--- a/upload/include/template/main.tpl
+++ b/upload/include/template/main.tpl
@@ -1,15 +1,17 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<pun_language>" lang="<pun_language>" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <pun_head>
 </head>
+
 <body>
 
 <div id="punwrap">
 <div id="pun<pun_page>" class="pun">
 
+<div class="top-box"><div><!-- Top Corners --></div></div>
+
 <div id="brdheader" class="block">
 	<div class="box">
 		<div id="brdtitle" class="inbox">
@@ -23,10 +25,14 @@
 
 <pun_announcement>
 
+<div id="brdmain">
 <pun_main>
+</div>
 
 <pun_footer>
 
+<div class="end-box"><div><!-- Bottom corners --></div></div>
+
 </div>
 </div>
 
diff --git a/upload/include/template/maintenance.tpl b/upload/include/template/maintenance.tpl
index 6224b93..0588caa 100644
--- a/upload/include/template/maintenance.tpl
+++ b/upload/include/template/maintenance.tpl
@@ -1,24 +1,23 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<pun_language>" lang="<pun_language>" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <pun_head>
 </head>
+
 <body>
 
 <div id="punwrap">
 <div id="punmaint" class="pun">
 
-<div class="block">
-	<h2><pun_maint_heading></h2>
-	<div class="box">
-		<div class="inbox">
-			<p><pun_maint_message></p>
-		</div>
-	</div>
+<div class="top-box"><div><!-- Top Corners --></div></div>
+
+<div id="brdmain">
+<pun_maint_main>
 </div>
 
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+
 </div>
 </div>
 
diff --git a/upload/include/template/redirect.tpl b/upload/include/template/redirect.tpl
index 85b8380..edefa63 100644
--- a/upload/include/template/redirect.tpl
+++ b/upload/include/template/redirect.tpl
@@ -1,26 +1,25 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<pun_language>" lang="<pun_language>" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <pun_head>
 </head>
+
 <body>
 
 <div id="punwrap">
 <div id="punredirect" class="pun">
 
-<div class="block">
-	<h2><pun_redir_heading></h2>
-	<div class="box">
-		<div class="inbox">
-			<p><pun_redir_text></p>
-		</div>
-	</div>
+<div class="top-box"><div><!-- Top Corners --></div></div>
+
+<div id="brdmain">
+<pun_redir_main>
 </div>
 
 <pun_footer>
 
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+
 </div>
 </div>
 
diff --git a/upload/include/utf8/index.html b/upload/include/utf8/index.html
index 2db9a3c..89337b2 100644
--- a/upload/include/utf8/index.html
+++ b/upload/include/utf8/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/include/utf8/mbstring/core.php b/upload/include/utf8/mbstring/core.php
index 3541ee0..bea1c32 100644
--- a/upload/include/utf8/mbstring/core.php
+++ b/upload/include/utf8/mbstring/core.php
@@ -1,18 +1,15 @@
 <?php
+
 /**
 * @version $Id: core.php,v 1.5 2006/02/28 22:12:25 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-/**
-* Define UTF8_CORE as required
-*/
-if ( !defined('UTF8_CORE') ) {
-    define('UTF8_CORE',TRUE);
-}
+// Define UTF8_CORE as required
+if (!defined('UTF8_CORE'))
+	define('UTF8_CORE', true);
 
-//--------------------------------------------------------------------
 /**
 * Wrapper round mb_strlen
 * Assumes you have mb_internal_encoding to UTF-8 already
@@ -23,12 +20,11 @@ if ( !defined('UTF8_CORE') ) {
 * @package utf8
 * @subpackage strings
 */
-function utf8_strlen($str){
-    return mb_strlen($str);
+function utf8_strlen($str)
+{
+	return mb_strlen($str);
 }
 
-
-//--------------------------------------------------------------------
 /**
 * Assumes mbstring internal encoding is set to UTF-8
 * Wrapper around mb_strpos
@@ -40,15 +36,17 @@ function utf8_strlen($str){
 * @package utf8
 * @subpackage strings
 */
-function utf8_strpos($str, $search, $offset = FALSE){
-    if ( $offset === FALSE ) {
-        return mb_strpos($str, $search);
-    } else {
-        return mb_strpos($str, $search, $offset);
-    }
+function utf8_strpos($str, $search, $offset = false)
+{
+	// Strip unvalid characters
+	$str = utf8_bad_strip($str);
+
+	if ($offset === false)
+		return mb_strpos($str, $search);
+	else
+		return mb_strpos($str, $search, $offset);
 }
 
-//--------------------------------------------------------------------
 /**
 * Assumes mbstring internal encoding is set to UTF-8
 * Wrapper around mb_strrpos
@@ -60,30 +58,36 @@ function utf8_strpos($str, $search, $offset = FALSE){
 * @package utf8
 * @subpackage strings
 */
-function utf8_strrpos($str, $search, $offset = FALSE){
-    if ( $offset === FALSE ) {
-        # Emulate behaviour of strrpos rather than raising warning
-        if ( empty($str) ) {
-            return FALSE;
-        }
-        return mb_strrpos($str, $search);
-    } else {
-        if ( !is_int($offset) ) {
-            trigger_error('utf8_strrpos expects parameter 3 to be long',E_USER_WARNING);
-            return FALSE;
-        }
-        
-        $str = mb_substr($str, $offset);
-        
-        if ( FALSE !== ( $pos = mb_strrpos($str, $search) ) ) {
-            return $pos + $offset;
-        }
-        
-        return FALSE;
-    }
+function utf8_strrpos($str, $search, $offset = false)
+{
+	// Strip unvalid characters
+	$str = utf8_bad_strip($str);
+
+	if (!$offset)
+	{
+		// Emulate behaviour of strrpos rather than raising warning
+		if (empty($str))
+			return false;
+
+		return mb_strrpos($str, $search);
+	}
+	else
+	{
+		if (!is_int($offset))
+		{
+			trigger_error('utf8_strrpos expects parameter 3 to be long', E_USER_WARNING);
+			return false;
+		}
+
+		$str = mb_substr($str, $offset);
+
+		if (($pos = mb_strrpos($str, $search)) !== false)
+			return $pos + $offset;
+
+		return false;
+	}
 }
 
-//--------------------------------------------------------------------
 /**
 * Assumes mbstring internal encoding is set to UTF-8
 * Wrapper around mb_substr
@@ -95,15 +99,14 @@ function utf8_strrpos($str, $search, $offset = FALSE){
 * @package utf8
 * @subpackage strings
 */
-function utf8_substr($str, $offset, $length = FALSE){
-    if ( $length === FALSE ) {
-        return mb_substr($str, $offset);
-    } else {
-        return mb_substr($str, $offset, $length);
-    }
+function utf8_substr($str, $offset, $length = false)
+{
+	if ($length === false)
+		return mb_substr($str, $offset);
+	else
+		return mb_substr($str, $offset, $length);
 }
 
-//--------------------------------------------------------------------
 /**
 * Assumes mbstring internal encoding is set to UTF-8
 * Wrapper around mb_strtolower
@@ -117,11 +120,11 @@ function utf8_substr($str, $offset, $length = FALSE){
 * @package utf8
 * @subpackage strings
 */
-function utf8_strtolower($str){
-    return mb_strtolower($str);
+function utf8_strtolower($str)
+{
+	return mb_strtolower($str);
 }
 
-//--------------------------------------------------------------------
 /**
 * Assumes mbstring internal encoding is set to UTF-8
 * Wrapper around mb_strtoupper
@@ -135,6 +138,7 @@ function utf8_strtolower($str){
 * @package utf8
 * @subpackage strings
 */
-function utf8_strtoupper($str){
-    return mb_strtoupper($str);
+function utf8_strtoupper($str)
+{
+	return mb_strtoupper($str);
 }
diff --git a/upload/include/utf8/mbstring/index.html b/upload/include/utf8/mbstring/index.html
index 2db9a3c..89337b2 100644
--- a/upload/include/utf8/mbstring/index.html
+++ b/upload/include/utf8/mbstring/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/include/utf8/native/core.php b/upload/include/utf8/native/core.php
index 5a2f8ec..58636f5 100644
--- a/upload/include/utf8/native/core.php
+++ b/upload/include/utf8/native/core.php
@@ -1,18 +1,15 @@
 <?php
+
 /**
 * @version $Id: core.php,v 1.9 2007/08/12 01:11:33 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-/**
-* Define UTF8_CORE as required
-*/
-if ( !defined('UTF8_CORE') ) {
-    define('UTF8_CORE',TRUE);
-}
+// Define UTF8_CORE as required
+if (!defined('UTF8_CORE'))
+	define('UTF8_CORE', true);
 
-//--------------------------------------------------------------------
 /**
 * Unicode aware replacement for strlen(). Returns the number
 * of characters in the string (not the number of bytes), replacing
@@ -30,12 +27,11 @@ if ( !defined('UTF8_CORE') ) {
 * @package utf8
 * @subpackage strings
 */
-function utf8_strlen($str){
-    return strlen(utf8_decode($str));
+function utf8_strlen($str)
+{
+	return strlen(utf8_decode($str));
 }
 
-
-//--------------------------------------------------------------------
 /**
 * UTF-8 aware alternative to strpos
 * Find position of first occurrence of a string
@@ -51,35 +47,34 @@ function utf8_strlen($str){
 * @package utf8
 * @subpackage strings
 */
-function utf8_strpos($str, $needle, $offset = NULL) {
-    
-    if ( is_null($offset) ) {
-    
-        $ar = explode($needle, $str, 2);
-        if ( count($ar) > 1 ) {
-            return utf8_strlen($ar[0]);
-        }
-        return FALSE;
-        
-    } else {
-        
-        if ( !is_int($offset) ) {
-            trigger_error('utf8_strpos: Offset must be an integer',E_USER_ERROR);
-            return FALSE;
-        }
-        
-        $str = utf8_substr($str, $offset);
-        
-        if ( FALSE !== ( $pos = utf8_strpos($str, $needle) ) ) {
-            return $pos + $offset;
-        }
-        
-        return FALSE;
-    }
-    
+function utf8_strpos($str, $needle, $offset = false)
+{
+	if ($offset === false)
+	{
+		$ar = explode($needle, $str, 2);
+
+		if (count($ar) > 1)
+			return utf8_strlen($ar[0]);
+
+		return false;
+	}
+	else
+	{
+		if (!is_int($offset))
+		{
+			trigger_error('utf8_strpos: Offset must be an integer', E_USER_ERROR);
+			return false;
+		}
+
+		$str = utf8_substr($str, $offset);
+
+		if (($pos = utf8_strpos($str, $needle)) !== false)
+			return $pos + $offset;
+
+		return false;
+	}
 }
 
-//--------------------------------------------------------------------
 /**
 * UTF-8 aware alternative to strrpos
 * Find position of last occurrence of a char in a string
@@ -95,39 +90,40 @@ function utf8_strpos($str, $needle, $offset = NULL) {
 * @package utf8
 * @subpackage strings
 */
-function utf8_strrpos($str, $needle, $offset = NULL) {
-    
-    if ( is_null($offset) ) {
-    
-        $ar = explode($needle, $str);
-        
-        if ( count($ar) > 1 ) {
-            // Pop off the end of the string where the last match was made
-            array_pop($ar);
-            $str = join($needle,$ar);
-            return utf8_strlen($str);
-        }
-        return FALSE;
-        
-    } else {
-        
-        if ( !is_int($offset) ) {
-            trigger_error('utf8_strrpos expects parameter 3 to be long',E_USER_WARNING);
-            return FALSE;
-        }
-        
-        $str = utf8_substr($str, $offset);
-        
-        if ( FALSE !== ( $pos = utf8_strrpos($str, $needle) ) ) {
-            return $pos + $offset;
-        }
-        
-        return FALSE;
-    }
-    
+function utf8_strrpos($str, $needle, $offset = false)
+{
+	if ($offset === false)
+	{
+		$ar = explode($needle, $str);
+
+		if (count($ar) > 1)
+		{
+			// Pop off the end of the string where the last match was made
+			array_pop($ar);
+			$str = join($needle, $ar);
+
+			return utf8_strlen($str);
+		}
+
+		return false;
+	}
+	else
+	{
+		if (!is_int($offset))
+		{
+			trigger_error('utf8_strrpos expects parameter 3 to be long', E_USER_WARNING);
+			return false;
+		}
+
+		$str = utf8_substr($str, $offset);
+
+		if (($pos = utf8_strrpos($str, $needle)) !== false)
+			return $pos + $offset;
+
+		return false;
+	}
 }
 
-//--------------------------------------------------------------------
 /**
 * UTF-8 aware alternative to substr
 * Return part of a string given character offset (and optionally length)
@@ -157,111 +153,104 @@ function utf8_strrpos($str, $needle, $offset = NULL) {
 * @package utf8
 * @subpackage strings
 */
-function utf8_substr($str, $offset, $length = NULL) {
-    
-    // generates E_NOTICE
-    // for PHP4 objects, but not PHP5 objects
-    $str = (string)$str;
-    $offset = (int)$offset;
-    if (!is_null($length)) $length = (int)$length;
-    
-    // handle trivial cases
-    if ($length === 0) return '';
-    if ($offset < 0 && $length < 0 && $length < $offset)
-        return '';
-    
-    // normalise negative offsets (we could use a tail
-    // anchored pattern, but they are horribly slow!)
-    if ($offset < 0) {
-        
-        // see notes
-        $strlen = strlen(utf8_decode($str));
-        $offset = $strlen + $offset;
-        if ($offset < 0) $offset = 0;
-        
-    }
-    
-    $Op = '';
-    $Lp = '';
-    
-    // establish a pattern for offset, a
-    // non-captured group equal in length to offset
-    if ($offset > 0) {
-        
-        $Ox = (int)($offset/65535);
-        $Oy = $offset%65535;
-        
-        if ($Ox) {
-            $Op = '(?:.{65535}){'.$Ox.'}';
-        }
-        
-        $Op = '^(?:'.$Op.'.{'.$Oy.'})';
-        
-    } else {
-        
-        // offset == 0; just anchor the pattern
-        $Op = '^';
-        
-    }
-    
-    // establish a pattern for length
-    if (is_null($length)) {
-        
-        // the rest of the string
-        $Lp = '(.*)$';
-        
-    } else {
-        
-        if (!isset($strlen)) {
-            // see notes
-            $strlen = strlen(utf8_decode($str));
-        }
-        
-        // another trivial case
-        if ($offset > $strlen) return '';
-        
-        if ($length > 0) {
-            
-            // reduce any length that would
-            // go passed the end of the string
-            $length = min($strlen-$offset, $length);
-            
-            $Lx = (int)( $length / 65535 );
-            $Ly = $length % 65535;
-            
-            // negative length requires a captured group
-            // of length characters
-            if ($Lx) $Lp = '(?:.{65535}){'.$Lx.'}';
-            $Lp = '('.$Lp.'.{'.$Ly.'})';
-            
-        } else if ($length < 0) {
-            
-            if ( $length < ($offset - $strlen) ) {
-                return '';
-            }
-            
-            $Lx = (int)((-$length)/65535);
-            $Ly = (-$length)%65535;
-            
-            // negative length requires ... capture everything
-            // except a group of  -length characters
-            // anchored at the tail-end of the string
-            if ($Lx) $Lp = '(?:.{65535}){'.$Lx.'}';
-            $Lp = '(.*)(?:'.$Lp.'.{'.$Ly.'})$';
-            
-        }
-        
-    }
-    
-    if (!preg_match( '#'.$Op.$Lp.'#us',$str, $match )) {
-        return '';
-    }
-    
-    return $match[1];
-    
+function utf8_substr($str, $offset, $length = false)
+{
+	// Generates E_NOTICE for PHP4 objects, but not PHP5 objects
+	$str = (string) $str;
+	$offset = (int) $offset;
+
+	if ($length)
+		$length = (int) $length;
+
+	// Handle trivial cases
+	if ($length === 0)
+		return '';
+	if ($offset < 0 && $length < 0 && $length < $offset)
+		return '';
+
+	// Normalise negative offsets (we could use a tail
+	// anchored pattern, but they are horribly slow!)
+	if ($offset < 0)
+	{
+		// See notes
+		$strlen = utf8_strlen($str);
+		$offset = $strlen + $offset;
+
+		if ($offset < 0)
+			$offset = 0;
+	}
+
+	$Op = '';
+	$Lp = '';
+
+	// Establish a pattern for offset, a
+	// non-captured group equal in length to offset
+	if ($offset > 0)
+	{
+		$Ox = (int) ($offset / 65535);
+		$Oy = $offset % 65535;
+
+		if ($Ox)
+			$Op = '(?:.{65535}){'.$Ox.'}';
+
+		$Op = '^(?:'.$Op.'.{'.$Oy.'})';
+	}
+	else
+		$Op = '^';
+
+
+	// Establish a pattern for length
+	if (!$length)
+	{
+		// The rest of the string
+		$Lp = '(.*)$';
+	}
+	else
+	{
+		// See notes
+		if (!isset($strlen))
+			$strlen = strlen(utf8_decode($str));
+
+		// Another trivial case
+		if ($offset > $strlen)
+			return '';
+
+		if ($length > 0)
+		{
+			// Reduce any length that would go passed the end of the string
+			$length = min($strlen-$offset, $length);
+
+			$Lx = (int)( $length / 65535 );
+			$Ly = $length % 65535;
+
+			// Negative length requires a captured group of length characters
+			if ($Lx) $Lp = '(?:.{65535}){'.$Lx.'}';
+			$Lp = '('.$Lp.'.{'.$Ly.'})';
+		}
+		else if ($length < 0)
+		{
+
+			if ($length < ($offset - $strlen))
+				return '';
+
+			$Lx = (int)((-$length)/65535);
+			$Ly = (-$length)%65535;
+
+			// Negative length requires ... capture everything except a group of
+			// -length characters anchored at the tail-end of the string
+			if ($Lx)
+				$Lp = '(?:.{65535}){'.$Lx.'}';
+
+			$Lp = '(.*)(?:'.$Lp.'.{'.$Ly.'})$';
+		}
+	}
+
+	if (!preg_match('#'.$Op.$Lp.'#us', $str, $match))
+		return '';
+
+	return $match[1];
 }
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to strtolower
 * Make a string lowercase
@@ -281,75 +270,72 @@ function utf8_substr($str, $offset, $length = NULL) {
 * @package utf8
 * @subpackage strings
 */
-function utf8_strtolower($string){
-    
-    static $UTF8_UPPER_TO_LOWER = NULL;
-    
-    if ( is_null($UTF8_UPPER_TO_LOWER) ) {
-        $UTF8_UPPER_TO_LOWER = array(
-    0x0041=>0x0061, 0x03A6=>0x03C6, 0x0162=>0x0163, 0x00C5=>0x00E5, 0x0042=>0x0062,
-    0x0139=>0x013A, 0x00C1=>0x00E1, 0x0141=>0x0142, 0x038E=>0x03CD, 0x0100=>0x0101,
-    0x0490=>0x0491, 0x0394=>0x03B4, 0x015A=>0x015B, 0x0044=>0x0064, 0x0393=>0x03B3,
-    0x00D4=>0x00F4, 0x042A=>0x044A, 0x0419=>0x0439, 0x0112=>0x0113, 0x041C=>0x043C,
-    0x015E=>0x015F, 0x0143=>0x0144, 0x00CE=>0x00EE, 0x040E=>0x045E, 0x042F=>0x044F,
-    0x039A=>0x03BA, 0x0154=>0x0155, 0x0049=>0x0069, 0x0053=>0x0073, 0x1E1E=>0x1E1F,
-    0x0134=>0x0135, 0x0427=>0x0447, 0x03A0=>0x03C0, 0x0418=>0x0438, 0x00D3=>0x00F3,
-    0x0420=>0x0440, 0x0404=>0x0454, 0x0415=>0x0435, 0x0429=>0x0449, 0x014A=>0x014B,
-    0x0411=>0x0431, 0x0409=>0x0459, 0x1E02=>0x1E03, 0x00D6=>0x00F6, 0x00D9=>0x00F9,
-    0x004E=>0x006E, 0x0401=>0x0451, 0x03A4=>0x03C4, 0x0423=>0x0443, 0x015C=>0x015D,
-    0x0403=>0x0453, 0x03A8=>0x03C8, 0x0158=>0x0159, 0x0047=>0x0067, 0x00C4=>0x00E4,
-    0x0386=>0x03AC, 0x0389=>0x03AE, 0x0166=>0x0167, 0x039E=>0x03BE, 0x0164=>0x0165,
-    0x0116=>0x0117, 0x0108=>0x0109, 0x0056=>0x0076, 0x00DE=>0x00FE, 0x0156=>0x0157,
-    0x00DA=>0x00FA, 0x1E60=>0x1E61, 0x1E82=>0x1E83, 0x00C2=>0x00E2, 0x0118=>0x0119,
-    0x0145=>0x0146, 0x0050=>0x0070, 0x0150=>0x0151, 0x042E=>0x044E, 0x0128=>0x0129,
-    0x03A7=>0x03C7, 0x013D=>0x013E, 0x0422=>0x0442, 0x005A=>0x007A, 0x0428=>0x0448,
-    0x03A1=>0x03C1, 0x1E80=>0x1E81, 0x016C=>0x016D, 0x00D5=>0x00F5, 0x0055=>0x0075,
-    0x0176=>0x0177, 0x00DC=>0x00FC, 0x1E56=>0x1E57, 0x03A3=>0x03C3, 0x041A=>0x043A,
-    0x004D=>0x006D, 0x016A=>0x016B, 0x0170=>0x0171, 0x0424=>0x0444, 0x00CC=>0x00EC,
-    0x0168=>0x0169, 0x039F=>0x03BF, 0x004B=>0x006B, 0x00D2=>0x00F2, 0x00C0=>0x00E0,
-    0x0414=>0x0434, 0x03A9=>0x03C9, 0x1E6A=>0x1E6B, 0x00C3=>0x00E3, 0x042D=>0x044D,
-    0x0416=>0x0436, 0x01A0=>0x01A1, 0x010C=>0x010D, 0x011C=>0x011D, 0x00D0=>0x00F0,
-    0x013B=>0x013C, 0x040F=>0x045F, 0x040A=>0x045A, 0x00C8=>0x00E8, 0x03A5=>0x03C5,
-    0x0046=>0x0066, 0x00DD=>0x00FD, 0x0043=>0x0063, 0x021A=>0x021B, 0x00CA=>0x00EA,
-    0x0399=>0x03B9, 0x0179=>0x017A, 0x00CF=>0x00EF, 0x01AF=>0x01B0, 0x0045=>0x0065,
-    0x039B=>0x03BB, 0x0398=>0x03B8, 0x039C=>0x03BC, 0x040C=>0x045C, 0x041F=>0x043F,
-    0x042C=>0x044C, 0x00DE=>0x00FE, 0x00D0=>0x00F0, 0x1EF2=>0x1EF3, 0x0048=>0x0068,
-    0x00CB=>0x00EB, 0x0110=>0x0111, 0x0413=>0x0433, 0x012E=>0x012F, 0x00C6=>0x00E6,
-    0x0058=>0x0078, 0x0160=>0x0161, 0x016E=>0x016F, 0x0391=>0x03B1, 0x0407=>0x0457,
-    0x0172=>0x0173, 0x0178=>0x00FF, 0x004F=>0x006F, 0x041B=>0x043B, 0x0395=>0x03B5,
-    0x0425=>0x0445, 0x0120=>0x0121, 0x017D=>0x017E, 0x017B=>0x017C, 0x0396=>0x03B6,
-    0x0392=>0x03B2, 0x0388=>0x03AD, 0x1E84=>0x1E85, 0x0174=>0x0175, 0x0051=>0x0071,
-    0x0417=>0x0437, 0x1E0A=>0x1E0B, 0x0147=>0x0148, 0x0104=>0x0105, 0x0408=>0x0458,
-    0x014C=>0x014D, 0x00CD=>0x00ED, 0x0059=>0x0079, 0x010A=>0x010B, 0x038F=>0x03CE,
-    0x0052=>0x0072, 0x0410=>0x0430, 0x0405=>0x0455, 0x0402=>0x0452, 0x0126=>0x0127,
-    0x0136=>0x0137, 0x012A=>0x012B, 0x038A=>0x03AF, 0x042B=>0x044B, 0x004C=>0x006C,
-    0x0397=>0x03B7, 0x0124=>0x0125, 0x0218=>0x0219, 0x00DB=>0x00FB, 0x011E=>0x011F,
-    0x041E=>0x043E, 0x1E40=>0x1E41, 0x039D=>0x03BD, 0x0106=>0x0107, 0x03AB=>0x03CB,
-    0x0426=>0x0446, 0x00DE=>0x00FE, 0x00C7=>0x00E7, 0x03AA=>0x03CA, 0x0421=>0x0441,
-    0x0412=>0x0432, 0x010E=>0x010F, 0x00D8=>0x00F8, 0x0057=>0x0077, 0x011A=>0x011B,
-    0x0054=>0x0074, 0x004A=>0x006A, 0x040B=>0x045B, 0x0406=>0x0456, 0x0102=>0x0103,
-    0x039B=>0x03BB, 0x00D1=>0x00F1, 0x041D=>0x043D, 0x038C=>0x03CC, 0x00C9=>0x00E9,
-    0x00D0=>0x00F0, 0x0407=>0x0457, 0x0122=>0x0123,
-            );
-    }
-    
-    $uni = utf8_to_unicode($string);
-    
-    if ( !$uni ) {
-        return FALSE;
-    }
-    
-    $cnt = count($uni);
-    for ($i=0; $i < $cnt; $i++){
-        if ( isset($UTF8_UPPER_TO_LOWER[$uni[$i]]) ) {
-            $uni[$i] = $UTF8_UPPER_TO_LOWER[$uni[$i]];
-        }
-    }
-    
-    return utf8_from_unicode($uni);
+function utf8_strtolower($string)
+{
+	static $UTF8_UPPER_TO_LOWER = false;
+
+	if (!$UTF8_UPPER_TO_LOWER)
+	{
+		$UTF8_UPPER_TO_LOWER = array(
+			0x0041=>0x0061, 0x03A6=>0x03C6, 0x0162=>0x0163, 0x00C5=>0x00E5, 0x0042=>0x0062,
+			0x0139=>0x013A, 0x00C1=>0x00E1, 0x0141=>0x0142, 0x038E=>0x03CD, 0x0100=>0x0101,
+			0x0490=>0x0491, 0x0394=>0x03B4, 0x015A=>0x015B, 0x0044=>0x0064, 0x0393=>0x03B3,
+			0x00D4=>0x00F4, 0x042A=>0x044A, 0x0419=>0x0439, 0x0112=>0x0113, 0x041C=>0x043C,
+			0x015E=>0x015F, 0x0143=>0x0144, 0x00CE=>0x00EE, 0x040E=>0x045E, 0x042F=>0x044F,
+			0x039A=>0x03BA, 0x0154=>0x0155, 0x0049=>0x0069, 0x0053=>0x0073, 0x1E1E=>0x1E1F,
+			0x0134=>0x0135, 0x0427=>0x0447, 0x03A0=>0x03C0, 0x0418=>0x0438, 0x00D3=>0x00F3,
+			0x0420=>0x0440, 0x0404=>0x0454, 0x0415=>0x0435, 0x0429=>0x0449, 0x014A=>0x014B,
+			0x0411=>0x0431, 0x0409=>0x0459, 0x1E02=>0x1E03, 0x00D6=>0x00F6, 0x00D9=>0x00F9,
+			0x004E=>0x006E, 0x0401=>0x0451, 0x03A4=>0x03C4, 0x0423=>0x0443, 0x015C=>0x015D,
+			0x0403=>0x0453, 0x03A8=>0x03C8, 0x0158=>0x0159, 0x0047=>0x0067, 0x00C4=>0x00E4,
+			0x0386=>0x03AC, 0x0389=>0x03AE, 0x0166=>0x0167, 0x039E=>0x03BE, 0x0164=>0x0165,
+			0x0116=>0x0117, 0x0108=>0x0109, 0x0056=>0x0076, 0x00DE=>0x00FE, 0x0156=>0x0157,
+			0x00DA=>0x00FA, 0x1E60=>0x1E61, 0x1E82=>0x1E83, 0x00C2=>0x00E2, 0x0118=>0x0119,
+			0x0145=>0x0146, 0x0050=>0x0070, 0x0150=>0x0151, 0x042E=>0x044E, 0x0128=>0x0129,
+			0x03A7=>0x03C7, 0x013D=>0x013E, 0x0422=>0x0442, 0x005A=>0x007A, 0x0428=>0x0448,
+			0x03A1=>0x03C1, 0x1E80=>0x1E81, 0x016C=>0x016D, 0x00D5=>0x00F5, 0x0055=>0x0075,
+			0x0176=>0x0177, 0x00DC=>0x00FC, 0x1E56=>0x1E57, 0x03A3=>0x03C3, 0x041A=>0x043A,
+			0x004D=>0x006D, 0x016A=>0x016B, 0x0170=>0x0171, 0x0424=>0x0444, 0x00CC=>0x00EC,
+			0x0168=>0x0169, 0x039F=>0x03BF, 0x004B=>0x006B, 0x00D2=>0x00F2, 0x00C0=>0x00E0,
+			0x0414=>0x0434, 0x03A9=>0x03C9, 0x1E6A=>0x1E6B, 0x00C3=>0x00E3, 0x042D=>0x044D,
+			0x0416=>0x0436, 0x01A0=>0x01A1, 0x010C=>0x010D, 0x011C=>0x011D, 0x00D0=>0x00F0,
+			0x013B=>0x013C, 0x040F=>0x045F, 0x040A=>0x045A, 0x00C8=>0x00E8, 0x03A5=>0x03C5,
+			0x0046=>0x0066, 0x00DD=>0x00FD, 0x0043=>0x0063, 0x021A=>0x021B, 0x00CA=>0x00EA,
+			0x0399=>0x03B9, 0x0179=>0x017A, 0x00CF=>0x00EF, 0x01AF=>0x01B0, 0x0045=>0x0065,
+			0x039B=>0x03BB, 0x0398=>0x03B8, 0x039C=>0x03BC, 0x040C=>0x045C, 0x041F=>0x043F,
+			0x042C=>0x044C, 0x00DE=>0x00FE, 0x00D0=>0x00F0, 0x1EF2=>0x1EF3, 0x0048=>0x0068,
+			0x00CB=>0x00EB, 0x0110=>0x0111, 0x0413=>0x0433, 0x012E=>0x012F, 0x00C6=>0x00E6,
+			0x0058=>0x0078, 0x0160=>0x0161, 0x016E=>0x016F, 0x0391=>0x03B1, 0x0407=>0x0457,
+			0x0172=>0x0173, 0x0178=>0x00FF, 0x004F=>0x006F, 0x041B=>0x043B, 0x0395=>0x03B5,
+			0x0425=>0x0445, 0x0120=>0x0121, 0x017D=>0x017E, 0x017B=>0x017C, 0x0396=>0x03B6,
+			0x0392=>0x03B2, 0x0388=>0x03AD, 0x1E84=>0x1E85, 0x0174=>0x0175, 0x0051=>0x0071,
+			0x0417=>0x0437, 0x1E0A=>0x1E0B, 0x0147=>0x0148, 0x0104=>0x0105, 0x0408=>0x0458,
+			0x014C=>0x014D, 0x00CD=>0x00ED, 0x0059=>0x0079, 0x010A=>0x010B, 0x038F=>0x03CE,
+			0x0052=>0x0072, 0x0410=>0x0430, 0x0405=>0x0455, 0x0402=>0x0452, 0x0126=>0x0127,
+			0x0136=>0x0137, 0x012A=>0x012B, 0x038A=>0x03AF, 0x042B=>0x044B, 0x004C=>0x006C,
+			0x0397=>0x03B7, 0x0124=>0x0125, 0x0218=>0x0219, 0x00DB=>0x00FB, 0x011E=>0x011F,
+			0x041E=>0x043E, 0x1E40=>0x1E41, 0x039D=>0x03BD, 0x0106=>0x0107, 0x03AB=>0x03CB,
+			0x0426=>0x0446, 0x00DE=>0x00FE, 0x00C7=>0x00E7, 0x03AA=>0x03CA, 0x0421=>0x0441,
+			0x0412=>0x0432, 0x010E=>0x010F, 0x00D8=>0x00F8, 0x0057=>0x0077, 0x011A=>0x011B,
+			0x0054=>0x0074, 0x004A=>0x006A, 0x040B=>0x045B, 0x0406=>0x0456, 0x0102=>0x0103,
+			0x039B=>0x03BB, 0x00D1=>0x00F1, 0x041D=>0x043D, 0x038C=>0x03CC, 0x00C9=>0x00E9,
+			0x00D0=>0x00F0, 0x0407=>0x0457, 0x0122=>0x0123);
+	}
+
+	$uni = utf8_to_unicode($string);
+
+	if (!$uni)
+		return false;
+
+	$cnt = count($uni);
+
+	for ($i=0; $i < $cnt; $i++)
+		if (isset($UTF8_UPPER_TO_LOWER[$uni[$i]]))
+			$uni[$i] = $UTF8_UPPER_TO_LOWER[$uni[$i]];
+
+	return utf8_from_unicode($uni);
 }
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to strtoupper
 * Make a string uppercase
@@ -369,70 +355,68 @@ function utf8_strtolower($string){
 * @package utf8
 * @subpackage strings
 */
-function utf8_strtoupper($string){
-    
-    static $UTF8_LOWER_TO_UPPER = NULL;
-    
-    if ( is_null($UTF8_LOWER_TO_UPPER) ) {
-        $UTF8_LOWER_TO_UPPER = array(
-    0x0061=>0x0041, 0x03C6=>0x03A6, 0x0163=>0x0162, 0x00E5=>0x00C5, 0x0062=>0x0042,
-    0x013A=>0x0139, 0x00E1=>0x00C1, 0x0142=>0x0141, 0x03CD=>0x038E, 0x0101=>0x0100,
-    0x0491=>0x0490, 0x03B4=>0x0394, 0x015B=>0x015A, 0x0064=>0x0044, 0x03B3=>0x0393,
-    0x00F4=>0x00D4, 0x044A=>0x042A, 0x0439=>0x0419, 0x0113=>0x0112, 0x043C=>0x041C,
-    0x015F=>0x015E, 0x0144=>0x0143, 0x00EE=>0x00CE, 0x045E=>0x040E, 0x044F=>0x042F,
-    0x03BA=>0x039A, 0x0155=>0x0154, 0x0069=>0x0049, 0x0073=>0x0053, 0x1E1F=>0x1E1E,
-    0x0135=>0x0134, 0x0447=>0x0427, 0x03C0=>0x03A0, 0x0438=>0x0418, 0x00F3=>0x00D3,
-    0x0440=>0x0420, 0x0454=>0x0404, 0x0435=>0x0415, 0x0449=>0x0429, 0x014B=>0x014A,
-    0x0431=>0x0411, 0x0459=>0x0409, 0x1E03=>0x1E02, 0x00F6=>0x00D6, 0x00F9=>0x00D9,
-    0x006E=>0x004E, 0x0451=>0x0401, 0x03C4=>0x03A4, 0x0443=>0x0423, 0x015D=>0x015C,
-    0x0453=>0x0403, 0x03C8=>0x03A8, 0x0159=>0x0158, 0x0067=>0x0047, 0x00E4=>0x00C4,
-    0x03AC=>0x0386, 0x03AE=>0x0389, 0x0167=>0x0166, 0x03BE=>0x039E, 0x0165=>0x0164,
-    0x0117=>0x0116, 0x0109=>0x0108, 0x0076=>0x0056, 0x00FE=>0x00DE, 0x0157=>0x0156,
-    0x00FA=>0x00DA, 0x1E61=>0x1E60, 0x1E83=>0x1E82, 0x00E2=>0x00C2, 0x0119=>0x0118,
-    0x0146=>0x0145, 0x0070=>0x0050, 0x0151=>0x0150, 0x044E=>0x042E, 0x0129=>0x0128,
-    0x03C7=>0x03A7, 0x013E=>0x013D, 0x0442=>0x0422, 0x007A=>0x005A, 0x0448=>0x0428,
-    0x03C1=>0x03A1, 0x1E81=>0x1E80, 0x016D=>0x016C, 0x00F5=>0x00D5, 0x0075=>0x0055,
-    0x0177=>0x0176, 0x00FC=>0x00DC, 0x1E57=>0x1E56, 0x03C3=>0x03A3, 0x043A=>0x041A,
-    0x006D=>0x004D, 0x016B=>0x016A, 0x0171=>0x0170, 0x0444=>0x0424, 0x00EC=>0x00CC,
-    0x0169=>0x0168, 0x03BF=>0x039F, 0x006B=>0x004B, 0x00F2=>0x00D2, 0x00E0=>0x00C0,
-    0x0434=>0x0414, 0x03C9=>0x03A9, 0x1E6B=>0x1E6A, 0x00E3=>0x00C3, 0x044D=>0x042D,
-    0x0436=>0x0416, 0x01A1=>0x01A0, 0x010D=>0x010C, 0x011D=>0x011C, 0x00F0=>0x00D0,
-    0x013C=>0x013B, 0x045F=>0x040F, 0x045A=>0x040A, 0x00E8=>0x00C8, 0x03C5=>0x03A5,
-    0x0066=>0x0046, 0x00FD=>0x00DD, 0x0063=>0x0043, 0x021B=>0x021A, 0x00EA=>0x00CA,
-    0x03B9=>0x0399, 0x017A=>0x0179, 0x00EF=>0x00CF, 0x01B0=>0x01AF, 0x0065=>0x0045,
-    0x03BB=>0x039B, 0x03B8=>0x0398, 0x03BC=>0x039C, 0x045C=>0x040C, 0x043F=>0x041F,
-    0x044C=>0x042C, 0x00FE=>0x00DE, 0x00F0=>0x00D0, 0x1EF3=>0x1EF2, 0x0068=>0x0048,
-    0x00EB=>0x00CB, 0x0111=>0x0110, 0x0433=>0x0413, 0x012F=>0x012E, 0x00E6=>0x00C6,
-    0x0078=>0x0058, 0x0161=>0x0160, 0x016F=>0x016E, 0x03B1=>0x0391, 0x0457=>0x0407,
-    0x0173=>0x0172, 0x00FF=>0x0178, 0x006F=>0x004F, 0x043B=>0x041B, 0x03B5=>0x0395,
-    0x0445=>0x0425, 0x0121=>0x0120, 0x017E=>0x017D, 0x017C=>0x017B, 0x03B6=>0x0396,
-    0x03B2=>0x0392, 0x03AD=>0x0388, 0x1E85=>0x1E84, 0x0175=>0x0174, 0x0071=>0x0051,
-    0x0437=>0x0417, 0x1E0B=>0x1E0A, 0x0148=>0x0147, 0x0105=>0x0104, 0x0458=>0x0408,
-    0x014D=>0x014C, 0x00ED=>0x00CD, 0x0079=>0x0059, 0x010B=>0x010A, 0x03CE=>0x038F,
-    0x0072=>0x0052, 0x0430=>0x0410, 0x0455=>0x0405, 0x0452=>0x0402, 0x0127=>0x0126,
-    0x0137=>0x0136, 0x012B=>0x012A, 0x03AF=>0x038A, 0x044B=>0x042B, 0x006C=>0x004C,
-    0x03B7=>0x0397, 0x0125=>0x0124, 0x0219=>0x0218, 0x00FB=>0x00DB, 0x011F=>0x011E,
-    0x043E=>0x041E, 0x1E41=>0x1E40, 0x03BD=>0x039D, 0x0107=>0x0106, 0x03CB=>0x03AB,
-    0x0446=>0x0426, 0x00FE=>0x00DE, 0x00E7=>0x00C7, 0x03CA=>0x03AA, 0x0441=>0x0421,
-    0x0432=>0x0412, 0x010F=>0x010E, 0x00F8=>0x00D8, 0x0077=>0x0057, 0x011B=>0x011A,
-    0x0074=>0x0054, 0x006A=>0x004A, 0x045B=>0x040B, 0x0456=>0x0406, 0x0103=>0x0102,
-    0x03BB=>0x039B, 0x00F1=>0x00D1, 0x043D=>0x041D, 0x03CC=>0x038C, 0x00E9=>0x00C9,
-    0x00F0=>0x00D0, 0x0457=>0x0407, 0x0123=>0x0122,
-            );
-    }
-    
-    $uni = utf8_to_unicode($string);
-    
-    if ( !$uni ) {
-        return FALSE;
-    }
-    
-    $cnt = count($uni);
-    for ($i=0; $i < $cnt; $i++){
-        if( isset($UTF8_LOWER_TO_UPPER[$uni[$i]]) ) {
-            $uni[$i] = $UTF8_LOWER_TO_UPPER[$uni[$i]];
-        }
-    }
-    
-    return utf8_from_unicode($uni);
+function utf8_strtoupper($string)
+{
+	static $UTF8_LOWER_TO_UPPER = false;
+
+	if (!$UTF8_LOWER_TO_UPPER)
+	{
+		$UTF8_LOWER_TO_UPPER = array(
+			0x0061=>0x0041, 0x03C6=>0x03A6, 0x0163=>0x0162, 0x00E5=>0x00C5, 0x0062=>0x0042,
+			0x013A=>0x0139, 0x00E1=>0x00C1, 0x0142=>0x0141, 0x03CD=>0x038E, 0x0101=>0x0100,
+			0x0491=>0x0490, 0x03B4=>0x0394, 0x015B=>0x015A, 0x0064=>0x0044, 0x03B3=>0x0393,
+			0x00F4=>0x00D4, 0x044A=>0x042A, 0x0439=>0x0419, 0x0113=>0x0112, 0x043C=>0x041C,
+			0x015F=>0x015E, 0x0144=>0x0143, 0x00EE=>0x00CE, 0x045E=>0x040E, 0x044F=>0x042F,
+			0x03BA=>0x039A, 0x0155=>0x0154, 0x0069=>0x0049, 0x0073=>0x0053, 0x1E1F=>0x1E1E,
+			0x0135=>0x0134, 0x0447=>0x0427, 0x03C0=>0x03A0, 0x0438=>0x0418, 0x00F3=>0x00D3,
+			0x0440=>0x0420, 0x0454=>0x0404, 0x0435=>0x0415, 0x0449=>0x0429, 0x014B=>0x014A,
+			0x0431=>0x0411, 0x0459=>0x0409, 0x1E03=>0x1E02, 0x00F6=>0x00D6, 0x00F9=>0x00D9,
+			0x006E=>0x004E, 0x0451=>0x0401, 0x03C4=>0x03A4, 0x0443=>0x0423, 0x015D=>0x015C,
+			0x0453=>0x0403, 0x03C8=>0x03A8, 0x0159=>0x0158, 0x0067=>0x0047, 0x00E4=>0x00C4,
+			0x03AC=>0x0386, 0x03AE=>0x0389, 0x0167=>0x0166, 0x03BE=>0x039E, 0x0165=>0x0164,
+			0x0117=>0x0116, 0x0109=>0x0108, 0x0076=>0x0056, 0x00FE=>0x00DE, 0x0157=>0x0156,
+			0x00FA=>0x00DA, 0x1E61=>0x1E60, 0x1E83=>0x1E82, 0x00E2=>0x00C2, 0x0119=>0x0118,
+			0x0146=>0x0145, 0x0070=>0x0050, 0x0151=>0x0150, 0x044E=>0x042E, 0x0129=>0x0128,
+			0x03C7=>0x03A7, 0x013E=>0x013D, 0x0442=>0x0422, 0x007A=>0x005A, 0x0448=>0x0428,
+			0x03C1=>0x03A1, 0x1E81=>0x1E80, 0x016D=>0x016C, 0x00F5=>0x00D5, 0x0075=>0x0055,
+			0x0177=>0x0176, 0x00FC=>0x00DC, 0x1E57=>0x1E56, 0x03C3=>0x03A3, 0x043A=>0x041A,
+			0x006D=>0x004D, 0x016B=>0x016A, 0x0171=>0x0170, 0x0444=>0x0424, 0x00EC=>0x00CC,
+			0x0169=>0x0168, 0x03BF=>0x039F, 0x006B=>0x004B, 0x00F2=>0x00D2, 0x00E0=>0x00C0,
+			0x0434=>0x0414, 0x03C9=>0x03A9, 0x1E6B=>0x1E6A, 0x00E3=>0x00C3, 0x044D=>0x042D,
+			0x0436=>0x0416, 0x01A1=>0x01A0, 0x010D=>0x010C, 0x011D=>0x011C, 0x00F0=>0x00D0,
+			0x013C=>0x013B, 0x045F=>0x040F, 0x045A=>0x040A, 0x00E8=>0x00C8, 0x03C5=>0x03A5,
+			0x0066=>0x0046, 0x00FD=>0x00DD, 0x0063=>0x0043, 0x021B=>0x021A, 0x00EA=>0x00CA,
+			0x03B9=>0x0399, 0x017A=>0x0179, 0x00EF=>0x00CF, 0x01B0=>0x01AF, 0x0065=>0x0045,
+			0x03BB=>0x039B, 0x03B8=>0x0398, 0x03BC=>0x039C, 0x045C=>0x040C, 0x043F=>0x041F,
+			0x044C=>0x042C, 0x00FE=>0x00DE, 0x00F0=>0x00D0, 0x1EF3=>0x1EF2, 0x0068=>0x0048,
+			0x00EB=>0x00CB, 0x0111=>0x0110, 0x0433=>0x0413, 0x012F=>0x012E, 0x00E6=>0x00C6,
+			0x0078=>0x0058, 0x0161=>0x0160, 0x016F=>0x016E, 0x03B1=>0x0391, 0x0457=>0x0407,
+			0x0173=>0x0172, 0x00FF=>0x0178, 0x006F=>0x004F, 0x043B=>0x041B, 0x03B5=>0x0395,
+			0x0445=>0x0425, 0x0121=>0x0120, 0x017E=>0x017D, 0x017C=>0x017B, 0x03B6=>0x0396,
+			0x03B2=>0x0392, 0x03AD=>0x0388, 0x1E85=>0x1E84, 0x0175=>0x0174, 0x0071=>0x0051,
+			0x0437=>0x0417, 0x1E0B=>0x1E0A, 0x0148=>0x0147, 0x0105=>0x0104, 0x0458=>0x0408,
+			0x014D=>0x014C, 0x00ED=>0x00CD, 0x0079=>0x0059, 0x010B=>0x010A, 0x03CE=>0x038F,
+			0x0072=>0x0052, 0x0430=>0x0410, 0x0455=>0x0405, 0x0452=>0x0402, 0x0127=>0x0126,
+			0x0137=>0x0136, 0x012B=>0x012A, 0x03AF=>0x038A, 0x044B=>0x042B, 0x006C=>0x004C,
+			0x03B7=>0x0397, 0x0125=>0x0124, 0x0219=>0x0218, 0x00FB=>0x00DB, 0x011F=>0x011E,
+			0x043E=>0x041E, 0x1E41=>0x1E40, 0x03BD=>0x039D, 0x0107=>0x0106, 0x03CB=>0x03AB,
+			0x0446=>0x0426, 0x00FE=>0x00DE, 0x00E7=>0x00C7, 0x03CA=>0x03AA, 0x0441=>0x0421,
+			0x0432=>0x0412, 0x010F=>0x010E, 0x00F8=>0x00D8, 0x0077=>0x0057, 0x011B=>0x011A,
+			0x0074=>0x0054, 0x006A=>0x004A, 0x045B=>0x040B, 0x0456=>0x0406, 0x0103=>0x0102,
+			0x03BB=>0x039B, 0x00F1=>0x00D1, 0x043D=>0x041D, 0x03CC=>0x038C, 0x00E9=>0x00C9,
+			0x00F0=>0x00D0, 0x0457=>0x0407, 0x0123=>0x0122);
+	}
+
+	$uni = utf8_to_unicode($string);
+
+	if (!$uni)
+		return false;
+
+	$cnt = count($uni);
+
+	for ($i=0; $i < $cnt; $i++)
+		if(isset($UTF8_LOWER_TO_UPPER[$uni[$i]]))
+			$uni[$i] = $UTF8_LOWER_TO_UPPER[$uni[$i]];
+
+	return utf8_from_unicode($uni);
 }
diff --git a/upload/include/utf8/native/index.html b/upload/include/utf8/native/index.html
index 2db9a3c..89337b2 100644
--- a/upload/include/utf8/native/index.html
+++ b/upload/include/utf8/native/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/include/utf8/ord.php b/upload/include/utf8/ord.php
index 79f13dc..a333f96 100644
--- a/upload/include/utf8/ord.php
+++ b/upload/include/utf8/ord.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: ord.php,v 1.4 2006/09/11 15:22:54 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to ord
 * Returns the unicode ordinal for a character
@@ -14,79 +14,65 @@
 * @see http://www.php.net/ord
 * @see http://www.php.net/manual/en/function.ord.php#46267
 */
-function utf8_ord($chr) {
-    
-    $ord0 = ord($chr);
-    
-    if ( $ord0 >= 0 && $ord0 <= 127 ) {
-        return $ord0;
-    }
-    
-    if ( !isset($chr{1}) ) {
-        trigger_error('Short sequence - at least 2 bytes expected, only 1 seen');
-        return FALSE;
-    }
-    
-    $ord1 = ord($chr{1});
-    if ( $ord0 >= 192 && $ord0 <= 223 ) {
-        return ( $ord0 - 192 ) * 64 
-            + ( $ord1 - 128 );
-    }
-    
-    if ( !isset($chr{2}) ) {
-        trigger_error('Short sequence - at least 3 bytes expected, only 2 seen');
-        return FALSE;
-    }
-    $ord2 = ord($chr{2});
-    if ( $ord0 >= 224 && $ord0 <= 239 ) {
-        return ($ord0-224)*4096 
-            + ($ord1-128)*64 
-                + ($ord2-128);
-    }
-    
-    if ( !isset($chr{3}) ) {
-        trigger_error('Short sequence - at least 4 bytes expected, only 3 seen');
-        return FALSE;
-    }
-    $ord3 = ord($chr{3});
-    if ($ord0>=240 && $ord0<=247) {
-        return ($ord0-240)*262144 
-            + ($ord1-128)*4096 
-                + ($ord2-128)*64 
-                    + ($ord3-128);
-    
-    }
-    
-    if ( !isset($chr{4}) ) {
-        trigger_error('Short sequence - at least 5 bytes expected, only 4 seen');
-        return FALSE;
-    }
-    $ord4 = ord($chr{4});
-    if ($ord0>=248 && $ord0<=251) {
-        return ($ord0-248)*16777216 
-            + ($ord1-128)*262144 
-                + ($ord2-128)*4096 
-                    + ($ord3-128)*64 
-                        + ($ord4-128);
-    }
-    
-    if ( !isset($chr{5}) ) {
-        trigger_error('Short sequence - at least 6 bytes expected, only 5 seen');
-        return FALSE;
-    }
-    if ($ord0>=252 && $ord0<=253) {
-        return ($ord0-252) * 1073741824 
-            + ($ord1-128)*16777216 
-                + ($ord2-128)*262144 
-                    + ($ord3-128)*4096 
-                        + ($ord4-128)*64 
-                            + (ord($c{5})-128);
-    }
-    
-    if ( $ord0 >= 254 && $ord0 <= 255 ) { 
-        trigger_error('Invalid UTF-8 with surrogate ordinal '.$ord0);
-        return FALSE;
-    }
-    
-}
+function utf8_ord($chr)
+{
+	$ord0 = ord($chr);
+
+	if ($ord0 >= 0 && $ord0 <= 127)
+		return $ord0;
+
+	if (!isset($chr{1}))
+	{
+		trigger_error('Short sequence - at least 2 bytes expected, only 1 seen');
+		return false;
+	}
+
+	$ord1 = ord($chr{1});
+	if ($ord0 >= 192 && $ord0 <= 223)
+		return ($ord0 - 192) * 64 + ($ord1 - 128);
+
+	if (!isset($chr{2}))
+	{
+		trigger_error('Short sequence - at least 3 bytes expected, only 2 seen');
+		return false;
+	}
+
+	$ord2 = ord($chr{2});
+	if ($ord0 >= 224 && $ord0 <= 239)
+		return ($ord0-224)*4096 + ($ord1-128)*64 + ($ord2-128);
 
+	if (!isset($chr{3}))
+	{
+		trigger_error('Short sequence - at least 4 bytes expected, only 3 seen');
+		return false;
+	}
+
+	$ord3 = ord($chr{3});
+	if ($ord0>=240 && $ord0<=247)
+		return ($ord0-240)*262144 + ($ord1-128)*4096 + ($ord2-128)*64 + ($ord3-128);
+
+	if (!isset($chr{4}))
+	{
+		trigger_error('Short sequence - at least 5 bytes expected, only 4 seen');
+		return false;
+	}
+
+	$ord4 = ord($chr{4});
+	if ($ord0>=248 && $ord0<=251)
+		return ($ord0-248)*16777216 + ($ord1-128)*262144 + ($ord2-128)*4096 + ($ord3-128)*64 + ($ord4-128);
+
+	if (!isset($chr{5}))
+	{
+		trigger_error('Short sequence - at least 6 bytes expected, only 5 seen');
+		return false;
+	}
+
+	if ($ord0>=252 && $ord0<=253)
+		return ($ord0-252) * 1073741824 + ($ord1-128)*16777216 + ($ord2-128)*262144 + ($ord3-128)*4096  + ($ord4-128)*64 + (ord($c{5})-128);
+
+	if ($ord0 >= 254 && $ord0 <= 255)
+	{
+		trigger_error('Invalid UTF-8 with surrogate ordinal '.$ord0);
+		return false;
+	}
+}
diff --git a/upload/include/utf8/str_ireplace.php b/upload/include/utf8/str_ireplace.php
index 4e4bae4..7257b0a 100644
--- a/upload/include/utf8/str_ireplace.php
+++ b/upload/include/utf8/str_ireplace.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: str_ireplace.php,v 1.2 2007/08/12 01:20:46 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to str_ireplace
 * Case-insensitive version of str_replace
@@ -21,60 +21,52 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_ireplace($search, $replace, $str, $count = NULL){
-    
-    if ( !is_array($search) ) {
-        
-        $slen = strlen($search);
-        if ( $slen == 0 ) {
-            return $str;
-        }
-        
-        $lendif = strlen($replace) - strlen($search);
-        $search = utf8_strtolower($search);
-        
-        $search = preg_quote($search);
-        $lstr = utf8_strtolower($str);
-        $i = 0;
-        $matched = 0;
-        while ( preg_match('/(.*)'.$search.'/Us',$lstr, $matches) ) {
-            if ( $i === $count ) {
-                break;
-            }
-            $mlen = strlen($matches[0]);
-            $lstr = substr($lstr, $mlen);
-            $str = substr_replace($str, $replace, $matched+strlen($matches[1]), $slen);
-            $matched += $mlen + $lendif;
-            $i++;
-        }
-        return $str;
-        
-    } else {
-        
-        foreach ( array_keys($search) as $k ) {
-            
-            if ( is_array($replace) ) {
-                
-                if ( array_key_exists($k,$replace) ) {
-                    
-                    $str = utf8_ireplace($search[$k], $replace[$k], $str, $count);
-                    
-                } else {
-                
-                    $str = utf8_ireplace($search[$k], '', $str, $count);
-                    
-                }
-                
-            } else {
-            
-                $str = utf8_ireplace($search[$k], $replace, $str, $count);
-                
-            }
-        }
-        return $str;
-        
-    }
+function utf8_ireplace($search, $replace, $str, $count=null)
+{
+	if (!is_array($search))
+	{
+		$slen = strlen($search);
 
-}
+		if ($slen == 0)
+			return $str;
+
+		$lendif = strlen($replace) - strlen($search);
+		$search = utf8_strtolower($search);
+
+		$search = preg_quote($search);
+		$lstr = utf8_strtolower($str);
+		$i = 0;
+		$matched = 0;
 
+		while (preg_match('/(.*)'.$search.'/Us', $lstr, $matches))
+		{
+			if ($i === $count)
+				break;
 
+			$mlen = strlen($matches[0]);
+			$lstr = substr($lstr, $mlen);
+			$str = substr_replace($str, $replace, $matched+strlen($matches[1]), $slen);
+			$matched += $mlen + $lendif;
+			$i++;
+		}
+
+		return $str;
+	}
+	else
+	{
+		foreach (array_keys($search) as $k)
+		{
+			if (is_array($replace))
+			{
+				if (array_key_exists($k, $replace))
+					$str = utf8_ireplace($search[$k], $replace[$k], $str, $count);
+				else
+					$str = utf8_ireplace($search[$k], '', $str, $count);
+			}
+			else
+				$str = utf8_ireplace($search[$k], $replace, $str, $count);
+		}
+
+		return $str;
+	}
+}
diff --git a/upload/include/utf8/str_pad.php b/upload/include/utf8/str_pad.php
index fef1fec..93a559a 100644
--- a/upload/include/utf8/str_pad.php
+++ b/upload/include/utf8/str_pad.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: str_pad.php,v 1.1 2006/09/03 09:25:13 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * Replacement for str_pad. $padStr may contain multi-byte characters.
 *
@@ -20,38 +20,40 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_str_pad($input, $length, $padStr = ' ', $type = STR_PAD_RIGHT) {
-    
-    $inputLen = utf8_strlen($input);
-    if ($length <= $inputLen) {
-        return $input;
-    }
-    
-    $padStrLen = utf8_strlen($padStr);
-    $padLen = $length - $inputLen;
-    
-    if ($type == STR_PAD_RIGHT) {
-        $repeatTimes = ceil($padLen / $padStrLen);
-        return utf8_substr($input . str_repeat($padStr, $repeatTimes), 0, $length);
-    }
-    
-    if ($type == STR_PAD_LEFT) {
-        $repeatTimes = ceil($padLen / $padStrLen);
-        return utf8_substr(str_repeat($padStr, $repeatTimes), 0, floor($padLen)) . $input;
-    }
-    
-    if ($type == STR_PAD_BOTH) {
-        
-        $padLen/= 2;
-        $padAmountLeft = floor($padLen);
-        $padAmountRight = ceil($padLen);
-        $repeatTimesLeft = ceil($padAmountLeft / $padStrLen);
-        $repeatTimesRight = ceil($padAmountRight / $padStrLen);
-        
-        $paddingLeft = utf8_substr(str_repeat($padStr, $repeatTimesLeft), 0, $padAmountLeft);
-        $paddingRight = utf8_substr(str_repeat($padStr, $repeatTimesRight), 0, $padAmountLeft);
-        return $paddingLeft . $input . $paddingRight;
-    }
-    
-    trigger_error('utf8_str_pad: Unknown padding type (' . $type . ')',E_USER_ERROR);
+function utf8_str_pad($input, $length, $padStr=' ', $type=STR_PAD_RIGHT)
+{
+	$inputLen = utf8_strlen($input);
+	if ($length <= $inputLen)
+		return $input;
+
+	$padStrLen = utf8_strlen($padStr);
+	$padLen = $length - $inputLen;
+
+	if ($type == STR_PAD_RIGHT)
+	{
+		$repeatTimes = ceil($padLen / $padStrLen);
+		return utf8_substr($input.str_repeat($padStr, $repeatTimes), 0, $length);
+	}
+
+	if ($type == STR_PAD_LEFT)
+	{
+		$repeatTimes = ceil($padLen / $padStrLen);
+		return utf8_substr(str_repeat($padStr, $repeatTimes), 0, floor($padLen)).$input;
+	}
+
+	if ($type == STR_PAD_BOTH)
+	{
+		$padLen /= 2;
+		$padAmountLeft = floor($padLen);
+		$padAmountRight = ceil($padLen);
+		$repeatTimesLeft = ceil($padAmountLeft / $padStrLen);
+		$repeatTimesRight = ceil($padAmountRight / $padStrLen);
+
+		$paddingLeft = utf8_substr(str_repeat($padStr, $repeatTimesLeft), 0, $padAmountLeft);
+		$paddingRight = utf8_substr(str_repeat($padStr, $repeatTimesRight), 0, $padAmountLeft);
+
+		return $paddingLeft.$input.$paddingRight;
+	}
+
+	trigger_error('utf8_str_pad: Unknown padding type ('.$type.')', E_USER_ERROR);
 }
diff --git a/upload/include/utf8/str_split.php b/upload/include/utf8/str_split.php
index b37bce7..15bc215 100644
--- a/upload/include/utf8/str_split.php
+++ b/upload/include/utf8/str_split.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: str_split.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to str_split
 * Convert a string to an array
@@ -18,18 +18,16 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_str_split($str, $split_len = 1) {
-    
-    if ( !preg_match('/^[0-9]+$/',$split_len) || $split_len < 1 ) {
-        return FALSE;
-    }
-    
-    $len = utf8_strlen($str);
-    if ( $len <= $split_len ) {
-        return array($str);
-    }
-    
-    preg_match_all('/.{'.$split_len.'}|[^\x00]{1,'.$split_len.'}$/us', $str, $ar);
-    return $ar[0];
-    
+function utf8_str_split($str, $split_len=1)
+{
+	if (!preg_match('/^[0-9]+$/',$split_len) || $split_len < 1)
+		return false;
+
+	$len = utf8_strlen($str);
+	if ($len <= $split_len)
+		return array($str);
+
+	preg_match_all('/.{'.$split_len.'}|[^\x00]{1,'.$split_len.'}$/us', $str, $ar);
+
+	return $ar[0];
 }
diff --git a/upload/include/utf8/strcasecmp.php b/upload/include/utf8/strcasecmp.php
index c26882f..423f443 100644
--- a/upload/include/utf8/strcasecmp.php
+++ b/upload/include/utf8/strcasecmp.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: strcasecmp.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to strcasecmp
 * A case insensivite string comparison
@@ -18,9 +18,10 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_strcasecmp($strX, $strY) {
-    $strX = utf8_strtolower($strX);
-    $strY = utf8_strtolower($strY);
-    return strcmp($strX, $strY);
-}
+function utf8_strcasecmp($strX, $strY)
+{
+	$strX = utf8_strtolower($strX);
+	$strY = utf8_strtolower($strY);
 
+	return strcmp($strX, $strY);
+}
diff --git a/upload/include/utf8/strcspn.php b/upload/include/utf8/strcspn.php
index 6250178..1e3756d 100644
--- a/upload/include/utf8/strcspn.php
+++ b/upload/include/utf8/strcspn.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: strcspn.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to strcspn
 * Find length of initial segment not matching mask
@@ -17,25 +17,20 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_strcspn($str, $mask, $start = NULL, $length = NULL) {
-    
-    if ( empty($mask) || strlen($mask) == 0 ) {
-        return NULL;
-    }
-    
-    $mask = preg_replace('!([\\\\\\-\\]\\[/^])!','\\\${1}',$mask);
-    
-    if ( $start !== NULL || $length !== NULL ) {
-        $str = utf8_substr($str, $start, $length);
-    }
-        
-    preg_match('/^[^'.$mask.']+/u',$str, $matches);
-    
-    if ( isset($matches[0]) ) {
-        return utf8_strlen($matches[0]);
-    }
-    
-    return 0;
-    
-}
+function utf8_strcspn($str, $mask, $start=null, $length=null)
+{
+	if (empty($mask) || strlen($mask) == 0)
+		return null;
+
+	$mask = preg_replace('!([\\\\\\-\\]\\[/^])!','\\\${1}', $mask);
+
+	if ($start !== null || $length !== null)
+		$str = utf8_substr($str, $start, $length);
 
+	preg_match('/^[^'.$mask.']+/u', $str, $matches);
+
+	if (isset($matches[0]))
+		return utf8_strlen($matches[0]);
+
+	return 0;
+}
diff --git a/upload/include/utf8/stristr.php b/upload/include/utf8/stristr.php
index e3d1212..fb9e6a5 100644
--- a/upload/include/utf8/stristr.php
+++ b/upload/include/utf8/stristr.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: stristr.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to stristr
 * Find first occurrence of a string using case insensitive comparison
@@ -18,19 +18,17 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_stristr($str, $search) {
-    
-    if ( strlen($search) == 0 ) {
-        return $str;
-    }
-    
-    $lstr = utf8_strtolower($str);
-    $lsearch = utf8_strtolower($search);
-    preg_match('/^(.*)'.preg_quote($lsearch).'/Us',$lstr, $matches);
-    
-    if ( count($matches) == 2 ) {
-        return substr($str, strlen($matches[1]));
-    }
-    
-    return FALSE;
+function utf8_stristr($str, $search)
+{
+	if (strlen($search) == 0)
+		return $str;
+
+	$lstr = utf8_strtolower($str);
+	$lsearch = utf8_strtolower($search);
+	preg_match('/^(.*)'.preg_quote($lsearch).'/Us', $lstr, $matches);
+
+	if (count($matches) == 2)
+		return substr($str, strlen($matches[1]));
+
+	return false;
 }
diff --git a/upload/include/utf8/strrev.php b/upload/include/utf8/strrev.php
index f4de9ee..ae9c32b 100644
--- a/upload/include/utf8/strrev.php
+++ b/upload/include/utf8/strrev.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: strrev.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to strrev
 * Reverse a string
@@ -15,8 +15,8 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_strrev($str){
-    preg_match_all('/./us', $str, $ar);
-    return join('',array_reverse($ar[0]));
+function utf8_strrev($str)
+{
+	preg_match_all('/./us', $str, $ar);
+	return implode(array_reverse($ar[0]));
 }
-
diff --git a/upload/include/utf8/strspn.php b/upload/include/utf8/strspn.php
index ee0b02e..424ceb7 100644
--- a/upload/include/utf8/strspn.php
+++ b/upload/include/utf8/strspn.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: strspn.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to strspn
 * Find length of initial segment matching mask
@@ -16,21 +16,17 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_strspn($str, $mask, $start = NULL, $length = NULL) {
-    
-    $mask = preg_replace('!([\\\\\\-\\]\\[/^])!','\\\${1}',$mask);
-    
-    if ( $start !== NULL || $length !== NULL ) {
-        $str = utf8_substr($str, $start, $length);
-    }
-        
-    preg_match('/^['.$mask.']+/u',$str, $matches);
-    
-    if ( isset($matches[0]) ) {
-        return utf8_strlen($matches[0]);
-    }
-    
-    return 0;
+function utf8_strspn($str, $mask, $start=null, $length=null)
+{
+	$mask = preg_replace('!([\\\\\\-\\]\\[/^])!', '\\\${1}', $mask);
 
-}
+	if ($start !== null || $length !== null)
+		$str = utf8_substr($str, $start, $length);
+
+	preg_match('/^['.$mask.']+/u', $str, $matches);
 
+	if (isset($matches[0]))
+		return utf8_strlen($matches[0]);
+
+	return 0;
+}
diff --git a/upload/include/utf8/substr_replace.php b/upload/include/utf8/substr_replace.php
index 03573c3..7fc7369 100644
--- a/upload/include/utf8/substr_replace.php
+++ b/upload/include/utf8/substr_replace.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: substr_replace.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware substr_replace.
 * Note: requires utf8_substr to be loaded
@@ -13,12 +13,15 @@
 * @see utf8_strlen
 * @see utf8_substr
 */
-function utf8_substr_replace($str, $repl, $start , $length = NULL ) {
-    preg_match_all('/./us', $str, $ar);
-    preg_match_all('/./us', $repl, $rar);
-    if( $length === NULL ) {
-        $length = utf8_strlen($str);
-    }
-    array_splice( $ar[0], $start, $length, $rar[0] );
-    return join('',$ar[0]);
+function utf8_substr_replace($str, $repl, $start , $length=null)
+{
+	preg_match_all('/./us', $str, $ar);
+	preg_match_all('/./us', $repl, $rar);
+
+	if($length === null)
+		$length = utf8_strlen($str);
+
+	array_splice($ar[0], $start, $length, $rar[0]);
+
+	return implode($ar[0]);
 }
diff --git a/upload/include/utf8/trim.php b/upload/include/utf8/trim.php
index 7f1cb3e..3d22840 100644
--- a/upload/include/utf8/trim.php
+++ b/upload/include/utf8/trim.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: trim.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware replacement for ltrim()
 * Note: you only need to use this if you are supplying the charlist
@@ -18,16 +18,17 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_ltrim( $str, $charlist = FALSE ) {
-    if($charlist === FALSE) return ltrim($str);
-    
-    //quote charlist for use in a characterclass
-    $charlist = preg_replace('!([\\\\\\-\\]\\[/^])!','\\\${1}',$charlist);
-    
-    return preg_replace('/^['.$charlist.']+/u','',$str);
+function utf8_ltrim( $str, $charlist=false)
+{
+	if($charlist === false)
+		return ltrim($str);
+
+	// Quote charlist for use in a characterclass
+	$charlist = preg_replace('!([\\\\\\-\\]\\[/^])!', '\\\${1}', $charlist);
+
+	return preg_replace('/^['.$charlist.']+/u', '', $str);
 }
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware replacement for rtrim()
 * Note: you only need to use this if you are supplying the charlist
@@ -40,13 +41,15 @@ function utf8_ltrim( $str, $charlist = FALSE ) {
 * @package utf8
 * @subpackage strings
 */
-function utf8_rtrim( $str, $charlist = FALSE ) {
-    if($charlist === FALSE) return rtrim($str);
-    
-    //quote charlist for use in a characterclass
-    $charlist = preg_replace('!([\\\\\\-\\]\\[/^])!','\\\${1}',$charlist);
-  
-    return preg_replace('/['.$charlist.']+$/u','',$str);
+function utf8_rtrim($str, $charlist=false)
+{
+	if($charlist === false)
+		return rtrim($str);
+
+	// Quote charlist for use in a characterclass
+	$charlist = preg_replace('!([\\\\\\-\\]\\[/^])!', '\\\${1}', $charlist);
+
+	return preg_replace('/['.$charlist.']+$/u', '', $str);
 }
 
 //---------------------------------------------------------------
@@ -62,7 +65,10 @@ function utf8_rtrim( $str, $charlist = FALSE ) {
 * @package utf8
 * @subpackage strings
 */
-function utf8_trim( $str, $charlist = FALSE ) {
-    if($charlist === FALSE) return trim($str);
-    return utf8_ltrim(utf8_rtrim($str, $charlist), $charlist);
-}
\ No newline at end of file
+function utf8_trim( $str, $charlist=false)
+{
+	if($charlist === false)
+		return trim($str);
+
+	return utf8_ltrim(utf8_rtrim($str, $charlist), $charlist);
+}
diff --git a/upload/include/utf8/ucfirst.php b/upload/include/utf8/ucfirst.php
index 3897bfe..efee55d 100644
--- a/upload/include/utf8/ucfirst.php
+++ b/upload/include/utf8/ucfirst.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: ucfirst.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to ucfirst
 * Make a string's first character uppercase
@@ -17,18 +17,19 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_ucfirst($str){
-    switch ( utf8_strlen($str) ) {
-        case 0:
-            return '';
-        break;
-        case 1:
-            return utf8_strtoupper($str);
-        break;
-        default:
-            preg_match('/^(.{1})(.*)$/us', $str, $matches);
-            return utf8_strtoupper($matches[1]).$matches[2];
-        break;
-    }
+function utf8_ucfirst($str)
+{
+	switch (utf8_strlen($str))
+	{
+		case 0:
+			return '';
+			break;
+		case 1:
+			return utf8_strtoupper($str);
+			break;
+		default:
+			preg_match('/^(.{1})(.*)$/us', $str, $matches);
+			return utf8_strtoupper($matches[1]).$matches[2];
+			break;
+	}
 }
-
diff --git a/upload/include/utf8/ucwords.php b/upload/include/utf8/ucwords.php
index 91553c9..e985cee 100644
--- a/upload/include/utf8/ucwords.php
+++ b/upload/include/utf8/ucwords.php
@@ -1,11 +1,11 @@
 <?php
+
 /**
 * @version $Id: ucwords.php,v 1.1 2006/02/25 13:50:17 harryf Exp $
 * @package utf8
 * @subpackage strings
 */
 
-//---------------------------------------------------------------
 /**
 * UTF-8 aware alternative to ucwords
 * Uppercase the first character of each word in a string
@@ -16,15 +16,16 @@
 * @package utf8
 * @subpackage strings
 */
-function utf8_ucwords($str) {
-    // Note: [\x0c\x09\x0b\x0a\x0d\x20] matches;
-    // form feeds, horizontal tabs, vertical tabs, linefeeds and carriage returns
-    // This corresponds to the definition of a "word" defined at http://www.php.net/ucwords
-    $pattern = '/(^|([\x0c\x09\x0b\x0a\x0d\x20]+))([^\x0c\x09\x0b\x0a\x0d\x20]{1})[^\x0c\x09\x0b\x0a\x0d\x20]*/u';
-    return preg_replace_callback($pattern, 'utf8_ucwords_callback',$str);
+function utf8_ucwords($str)
+{
+	// Note: [\x0c\x09\x0b\x0a\x0d\x20] matches;
+	// Form feeds, horizontal tabs, vertical tabs, linefeeds and carriage returns
+	// This corresponds to the definition of a "word" defined at http://www.php.net/ucwords
+	$pattern = '/(^|([\x0c\x09\x0b\x0a\x0d\x20]+))([^\x0c\x09\x0b\x0a\x0d\x20]{1})[^\x0c\x09\x0b\x0a\x0d\x20]*/u';
+
+	return preg_replace_callback($pattern, 'utf8_ucwords_callback', $str);
 }
 
-//---------------------------------------------------------------
 /**
 * Callback function for preg_replace_callback call in utf8_ucwords
 * You don't need to call this yourself
@@ -35,10 +36,11 @@ function utf8_ucwords($str) {
 * @package utf8
 * @subpackage strings
 */
-function utf8_ucwords_callback($matches) {
-    $leadingws = $matches[2];
-    $ucfirst = utf8_strtoupper($matches[3]);
-    $ucword = utf8_substr_replace(ltrim($matches[0]),$ucfirst,0,1);
-    return $leadingws . $ucword;
-}
+function utf8_ucwords_callback($matches)
+{
+	$leadingws = $matches[2];
+	$ucfirst = utf8_strtoupper($matches[3]);
+	$ucword = utf8_substr_replace(ltrim($matches[0]), $ucfirst, 0, 1);
 
+	return $leadingws.$ucword;
+}
diff --git a/upload/include/utf8/utf8.php b/upload/include/utf8/utf8.php
index 294557d..281f18c 100644
--- a/upload/include/utf8/utf8.php
+++ b/upload/include/utf8/utf8.php
@@ -21,42 +21,52 @@
 * @package utf8
 */
 
-/**
-* If string overloading is active, it will break many of the
-* native implementations. mbstring.func_overload must be set
-* to 0, 1 or 4 in php.ini (string overloading disabled).
-* Also need to check we have the correct internal mbstring
-* encoding
-*/
-if (extension_loaded('mbstring'))
-{
-	if (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING)
-		trigger_error('String functions are overloaded by mbstring', E_USER_ERROR);
-
-	mb_internal_encoding('UTF-8');
-}
-
 // Check whether PCRE has been compiled with UTF-8 support
 $UTF8_ar = array();
-if (preg_match('/^.{1}$/u', 'ñ', $UTF8_ar) != 1)
+if (preg_match('/^.{1}$/u', "ñ", $UTF8_ar) != 1)
 	trigger_error('PCRE is not compiled with UTF-8 support', E_USER_ERROR);
 
 unset($UTF8_ar);
 
-// Load the smartest implementations of utf8_strpos, utf8_strrpos and utf8_substr
-if (!defined('UTF8_CORE'))
+// Put the current directory in this constant
+if (!defined('UTF8'))
+	define('UTF8', dirname(__FILE__));
+
+if (extension_loaded('mbstring') && !defined('UTF8_USE_MBSTRING') && !defined('UTF8_USE_NATIVE'))
+	define('UTF8_USE_MBSTRING', true);
+else
+	define('UTF8_USE_NATIVE', true);
+
+// utf8_strpos() and utf8_strrpos() need utf8_bad_strip() to strip invalid
+// characters. Mbstring doesn't do this while the Native implementation does.
+require UTF8.'/utils/bad.php';
+
+if (defined('UTF8_USE_MBSTRING'))
+{
+	/**
+	* If string overloading is active, it will break many of the
+	* native implementations. mbstring.func_overload must be set
+	* to 0, 1 or 4 in php.ini (string overloading disabled).
+	* Also need to check we have the correct internal mbstring
+	* encoding
+	*/
+	if (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING)
+		trigger_error('String functions are overloaded by mbstring', E_USER_ERROR);
+
+	mb_language('uni');
+	mb_internal_encoding('UTF-8');
+
+	if (!defined('UTF8_CORE'))
+		require UTF8.'/mbstring/core.php';
+}
+elseif (defined('UTF8_USE_NATIVE'))
 {
-	if (function_exists('mb_substr'))
-		require PUN_ROOT.'include/utf8/mbstring/core.php';
-	else
+	if (!defined('UTF8_CORE'))
 	{
-		require PUN_ROOT.'include/utf8/utils/unicode.php';
-		require PUN_ROOT.'include/utf8/native/core.php';
+		require UTF8.'/utils/unicode.php';
+		require UTF8.'/native/core.php';
 	}
 }
 
-// Load the native implementation of utf8_substr_replace
-require PUN_ROOT.'include/utf8/substr_replace.php';
-
-require PUN_ROOT.'include/utf8/ucwords.php';
-require PUN_ROOT.'include/utf8/trim.php';
+// Load the native implementation of utf8_trim
+require UTF8.'/trim.php';
diff --git a/upload/include/utf8/utils/ascii.php b/upload/include/utf8/utils/ascii.php
index cb05297..af75b92 100644
--- a/upload/include/utf8/utils/ascii.php
+++ b/upload/include/utf8/utils/ascii.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
 * Tools to help with ASCII in UTF-8
 * @version $Id: ascii.php,v 1.5 2006/10/16 20:38:12 harryf Exp $
@@ -6,7 +7,6 @@
 * @subpackage ascii
 */
 
-//--------------------------------------------------------------------
 /**
 * Tests whether a string contains only 7bit ASCII bytes.
 * You might use this to conditionally check whether a string
@@ -21,40 +21,39 @@
 *     $someString = utf8_strtolower($someString);
 * }
 * </code>
-* 
+*
 * @param string
 * @return boolean TRUE if it's all ASCII
 * @package utf8
 * @subpackage ascii
 * @see utf8_is_ascii_ctrl
 */
-function utf8_is_ascii($str) {
-    // Search for any bytes which are outside the ASCII range...
-    return (preg_match('/(?:[^\x00-\x7F])/',$str) !== 1);
+function utf8_is_ascii($str)
+{
+	// Search for any bytes which are outside the ASCII range...
+	return (preg_match('/(?:[^\x00-\x7F])/', $str) !== 1);
 }
 
-//--------------------------------------------------------------------
 /**
 * Tests whether a string contains only 7bit ASCII bytes with device
 * control codes omitted. The device control codes can be found on the
 * second table here: http://www.w3schools.com/tags/ref_ascii.asp
-* 
+*
 * @param string
 * @return boolean TRUE if it's all ASCII without device control codes
 * @package utf8
 * @subpackage ascii
 * @see utf8_is_ascii
 */
-function utf8_is_ascii_ctrl($str) {
-    if ( strlen($str) > 0 ) {
-        // Search for any bytes which are outside the ASCII range,
-        // or are device control codes
-        return (preg_match('/[^\x09\x0A\x0D\x20-\x7E]/',$str) !== 1);
-    }
-    return FALSE;
+function utf8_is_ascii_ctrl($str)
+{
+	// Search for any bytes which are outside the ASCII range, or are device control codes
+	if (strlen($str) > 0)
+		return (preg_match('/[^\x09\x0A\x0D\x20-\x7E]/', $str) !== 1);
+
+	return false;
 }
 
-//--------------------------------------------------------------------
 /**
 * Strip out all non-7bit ASCII bytes
 * If you need to transmit a string to system which you know can only
@@ -65,22 +64,24 @@ function utf8_is_ascii_ctrl($str) {
 * @subpackage ascii
 * @see utf8_strip_non_ascii_ctrl
 */
-function utf8_strip_non_ascii($str) {
-    ob_start();
-    while ( preg_match(
-        '/^([\x00-\x7F]+)|([^\x00-\x7F]+)/S',
-            $str, $matches) ) {
-        if ( !isset($matches[2]) ) {
-            echo $matches[0];
-        }
-        $str = substr($str, strlen($matches[0]));
-    }
-    $result = ob_get_contents();
-    ob_end_clean();
-    return $result;
+function utf8_strip_non_ascii($str)
+{
+	ob_start();
+
+	while (preg_match('/^([\x00-\x7F]+)|([^\x00-\x7F]+)/S', $str, $matches))
+	{
+		if (!isset($matches[2]))
+			echo $matches[0];
+
+		$str = substr($str, strlen($matches[0]));
+	}
+
+	$result = ob_get_contents();
+	ob_end_clean();
+
+	return $result;
 }
 
-//--------------------------------------------------------------------
 /**
 * Strip out device control codes in the ASCII range
 * which are not permitted in XML. Note that this leaves
@@ -90,48 +91,52 @@ function utf8_strip_non_ascii($str) {
 * @param string
 * @return string control codes removed
 */
-function utf8_strip_ascii_ctrl($str) {
-    ob_start();
-    while ( preg_match(
-        '/^([^\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+)|([\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+)/S',
-            $str, $matches) ) {
-        if ( !isset($matches[2]) ) {
-            echo $matches[0];
-        }
-        $str = substr($str, strlen($matches[0]));
-    }
-    $result = ob_get_contents();
-    ob_end_clean();
-    return $result;
+function utf8_strip_ascii_ctrl($str)
+{
+	ob_start();
+
+	while (preg_match('/^([^\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+)|([\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+)/S', $str, $matches))
+	{
+		if (!isset($matches[2]))
+			echo $matches[0];
+
+		$str = substr($str, strlen($matches[0]));
+	}
+
+	$result = ob_get_contents();
+	ob_end_clean();
+
+	return $result;
 }
 
-//--------------------------------------------------------------------
 /**
 * Strip out all non 7bit ASCII bytes and ASCII device control codes.
 * For a list of ASCII device control codes see the 2nd table here:
 * http://www.w3schools.com/tags/ref_ascii.asp
-* 
+*
 * @param string
 * @return boolean TRUE if it's all ASCII
 * @package utf8
 * @subpackage ascii
 */
-function utf8_strip_non_ascii_ctrl($str) {
-    ob_start();
-    while ( preg_match(
-        '/^([\x09\x0A\x0D\x20-\x7E]+)|([^\x09\x0A\x0D\x20-\x7E]+)/S',
-            $str, $matches) ) {
-        if ( !isset($matches[2]) ) {
-            echo $matches[0];
-        }
-        $str = substr($str, strlen($matches[0]));
-    }
-    $result = ob_get_contents();
-    ob_end_clean();
-    return $result;
+function utf8_strip_non_ascii_ctrl($str)
+{
+	ob_start();
+
+	while (preg_match( '/^([\x09\x0A\x0D\x20-\x7E]+)|([^\x09\x0A\x0D\x20-\x7E]+)/S', $str, $matches))
+	{
+		if (!isset($matches[2]))
+			echo $matches[0];
+
+		$str = substr($str, strlen($matches[0]));
+	}
+
+	$result = ob_get_contents();
+	ob_end_clean();
+
+	return $result;
 }
 
-//---------------------------------------------------------------
 /**
 * Replace accented UTF-8 characters by unaccented ASCII-7 "equivalents".
 * The purpose of this function is to replace characters commonly found in Latin
@@ -154,67 +159,63 @@ function utf8_strip_non_ascii_ctrl($str) {
 * @package utf8
 * @subpackage ascii
 */
-function utf8_accents_to_ascii( $str, $case=0 ){
-    
-    static $UTF8_LOWER_ACCENTS = NULL;
-    static $UTF8_UPPER_ACCENTS = NULL;
-    
-    if($case <= 0){
-        
-        if ( is_null($UTF8_LOWER_ACCENTS) ) {
-            $UTF8_LOWER_ACCENTS = array(
-  'à' => 'a', 'ô' => 'o', 'ď' => 'd', 'ḟ' => 'f', 'ë' => 'e', 'š' => 's', 'ơ' => 'o',
-  'ß' => 'ss', 'ă' => 'a', 'ř' => 'r', 'ț' => 't', 'ň' => 'n', 'ā' => 'a', 'ķ' => 'k',
-  'ŝ' => 's', 'ỳ' => 'y', 'ņ' => 'n', 'ĺ' => 'l', 'ħ' => 'h', 'ṗ' => 'p', 'ó' => 'o',
-  'ú' => 'u', 'ě' => 'e', 'é' => 'e', 'ç' => 'c', 'ẁ' => 'w', 'ċ' => 'c', 'õ' => 'o',
-  'ṡ' => 's', 'ø' => 'o', 'ģ' => 'g', 'ŧ' => 't', 'ș' => 's', 'ė' => 'e', 'ĉ' => 'c',
-  'ś' => 's', 'î' => 'i', 'ű' => 'u', 'ć' => 'c', 'ę' => 'e', 'ŵ' => 'w', 'ṫ' => 't',
-  'ū' => 'u', 'č' => 'c', 'ö' => 'oe', 'è' => 'e', 'ŷ' => 'y', 'ą' => 'a', 'ł' => 'l',
-  'ų' => 'u', 'ů' => 'u', 'ş' => 's', 'ğ' => 'g', 'ļ' => 'l', 'ƒ' => 'f', 'ž' => 'z',
-  'ẃ' => 'w', 'ḃ' => 'b', 'å' => 'a', 'ì' => 'i', 'ï' => 'i', 'ḋ' => 'd', 'ť' => 't',
-  'ŗ' => 'r', 'ä' => 'ae', 'í' => 'i', 'ŕ' => 'r', 'ê' => 'e', 'ü' => 'ue', 'ò' => 'o',
-  'ē' => 'e', 'ñ' => 'n', 'ń' => 'n', 'ĥ' => 'h', 'ĝ' => 'g', 'đ' => 'd', 'ĵ' => 'j',
-  'ÿ' => 'y', 'ũ' => 'u', 'ŭ' => 'u', 'ư' => 'u', 'ţ' => 't', 'ý' => 'y', 'ő' => 'o',
-  'â' => 'a', 'ľ' => 'l', 'ẅ' => 'w', 'ż' => 'z', 'ī' => 'i', 'ã' => 'a', 'ġ' => 'g',
-  'ṁ' => 'm', 'ō' => 'o', 'ĩ' => 'i', 'ù' => 'u', 'į' => 'i', 'ź' => 'z', 'á' => 'a',
-  'û' => 'u', 'þ' => 'th', 'ð' => 'dh', 'æ' => 'ae', 'µ' => 'u', 'ĕ' => 'e', 
-            );
-        }
-        
-        $str = str_replace(
-                array_keys($UTF8_LOWER_ACCENTS),
-                array_values($UTF8_LOWER_ACCENTS),
-                $str
-            );
-    }
-    
-    if($case >= 0){
-        if ( is_null($UTF8_UPPER_ACCENTS) ) {
-            $UTF8_UPPER_ACCENTS = array(
-  'À' => 'A', 'Ô' => 'O', 'Ď' => 'D', 'Ḟ' => 'F', 'Ë' => 'E', 'Š' => 'S', 'Ơ' => 'O',
-  'Ă' => 'A', 'Ř' => 'R', 'Ț' => 'T', 'Ň' => 'N', 'Ā' => 'A', 'Ķ' => 'K',
-  'Ŝ' => 'S', 'Ỳ' => 'Y', 'Ņ' => 'N', 'Ĺ' => 'L', 'Ħ' => 'H', 'Ṗ' => 'P', 'Ó' => 'O',
-  'Ú' => 'U', 'Ě' => 'E', 'É' => 'E', 'Ç' => 'C', 'Ẁ' => 'W', 'Ċ' => 'C', 'Õ' => 'O',
-  'Ṡ' => 'S', 'Ø' => 'O', 'Ģ' => 'G', 'Ŧ' => 'T', 'Ș' => 'S', 'Ė' => 'E', 'Ĉ' => 'C',
-  'Ś' => 'S', 'Î' => 'I', 'Ű' => 'U', 'Ć' => 'C', 'Ę' => 'E', 'Ŵ' => 'W', 'Ṫ' => 'T',
-  'Ū' => 'U', 'Č' => 'C', 'Ö' => 'Oe', 'È' => 'E', 'Ŷ' => 'Y', 'Ą' => 'A', 'Ł' => 'L',
-  'Ų' => 'U', 'Ů' => 'U', 'Ş' => 'S', 'Ğ' => 'G', 'Ļ' => 'L', 'Ƒ' => 'F', 'Ž' => 'Z',
-  'Ẃ' => 'W', 'Ḃ' => 'B', 'Å' => 'A', 'Ì' => 'I', 'Ï' => 'I', 'Ḋ' => 'D', 'Ť' => 'T',
-  'Ŗ' => 'R', 'Ä' => 'Ae', 'Í' => 'I', 'Ŕ' => 'R', 'Ê' => 'E', 'Ü' => 'Ue', 'Ò' => 'O',
-  'Ē' => 'E', 'Ñ' => 'N', 'Ń' => 'N', 'Ĥ' => 'H', 'Ĝ' => 'G', 'Đ' => 'D', 'Ĵ' => 'J',
-  'Ÿ' => 'Y', 'Ũ' => 'U', 'Ŭ' => 'U', 'Ư' => 'U', 'Ţ' => 'T', 'Ý' => 'Y', 'Ő' => 'O',
-  'Â' => 'A', 'Ľ' => 'L', 'Ẅ' => 'W', 'Ż' => 'Z', 'Ī' => 'I', 'Ã' => 'A', 'Ġ' => 'G',
-  'Ṁ' => 'M', 'Ō' => 'O', 'Ĩ' => 'I', 'Ù' => 'U', 'Į' => 'I', 'Ź' => 'Z', 'Á' => 'A',
-  'Û' => 'U', 'Þ' => 'Th', 'Ð' => 'Dh', 'Æ' => 'Ae', 'Ĕ' => 'E',
-            );
-        }
-        $str = str_replace(
-                array_keys($UTF8_UPPER_ACCENTS),
-                array_values($UTF8_UPPER_ACCENTS),
-                $str
-            );
-    }
-    
-    return $str;
-    
+function utf8_accents_to_ascii($str, $case=0)
+{
+	static $UTF8_LOWER_ACCENTS = null;
+	static $UTF8_UPPER_ACCENTS = null;
+
+	if($case <= 0)
+	{
+
+		if (is_null($UTF8_LOWER_ACCENTS))
+		{
+			$UTF8_LOWER_ACCENTS = array(
+				'à' => 'a', 'ô' => 'o', 'ď' => 'd', 'ḟ' => 'f', 'ë' => 'e', 'š' => 's', 'ơ' => 'o',
+				'ß' => 'ss', 'ă' => 'a', 'ř' => 'r', 'ț' => 't', 'ň' => 'n', 'ā' => 'a', 'ķ' => 'k',
+				'ŝ' => 's', 'ỳ' => 'y', 'ņ' => 'n', 'ĺ' => 'l', 'ħ' => 'h', 'ṗ' => 'p', 'ó' => 'o',
+				'ú' => 'u', 'ě' => 'e', 'é' => 'e', 'ç' => 'c', 'ẁ' => 'w', 'ċ' => 'c', 'õ' => 'o',
+				'ṡ' => 's', 'ø' => 'o', 'ģ' => 'g', 'ŧ' => 't', 'ș' => 's', 'ė' => 'e', 'ĉ' => 'c',
+				'ś' => 's', 'î' => 'i', 'ű' => 'u', 'ć' => 'c', 'ę' => 'e', 'ŵ' => 'w', 'ṫ' => 't',
+				'ū' => 'u', 'č' => 'c', 'ö' => 'oe', 'è' => 'e', 'ŷ' => 'y', 'ą' => 'a', 'ł' => 'l',
+				'ų' => 'u', 'ů' => 'u', 'ş' => 's', 'ğ' => 'g', 'ļ' => 'l', 'ƒ' => 'f', 'ž' => 'z',
+				'ẃ' => 'w', 'ḃ' => 'b', 'å' => 'a', 'ì' => 'i', 'ï' => 'i', 'ḋ' => 'd', 'ť' => 't',
+				'ŗ' => 'r', 'ä' => 'ae', 'í' => 'i', 'ŕ' => 'r', 'ê' => 'e', 'ü' => 'ue', 'ò' => 'o',
+				'ē' => 'e', 'ñ' => 'n', 'ń' => 'n', 'ĥ' => 'h', 'ĝ' => 'g', 'đ' => 'd', 'ĵ' => 'j',
+				'ÿ' => 'y', 'ũ' => 'u', 'ŭ' => 'u', 'ư' => 'u', 'ţ' => 't', 'ý' => 'y', 'ő' => 'o',
+				'â' => 'a', 'ľ' => 'l', 'ẅ' => 'w', 'ż' => 'z', 'ī' => 'i', 'ã' => 'a', 'ġ' => 'g',
+				'ṁ' => 'm', 'ō' => 'o', 'ĩ' => 'i', 'ù' => 'u', 'į' => 'i', 'ź' => 'z', 'á' => 'a',
+				'û' => 'u', 'þ' => 'th', 'ð' => 'dh', 'æ' => 'ae', 'µ' => 'u', 'ĕ' => 'e',
+				);
+		}
+
+		$str = str_replace(array_keys($UTF8_LOWER_ACCENTS), array_values($UTF8_LOWER_ACCENTS), $str);
+	}
+
+	if($case >= 0)
+	{
+		if (is_null($UTF8_UPPER_ACCENTS))
+		{
+			$UTF8_UPPER_ACCENTS = array(
+				'À' => 'A', 'Ô' => 'O', 'Ď' => 'D', 'Ḟ' => 'F', 'Ë' => 'E', 'Š' => 'S', 'Ơ' => 'O',
+				'Ă' => 'A', 'Ř' => 'R', 'Ț' => 'T', 'Ň' => 'N', 'Ā' => 'A', 'Ķ' => 'K',
+				'Ŝ' => 'S', 'Ỳ' => 'Y', 'Ņ' => 'N', 'Ĺ' => 'L', 'Ħ' => 'H', 'Ṗ' => 'P', 'Ó' => 'O',
+				'Ú' => 'U', 'Ě' => 'E', 'É' => 'E', 'Ç' => 'C', 'Ẁ' => 'W', 'Ċ' => 'C', 'Õ' => 'O',
+				'Ṡ' => 'S', 'Ø' => 'O', 'Ģ' => 'G', 'Ŧ' => 'T', 'Ș' => 'S', 'Ė' => 'E', 'Ĉ' => 'C',
+				'Ś' => 'S', 'Î' => 'I', 'Ű' => 'U', 'Ć' => 'C', 'Ę' => 'E', 'Ŵ' => 'W', 'Ṫ' => 'T',
+				'Ū' => 'U', 'Č' => 'C', 'Ö' => 'Oe', 'È' => 'E', 'Ŷ' => 'Y', 'Ą' => 'A', 'Ł' => 'L',
+				'Ų' => 'U', 'Ů' => 'U', 'Ş' => 'S', 'Ğ' => 'G', 'Ļ' => 'L', 'Ƒ' => 'F', 'Ž' => 'Z',
+				'Ẃ' => 'W', 'Ḃ' => 'B', 'Å' => 'A', 'Ì' => 'I', 'Ï' => 'I', 'Ḋ' => 'D', 'Ť' => 'T',
+				'Ŗ' => 'R', 'Ä' => 'Ae', 'Í' => 'I', 'Ŕ' => 'R', 'Ê' => 'E', 'Ü' => 'Ue', 'Ò' => 'O',
+				'Ē' => 'E', 'Ñ' => 'N', 'Ń' => 'N', 'Ĥ' => 'H', 'Ĝ' => 'G', 'Đ' => 'D', 'Ĵ' => 'J',
+				'Ÿ' => 'Y', 'Ũ' => 'U', 'Ŭ' => 'U', 'Ư' => 'U', 'Ţ' => 'T', 'Ý' => 'Y', 'Ő' => 'O',
+				'Â' => 'A', 'Ľ' => 'L', 'Ẅ' => 'W', 'Ż' => 'Z', 'Ī' => 'I', 'Ã' => 'A', 'Ġ' => 'G',
+				'Ṁ' => 'M', 'Ō' => 'O', 'Ĩ' => 'I', 'Ù' => 'U', 'Į' => 'I', 'Ź' => 'Z', 'Á' => 'A',
+				'Û' => 'U', 'Þ' => 'Th', 'Ð' => 'Dh', 'Æ' => 'Ae', 'Ĕ' => 'E',
+				);
+		}
+
+		$str = str_replace(array_keys($UTF8_UPPER_ACCENTS), array_values($UTF8_UPPER_ACCENTS),  $str);
+	}
+
+	return $str;
 }
diff --git a/upload/include/utf8/utils/bad.php b/upload/include/utf8/utils/bad.php
index 52f1aee..78e9d17 100644
--- a/upload/include/utf8/utils/bad.php
+++ b/upload/include/utf8/utils/bad.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
 * @version $Id: bad.php,v 1.2 2006/02/26 13:20:44 harryf Exp $
 * Tools for locating / replacing bad bytes in UTF-8 strings
@@ -17,7 +18,6 @@
 * @see utf8_is_valid
 */
 
-//--------------------------------------------------------------------
 /**
 * Locates the first bad byte in a UTF-8 string returning it's
 * byte index in the string
@@ -30,31 +30,35 @@
 * @package utf8
 * @subpackage bad
 */
-function utf8_bad_find($str) {
-    $UTF8_BAD =
-    '([\x00-\x7F]'.                          # ASCII (including control chars)
-    '|[\xC2-\xDF][\x80-\xBF]'.               # non-overlong 2-byte
-    '|\xE0[\xA0-\xBF][\x80-\xBF]'.           # excluding overlongs
-    '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # straight 3-byte
-    '|\xED[\x80-\x9F][\x80-\xBF]'.           # excluding surrogates
-    '|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # planes 1-3
-    '|[\xF1-\xF3][\x80-\xBF]{3}'.            # planes 4-15
-    '|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # plane 16
-    '|(.{1}))';                              # invalid byte
-    $pos = 0;
-    $badList = array();
-    while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches)) {
-        $bytes = strlen($matches[0]);
-        if ( isset($matches[2])) {
-            return $pos;
-        }
-        $pos += $bytes;
-        $str = substr($str,$bytes);
-    }
-    return FALSE;
+function utf8_bad_find($str)
+{
+	$UTF8_BAD =
+		'([\x00-\x7F]'.                          # ASCII (including control chars)
+		'|[\xC2-\xDF][\x80-\xBF]'.               # Non-overlong 2-byte
+		'|\xE0[\xA0-\xBF][\x80-\xBF]'.           # Excluding overlongs
+		'|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # Straight 3-byte
+		'|\xED[\x80-\x9F][\x80-\xBF]'.           # Excluding surrogates
+		'|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # Planes 1-3
+		'|[\xF1-\xF3][\x80-\xBF]{3}'.            # Planes 4-15
+		'|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # Plane 16
+		'|(.{1}))';                              # Invalid byte
+	$pos = 0;
+	$badList = array();
+
+	while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches))
+	{
+		$bytes = strlen($matches[0]);
+
+		if (isset($matches[2]))
+			return $pos;
+
+		$pos += $bytes;
+		$str = substr($str,$bytes);
+	}
+
+	return false;
 }
 
-//--------------------------------------------------------------------
 /**
 * Locates all bad bytes in a UTF-8 string and returns a list of their
 * byte index in the string
@@ -67,34 +71,38 @@ function utf8_bad_find($str) {
 * @package utf8
 * @subpackage bad
 */
-function utf8_bad_findall($str) {
-    $UTF8_BAD =
-    '([\x00-\x7F]'.                          # ASCII (including control chars)
-    '|[\xC2-\xDF][\x80-\xBF]'.               # non-overlong 2-byte
-    '|\xE0[\xA0-\xBF][\x80-\xBF]'.           # excluding overlongs
-    '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # straight 3-byte
-    '|\xED[\x80-\x9F][\x80-\xBF]'.           # excluding surrogates
-    '|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # planes 1-3
-    '|[\xF1-\xF3][\x80-\xBF]{3}'.            # planes 4-15
-    '|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # plane 16
-    '|(.{1}))';                              # invalid byte
-    $pos = 0;
-    $badList = array();
-    while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches)) {
-        $bytes = strlen($matches[0]);
-        if ( isset($matches[2])) {
-            $badList[] = $pos;
-        }
-        $pos += $bytes;
-        $str = substr($str,$bytes);
-    }
-    if ( count($badList) > 0 ) {
-        return $badList;
-    }
-    return FALSE;
+function utf8_bad_findall($str)
+{
+	$UTF8_BAD =
+		'([\x00-\x7F]'.                          # ASCII (including control chars)
+		'|[\xC2-\xDF][\x80-\xBF]'.               # Non-overlong 2-byte
+		'|\xE0[\xA0-\xBF][\x80-\xBF]'.           # Excluding overlongs
+		'|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # Straight 3-byte
+		'|\xED[\x80-\x9F][\x80-\xBF]'.           # Excluding surrogates
+		'|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # Planes 1-3
+		'|[\xF1-\xF3][\x80-\xBF]{3}'.            # Planes 4-15
+		'|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # Plane 16
+		'|(.{1}))';                              # Invalid byte
+	$pos = 0;
+	$badList = array();
+
+	while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches))
+	{
+		$bytes = strlen($matches[0]);
+
+		if (isset($matches[2]))
+			$badList[] = $pos;
+
+		$pos += $bytes;
+		$str = substr($str,$bytes);
+	}
+
+	if (count($badList) > 0)
+		return $badList;
+
+	return false;
 }
 
-//--------------------------------------------------------------------
 /**
 * Strips out any bad bytes from a UTF-8 string and returns the rest
 * PCRE Pattern to locate bad bytes in a UTF-8 string
@@ -106,30 +114,35 @@ function utf8_bad_findall($str) {
 * @package utf8
 * @subpackage bad
 */
-function utf8_bad_strip($str) {
-    $UTF8_BAD =
-    '([\x00-\x7F]'.                          # ASCII (including control chars)
-    '|[\xC2-\xDF][\x80-\xBF]'.               # non-overlong 2-byte
-    '|\xE0[\xA0-\xBF][\x80-\xBF]'.           # excluding overlongs
-    '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # straight 3-byte
-    '|\xED[\x80-\x9F][\x80-\xBF]'.           # excluding surrogates
-    '|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # planes 1-3
-    '|[\xF1-\xF3][\x80-\xBF]{3}'.            # planes 4-15
-    '|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # plane 16
-    '|(.{1}))';                              # invalid byte
-    ob_start();
-    while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches)) {
-        if ( !isset($matches[2])) {
-            echo $matches[0];
-        }
-        $str = substr($str,strlen($matches[0]));
-    }
-    $result = ob_get_contents();
-    ob_end_clean();
-    return $result;
+function utf8_bad_strip($str)
+{
+	$UTF8_BAD =
+		'([\x00-\x7F]'.                          # ASCII (including control chars)
+		'|[\xC2-\xDF][\x80-\xBF]'.               # Non-overlong 2-byte
+		'|\xE0[\xA0-\xBF][\x80-\xBF]'.           # Excluding overlongs
+		'|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # Straight 3-byte
+		'|\xED[\x80-\x9F][\x80-\xBF]'.           # Excluding surrogates
+		'|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # Planes 1-3
+		'|[\xF1-\xF3][\x80-\xBF]{3}'.            # Planes 4-15
+		'|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # Plane 16
+		'|(.{1}))';                              # Invalid byte
+
+	ob_start();
+
+	while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches))
+	{
+		if (!isset($matches[2]))
+			echo $matches[0];
+
+		$str = substr($str, strlen($matches[0]));
+	}
+
+	$result = ob_get_contents();
+	ob_end_clean();
+
+	return $result;
 }
 
-//--------------------------------------------------------------------
 /**
 * Replace bad bytes with an alternative character - ASCII character
 * recommended is replacement char
@@ -143,32 +156,37 @@ function utf8_bad_strip($str) {
 * @package utf8
 * @subpackage bad
 */
-function utf8_bad_replace($str, $replace = '?') {
-    $UTF8_BAD =
-    '([\x00-\x7F]'.                          # ASCII (including control chars)
-    '|[\xC2-\xDF][\x80-\xBF]'.               # non-overlong 2-byte
-    '|\xE0[\xA0-\xBF][\x80-\xBF]'.           # excluding overlongs
-    '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # straight 3-byte
-    '|\xED[\x80-\x9F][\x80-\xBF]'.           # excluding surrogates
-    '|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # planes 1-3
-    '|[\xF1-\xF3][\x80-\xBF]{3}'.            # planes 4-15
-    '|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # plane 16
-    '|(.{1}))';                              # invalid byte
-    ob_start();
-    while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches)) {
-        if ( !isset($matches[2])) {
-            echo $matches[0];
-        } else {
-            echo $replace;
-        }
-        $str = substr($str,strlen($matches[0]));
-    }
-    $result = ob_get_contents();
-    ob_end_clean();
-    return $result;
+function utf8_bad_replace($str, $replace='?')
+{
+	$UTF8_BAD =
+		'([\x00-\x7F]'.                          # ASCII (including control chars)
+		'|[\xC2-\xDF][\x80-\xBF]'.               # Non-overlong 2-byte
+		'|\xE0[\xA0-\xBF][\x80-\xBF]'.           # Excluding overlongs
+		'|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # Straight 3-byte
+		'|\xED[\x80-\x9F][\x80-\xBF]'.           # Excluding surrogates
+		'|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # Planes 1-3
+		'|[\xF1-\xF3][\x80-\xBF]{3}'.            # Planes 4-15
+		'|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # Plane 16
+		'|(.{1}))';                              # Invalid byte
+
+	ob_start();
+
+	while (preg_match('/'.$UTF8_BAD.'/S', $str, $matches))
+	{
+		if (!isset($matches[2]))
+			echo $matches[0];
+		else
+			echo $replace;
+
+		$str = substr($str, strlen($matches[0]));
+	}
+
+	$result = ob_get_contents();
+	ob_end_clean();
+
+	return $result;
 }
 
-//--------------------------------------------------------------------
 /**
 * Return code from utf8_bad_identify() when a five octet sequence is detected.
 * Note: 5 octets sequences are valid UTF-8 but are not supported by Unicode so
@@ -177,7 +195,7 @@ function utf8_bad_replace($str, $replace = '?') {
 * @package utf8
 * @subpackage bad
 */
-define('UTF8_BAD_5OCTET',1);
+define('UTF8_BAD_5OCTET', 1);
 
 /**
 * Return code from utf8_bad_identify() when a six octet sequence is detected.
@@ -187,7 +205,7 @@ define('UTF8_BAD_5OCTET',1);
 * @package utf8
 * @subpackage bad
 */
-define('UTF8_BAD_6OCTET',2);
+define('UTF8_BAD_6OCTET', 2);
 
 /**
 * Return code from utf8_bad_identify().
@@ -196,7 +214,7 @@ define('UTF8_BAD_6OCTET',2);
 * @package utf8
 * @subpackage bad
 */
-define('UTF8_BAD_SEQID',3);
+define('UTF8_BAD_SEQID', 3);
 
 /**
 * Return code from utf8_bad_identify().
@@ -205,7 +223,7 @@ define('UTF8_BAD_SEQID',3);
 * @package utf8
 * @subpackage bad
 */
-define('UTF8_BAD_NONSHORT',4);
+define('UTF8_BAD_NONSHORT', 4);
 
 /**
 * Return code from utf8_bad_identify().
@@ -214,7 +232,7 @@ define('UTF8_BAD_NONSHORT',4);
 * @package utf8
 * @subpackage bad
 */
-define('UTF8_BAD_SURROGATE',5);
+define('UTF8_BAD_SURROGATE', 5);
 
 /**
 * Return code from utf8_bad_identify().
@@ -223,7 +241,7 @@ define('UTF8_BAD_SURROGATE',5);
 * @package utf8
 * @subpackage bad
 */
-define('UTF8_BAD_UNIOUTRANGE',6);
+define('UTF8_BAD_UNIOUTRANGE', 6);
 
 /**
 * Return code from utf8_bad_identify().
@@ -233,9 +251,8 @@ define('UTF8_BAD_UNIOUTRANGE',6);
 * @package utf8
 * @subpackage bad
 */
-define('UTF8_BAD_SEQINCOMPLETE',7);
+define('UTF8_BAD_SEQINCOMPLETE', 7);
 
-//--------------------------------------------------------------------
 /**
 * Reports on the type of bad byte found in a UTF-8 string. Returns a
 * status code on the first bad byte found
@@ -247,131 +264,129 @@ define('UTF8_BAD_SEQINCOMPLETE',7);
 * @package utf8
 * @subpackage bad
 */
-function utf8_bad_identify($str, &$i) {
-    
-    $mState = 0;     // cached expected number of octets after the current octet
-                     // until the beginning of the next UTF8 character sequence
-    $mUcs4  = 0;     // cached Unicode character
-    $mBytes = 1;     // cached expected number of octets in the current sequence
-    
-    $len = strlen($str);
-    
-    for($i = 0; $i < $len; $i++) {
-        
-        $in = ord($str{$i});
-        
-        if ( $mState == 0) {
-            
-            // When mState is zero we expect either a US-ASCII character or a
-            // multi-octet sequence.
-            if (0 == (0x80 & ($in))) {
-                // US-ASCII, pass straight through.
-                $mBytes = 1;
-                
-            } else if (0xC0 == (0xE0 & ($in))) {
-                // First octet of 2 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x1F) << 6;
-                $mState = 1;
-                $mBytes = 2;
-                
-            } else if (0xE0 == (0xF0 & ($in))) {
-                // First octet of 3 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x0F) << 12;
-                $mState = 2;
-                $mBytes = 3;
-                
-            } else if (0xF0 == (0xF8 & ($in))) {
-                // First octet of 4 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x07) << 18;
-                $mState = 3;
-                $mBytes = 4;
-                
-            } else if (0xF8 == (0xFC & ($in))) {
-                
-                /* First octet of 5 octet sequence.
-                *
-                * This is illegal because the encoded codepoint must be either
-                * (a) not the shortest form or
-                * (b) outside the Unicode range of 0-0x10FFFF.
-                */
-                
-                return UTF8_BAD_5OCTET;
-                
-            } else if (0xFC == (0xFE & ($in))) {
-                
-                // First octet of 6 octet sequence, see comments for 5 octet sequence.
-                return UTF8_BAD_6OCTET;
-                
-            } else {
-                // Current octet is neither in the US-ASCII range nor a legal first
-                // octet of a multi-octet sequence.
-                return UTF8_BAD_SEQID;
-                
-            }
-        
-        } else {
-            
-            // When mState is non-zero, we expect a continuation of the multi-octet
-            // sequence
-            if (0x80 == (0xC0 & ($in))) {
-                
-                // Legal continuation.
-                $shift = ($mState - 1) * 6;
-                $tmp = $in;
-                $tmp = ($tmp & 0x0000003F) << $shift;
-                $mUcs4 |= $tmp;
-            
-                /**
-                * End of the multi-octet sequence. mUcs4 now contains the final
-                * Unicode codepoint to be output
-                */
-                if (0 == --$mState) {
-                    
-                    // From Unicode 3.1, non-shortest form is illegal
-                    if (((2 == $mBytes) && ($mUcs4 < 0x0080)) ||
-                        ((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
-                        ((4 == $mBytes) && ($mUcs4 < 0x10000)) ) {
-                        return UTF8_BAD_NONSHORT;
-                        
-                    // From Unicode 3.2, surrogate characters are illegal
-                    } else if (($mUcs4 & 0xFFFFF800) == 0xD800) {
-                        return UTF8_BAD_SURROGATE;
-                        
-                    // Codepoints outside the Unicode range are illegal
-                    } else if ($mUcs4 > 0x10FFFF) {
-                        return UTF8_BAD_UNIOUTRANGE;
-                    }
-                    
-                    //initialize UTF8 cache
-                    $mState = 0;
-                    $mUcs4  = 0;
-                    $mBytes = 1;
-                }
-            
-            } else {
-                // ((0xC0 & (*in) != 0x80) && (mState != 0))
-                // Incomplete multi-octet sequence.
-                $i--;
-                return UTF8_BAD_SEQINCOMPLETE;
-            }
-        }
-    }
-    
-    if ( $mState != 0 ) {
-        // Incomplete multi-octet sequence.
-        $i--;
-        return UTF8_BAD_SEQINCOMPLETE;
-    }
-    
-    // No bad octets found
-    $i = NULL;
-    return FALSE;
+function utf8_bad_identify($str, &$i)
+{
+	$mState = 0;	// Cached expected number of octets after the current octet
+					// until the beginning of the next UTF8 character sequence
+	$mUcs4  = 0;	// Cached Unicode character
+	$mBytes = 1;	// Cached expected number of octets in the current sequence
+
+	$len = strlen($str);
+
+	for($i=0; $i < $len; $i++)
+	{
+		$in = ord($str{$i});
+
+		if ( $mState == 0)
+		{
+			// When mState is zero we expect either a US-ASCII character or a multi-octet sequence.
+			if (0 == (0x80 & ($in)))
+			{
+				// US-ASCII, pass straight through.
+				$mBytes = 1;
+			}
+			else if (0xC0 == (0xE0 & ($in)))
+			{
+				// First octet of 2 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x1F) << 6;
+				$mState = 1;
+				$mBytes = 2;
+			}
+			else if (0xE0 == (0xF0 & ($in)))
+			{
+				// First octet of 3 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x0F) << 12;
+				$mState = 2;
+				$mBytes = 3;
+			}
+			else if (0xF0 == (0xF8 & ($in)))
+			{
+				// First octet of 4 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x07) << 18;
+				$mState = 3;
+				$mBytes = 4;
+			}
+			else if (0xF8 == (0xFC & ($in)))
+			{
+				/* First octet of 5 octet sequence.
+				*
+				* This is illegal because the encoded codepoint must be either
+				* (a) not the shortest form or
+				* (b) outside the Unicode range of 0-0x10FFFF.
+				*/
+				return UTF8_BAD_5OCTET;
+			}
+			else if (0xFC == (0xFE & ($in)))
+			{
+				// First octet of 6 octet sequence, see comments for 5 octet sequence.
+				return UTF8_BAD_6OCTET;
+			}
+			else
+			{
+				// Current octet is neither in the US-ASCII range nor a legal first
+				// octet of a multi-octet sequence.
+				return UTF8_BAD_SEQID;
+			}
+		}
+		else
+		{
+			// When mState is non-zero, we expect a continuation of the multi-octet sequence
+			if (0x80 == (0xC0 & ($in)))
+			{
+				// Legal continuation.
+				$shift = ($mState - 1) * 6;
+				$tmp = $in;
+				$tmp = ($tmp & 0x0000003F) << $shift;
+				$mUcs4 |= $tmp;
+
+				/**
+				* End of the multi-octet sequence. mUcs4 now contains the final
+				* Unicode codepoint to be output
+				*/
+				if (0 == --$mState)
+				{
+					// From Unicode 3.1, non-shortest form is illegal
+					if (((2 == $mBytes) && ($mUcs4 < 0x0080)) ||
+					((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
+					((4 == $mBytes) && ($mUcs4 < 0x10000)) )
+						return UTF8_BAD_NONSHORT;
+					else if (($mUcs4 & 0xFFFFF800) == 0xD800) // From Unicode 3.2, surrogate characters are illegal
+						return UTF8_BAD_SURROGATE;
+					else if ($mUcs4 > 0x10FFFF) // Codepoints outside the Unicode range are illegal
+						return UTF8_BAD_UNIOUTRANGE;
+
+					// Initialize UTF8 cache
+					$mState = 0;
+					$mUcs4  = 0;
+					$mBytes = 1;
+				}
+
+			}
+			else
+			{
+				// ((0xC0 & (*in) != 0x80) && (mState != 0))
+				// Incomplete multi-octet sequence.
+				$i--;
+				return UTF8_BAD_SEQINCOMPLETE;
+			}
+		}
+	}
+
+	// Incomplete multi-octet sequence
+	if ($mState != 0)
+	{
+		$i--;
+		return UTF8_BAD_SEQINCOMPLETE;
+	}
+
+	// No bad octets found
+	$i = null;
+	return false;
 }
 
-//--------------------------------------------------------------------
 /**
 * Takes a return code from utf8_bad_identify() are returns a message
 * (in English) explaining what the problem is.
@@ -381,41 +396,40 @@ function utf8_bad_identify($str, &$i) {
 * @package utf8
 * @subpackage bad
 */
-function utf8_bad_explain($code) {
-    
-    switch ($code) {
-        
-        case UTF8_BAD_5OCTET:
-            return 'Five octet sequences are valid UTF-8 but are not supported by Unicode';
-        break;
-        
-        case UTF8_BAD_6OCTET:
-            return 'Six octet sequences are valid UTF-8 but are not supported by Unicode';
-        break;
-        
-        case UTF8_BAD_SEQID:
-            return 'Invalid octet for use as start of multi-byte UTF-8 sequence';
-        break;
-        
-        case UTF8_BAD_NONSHORT:
-            return 'From Unicode 3.1, non-shortest form is illegal';
-        break;
-        
-        case UTF8_BAD_SURROGATE:
-            return 'From Unicode 3.2, surrogate characters are illegal';
-        break;
-        
-        case UTF8_BAD_UNIOUTRANGE:
-            return 'Codepoints outside the Unicode range are illegal';
-        break;
-        
-        case UTF8_BAD_SEQINCOMPLETE:
-            return 'Incomplete multi-octet sequence';
-        break;
-        
-    }
-    
-    trigger_error('Unknown error code: '.$code,E_USER_WARNING);
-    return FALSE;
-    
+function utf8_bad_explain($code)
+{
+	switch ($code)
+	{
+		case UTF8_BAD_5OCTET:
+		return 'Five octet sequences are valid UTF-8 but are not supported by Unicode';
+		break;
+
+		case UTF8_BAD_6OCTET:
+		return 'Six octet sequences are valid UTF-8 but are not supported by Unicode';
+		break;
+
+		case UTF8_BAD_SEQID:
+		return 'Invalid octet for use as start of multi-byte UTF-8 sequence';
+		break;
+
+		case UTF8_BAD_NONSHORT:
+		return 'From Unicode 3.1, non-shortest form is illegal';
+		break;
+
+		case UTF8_BAD_SURROGATE:
+		return 'From Unicode 3.2, surrogate characters are illegal';
+		break;
+
+		case UTF8_BAD_UNIOUTRANGE:
+		return 'Codepoints outside the Unicode range are illegal';
+		break;
+
+		case UTF8_BAD_SEQINCOMPLETE:
+		return 'Incomplete multi-octet sequence';
+		break;
+	}
+
+	trigger_error('Unknown error code: '.$code, E_USER_WARNING);
+
+	return false;
 }
diff --git a/upload/include/utf8/utils/index.html b/upload/include/utf8/utils/index.html
index 2db9a3c..89337b2 100644
--- a/upload/include/utf8/utils/index.html
+++ b/upload/include/utf8/utils/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/include/utf8/utils/patterns.php b/upload/include/utf8/utils/patterns.php
index a3dee6a..5a85a4f 100644
--- a/upload/include/utf8/utils/patterns.php
+++ b/upload/include/utf8/utils/patterns.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
 * PCRE Regular expressions for UTF-8. Note this file is not actually used by
 * the rest of the library but these regular expressions can be useful to have
@@ -9,7 +10,6 @@
 * @subpackage patterns
 */
 
-//--------------------------------------------------------------------
 /**
 * PCRE Pattern to check a UTF-8 string is valid
 * Comes from W3 FAQ: Multilingual Forms
@@ -19,17 +19,16 @@
 * @subpackage patterns
 */
 $UTF8_VALID = '^('.
-    '[\x00-\x7F]'.                          # ASCII (including control chars)
-    '|[\xC2-\xDF][\x80-\xBF]'.              # non-overlong 2-byte
-    '|\xE0[\xA0-\xBF][\x80-\xBF]'.          # excluding overlongs
-    '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.   # straight 3-byte
-    '|\xED[\x80-\x9F][\x80-\xBF]'.          # excluding surrogates
-    '|\xF0[\x90-\xBF][\x80-\xBF]{2}'.       # planes 1-3
-    '|[\xF1-\xF3][\x80-\xBF]{3}'.           # planes 4-15
-    '|\xF4[\x80-\x8F][\x80-\xBF]{2}'.       # plane 16
-    ')*$';
+	'[\x00-\x7F]'.                          # ASCII (including control chars)
+	'|[\xC2-\xDF][\x80-\xBF]'.              # Non-overlong 2-byte
+	'|\xE0[\xA0-\xBF][\x80-\xBF]'.          # Excluding overlongs
+	'|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.   # Straight 3-byte
+	'|\xED[\x80-\x9F][\x80-\xBF]'.          # Excluding surrogates
+	'|\xF0[\x90-\xBF][\x80-\xBF]{2}'.       # Planes 1-3
+	'|[\xF1-\xF3][\x80-\xBF]{3}'.           # Planes 4-15
+	'|\xF4[\x80-\x8F][\x80-\xBF]{2}'.       # Plane 16
+	')*$';
 
-//--------------------------------------------------------------------
 /**
 * PCRE Pattern to match single UTF-8 characters
 * Comes from W3 FAQ: Multilingual Forms
@@ -39,16 +38,15 @@ $UTF8_VALID = '^('.
 * @subpackage patterns
 */
 $UTF8_MATCH =
-    '([\x00-\x7F])'.                          # ASCII (including control chars)
-    '|([\xC2-\xDF][\x80-\xBF])'.              # non-overlong 2-byte
-    '|(\xE0[\xA0-\xBF][\x80-\xBF])'.          # excluding overlongs
-    '|([\xE1-\xEC\xEE\xEF][\x80-\xBF]{2})'.   # straight 3-byte
-    '|(\xED[\x80-\x9F][\x80-\xBF])'.          # excluding surrogates
-    '|(\xF0[\x90-\xBF][\x80-\xBF]{2})'.       # planes 1-3
-    '|([\xF1-\xF3][\x80-\xBF]{3})'.           # planes 4-15
-    '|(\xF4[\x80-\x8F][\x80-\xBF]{2})';       # plane 16
+	'([\x00-\x7F])'.                          # ASCII (including control chars)
+	'|([\xC2-\xDF][\x80-\xBF])'.              # Non-overlong 2-byte
+	'|(\xE0[\xA0-\xBF][\x80-\xBF])'.          # Excluding overlongs
+	'|([\xE1-\xEC\xEE\xEF][\x80-\xBF]{2})'.   # Straight 3-byte
+	'|(\xED[\x80-\x9F][\x80-\xBF])'.          # Excluding surrogates
+	'|(\xF0[\x90-\xBF][\x80-\xBF]{2})'.       # Planes 1-3
+	'|([\xF1-\xF3][\x80-\xBF]{3})'.           # Planes 4-15
+	'|(\xF4[\x80-\x8F][\x80-\xBF]{2})';       # Plane 16
 
-//--------------------------------------------------------------------
 /**
 * PCRE Pattern to locate bad bytes in a UTF-8 string
 * Comes from W3 FAQ: Multilingual Forms
@@ -58,12 +56,12 @@ $UTF8_MATCH =
 * @subpackage patterns
 */
 $UTF8_BAD =
-    '([\x00-\x7F]'.                          # ASCII (including control chars)
-    '|[\xC2-\xDF][\x80-\xBF]'.               # non-overlong 2-byte
-    '|\xE0[\xA0-\xBF][\x80-\xBF]'.           # excluding overlongs
-    '|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # straight 3-byte
-    '|\xED[\x80-\x9F][\x80-\xBF]'.           # excluding surrogates
-    '|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # planes 1-3
-    '|[\xF1-\xF3][\x80-\xBF]{3}'.            # planes 4-15
-    '|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # plane 16
-    '|(.{1}))';                              # invalid byte
+	'([\x00-\x7F]'.                          # ASCII (including control chars)
+	'|[\xC2-\xDF][\x80-\xBF]'.               # Non-overlong 2-byte
+	'|\xE0[\xA0-\xBF][\x80-\xBF]'.           # Excluding overlongs
+	'|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}'.    # Straight 3-byte
+	'|\xED[\x80-\x9F][\x80-\xBF]'.           # Excluding surrogates
+	'|\xF0[\x90-\xBF][\x80-\xBF]{2}'.        # Planes 1-3
+	'|[\xF1-\xF3][\x80-\xBF]{3}'.            # Planes 4-15
+	'|\xF4[\x80-\x8F][\x80-\xBF]{2}'.        # Plane 16
+	'|(.{1}))';                              # Invalid byte
diff --git a/upload/include/utf8/utils/position.php b/upload/include/utf8/utils/position.php
index db8ba3b..7c62d10 100644
--- a/upload/include/utf8/utils/position.php
+++ b/upload/include/utf8/utils/position.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
 * Locate a byte index given a UTF-8 character index
 * @version $Id: position.php,v 1.1 2006/10/01 00:01:31 harryf Exp $
@@ -6,7 +7,6 @@
 * @subpackage position
 */
 
-//--------------------------------------------------------------------
 /**
 * Given a string and a character index in the string, in
 * terms of the UTF-8 character position, returns the byte
@@ -27,93 +27,87 @@
 * @package utf8
 * @subpackage position
 */
-function utf8_byte_position() {
-    
-    $args = func_get_args();
-    $str =& array_shift($args);
-    if (!is_string($str)) return false;
-    
-    $result = array();
-    
-    // trivial byte index, character offset pair
-    $prev = array(0,0);
-    
-    // use a short piece of str to estimate bytes per character
-    // $i (& $j) -> byte indexes into $str
-    $i = utf8_locate_next_chr($str, 300);
-    
-    // $c -> character offset into $str
-    $c = strlen(utf8_decode(substr($str,0,$i)));
-    
-    // deal with arguments from lowest to highest
-    sort($args);
-    
-    foreach ($args as $offset) {
-        // sanity checks FIXME
-        
-        // 0 is an easy check
-        if ($offset == 0) { $result[] = 0; continue; }
-        
-        // ensure no endless looping
-        $safety_valve = 50;
-        
-        do {
-            
-            if ( ($c - $prev[1]) == 0 ) {
-                // Hack: gone past end of string
-                $error = 0;
-                $i = strlen($str);
-                break;
-            }
-            
-            $j = $i + (int)(($offset-$c) * ($i - $prev[0]) / ($c - $prev[1]));
-            
-            // correct to utf8 character boundary
-            $j = utf8_locate_next_chr($str, $j);
-            
-            // save the index, offset for use next iteration
-            $prev = array($i,$c);
-            
-            if ($j > $i) {
-                // determine new character offset
-                $c += strlen(utf8_decode(substr($str,$i,$j-$i)));
-            } else {
-                // ditto
-                $c -= strlen(utf8_decode(substr($str,$j,$i-$j)));
-            }
-            
-            $error = abs($c-$offset);
-            
-            // ready for next time around
-            $i = $j;
-        
-        // from 7 it is faster to iterate over the string
-        } while ( ($error > 7) && --$safety_valve) ;
-        
-        if ($error && $error <= 7) {
-            
-            if ($c < $offset) {
-                // move up
-                while ($error--) { $i = utf8_locate_next_chr($str,++$i); }
-            } else {
-                // move down
-                while ($error--) { $i = utf8_locate_current_chr($str,--$i); }
-            }
-            
-            // ready for next arg
-            $c = $offset;
-        }
-        $result[] = $i;
-    }
-    
-    if ( count($result) == 1 ) {
-        return $result[0];
-    }
-    
-    return $result;
+function utf8_byte_position()
+{
+	$args = func_get_args();
+	$str =& array_shift($args);
+
+	if (!is_string($str))
+		return false;
+
+	$result = array();
+	$prev = array(0, 0); // Trivial byte index, character offset pair
+	$i = utf8_locate_next_chr($str, 300); // Use a short piece of str to estimate bytes per character. $i (& $j) -> byte indexes into $str
+	$c = strlen(utf8_decode(substr($str, 0, $i))); // $c -> character offset into $str
+
+	// Deal with arguments from lowest to highest
+	sort($args);
+
+	foreach ($args as $offset)
+	{
+		// Sanity checks FIXME
+
+		// 0 is an easy check
+		if ($offset == 0)
+		{
+			$result[] = 0; continue;
+		}
+
+		// Ensure no endless looping
+		$safety_valve = 50;
+
+		do
+		{
+			if (($c - $prev[1]) == 0)
+			{
+				// Hack: gone past end of string
+				$error = 0;
+				$i = strlen($str);
+				break;
+			}
+
+			$j = $i + (int)(($offset-$c) * ($i - $prev[0]) / ($c - $prev[1]));
+			$j = utf8_locate_next_chr($str, $j); // Correct to utf8 character boundary
+			$prev = array($i,$c); // Save the index, offset for use next iteration
+
+			if ($j > $i)
+				$c += strlen(utf8_decode(substr($str, $i, $j-$i))); // Determine new character offset
+			else
+				$c -= strlen(utf8_decode(substr($str, $j, $i-$j))); // Ditto
+
+			$error = abs($c-$offset);
+			$i = $j; // Ready for next time around
+		}
+		while (($error > 7) && --$safety_valve); // From 7 it is faster to iterate over the string
+
+		if ($error && $error <= 7)
+		{
+			if ($c < $offset)
+			{
+				// Move up
+				while ($error--)
+					$i = utf8_locate_next_chr($str, ++$i);
+			}
+			else
+			{
+				// Move down
+				while ($error--)
+					$i = utf8_locate_current_chr($str, --$i);
+			}
+
+			// Ready for next arg
+			$c = $offset;
+		}
+
+		$result[] = $i;
+	}
+
+	if (count($result) == 1)
+		return $result[0];
+
+	return $result;
 }
 
-//--------------------------------------------------------------------
 /**
 * Given a string and any byte index, returns the byte index
 * of the start of the current UTF-8 character, relative to supplied
@@ -128,22 +122,24 @@ function utf8_byte_position() {
 * @package utf8
 * @subpackage position
 */
-function utf8_locate_current_chr( &$str, $idx ) {
-    
-    if ($idx <= 0) return 0;
-    
-    $limit = strlen($str);
-    if ($idx >= $limit) return $limit;
-    
-    // Binary value for any byte after the first in a multi-byte UTF-8 character
-    // will be like 10xxxxxx so & 0xC0 can be used to detect this kind
-    // of byte - assuming well formed UTF-8
-    while ($idx && ((ord($str[$idx]) & 0xC0) == 0x80)) $idx--;
-    
-    return $idx;
+function utf8_locate_current_chr( &$str, $idx )
+{
+	if ($idx <= 0)
+		return 0;
+
+	$limit = strlen($str);
+	if ($idx >= $limit)
+		return $limit;
+
+	// Binary value for any byte after the first in a multi-byte UTF-8 character
+	// will be like 10xxxxxx so & 0xC0 can be used to detect this kind
+	// of byte - assuming well formed UTF-8
+	while ($idx && ((ord($str[$idx]) & 0xC0) == 0x80))
+		$idx--;
+
+	return $idx;
 }
 
-//--------------------------------------------------------------------
 /**
 * Given a string and any byte index, returns the byte index
 * of the start of the next UTF-8 character, relative to supplied
@@ -156,18 +152,20 @@ function utf8_locate_current_chr( &$str, $idx ) {
 * @package utf8
 * @subpackage position
 */
-function utf8_locate_next_chr( &$str, $idx ) {
-    
-    if ($idx <= 0) return 0;
-    
-    $limit = strlen($str);
-    if ($idx >= $limit) return $limit;
-    
-    // Binary value for any byte after the first in a multi-byte UTF-8 character
-    // will be like 10xxxxxx so & 0xC0 can be used to detect this kind
-    // of byte - assuming well formed UTF-8
-    while (($idx < $limit) && ((ord($str[$idx]) & 0xC0) == 0x80)) $idx++;
-    
-    return $idx;
-}
+function utf8_locate_next_chr(&$str, $idx)
+{
+	if ($idx <= 0)
+		return 0;
+
+	$limit = strlen($str);
+	if ($idx >= $limit)
+		return $limit;
 
+	// Binary value for any byte after the first in a multi-byte UTF-8 character
+	// will be like 10xxxxxx so & 0xC0 can be used to detect this kind
+	// of byte - assuming well formed UTF-8
+	while (($idx < $limit) && ((ord($str[$idx]) & 0xC0) == 0x80))
+		$idx++;
+
+	return $idx;
+}
diff --git a/upload/include/utf8/utils/specials.php b/upload/include/utf8/utils/specials.php
index 30613ee..69219dc 100644
--- a/upload/include/utf8/utils/specials.php
+++ b/upload/include/utf8/utils/specials.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
 * Utilities for processing "special" characters in UTF-8. "Special" largely means anything which would
 * be regarded as a non-word character, like ASCII control characters and punctuation. This has a "Roman"
@@ -10,9 +11,8 @@
 * @see utf8_is_valid
 */
 
-//--------------------------------------------------------------------
 /**
-* Used internally. Builds a PCRE pattern from the $UTF8_SPECIAL_CHARS 
+* Used internally. Builds a PCRE pattern from the $UTF8_SPECIAL_CHARS
 * array defined in this file
 * The $UTF8_SPECIAL_CHARS should contain all special characters (non-letter/non-digit)
 * defined in the various local charsets - it's not a complete list of
@@ -27,70 +27,71 @@
 * @see utf8_is_word_chars
 * @see utf8_strip_specials
 */
-function utf8_specials_pattern() {
-    static $pattern = NULL;
-    
-    if ( !$pattern ) {
-        $UTF8_SPECIAL_CHARS = array(
-    0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023,
-    0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c,
-    0x002f,         0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x005b,
-    0x005c, 0x005d, 0x005e,         0x0060, 0x007b, 0x007c, 0x007d, 0x007e,
-    0x007f, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088,
-    0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092,
-    0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c,
-    0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6,
-    0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0,
-    0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba,
-    0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00d7, 0x00f7, 0x02c7, 0x02d8, 0x02d9,
-    0x02da, 0x02db, 0x02dc, 0x02dd, 0x0300, 0x0301, 0x0303, 0x0309, 0x0323, 0x0384,
-    0x0385, 0x0387, 0x03b2, 0x03c6, 0x03d1, 0x03d2, 0x03d5, 0x03d6, 0x05b0, 0x05b1,
-    0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, 0x05b8, 0x05b9, 0x05bb, 0x05bc,
-    0x05bd, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f3, 0x05f4, 0x060c,
-    0x061b, 0x061f, 0x0640, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, 0x0650, 0x0651,
-    0x0652, 0x066a, 0x0e3f, 0x200c, 0x200d, 0x200e, 0x200f, 0x2013, 0x2014, 0x2015,
-    0x2017, 0x2018, 0x2019, 0x201a, 0x201c, 0x201d, 0x201e, 0x2020, 0x2021, 0x2022,
-    0x2026, 0x2030, 0x2032, 0x2033, 0x2039, 0x203a, 0x2044, 0x20a7, 0x20aa, 0x20ab,
-    0x20ac, 0x2116, 0x2118, 0x2122, 0x2126, 0x2135, 0x2190, 0x2191, 0x2192, 0x2193,
-    0x2194, 0x2195, 0x21b5, 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x2200, 0x2202,
-    0x2203, 0x2205, 0x2206, 0x2207, 0x2208, 0x2209, 0x220b, 0x220f, 0x2211, 0x2212,
-    0x2215, 0x2217, 0x2219, 0x221a, 0x221d, 0x221e, 0x2220, 0x2227, 0x2228, 0x2229,
-    0x222a, 0x222b, 0x2234, 0x223c, 0x2245, 0x2248, 0x2260, 0x2261, 0x2264, 0x2265,
-    0x2282, 0x2283, 0x2284, 0x2286, 0x2287, 0x2295, 0x2297, 0x22a5, 0x22c5, 0x2310,
-    0x2320, 0x2321, 0x2329, 0x232a, 0x2469, 0x2500, 0x2502, 0x250c, 0x2510, 0x2514,
-    0x2518, 0x251c, 0x2524, 0x252c, 0x2534, 0x253c, 0x2550, 0x2551, 0x2552, 0x2553,
-    0x2554, 0x2555, 0x2556, 0x2557, 0x2558, 0x2559, 0x255a, 0x255b, 0x255c, 0x255d,
-    0x255e, 0x255f, 0x2560, 0x2561, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567,
-    0x2568, 0x2569, 0x256a, 0x256b, 0x256c, 0x2580, 0x2584, 0x2588, 0x258c, 0x2590,
-    0x2591, 0x2592, 0x2593, 0x25a0, 0x25b2, 0x25bc, 0x25c6, 0x25ca, 0x25cf, 0x25d7,
-    0x2605, 0x260e, 0x261b, 0x261e, 0x2660, 0x2663, 0x2665, 0x2666, 0x2701, 0x2702,
-    0x2703, 0x2704, 0x2706, 0x2707, 0x2708, 0x2709, 0x270c, 0x270d, 0x270e, 0x270f,
-    0x2710, 0x2711, 0x2712, 0x2713, 0x2714, 0x2715, 0x2716, 0x2717, 0x2718, 0x2719,
-    0x271a, 0x271b, 0x271c, 0x271d, 0x271e, 0x271f, 0x2720, 0x2721, 0x2722, 0x2723,
-    0x2724, 0x2725, 0x2726, 0x2727, 0x2729, 0x272a, 0x272b, 0x272c, 0x272d, 0x272e,
-    0x272f, 0x2730, 0x2731, 0x2732, 0x2733, 0x2734, 0x2735, 0x2736, 0x2737, 0x2738,
-    0x2739, 0x273a, 0x273b, 0x273c, 0x273d, 0x273e, 0x273f, 0x2740, 0x2741, 0x2742,
-    0x2743, 0x2744, 0x2745, 0x2746, 0x2747, 0x2748, 0x2749, 0x274a, 0x274b, 0x274d,
-    0x274f, 0x2750, 0x2751, 0x2752, 0x2756, 0x2758, 0x2759, 0x275a, 0x275b, 0x275c,
-    0x275d, 0x275e, 0x2761, 0x2762, 0x2763, 0x2764, 0x2765, 0x2766, 0x2767, 0x277f,
-    0x2789, 0x2793, 0x2794, 0x2798, 0x2799, 0x279a, 0x279b, 0x279c, 0x279d, 0x279e,
-    0x279f, 0x27a0, 0x27a1, 0x27a2, 0x27a3, 0x27a4, 0x27a5, 0x27a6, 0x27a7, 0x27a8,
-    0x27a9, 0x27aa, 0x27ab, 0x27ac, 0x27ad, 0x27ae, 0x27af, 0x27b1, 0x27b2, 0x27b3,
-    0x27b4, 0x27b5, 0x27b6, 0x27b7, 0x27b8, 0x27b9, 0x27ba, 0x27bb, 0x27bc, 0x27bd,
-    0x27be, 0xf6d9, 0xf6da, 0xf6db, 0xf8d7, 0xf8d8, 0xf8d9, 0xf8da, 0xf8db, 0xf8dc,
-    0xf8dd, 0xf8de, 0xf8df, 0xf8e0, 0xf8e1, 0xf8e2, 0xf8e3, 0xf8e4, 0xf8e5, 0xf8e6,
-    0xf8e7, 0xf8e8, 0xf8e9, 0xf8ea, 0xf8eb, 0xf8ec, 0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0,
-    0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4, 0xf8f5, 0xf8f6, 0xf8f7, 0xf8f8, 0xf8f9, 0xf8fa,
-    0xf8fb, 0xf8fc, 0xf8fd, 0xf8fe, 0xfe7c, 0xfe7d,
-            );
-        $pattern = preg_quote(utf8_from_unicode($UTF8_SPECIAL_CHARS), '/');
-        $pattern = '/[\x00-\x19'.$pattern.']/u';
-    }
-    
-    return $pattern;
+function utf8_specials_pattern()
+{
+	static $pattern = null;
+
+	if (!$pattern)
+	{
+		$UTF8_SPECIAL_CHARS = array(
+			0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023,
+			0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c,
+			0x002f,         0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x005b,
+			0x005c, 0x005d, 0x005e,         0x0060, 0x007b, 0x007c, 0x007d, 0x007e,
+			0x007f, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088,
+			0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092,
+			0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c,
+			0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6,
+			0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0,
+			0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba,
+			0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00d7, 0x00f7, 0x02c7, 0x02d8, 0x02d9,
+			0x02da, 0x02db, 0x02dc, 0x02dd, 0x0300, 0x0301, 0x0303, 0x0309, 0x0323, 0x0384,
+			0x0385, 0x0387, 0x03b2, 0x03c6, 0x03d1, 0x03d2, 0x03d5, 0x03d6, 0x05b0, 0x05b1,
+			0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, 0x05b8, 0x05b9, 0x05bb, 0x05bc,
+			0x05bd, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05f3, 0x05f4, 0x060c,
+			0x061b, 0x061f, 0x0640, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f, 0x0650, 0x0651,
+			0x0652, 0x066a, 0x0e3f, 0x200c, 0x200d, 0x200e, 0x200f, 0x2013, 0x2014, 0x2015,
+			0x2017, 0x2018, 0x2019, 0x201a, 0x201c, 0x201d, 0x201e, 0x2020, 0x2021, 0x2022,
+			0x2026, 0x2030, 0x2032, 0x2033, 0x2039, 0x203a, 0x2044, 0x20a7, 0x20aa, 0x20ab,
+			0x20ac, 0x2116, 0x2118, 0x2122, 0x2126, 0x2135, 0x2190, 0x2191, 0x2192, 0x2193,
+			0x2194, 0x2195, 0x21b5, 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x2200, 0x2202,
+			0x2203, 0x2205, 0x2206, 0x2207, 0x2208, 0x2209, 0x220b, 0x220f, 0x2211, 0x2212,
+			0x2215, 0x2217, 0x2219, 0x221a, 0x221d, 0x221e, 0x2220, 0x2227, 0x2228, 0x2229,
+			0x222a, 0x222b, 0x2234, 0x223c, 0x2245, 0x2248, 0x2260, 0x2261, 0x2264, 0x2265,
+			0x2282, 0x2283, 0x2284, 0x2286, 0x2287, 0x2295, 0x2297, 0x22a5, 0x22c5, 0x2310,
+			0x2320, 0x2321, 0x2329, 0x232a, 0x2469, 0x2500, 0x2502, 0x250c, 0x2510, 0x2514,
+			0x2518, 0x251c, 0x2524, 0x252c, 0x2534, 0x253c, 0x2550, 0x2551, 0x2552, 0x2553,
+			0x2554, 0x2555, 0x2556, 0x2557, 0x2558, 0x2559, 0x255a, 0x255b, 0x255c, 0x255d,
+			0x255e, 0x255f, 0x2560, 0x2561, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567,
+			0x2568, 0x2569, 0x256a, 0x256b, 0x256c, 0x2580, 0x2584, 0x2588, 0x258c, 0x2590,
+			0x2591, 0x2592, 0x2593, 0x25a0, 0x25b2, 0x25bc, 0x25c6, 0x25ca, 0x25cf, 0x25d7,
+			0x2605, 0x260e, 0x261b, 0x261e, 0x2660, 0x2663, 0x2665, 0x2666, 0x2701, 0x2702,
+			0x2703, 0x2704, 0x2706, 0x2707, 0x2708, 0x2709, 0x270c, 0x270d, 0x270e, 0x270f,
+			0x2710, 0x2711, 0x2712, 0x2713, 0x2714, 0x2715, 0x2716, 0x2717, 0x2718, 0x2719,
+			0x271a, 0x271b, 0x271c, 0x271d, 0x271e, 0x271f, 0x2720, 0x2721, 0x2722, 0x2723,
+			0x2724, 0x2725, 0x2726, 0x2727, 0x2729, 0x272a, 0x272b, 0x272c, 0x272d, 0x272e,
+			0x272f, 0x2730, 0x2731, 0x2732, 0x2733, 0x2734, 0x2735, 0x2736, 0x2737, 0x2738,
+			0x2739, 0x273a, 0x273b, 0x273c, 0x273d, 0x273e, 0x273f, 0x2740, 0x2741, 0x2742,
+			0x2743, 0x2744, 0x2745, 0x2746, 0x2747, 0x2748, 0x2749, 0x274a, 0x274b, 0x274d,
+			0x274f, 0x2750, 0x2751, 0x2752, 0x2756, 0x2758, 0x2759, 0x275a, 0x275b, 0x275c,
+			0x275d, 0x275e, 0x2761, 0x2762, 0x2763, 0x2764, 0x2765, 0x2766, 0x2767, 0x277f,
+			0x2789, 0x2793, 0x2794, 0x2798, 0x2799, 0x279a, 0x279b, 0x279c, 0x279d, 0x279e,
+			0x279f, 0x27a0, 0x27a1, 0x27a2, 0x27a3, 0x27a4, 0x27a5, 0x27a6, 0x27a7, 0x27a8,
+			0x27a9, 0x27aa, 0x27ab, 0x27ac, 0x27ad, 0x27ae, 0x27af, 0x27b1, 0x27b2, 0x27b3,
+			0x27b4, 0x27b5, 0x27b6, 0x27b7, 0x27b8, 0x27b9, 0x27ba, 0x27bb, 0x27bc, 0x27bd,
+			0x27be, 0xf6d9, 0xf6da, 0xf6db, 0xf8d7, 0xf8d8, 0xf8d9, 0xf8da, 0xf8db, 0xf8dc,
+			0xf8dd, 0xf8de, 0xf8df, 0xf8e0, 0xf8e1, 0xf8e2, 0xf8e3, 0xf8e4, 0xf8e5, 0xf8e6,
+			0xf8e7, 0xf8e8, 0xf8e9, 0xf8ea, 0xf8eb, 0xf8ec, 0xf8ed, 0xf8ee, 0xf8ef, 0xf8f0,
+			0xf8f1, 0xf8f2, 0xf8f3, 0xf8f4, 0xf8f5, 0xf8f6, 0xf8f7, 0xf8f8, 0xf8f9, 0xf8fa,
+			0xf8fb, 0xf8fc, 0xf8fd, 0xf8fe, 0xfe7c, 0xfe7d);
+
+		$pattern = preg_quote(utf8_from_unicode($UTF8_SPECIAL_CHARS), '/');
+		$pattern = '/[\x00-\x19'.$pattern.']/u';
+	}
+
+	return $pattern;
 }
 
-//--------------------------------------------------------------------
 /**
 * Checks a string for whether it contains only word characters. This
 * is logically equivalent to the \w PCRE meta character. Note that
@@ -103,14 +104,14 @@ function utf8_specials_pattern() {
 * @return boolean TRUE if the string only contains word characters
 * @see utf8_specials_pattern
 */
-function utf8_is_word_chars($str) {
-    return !(bool)preg_match(utf8_specials_pattern(),$str);
+function utf8_is_word_chars($str)
+{
+	return !(bool) preg_match(utf8_specials_pattern(), $str);
 }
 
-//--------------------------------------------------------------------
 /**
 * Removes special characters (nonalphanumeric) from a UTF-8 string
-* 
+*
 * This can be useful as a helper for sanitizing a string for use as
 * something like a file name or a unique identifier. Be warned though
 * it does not handle all possible non-alphanumeric characters and is
@@ -124,8 +125,7 @@ function utf8_is_word_chars($str) {
 * @return string with common non-alphanumeric characters removed
 * @see utf8_specials_pattern
 */
-function utf8_strip_specials($string, $repl=''){
-    return preg_replace(utf8_specials_pattern(), $repl, $string);
+function utf8_strip_specials($string, $repl='')
+{
+	return preg_replace(utf8_specials_pattern(), $repl, $string);
 }
-
-
diff --git a/upload/include/utf8/utils/unicode.php b/upload/include/utf8/utils/unicode.php
index d234a2a..f0e86cb 100644
--- a/upload/include/utf8/utils/unicode.php
+++ b/upload/include/utf8/utils/unicode.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
 * @version $Id: unicode.php,v 1.2 2006/02/26 13:20:44 harryf Exp $
 * Tools for conversion between UTF-8 and unicode
@@ -16,9 +17,8 @@
 * @subpackage unicode
 */
 
-//--------------------------------------------------------------------
 /**
-* Takes an UTF-8 string and returns an array of ints representing the 
+* Takes an UTF-8 string and returns an array of ints representing the
 * Unicode characters. Astral planes are supported ie. the ints in the
 * output can be > 0xFFFF. Occurrances of the BOM are ignored. Surrogates
 * are not allowed.
@@ -34,161 +34,145 @@
 * @package utf8
 * @subpackage unicode
 */
-function utf8_to_unicode($str) {
-    $mState = 0;     // cached expected number of octets after the current octet
-                     // until the beginning of the next UTF8 character sequence
-    $mUcs4  = 0;     // cached Unicode character
-    $mBytes = 1;     // cached expected number of octets in the current sequence
-    
-    $out = array();
-    
-    $len = strlen($str);
-    
-    for($i = 0; $i < $len; $i++) {
-        
-        $in = ord($str{$i});
-        
-        if ( $mState == 0) {
-            
-            // When mState is zero we expect either a US-ASCII character or a
-            // multi-octet sequence.
-            if (0 == (0x80 & ($in))) {
-                // US-ASCII, pass straight through.
-                $out[] = $in;
-                $mBytes = 1;
-                
-            } else if (0xC0 == (0xE0 & ($in))) {
-                // First octet of 2 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x1F) << 6;
-                $mState = 1;
-                $mBytes = 2;
-                
-            } else if (0xE0 == (0xF0 & ($in))) {
-                // First octet of 3 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x0F) << 12;
-                $mState = 2;
-                $mBytes = 3;
-                
-            } else if (0xF0 == (0xF8 & ($in))) {
-                // First octet of 4 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x07) << 18;
-                $mState = 3;
-                $mBytes = 4;
-                
-            } else if (0xF8 == (0xFC & ($in))) {
-                /* First octet of 5 octet sequence.
-                *
-                * This is illegal because the encoded codepoint must be either
-                * (a) not the shortest form or
-                * (b) outside the Unicode range of 0-0x10FFFF.
-                * Rather than trying to resynchronize, we will carry on until the end
-                * of the sequence and let the later error handling code catch it.
-                */
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x03) << 24;
-                $mState = 4;
-                $mBytes = 5;
-                
-            } else if (0xFC == (0xFE & ($in))) {
-                // First octet of 6 octet sequence, see comments for 5 octet sequence.
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 1) << 30;
-                $mState = 5;
-                $mBytes = 6;
-                
-            } else {
-                /* Current octet is neither in the US-ASCII range nor a legal first
-                 * octet of a multi-octet sequence.
-                 */
-                trigger_error(
-                        'utf8_to_unicode: Illegal sequence identifier '.
-                            'in UTF-8 at byte '.$i,
-                        E_USER_WARNING
-                    );
-                return FALSE;
-                
-            }
-        
-        } else {
-            
-            // When mState is non-zero, we expect a continuation of the multi-octet
-            // sequence
-            if (0x80 == (0xC0 & ($in))) {
-                
-                // Legal continuation.
-                $shift = ($mState - 1) * 6;
-                $tmp = $in;
-                $tmp = ($tmp & 0x0000003F) << $shift;
-                $mUcs4 |= $tmp;
-            
-                /**
-                * End of the multi-octet sequence. mUcs4 now contains the final
-                * Unicode codepoint to be output
-                */
-                if (0 == --$mState) {
-                    
-                    /*
-                    * Check for illegal sequences and codepoints.
-                    */
-                    // From Unicode 3.1, non-shortest form is illegal
-                    if (((2 == $mBytes) && ($mUcs4 < 0x0080)) ||
-                        ((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
-                        ((4 == $mBytes) && ($mUcs4 < 0x10000)) ||
-                        (4 < $mBytes) ||
-                        // From Unicode 3.2, surrogate characters are illegal
-                        (($mUcs4 & 0xFFFFF800) == 0xD800) ||
-                        // Codepoints outside the Unicode range are illegal
-                        ($mUcs4 > 0x10FFFF)) {
-                        
-                        trigger_error(
-                                'utf8_to_unicode: Illegal sequence or codepoint '.
-                                    'in UTF-8 at byte '.$i,
-                                E_USER_WARNING
-                            );
-                        
-                        return FALSE;
-                        
-                    }
-                    
-                    if (0xFEFF != $mUcs4) {
-                        // BOM is legal but we don't want to output it
-                        $out[] = $mUcs4;
-                    }
-                    
-                    //initialize UTF8 cache
-                    $mState = 0;
-                    $mUcs4  = 0;
-                    $mBytes = 1;
-                }
-            
-            } else {
-                /**
-                *((0xC0 & (*in) != 0x80) && (mState != 0))
-                * Incomplete multi-octet sequence.
-                */
-                trigger_error(
-                        'utf8_to_unicode: Incomplete multi-octet '.
-                        '   sequence in UTF-8 at byte '.$i,
-                        E_USER_WARNING
-                    );
-                
-                return FALSE;
-            }
-        }
-    }
-    return $out;
+function utf8_to_unicode($str)
+{
+	$mState = 0;	// Cached expected number of octets after the current octet
+					// until the beginning of the next UTF8 character sequence
+	$mUcs4  = 0;	// Cached Unicode character
+	$mBytes = 1;	// Cached expected number of octets in the current sequence
+
+	$out = array();
+	$len = strlen($str);
+
+	for($i = 0; $i < $len; $i++)
+	{
+		$in = ord($str[$i]);
+
+		if ($mState == 0)
+		{
+			// When mState is zero we expect either a US-ASCII character or a multi-octet sequence.
+			if (0 == (0x80 & ($in)))
+			{
+				// US-ASCII, pass straight through.
+				$out[] = $in;
+				$mBytes = 1;
+			}
+			else if (0xC0 == (0xE0 & ($in)))
+			{
+				// First octet of 2 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x1F) << 6;
+				$mState = 1;
+				$mBytes = 2;
+			}
+			else if (0xE0 == (0xF0 & ($in)))
+			{
+				// First octet of 3 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x0F) << 12;
+				$mState = 2;
+				$mBytes = 3;
+			}
+			else if (0xF0 == (0xF8 & ($in)))
+			{
+				// First octet of 4 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x07) << 18;
+				$mState = 3;
+				$mBytes = 4;
+			}
+			else if (0xF8 == (0xFC & ($in)))
+			{
+				/* First octet of 5 octet sequence.
+				*
+				* This is illegal because the encoded codepoint must be either
+				* (a) not the shortest form or
+				* (b) outside the Unicode range of 0-0x10FFFF.
+				* Rather than trying to resynchronize, we will carry on until the end
+				* of the sequence and let the later error handling code catch it.
+				*/
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x03) << 24;
+				$mState = 4;
+				$mBytes = 5;
+			}
+			else if (0xFC == (0xFE & ($in)))
+			{
+				// First octet of 6 octet sequence, see comments for 5 octet sequence.
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 1) << 30;
+				$mState = 5;
+				$mBytes = 6;
+			}
+			else
+			{
+				// Current octet is neither in the US-ASCII range nor a legal first octet of a multi-octet sequence
+				trigger_error('utf8_to_unicode: Illegal sequence identifier in UTF-8 at byte '.$i, E_USER_WARNING);
+				return false;
+			}
+		}
+		else
+		{
+			// When mState is non-zero, we expect a continuation of the multi-octet sequence
+			if (0x80 == (0xC0 & ($in)))
+			{
+				// Legal continuation.
+				$shift = ($mState - 1) * 6;
+				$tmp = $in;
+				$tmp = ($tmp & 0x0000003F) << $shift;
+				$mUcs4 |= $tmp;
+
+				/**
+				* End of the multi-octet sequence. mUcs4 now contains the final
+				* Unicode codepoint to be output
+				*/
+				if (0 == --$mState)
+				{
+					/*
+					* Check for illegal sequences and codepoints.
+					*/
+					// From Unicode 3.1, non-shortest form is illegal
+					if (((2 == $mBytes) && ($mUcs4 < 0x0080)) || ((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
+					   ((4 == $mBytes) && ($mUcs4 < 0x10000)) || (4 < $mBytes) ||
+					   // From Unicode 3.2, surrogate characters are illegal
+					   (($mUcs4 & 0xFFFFF800) == 0xD800) ||
+					   // Codepoints outside the Unicode range are illegal
+					   ($mUcs4 > 0x10FFFF))
+					{
+						trigger_error('utf8_to_unicode: Illegal sequence or codepoint in UTF-8 at byte '.$i, E_USER_WARNING);
+						return false;
+					}
+
+					// BOM is legal but we don't want to output it
+					if (0xFEFF != $mUcs4)
+						$out[] = $mUcs4;
+
+					// Initialize UTF8 cache
+					$mState = 0;
+					$mUcs4  = 0;
+					$mBytes = 1;
+				}
+
+			}
+			else
+			{
+				/* ((0xC0 & (*in) != 0x80) && (mState != 0))
+				Incomplete multi-octet sequence. */
+				trigger_error('utf8_to_unicode: Incomplete multi-octet sequence in UTF-8 at byte '.$i, E_USER_WARNING);
+				return false;
+			}
+		}
+	}
+
+	return $out;
 }
 
-//--------------------------------------------------------------------
 /**
-* Takes an array of ints representing the Unicode characters and returns 
+* Takes an array of ints representing the Unicode characters and returns
 * a UTF-8 string. Astral planes are supported ie. the ints in the
 * input can be > 0xFFFF. Occurrances of the BOM are ignored. Surrogates
 * are not allowed.
-* Returns false if the input array contains ints that represent 
+* Returns false if the input array contains ints that represent
 * surrogates or are outside the Unicode range
 * and raises a PHP error at level E_USER_WARNING
 * Note: this function has been modified slightly in this library to use
@@ -202,68 +186,56 @@ function utf8_to_unicode($str) {
 * @package utf8
 * @subpackage unicode
 */
-function utf8_from_unicode($arr) {
-    ob_start();
-    
-    foreach (array_keys($arr) as $k) {
-        
-        # ASCII range (including control chars)
-        if ( ($arr[$k] >= 0) && ($arr[$k] <= 0x007f) ) {
-            
-            echo chr($arr[$k]);
-        
-        # 2 byte sequence
-        } else if ($arr[$k] <= 0x07ff) {
-            
-            echo chr(0xc0 | ($arr[$k] >> 6));
-            echo chr(0x80 | ($arr[$k] & 0x003f));
-        
-        # Byte order mark (skip)
-        } else if($arr[$k] == 0xFEFF) {
-            
-            // nop -- zap the BOM
-        
-        # Test for illegal surrogates
-        } else if ($arr[$k] >= 0xD800 && $arr[$k] <= 0xDFFF) {
-            
-            // found a surrogate
-            trigger_error(
-                'utf8_from_unicode: Illegal surrogate '.
-                    'at index: '.$k.', value: '.$arr[$k],
-                E_USER_WARNING
-                );
-            
-            return FALSE;
-        
-        # 3 byte sequence
-        } else if ($arr[$k] <= 0xffff) {
-            
-            echo chr(0xe0 | ($arr[$k] >> 12));
-            echo chr(0x80 | (($arr[$k] >> 6) & 0x003f));
-            echo chr(0x80 | ($arr[$k] & 0x003f));
-        
-        # 4 byte sequence
-        } else if ($arr[$k] <= 0x10ffff) {
-            
-            echo chr(0xf0 | ($arr[$k] >> 18));
-            echo chr(0x80 | (($arr[$k] >> 12) & 0x3f));
-            echo chr(0x80 | (($arr[$k] >> 6) & 0x3f));
-            echo chr(0x80 | ($arr[$k] & 0x3f));
-            
-        } else {
-            
-            trigger_error(
-                'utf8_from_unicode: Codepoint out of Unicode range '.
-                    'at index: '.$k.', value: '.$arr[$k],
-                E_USER_WARNING
-                );
-            
-            // out of range
-            return FALSE;
-        }
-    }
-    
-    $result = ob_get_contents();
-    ob_end_clean();
-    return $result;
+function utf8_from_unicode($arr)
+{
+	ob_start();
+
+	foreach (array_keys($arr) as $k)
+	{
+		if ( ($arr[$k] >= 0) && ($arr[$k] <= 0x007f) ) // ASCII range (including control chars)
+		{
+			echo chr($arr[$k]);
+		}
+		else if ($arr[$k] <= 0x07ff) //2 byte sequence
+		{
+			echo chr(0xc0 | ($arr[$k] >> 6));
+			echo chr(0x80 | ($arr[$k] & 0x003f));
+		}
+		else if($arr[$k] == 0xFEFF) // Byte order mark (skip)
+		{
+			// Nop -- zap the BOM
+		}
+		else if ($arr[$k] >= 0xD800 && $arr[$k] <= 0xDFFF) // Test for illegal surrogates
+		{
+			// Found a surrogate
+			trigger_error('utf8_from_unicode: Illegal surrogate at index: '.$k.', value: '.$arr[$k], E_USER_WARNING);
+
+			return false;
+		}
+		else if ($arr[$k] <= 0xffff) // 3 byte sequence
+		{
+			echo chr(0xe0 | ($arr[$k] >> 12));
+			echo chr(0x80 | (($arr[$k] >> 6) & 0x003f));
+			echo chr(0x80 | ($arr[$k] & 0x003f));
+		}
+		else if ($arr[$k] <= 0x10ffff) // 4 byte sequence
+		{
+			echo chr(0xf0 | ($arr[$k] >> 18));
+			echo chr(0x80 | (($arr[$k] >> 12) & 0x3f));
+			echo chr(0x80 | (($arr[$k] >> 6) & 0x3f));
+			echo chr(0x80 | ($arr[$k] & 0x3f));
+		}
+		else
+		{
+			trigger_error('utf8_from_unicode: Codepoint out of Unicode range at index: '.$k.', value: '.$arr[$k], E_USER_WARNING);
+
+			// Out of range
+			return false;
+		}
+	}
+
+	$result = ob_get_contents();
+	ob_end_clean();
+
+	return $result;
 }
diff --git a/upload/include/utf8/utils/validation.php b/upload/include/utf8/utils/validation.php
index 0f9fd37..90dce8e 100644
--- a/upload/include/utf8/utils/validation.php
+++ b/upload/include/utf8/utils/validation.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
 * @version $Id: validation.php,v 1.2 2006/02/26 13:20:44 harryf Exp $
 * Tools for validing a UTF-8 string is well formed.
@@ -16,7 +17,6 @@
 * @subpackage validation
 */
 
-//--------------------------------------------------------------------
 /**
 * Tests a string as to whether it's valid UTF-8 and supported by the
 * Unicode standard
@@ -29,135 +29,134 @@
 * @package utf8
 * @subpackage validation
 */
-function utf8_is_valid($str) {
-    
-    $mState = 0;     // cached expected number of octets after the current octet
-                     // until the beginning of the next UTF8 character sequence
-    $mUcs4  = 0;     // cached Unicode character
-    $mBytes = 1;     // cached expected number of octets in the current sequence
-    
-    $len = strlen($str);
-    
-    for($i = 0; $i < $len; $i++) {
-        
-        $in = ord($str{$i});
-        
-        if ( $mState == 0) {
-            
-            // When mState is zero we expect either a US-ASCII character or a
-            // multi-octet sequence.
-            if (0 == (0x80 & ($in))) {
-                // US-ASCII, pass straight through.
-                $mBytes = 1;
-                
-            } else if (0xC0 == (0xE0 & ($in))) {
-                // First octet of 2 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x1F) << 6;
-                $mState = 1;
-                $mBytes = 2;
-                
-            } else if (0xE0 == (0xF0 & ($in))) {
-                // First octet of 3 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x0F) << 12;
-                $mState = 2;
-                $mBytes = 3;
-                
-            } else if (0xF0 == (0xF8 & ($in))) {
-                // First octet of 4 octet sequence
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x07) << 18;
-                $mState = 3;
-                $mBytes = 4;
-                
-            } else if (0xF8 == (0xFC & ($in))) {
-                /* First octet of 5 octet sequence.
-                *
-                * This is illegal because the encoded codepoint must be either
-                * (a) not the shortest form or
-                * (b) outside the Unicode range of 0-0x10FFFF.
-                * Rather than trying to resynchronize, we will carry on until the end
-                * of the sequence and let the later error handling code catch it.
-                */
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 0x03) << 24;
-                $mState = 4;
-                $mBytes = 5;
-                
-            } else if (0xFC == (0xFE & ($in))) {
-                // First octet of 6 octet sequence, see comments for 5 octet sequence.
-                $mUcs4 = ($in);
-                $mUcs4 = ($mUcs4 & 1) << 30;
-                $mState = 5;
-                $mBytes = 6;
-                
-            } else {
-                /* Current octet is neither in the US-ASCII range nor a legal first
-                 * octet of a multi-octet sequence.
-                 */
-                return FALSE;
-                
-            }
-        
-        } else {
-            
-            // When mState is non-zero, we expect a continuation of the multi-octet
-            // sequence
-            if (0x80 == (0xC0 & ($in))) {
-                
-                // Legal continuation.
-                $shift = ($mState - 1) * 6;
-                $tmp = $in;
-                $tmp = ($tmp & 0x0000003F) << $shift;
-                $mUcs4 |= $tmp;
-            
-                /**
-                * End of the multi-octet sequence. mUcs4 now contains the final
-                * Unicode codepoint to be output
-                */
-                if (0 == --$mState) {
-                    
-                    /*
-                    * Check for illegal sequences and codepoints.
-                    */
-                    // From Unicode 3.1, non-shortest form is illegal
-                    if (((2 == $mBytes) && ($mUcs4 < 0x0080)) ||
-                        ((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
-                        ((4 == $mBytes) && ($mUcs4 < 0x10000)) ||
-                        (4 < $mBytes) ||
-                        // From Unicode 3.2, surrogate characters are illegal
-                        (($mUcs4 & 0xFFFFF800) == 0xD800) ||
-                        // Codepoints outside the Unicode range are illegal
-                        ($mUcs4 > 0x10FFFF)) {
-                        
-                        return FALSE;
-                        
-                    }
-                    
-                    //initialize UTF8 cache
-                    $mState = 0;
-                    $mUcs4  = 0;
-                    $mBytes = 1;
-                }
-            
-            } else {
-                /**
-                *((0xC0 & (*in) != 0x80) && (mState != 0))
-                * Incomplete multi-octet sequence.
-                */
-                
-                return FALSE;
-            }
-        }
-    }
-    return TRUE;
+function utf8_is_valid($str)
+{
+	$mState = 0;	// Cached expected number of octets after the current octet
+					// until the beginning of the next UTF8 character sequence
+	$mUcs4  = 0;	// Cached Unicode character
+	$mBytes = 1;	// Cached expected number of octets in the current sequence
+
+	$len = strlen($str);
+
+	for($i = 0; $i < $len; $i++)
+	{
+		$in = ord($str{$i});
+
+		if ( $mState == 0)
+		{
+			// When mState is zero we expect either a US-ASCII character or a multi-octet sequence.
+			if (0 == (0x80 & ($in)))
+			{
+				$mBytes = 1; // US-ASCII, pass straight through
+			}
+			else if (0xC0 == (0xE0 & ($in)))
+			{
+				// First octet of 2 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x1F) << 6;
+				$mState = 1;
+				$mBytes = 2;
+			}
+			else if (0xE0 == (0xF0 & ($in)))
+			{
+				// First octet of 3 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x0F) << 12;
+				$mState = 2;
+				$mBytes = 3;
+			}
+			else if (0xF0 == (0xF8 & ($in)))
+			{
+				// First octet of 4 octet sequence
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x07) << 18;
+				$mState = 3;
+				$mBytes = 4;
+			}
+			else if (0xF8 == (0xFC & ($in)))
+			{
+				/* First octet of 5 octet sequence.
+				*
+				* This is illegal because the encoded codepoint must be either
+				* (a) not the shortest form or
+				* (b) outside the Unicode range of 0-0x10FFFF.
+				* Rather than trying to resynchronize, we will carry on until the end
+				* of the sequence and let the later error handling code catch it.
+				*/
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 0x03) << 24;
+				$mState = 4;
+				$mBytes = 5;
+			}
+			else if (0xFC == (0xFE & ($in)))
+			{
+				// First octet of 6 octet sequence, see comments for 5 octet sequence.
+				$mUcs4 = ($in);
+				$mUcs4 = ($mUcs4 & 1) << 30;
+				$mState = 5;
+				$mBytes = 6;
+			}
+			else
+			{
+				// Current octet is neither in the US-ASCII range nor a legal first octet of a multi-octet sequence.
+				return false;
+			}
+		}
+		else
+		{
+			// When mState is non-zero, we expect a continuation of the multi-octet sequence
+			if (0x80 == (0xC0 & ($in)))
+			{
+				// Legal continuation.
+				$shift = ($mState - 1) * 6;
+				$tmp = $in;
+				$tmp = ($tmp & 0x0000003F) << $shift;
+				$mUcs4 |= $tmp;
+
+				/**
+				* End of the multi-octet sequence. mUcs4 now contains the final
+				* Unicode codepoint to be output
+				*/
+				if (0 == --$mState)
+				{
+					/*
+					* Check for illegal sequences and codepoints.
+					*/
+					// From Unicode 3.1, non-shortest form is illegal
+					if (((2 == $mBytes) && ($mUcs4 < 0x0080)) || ((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
+					((4 == $mBytes) && ($mUcs4 < 0x10000)) || (4 < $mBytes) ||
+					// From Unicode 3.2, surrogate characters are illegal
+					(($mUcs4 & 0xFFFFF800) == 0xD800) ||
+					// Codepoints outside the Unicode range are illegal
+					($mUcs4 > 0x10FFFF))
+					{
+						return FALSE;
+					}
+
+					// Initialize UTF8 cache
+					$mState = 0;
+					$mUcs4  = 0;
+					$mBytes = 1;
+				}
+			}
+			else
+			{
+				/**
+				*((0xC0 & (*in) != 0x80) && (mState != 0))
+				* Incomplete multi-octet sequence.
+				*/
+
+				return false;
+			}
+		}
+	}
+
+	return true;
 }
 
-//--------------------------------------------------------------------
 /**
 * Tests whether a string complies as UTF-8. This will be much
-* faster than utf8_is_valid but will pass five and six octet
+* faster than utf8_is_valid, but will pass five and six octet
 * UTF-8 sequences, which are not supported by Unicode and
 * so cannot be displayed correctly in a browser. In other words
 * it is not as strict as utf8_is_valid but it's faster. If you use
@@ -165,6 +164,8 @@ function utf8_is_valid($str) {
 * attackers will be able to inject 5 and 6 byte sequences (which
 * may or may not be a significant risk, depending on what you are
 * are doing)
+* Note: Does not pass five and six octet UTF-8 sequences anymore in
+*       in the unit tests.
 * @see utf8_is_valid
 * @see http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php#54805
 * @param string UTF-8 string to check
@@ -172,14 +173,14 @@ function utf8_is_valid($str) {
 * @package utf8
 * @subpackage validation
 */
-function utf8_compliant($str) {
-    if ( strlen($str) == 0 ) {
-        return TRUE;
-    }
-    // If even just the first character can be matched, when the /u
-    // modifier is used, then it's valid UTF-8. If the UTF-8 is somehow
-    // invalid, nothing at all will match, even if the string contains
-    // some valid sequences
-    return (preg_match('/^.{1}/us',$str,$ar) == 1);
-}
+function utf8_compliant($str)
+{
+	if (strlen($str) == 0)
+		return true;
 
+	// If even just the first character can be matched, when the /u
+	// modifier is used, then it's valid UTF-8. If the UTF-8 is somehow
+	// invalid, nothing at all will match, even if the string contains
+	// some valid sequences
+	return (preg_match('/^.{1}/us', $str, $ar) == 1);
+}
diff --git a/upload/index.php b/upload/index.php
index 1d8ed64..5e71bdd 100644
--- a/upload/index.php
+++ b/upload/index.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 define('PUN_ROOT', './');
 require PUN_ROOT.'include/common.php';
@@ -46,8 +29,14 @@ if (!$pun_user['is_guest'])
 	$tracked_topics = get_tracked_topics();
 }
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']);
+if ($pun_config['o_feed_type'] == '1')
+	$page_head = array('feed' => '<link rel="alternate" type="application/rss+xml" href="extern.php?action=feed&amp;type=rss" title="'.$lang_common['RSS active topics feed'].'" />');
+else if ($pun_config['o_feed_type'] == '2')
+	$page_head = array('feed' => '<link rel="alternate" type="application/atom+xml" href="extern.php?action=feed&amp;type=atom" title="'.$lang_common['Atom active topics feed'].'" />');
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']));
 define('PUN_ALLOW_INDEX', 1);
+define('PUN_ACTIVE_PAGE', 'index');
 require PUN_ROOT.'header.php';
 
 // Print the categories and forums
@@ -55,16 +44,18 @@ $result = $db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name,
 
 $cur_category = 0;
 $cat_count = 0;
+$forum_count = 0;
 while ($cur_forum = $db->fetch_assoc($result))
 {
 	$moderators = '';
 
-	if ($cur_forum['cid'] != $cur_category)	// A new category since last iteration?
+	if ($cur_forum['cid'] != $cur_category) // A new category since last iteration?
 	{
 		if ($cur_category != 0)
 			echo "\t\t\t".'</tbody>'."\n\t\t\t".'</table>'."\n\t\t".'</div>'."\n\t".'</div>'."\n".'</div>'."\n\n";
 
 		++$cat_count;
+		$forum_count = 0;
 
 ?>
 <div id="idx<?php echo $cat_count ?>" class="blocktable">
@@ -86,8 +77,9 @@ while ($cur_forum = $db->fetch_assoc($result))
 		$cur_category = $cur_forum['cid'];
 	}
 
-	$item_status = '';
-	$icon_text = $lang_common['Normal icon'];
+	++$forum_count;
+	$item_status = ($forum_count % 2 == 0) ? 'roweven' : 'rowodd';
+	$forum_field_new = '';
 	$icon_type = 'icon';
 
 	// Are there new posts since our last visit?
@@ -98,9 +90,9 @@ while ($cur_forum = $db->fetch_assoc($result))
 		{
 			if ((empty($tracked_topics['topics'][$check_topic_id]) || $tracked_topics['topics'][$check_topic_id] < $check_last_post) && (empty($tracked_topics['forums'][$cur_forum['fid']]) || $tracked_topics['forums'][$cur_forum['fid']] < $check_last_post))
 			{
-				$item_status = 'inew';
-				$icon_text = $lang_common['New icon'];
-				$icon_type = 'icon inew';
+				$item_status .= ' inew';
+				$forum_field_new = '<span class="newtext">[ <a href="search.php?action=show_new&amp;fid='.$cur_forum['fid'].'">'.$lang_common['New posts'].'</a> ]</span>';
+				$icon_type = 'icon icon-new';
 
 				break;
 			}
@@ -110,35 +102,35 @@ while ($cur_forum = $db->fetch_assoc($result))
 	// Is this a redirect forum?
 	if ($cur_forum['redirect_url'] != '')
 	{
-		$forum_field = '<h3><a href="'.pun_htmlspecialchars($cur_forum['redirect_url']).'" title="'.$lang_index['Link to'].' '.pun_htmlspecialchars($cur_forum['redirect_url']).'">'.pun_htmlspecialchars($cur_forum['forum_name']).'</a></h3>';
-		$num_topics = $num_posts = '&nbsp;';
-		$item_status = 'iredirect';
-		$icon_text = $lang_common['Redirect icon'];
+		$forum_field = '<h3><span class="redirtext">'.$lang_index['Link to'].'</span> <a href="'.pun_htmlspecialchars($cur_forum['redirect_url']).'" title="'.$lang_index['Link to'].' '.pun_htmlspecialchars($cur_forum['redirect_url']).'">'.pun_htmlspecialchars($cur_forum['forum_name']).'</a></h3>';
+		$num_topics = $num_posts = '-';
+		$item_status .= ' iredirect';
 		$icon_type = 'icon';
 	}
 	else
 	{
-		$forum_field = '<h3><a href="viewforum.php?id='.$cur_forum['fid'].'">'.pun_htmlspecialchars($cur_forum['forum_name']).'</a></h3>';
+		$forum_field = '<h3><a href="viewforum.php?id='.$cur_forum['fid'].'">'.pun_htmlspecialchars($cur_forum['forum_name']).'</a>'.(!empty($forum_field_new) ? ' '.$forum_field_new : '').'</h3>';
 		$num_topics = $cur_forum['num_topics'];
 		$num_posts = $cur_forum['num_posts'];
 	}
 
 	if ($cur_forum['forum_desc'] != '')
-		$forum_field .= "\n\t\t\t\t\t\t\t\t".$cur_forum['forum_desc'];
-
+		$forum_field .= "\n\t\t\t\t\t\t\t\t".'<div class="forumdesc">'.$cur_forum['forum_desc'].'</div>';
 
-	// If there is a last_post/last_poster.
+	// If there is a last_post/last_poster
 	if ($cur_forum['last_post'] != '')
 		$last_post = '<a href="viewtopic.php?pid='.$cur_forum['last_post_id'].'#p'.$cur_forum['last_post_id'].'">'.format_time($cur_forum['last_post']).'</a> <span class="byuser">'.$lang_common['by'].' '.pun_htmlspecialchars($cur_forum['last_poster']).'</span>';
+	else if ($cur_forum['redirect_url'] != '')
+		$last_post = '- - -';
 	else
-		$last_post = '&nbsp;';
+		$last_post = $lang_common['Never'];
 
 	if ($cur_forum['moderators'] != '')
 	{
 		$mods_array = unserialize($cur_forum['moderators']);
 		$moderators = array();
 
-		while (list($mod_username, $mod_id) = @each($mods_array))
+		foreach ($mods_array as $mod_username => $mod_id)
 		{
 			if ($pun_user['g_view_users'] == '1')
 				$moderators[] = '<a href="profile.php?id='.$mod_id.'">'.pun_htmlspecialchars($mod_username).'</a>';
@@ -146,15 +138,15 @@ while ($cur_forum = $db->fetch_assoc($result))
 				$moderators[] = pun_htmlspecialchars($mod_username);
 		}
 
-		$moderators = "\t\t\t\t\t\t\t\t".'<p><em>('.$lang_common['Moderated by'].'</em> '.implode(', ', $moderators).')</p>'."\n";
+		$moderators = "\t\t\t\t\t\t\t\t".'<p class="modlist">(<em>'.$lang_common['Moderated by'].'</em> '.implode(', ', $moderators).')</p>'."\n";
 	}
 
 ?>
- 				<tr<?php if ($item_status != '') echo ' class="'.$item_status.'"'; ?>>
+				<tr class="<?php echo $item_status ?>">
 					<td class="tcl">
-						<div class="intd">
-							<div class="<?php echo $icon_type ?>"><div class="nosize"><?php echo $icon_text ?></div></div>
-							<div class="tclcon">
+						<div class="<?php echo $icon_type ?>"><div class="nosize"><?php echo forum_number_format($forum_count) ?></div></div>
+						<div class="tclcon">
+							<div>
 								<?php echo $forum_field."\n".$moderators ?>
 							</div>
 						</div>
@@ -196,13 +188,13 @@ else
 		<div class="inbox">
 			<dl class="conr">
 				<dt><strong><?php echo $lang_index['Board stats'] ?></strong></dt>
-				<dd><?php echo $lang_index['No of users'].': <strong>'.forum_number_format($stats['total_users']) ?></strong></dd>
-				<dd><?php echo $lang_index['No of topics'].': <strong>'.forum_number_format($stats['total_topics']) ?></strong></dd>
-				<dd><?php echo $lang_index['No of posts'].': <strong>'.forum_number_format($stats['total_posts']) ?></strong></dd>
+				<dd><?php printf($lang_index['No of users'], '<strong>'.forum_number_format($stats['total_users']).'</strong>') ?></dd>
+				<dd><?php printf($lang_index['No of topics'], '<strong>'.forum_number_format($stats['total_topics']).'</strong>') ?></dd>
+				<dd><?php printf($lang_index['No of posts'], '<strong>'.forum_number_format($stats['total_posts']).'</strong>') ?></dd>
 			</dl>
 			<dl class="conl">
 				<dt><strong><?php echo $lang_index['User info'] ?></strong></dt>
-				<dd><?php echo $lang_index['Newest user'] ?>: <?php echo $stats['newest_user'] ?></dd>
+				<dd><?php printf($lang_index['Newest user'], $stats['newest_user']) ?></dd>
 <?php
 
 if ($pun_config['o_users_online'] == '1')
@@ -226,17 +218,17 @@ if ($pun_config['o_users_online'] == '1')
 	}
 
 	$num_users = count($users);
-	echo "\t\t\t\t".'<dd>'. $lang_index['Users online'].': <strong>'.forum_number_format($num_users).'</strong></dd>'."\n\t\t\t\t".'<dd>'.$lang_index['Guests online'].': <strong>'.forum_number_format($num_guests).'</strong></dd>'."\n\t\t\t".'</dl>'."\n";
+	echo "\t\t\t\t".'<dd>'.sprintf($lang_index['Users online'], '<strong>'.forum_number_format($num_users).'</strong>').'</dd>'."\n\t\t\t\t".'<dd>'.sprintf($lang_index['Guests online'], '<strong>'.forum_number_format($num_guests).'</strong>').'</dd>'."\n\t\t\t".'</dl>'."\n";
 
 
 	if ($num_users > 0)
-		echo "\t\t\t".'<dl id="onlinelist" class= "clearb">'."\n\t\t\t\t".'<dt><strong>'.$lang_index['Online'].':&nbsp;</strong></dt>'."\t\t\t\t".implode(',</dd> ', $users).'</dd>'."\n\t\t\t".'</dl>'."\n";
+		echo "\t\t\t".'<dl id="onlinelist" class="clearb">'."\n\t\t\t\t".'<dt><strong>'.$lang_index['Online'].' </strong></dt>'."\t\t\t\t".implode(',</dd> ', $users).'</dd>'."\n\t\t\t".'</dl>'."\n";
 	else
 		echo "\t\t\t".'<div class="clearer"></div>'."\n";
 
 }
 else
-	echo "\t\t".'</dl>'."\n\t\t\t".'<div class="clearer"></div>'."\n";
+	echo "\t\t\t".'</dl>'."\n\t\t\t".'<div class="clearer"></div>'."\n";
 
 
 ?>
diff --git a/upload/install.php b/upload/install.php
index c2a3207..6a6585e 100644
--- a/upload/install.php
+++ b/upload/install.php
@@ -1,49 +1,46 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 // The FluxBB version this script installs
-define('FORUM_VERSION', '1.4');
-define('FORUM_DB_REVISION', 0);
+define('FORUM_VERSION', '1.4-rc3');
+define('FORUM_DB_REVISION', 5);
+
+define('MIN_PHP_VERSION', '4.3.0');
+define('MIN_MYSQL_VERSION', '4.1.2');
+define('MIN_PGSQL_VERSION', '7.0.0');
+define('PUN_SEARCH_MIN_WORD', 3);
+define('PUN_SEARCH_MAX_WORD', 20);
 
 
 define('PUN_ROOT', './');
+
 if (file_exists(PUN_ROOT.'config.php'))
-	exit('The file \'config.php\' already exists which would mean that FluxBB is already installed. You should go <a href="index.php">here</a> instead.');
+{
+	// Check to see whether FluxBB is already installed
+	include PUN_ROOT.'config.php';
 
+	// If we have the 1.3-legacy constant defined, define the proper 1.4 constant so we don't get an incorrect "need to install" message
+	if (defined('FORUM'))
+		define('PUN', FORUM);
 
-// Make sure we are running at least PHP 4.1.0
-if (intval(str_replace('.', '', phpversion())) < 410)
-	exit('You are running PHP version '.PHP_VERSION.'. FluxBB requires at least PHP 4.1.0 to run properly. You must upgrade your PHP installation before you can continue.');
+	// If PUN is defined, config.php is probably valid and thus the software is installed
+	if (defined('PUN'))
+		exit('It seems like FluxBB is already installed. You should go <a href="index.php">here</a> instead.');
+}
 
-// Disable error reporting for uninitialized variables
-error_reporting(E_ALL);
+// Define PUN because email.php requires it
+define('PUN', 1);
 
-// Turn off PHP time limit
-@set_time_limit(0);
+// Make sure we are running at least MIN_PHP_VERSION
+if (!function_exists('version_compare') || version_compare(PHP_VERSION, MIN_PHP_VERSION, '<'))
+	exit('You are running PHP version '.PHP_VERSION.'. FluxBB '.FORUM_VERSION.' requires at least PHP '.MIN_PHP_VERSION.' to run properly. You must upgrade your PHP installation before you can continue.');
 
-// We need some stuff from functions.php
+// Load the functions script
 require PUN_ROOT.'include/functions.php';
 
 // Load UTF-8 functions
@@ -52,6 +49,36 @@ require PUN_ROOT.'include/utf8/utf8.php';
 // Strip out "bad" UTF-8 characters
 forum_remove_bad_characters();
 
+// Reverse the effect of register_globals
+forum_unregister_globals();
+
+// Disable error reporting for uninitialized variables
+error_reporting(E_ALL);
+
+// Force POSIX locale (to prevent functions such as strtolower() from messing up UTF-8 strings)
+setlocale(LC_CTYPE, 'C');
+
+// Turn off magic_quotes_runtime
+if (get_magic_quotes_runtime())
+	set_magic_quotes_runtime(0);
+
+// Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled)
+if (get_magic_quotes_gpc())
+{
+	function stripslashes_array($array)
+	{
+		return is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array);
+	}
+
+	$_GET = stripslashes_array($_GET);
+	$_POST = stripslashes_array($_POST);
+	$_COOKIE = stripslashes_array($_COOKIE);
+	$_REQUEST = stripslashes_array($_REQUEST);
+}
+
+// Turn off PHP time limit
+@set_time_limit(0);
+
 //
 // Generate output to be used for config.php
 //
@@ -97,7 +124,7 @@ if (!isset($_POST['form_sent']))
 	if (function_exists('mysql_connect'))
 	{
 		$db_extensions[] = array('mysql', 'MySQL Standard');
-		$db_extensions[] = array('mysql_innodb', 'MySQL (InnoDB)');
+		$db_extensions[] = array('mysql_innodb', 'MySQL Standard (InnoDB)');
 		$mysql_innodb = true;
 
 		if (count($db_extensions) > 2)
@@ -111,6 +138,19 @@ if (!isset($_POST['form_sent']))
 	if (empty($db_extensions))
 		exit('This PHP environment does not have support for any of the databases that FluxBB supports. PHP needs to have support for either MySQL, PostgreSQL or SQLite in order for FluxBB to be installed.');
 
+	// Make an educated guess regarding base_url
+	$base_url  = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';	// protocol
+	$base_url .= preg_replace('/:(80|443)$/', '', $_SERVER['HTTP_HOST']);							// host[:port]
+	$base_url .= str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));							// path
+
+	if (substr($base_url, -1) == '/')
+		$base_url = substr($base_url, 0, -1);
+
+	$title = 'My FluxBB forum';
+	$description = '<p><span>Unfortunately no one can be told what FluxBB is - you have to see it for yourself.</span></p>';
+	$default_lang = 'English';
+	$default_style = 'Air';
+
 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
@@ -118,9 +158,8 @@ if (!isset($_POST['form_sent']))
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>FluxBB Installation</title>
-<link rel="stylesheet" type="text/css" href="style/Oxygen.css" />
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
 <script type="text/javascript">
-<!--
 function process_form(the_form)
 {
 	var element_names = new Object()
@@ -131,12 +170,12 @@ function process_form(the_form)
 	element_names["req_username"] = "Administrator username"
 	element_names["req_password1"] = "Administrator password 1"
 	element_names["req_password2"] = "Administrator password 2"
-	element_names["req_email"] = "Administrator's e-mail"
+	element_names["req_email"] = "Administrator's email"
 	element_names["req_base_url"] = "Base URL"
 
 	if (document.all || document.getElementById)
 	{
-		for (i = 0; i < the_form.length; ++i)
+		for (var i = 0; i < the_form.length; ++i)
 		{
 			var elem = the_form.elements[i]
 			if (elem.name && elem.name.substring(0, 4) == "req_")
@@ -153,23 +192,32 @@ function process_form(the_form)
 
 	return true
 }
-// -->
 </script>
+<style type="text/css">
+<!--
+#punwrap {
+	margin: 20px 10%;
+	}
+-->
+</style>
 </head>
 <body onload="document.getElementById('install').req_db_type.focus()">
 
-<div id="puninstall" style="margin: auto 10% auto 10%">
-<div class="pun">
+<div id="punwrap">
+<div id="puninstall" class="pun">
+
+<div class="top-box"><div><!-- Top Corners --></div></div>
 
-<div class="block">
-	<h2><span>FluxBB Installation</span></h2>
+<div id="brdheader" class="block">
 	<div class="box">
-		<div class="inbox">
-			<p>Welcome to FluxBB installation! You are about to install FluxBB. In order to install FluxBB you must complete the form set out below. If you encounter any difficulties with the installation, please refer to the documentation.</p>
+		<div id="brdtitle" class="inbox">
+			<h1><span>FluxBB Installation</span></h1>
+			<div id="brddesc"><p>Welcome to FluxBB installation. You are about to install FluxBB. In order to install FluxBB, you must complete the form set out below. If you encounter any difficulties with the installation, please refer to the documentation.</p></div>
 		</div>
 	</div>
 </div>
 
+<div id="brdmain">
 <div class="blockform">
 	<h2><span>Install FluxBB 1.4</span></h2>
 	<div class="box">
@@ -185,8 +233,8 @@ function process_form(the_form)
 					<div class="infldset">
 						<p>FluxBB currently supports MySQL, PostgreSQL and SQLite. If your database of choice is missing from the drop-down menu below, it means this PHP environment does not have support for that particular database. More information regarding support for particular versions of each database can be found in the FAQ.</p>
 <?php if ($dual_mysql): ?>						<p>FluxBB has detected that your PHP environment supports two different ways of communicating with MySQL. The two options are called standard and improved. If you are uncertain which one to use, start by trying improved and if that fails, try standard.</p>
-<?php endif; ?><?php if ($mysql_innodb): ?>					<p>FluxBB has detected that your MySQL server might support <a href="http://dev.mysql.com/doc/refman/5.0/en/innodb-overview.html">InnoDB</a>. This would be a good choice if you are planning to run a large forum. If you are uncertain, it is recommended to not use InnoDB.</p>
-<?php endif; ?>						<label><strong>Database type</strong>
+<?php endif; ?><?php if ($mysql_innodb): ?>						<p>FluxBB has detected that your MySQL server might support <a href="http://dev.mysql.com/doc/refman/5.0/en/innodb.html">InnoDB</a>. This would be a good choice if you are planning to run a large forum. If you are uncertain, it is recommended that you do not use InnoDB.</p>
+<?php endif; ?>						<label class="required"><strong>Database type <span>(Required)</span></strong>
 						<br /><select name="req_db_type">
 <?php
 
@@ -204,16 +252,16 @@ function process_form(the_form)
 					<legend>Enter your database server hostname</legend>
 					<div class="infldset">
 						<p>The address of the database server (example: localhost, db.myhost.com or 192.168.0.15). You can specify a custom port number if your database doesn't run on the default port (example: localhost:3580). For SQLite support, just enter anything or leave it at 'localhost'.</p>
-						<label><strong>Database server hostname</strong><br /><input type="text" name="req_db_host" value="localhost" size="50" maxlength="100" /><br /></label>
+						<label class="required"><strong>Database server hostname <span>(Required)</span></strong><br /><input type="text" name="req_db_host" value="localhost" size="50" maxlength="100" /><br /></label>
 					</div>
 				</fieldset>
 			</div>
 			<div class="inform">
 				<fieldset>
-					<legend>Enter then name of your database</legend>
+					<legend>Enter the name of your database</legend>
 					<div class="infldset">
 						<p>The name of the database that FluxBB will be installed into. The database must exist. For SQLite, this is the relative path to the database file. If the SQLite database file does not exist, FluxBB will attempt to create it.</p>
-						<label for="req_db_name"><strong>Database name</strong><br /><input id="req_db_name" type="text" name="req_db_name" size="30" maxlength="50" /><br /></label>
+						<label class="required"><strong>Database name <span>(Required)</span></strong><br /><input id="req_db_name" type="text" name="req_db_name" size="30" maxlength="50" /><br /></label>
 					</div>
 				</fieldset>
 			</div>
@@ -232,7 +280,7 @@ function process_form(the_form)
 				<fieldset>
 					<legend>Enter database table prefix</legend>
 					<div class="infldset">
-						<p>If you like you can specify a table prefix. This way you can run multiple copies of FluxBB in the same database (example: foo_).</p>
+						<p>If you like, you can specify a table prefix. This way you can run multiple copies of FluxBB in the same database (example: foo_).</p>
 						<label>Table prefix<br /><input id="db_prefix" type="text" name="db_prefix" size="20" maxlength="30" /><br /></label>
 					</div>
 				</fieldset>
@@ -240,33 +288,55 @@ function process_form(the_form)
 			<div class="inform">
 				<div class="forminfo">
 					<h3>Administration setup</h3>
-					<p>Please enter the requested information in order to setup an administrator for your FluxBB installation</p>
+					<p>Please enter the requested information in order to setup an administrator for your FluxBB installation.</p>
 				</div>
 				<fieldset>
-					<legend>Enter Administrators username</legend>
+					<legend>Enter Administrator's username</legend>
 					<div class="infldset">
 						<p>The username of the forum administrator. You can later create more administrators and moderators. Usernames can be between 2 and 25 characters long.</p>
-						<label><strong>Administrator username</strong><br /><input type="text" name="req_username" size="25" maxlength="25" /><br /></label>
+						<label class="required"><strong>Administrator's username <span>(Required)</span></strong><br /><input type="text" name="req_username" size="25" maxlength="25" /><br /></label>
 					</div>
 				</fieldset>
 			</div>
 			<div class="inform">
 				<fieldset>
-					<legend>Enter and confirm Administrator password</legend>
+					<legend>Enter and confirm Administrator's password</legend>
 					<div class="infldset">
-					<p>Passwords can be between 4 and 16 characters long. Passwords are case sensitive.</p>
-						<label class="conl"><strong>Password</strong><br /><input id="req_password1" type="password" name="req_password1" size="16" maxlength="16" /><br /></label>
-						<label class="conl"><strong>Confirm password</strong><br /><input type="password" name="req_password2" size="16" maxlength="16" /><br /></label>
+					<p>Passwords must be at least 4 characters long. Passwords are case sensitive.</p>
+						<label class="conl required"><strong>Password <span>(Required)</span></strong><br /><input id="req_password1" type="password" name="req_password1" size="16" /><br /></label>
+						<label class="conl required"><strong>Confirm password <span>(Required)</span></strong><br /><input type="password" name="req_password2" size="16" /><br /></label>
 						<div class="clearer"></div>
 					</div>
 				</fieldset>
 			</div>
 			<div class="inform">
 				<fieldset>
-					<legend>Enter Administrator's e-mail</legend>
+					<legend>Enter Administrator's email</legend>
+					<div class="infldset">
+						<p>The email address of the forum administrator.</p>
+						<label class="required"><strong>Administrator's email <span>(Required)</span></strong><br /><input id="req_email" type="text" name="req_email" size="50" maxlength="80" /><br /></label>
+					</div>
+				</fieldset>
+			</div>
+			<div class="inform">
+				<div class="forminfo">
+					<h3>Board setup</h3>
+					<p>Please enter the requested information in order to setup your FluxBB board.</p>
+				</div>
+				<fieldset>
+					<legend>Enter your board's title</legend>
 					<div class="infldset">
-						<p>The e-mail address of the forum administrator.</p>
-						<label for="req_email"><strong>Administrator's e-mail</strong><br /><input id="req_email" type="text" name="req_email" size="50" maxlength="50" /><br /></label>
+						<p>The title of this bulletin board (shown at the top of every page).</p>
+						<label class="required"><strong>Board title <span>(Required)</span></strong><br /><input id="req_title" type="text" name="req_title" value="<?php echo pun_htmlspecialchars($title) ?>" size="60" maxlength="255" /><br /></label>
+					</div>
+				</fieldset>
+			</div>
+			<div class="inform">
+				<fieldset>
+					<legend>Enter your board's description</legend>
+					<div class="infldset">
+						<p>A short description of this bulletin board (shown at the top of every page). This field may contain HTML.</p>
+						<label><strong>Board description</strong><br /><input id="desc" type="text" name="desc" value="<?php echo pun_htmlspecialchars($description) ?>" size="60" maxlength="255" /><br /></label>
 					</div>
 				</fieldset>
 			</div>
@@ -274,15 +344,82 @@ function process_form(the_form)
 				<fieldset>
 					<legend>Enter the Base URL of your FluxBB installation</legend>
 					<div class="infldset">
-						<p>The URL (without trailing slash) of your FluxBB forum (example: http://forum.myhost.com or http://myhost.com/~myuser). This <strong>must</strong> be correct or administrators and moderators will not be able to submit any forms. Please note that the preset value below is just an educated guess by FluxBB.</p>
-						<label><strong>Base URL</strong><br /><input type="text" name="req_base_url" value="http://<?php echo $_SERVER['SERVER_NAME'].str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])) ?>" size="60" maxlength="100" /><br /></label>
+						<p>The URL (without trailing slash) of your FluxBB forum (example: http://forum.myhost.com or http://myhost.com/~myuser). This <strong>must</strong> be correct, otherwise, administrators and moderators will not be able to submit any forms. Please note that the preset value below is just an educated guess by FluxBB.</p>
+						<label class="required"><strong>Base URL <span>(Required)</span></strong><br /><input id="req_base_url" type="text" name="req_base_url" value="<?php echo pun_htmlspecialchars($base_url) ?>" size="60" maxlength="100" /><br /></label>
+					</div>
+				</fieldset>
+			</div>
+			<div class="inform">
+				<fieldset>
+					<legend>Choose the default language</legend>
+					<div class="infldset">
+						<p>The default language used for guests and users who haven't changed from the default in their profile.</p>
+						<label class="required"><strong>Default language <span>(Required)</span></strong><br /><select id="req_default_lang" name="req_default_lang">
+<?php
+
+		$languages = array();
+		$d = dir(PUN_ROOT.'lang');
+		while (($entry = $d->read()) !== false)
+		{
+			if ($entry{0} != '.' && is_dir(PUN_ROOT.'lang/'.$entry) && file_exists(PUN_ROOT.'lang/'.$entry.'/common.php'))
+				$languages[] = $entry;
+		}
+		$d->close();
+
+		@natsort($languages);
+
+		foreach ($languages as $temp)
+		{
+			if ($temp == $default_lang)
+				echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.$temp.'</option>'."\n";
+			else
+				echo "\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'">'.$temp.'</option>'."\n";
+		}
+
+?>
+						</select><br /></label>
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="start" value="Start install" /></p>
+			<div class="inform">
+				<fieldset>
+					<legend>Choose the default style</legend>
+					<div class="infldset">
+						<p>The default style used for guests and users who haven't changed from the default in their profile.</p>
+						<label class="required"><strong>Default style <span>(Required)</span></strong><br /><select id="req_default_style" name="req_default_style">
+<?php
+
+		$styles = array();
+		$d = dir(PUN_ROOT.'style');
+		while (($entry = $d->read()) !== false)
+		{
+			if (substr($entry, strlen($entry)-4) == '.css')
+				$styles[] = substr($entry, 0, strlen($entry)-4);
+		}
+		$d->close();
+
+		@natsort($styles);
+
+		foreach ($styles as $temp)
+		{
+			if ($temp == $default_style)
+				echo "\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.str_replace('_', ' ', $temp).'</option>'."\n";
+			else
+				echo "\t\t\t\t\t\t\t\t\t".'<option value="'.$temp.'">'.str_replace('_', ' ', $temp).'</option>'."\n";
+		}
+
+?>
+						</select><br /></label>
+					</div>
+				</fieldset>
+			</div>
+			<p class="buttons"><input type="submit" name="start" value="Start install" /></p>
 		</form>
 	</div>
 </div>
+</div>
+
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
 
 </div>
 </div>
@@ -294,50 +431,61 @@ function process_form(the_form)
 }
 else
 {
-	//
-	// Strip slashes only if magic_quotes_gpc is on.
-	//
-	function unescape($str)
-	{
-		return (get_magic_quotes_gpc() == 1) ? stripslashes($str) : $str;
-	}
-	
 	$db_type = $_POST['req_db_type'];
-	$db_host = trim($_POST['req_db_host']);
-	$db_name = trim($_POST['req_db_name']);
-	$db_username = unescape(trim($_POST['db_username']));
-	$db_password = unescape(trim($_POST['db_password']));
-	$db_prefix = trim($_POST['db_prefix']);
-	$username = unescape(trim($_POST['req_username']));
-	$email = strtolower(trim($_POST['req_email']));
-	$password1 = unescape(trim($_POST['req_password1']));
-	$password2 = unescape(trim($_POST['req_password2']));
-
+	$db_host = pun_trim($_POST['req_db_host']);
+	$db_name = pun_trim($_POST['req_db_name']);
+	$db_username = pun_trim($_POST['db_username']);
+	$db_password = pun_trim($_POST['db_password']);
+	$db_prefix = pun_trim($_POST['db_prefix']);
+	$username = pun_trim($_POST['req_username']);
+	$email = strtolower(pun_trim($_POST['req_email']));
+	$password1 = pun_trim($_POST['req_password1']);
+	$password2 = pun_trim($_POST['req_password2']);
+	$title = pun_trim($_POST['req_title']);
+	$description = pun_trim($_POST['desc']);
+	$base_url = pun_trim($_POST['req_base_url']);
+	$default_lang = pun_trim($_POST['req_default_lang']);
+	$default_style = pun_trim($_POST['req_default_style']);
 
 	// Make sure base_url doesn't end with a slash
-	if (substr($_POST['req_base_url'], -1) == '/')
-		$base_url = substr($_POST['req_base_url'], 0, -1);
-	else
-		$base_url = $_POST['req_base_url'];
-
+	if (substr($base_url, -1) == '/')
+		$base_url = substr($base_url, 0, -1);
 
 	// Validate username and passwords
-	if (strlen($username) < 2)
-		error('Usernames must be at least 2 characters long. Please go back and correct.');
-	if (strlen($password1) < 4)
-		error('Passwords must be at least 4 characters long. Please go back and correct.');
-	if ($password1 != $password2)
-		error('Passwords do not match. Please go back and correct.');
-	if (!strcasecmp($username, 'Guest'))
-		error('The username guest is reserved. Please go back and correct.');
-	if (preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $username) || preg_match('/((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))/', $username))
-		error('Usernames may not be in the form of an IP address. Please go back and correct.');
-	if (preg_match('#\[b\]|\[/b\]|\[u\]|\[/u\]|\[i\]|\[/i\]|\[color|\[/color\]|\[quote\]|\[/quote\]|\[code\]|\[/code\]|\[img\]|\[/img\]|\[url|\[/url\]|\[email|\[/email\]#i', $username))
-		error('Usernames may not contain any of the text formatting tags (BBCode) that the forum uses. Please go back and correct.');
-
-	if (strlen($email) > 80 || !preg_match('/^(([^<>()[\]\\.,;:\s@"\']+(\.[^<>()[\]\\.,;:\s@"\']+)*)|("[^"\']+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\d\-]+\.)+[a-zA-Z]{2,}))$/', $email))
-		error('The administrator e-mail address you entered is invalid. Please go back and correct.');
-
+	if (pun_strlen($username) < 2)
+		error('Usernames must be at least 2 characters long. Please go back and correct');
+	else if (pun_strlen($username) > 25) // This usually doesn't happen since the form element only accepts 25 characters
+		error('Usernames must not be more than 25 characters long. Please go back and correct');
+	else if (!strcasecmp($username, 'Guest'))
+		error('The username guest is reserved. Please go back and correct');
+	else if (preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $username) || preg_match('/((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))/', $username))
+		error('Usernames may not be in the form of an IP address. Please go back and correct');
+	else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false)
+		error('Usernames may not contain all the characters \', " and [ or ] at once. Please choose another username');
+	else if (preg_match('/(?:\[\/?(?:b|u|i|h|colou?r|quote|code|img|url|email|list)\]|\[(?:code|quote|list)=)/i', $username))
+		error('Usernames may not contain any of the text formatting tags (BBCode) that the forum uses. Please go back and correct');
+
+	if (pun_strlen($password1) < 4)
+		error('Passwords must be at least 4 characters long. Please go back and correct');
+	else if ($password1 != $password2)
+		error('Passwords do not match. Please go back and correct');
+
+	// Validate email
+	require PUN_ROOT.'include/email.php';
+
+	if (!is_valid_email($email))
+		error('The administrator email address you entered is invalid. Please go back and correct');
+
+	if ($title == '')
+		error('You must enter a board title.');
+
+	$default_lang = preg_replace('#[\.\\\/]#', '', $default_lang);
+	if (!file_exists(PUN_ROOT.'lang/'.$default_lang.'/common.php'))
+		error('The default language chosen doesn\'t seem to exist. Please go back and correct');
+
+	$default_style = preg_replace('#[\.\\\/]#', '', $default_style);
+	if (!file_exists(PUN_ROOT.'style/'.$default_style.'.css'))
+		error('The default style chosen doesn\'t seem to exist. Please go back and correct');
 
 	// Load the appropriate DB layer class
 	switch ($db_type)
@@ -345,7 +493,7 @@ else
 		case 'mysql':
 			require PUN_ROOT.'include/dblayer/mysql.php';
 			break;
-		
+
 		case 'mysql_innodb':
 			require PUN_ROOT.'include/dblayer/mysql_innodb.php';
 			break;
@@ -353,7 +501,7 @@ else
 		case 'mysqli':
 			require PUN_ROOT.'include/dblayer/mysqli.php';
 			break;
-		
+
 		case 'mysqli_innodb':
 			require PUN_ROOT.'include/dblayer/mysqli_innodb.php';
 			break;
@@ -367,12 +515,15 @@ else
 			break;
 
 		default:
-			error('\''.pun_htmlspecialchars($db_type).'\' is not a valid database type.');
+			error('\''.pun_htmlspecialchars($db_type).'\' is not a valid database type');
 	}
 
 	// Create the database object (and connect/select db)
 	$db = new DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, false);
 
+	// Validate prefix
+	if (strlen($db_prefix) > 0 && (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $db_prefix) || strlen($db_prefix) > 40))
+		error('The table prefix \''.$db->prefix.'\' contains illegal characters or is too long. The prefix may contain the letters a to z, any numbers and the underscore character. They must however not start with a number. The maximum length is 40 characters. Please choose a different prefix');
 
 	// Do some DB type specific checks
 	switch ($db_type)
@@ -381,17 +532,20 @@ else
 		case 'mysqli':
 		case 'mysql_innodb':
 		case 'mysqli_innodb':
+			$mysql_info = $db->get_version();
+			if (version_compare($mysql_info['version'], MIN_MYSQL_VERSION, '<'))
+				error('You are running MySQL version '.$mysql_version.'. FluxBB '.FORUM_VERSION.' requires at least MySQL '.MIN_MYSQL_VERSION.' to run properly. You must upgrade your MySQL installation before you can continue');
 			break;
 
 		case 'pgsql':
-			// Make sure we are running at least PHP 4.3.0 (needed only for PostgreSQL)
-			if (version_compare(PHP_VERSION, '4.3.0', '<'))
-				error('You are running PHP version '.PHP_VERSION.'. FluxBB requires at least PHP 4.3.0 to run properly when using PostgreSQL. You must upgrade your PHP installation or use a different database before you can continue.');
+			$pgsql_info = $db->get_version();
+			if (version_compare($pgsql_info['version'], MIN_PGSQL_VERSION, '<'))
+				error('You are running PostgreSQL version '.$pgsql_info.'. FluxBB '.FORUM_VERSION.' requires at least PostgreSQL '.MIN_PGSQL_VERSION.' to run properly. You must upgrade your PostgreSQL installation before you can continue');
 			break;
 
 		case 'sqlite':
 			if (strtolower($db_prefix) == 'sqlite_')
-				error('The table prefix \'sqlite_\' is reserved for use by the SQLite engine. Please choose a different prefix.');
+				error('The table prefix \'sqlite_\' is reserved for use by the SQLite engine. Please choose a different prefix');
 			break;
 	}
 
@@ -399,16 +553,16 @@ else
 	// Make sure FluxBB isn't already installed
 	$result = $db->query('SELECT 1 FROM '.$db_prefix.'users WHERE id=1');
 	if ($db->num_rows($result))
-		error('A table called "'.$db_prefix.'users" is already present in the database "'.$db_name.'". This could mean that FluxBB is already installed or that another piece of software is installed and is occupying one or more of the table names FluxBB requires. If you want to install multiple copies of FluxBB in the same database, you must choose a different table prefix.');
-	
-	// Check if InnoDB is available 
- 	if ($db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb') 
- 	{ 
-		$result = $db->query('SHOW VARIABLES LIKE \'have_innodb\''); 
-		list (, $result) = $db->fetch_row($result); 
-		if ((strtoupper($result) != 'YES')) 
-			error('InnoDB does not seem to be enabled. Please choose a database layer that does not have InnoDB support, or enable InnoDB on your MySQL server.'); 
- 	}
+		error('A table called "'.$db_prefix.'users" is already present in the database "'.$db_name.'". This could mean that FluxBB is already installed or that another piece of software is installed and is occupying one or more of the table names FluxBB requires. If you want to install multiple copies of FluxBB in the same database, you must choose a different table prefix');
+
+	// Check if InnoDB is available
+	if ($db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
+	{
+		$result = $db->query('SHOW VARIABLES LIKE \'have_innodb\'');
+		list (, $result) = $db->fetch_row($result);
+		if ((strtoupper($result) != 'YES'))
+			error('InnoDB does not seem to be enabled. Please choose a database layer that does not have InnoDB support, or enable InnoDB on your MySQL server');
+	}
 
 
 	// Start a transaction
@@ -448,10 +602,16 @@ else
 				'default'		=> '0'
 			)
 		),
-		'PRIMARY KEY'	=> array('id')
+		'PRIMARY KEY'	=> array('id'),
+		'INDEXES'		=> array(
+			'username_idx'	=> array('username')
+		)
 	);
 
-	$db->create_table('bans', $schema);
+	if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
+		$schema['INDEXES']['username_idx'] = array('username(25)');
+
+	$db->create_table('bans', $schema) or error('Unable to create bans table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -474,7 +634,7 @@ else
 		'PRIMARY KEY'	=> array('id')
 	);
 
-	$db->create_table('categories', $schema);
+	$db->create_table('categories', $schema) or error('Unable to create categories table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -497,7 +657,7 @@ else
 		'PRIMARY KEY'	=> array('id')
 	);
 
-	$db->create_table('censoring', $schema);
+	$db->create_table('censoring', $schema) or error('Unable to create censoring table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -515,7 +675,7 @@ else
 		'PRIMARY KEY'	=> array('conf_name')
 	);
 
-	$db->create_table('config', $schema);
+	$db->create_table('config', $schema) or error('Unable to create config table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -549,7 +709,7 @@ else
 		'PRIMARY KEY'	=> array('group_id', 'forum_id')
 	);
 
-	$db->create_table('forum_perms', $schema);
+	$db->create_table('forum_perms', $schema) or error('Unable to create forum_perms table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -616,7 +776,7 @@ else
 		'PRIMARY KEY'	=> array('id')
 	);
 
-	$db->create_table('forums', $schema);
+	$db->create_table('forums', $schema) or error('Unable to create forums table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -733,7 +893,7 @@ else
 		'PRIMARY KEY'	=> array('g_id')
 	);
 
-	$db->create_table('groups', $schema);
+	$db->create_table('groups', $schema) or error('Unable to create groups table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -782,11 +942,11 @@ else
 		$schema['UNIQUE KEYS']['user_id_ident_idx'] = array('user_id', 'ident(25)');
 		$schema['INDEXES']['ident_idx'] = array('ident(25)');
 	}
-	
-	if ($db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb') 
+
+	if ($db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
 		$schema['ENGINE'] = 'InnoDB';
 
-	$db->create_table('online', $schema);
+	$db->create_table('online', $schema) or error('Unable to create online table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -848,7 +1008,7 @@ else
 		)
 	);
 
-	$db->create_table('posts', $schema);
+	$db->create_table('posts', $schema) or error('Unable to create posts table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -871,7 +1031,7 @@ else
 		'PRIMARY KEY'	=> array('id')
 	);
 
-	$db->create_table('ranks', $schema);
+	$db->create_table('ranks', $schema) or error('Unable to create ranks table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -924,7 +1084,7 @@ else
 		)
 	);
 
-	$db->create_table('reports', $schema);
+	$db->create_table('reports', $schema) or error('Unable to create reports table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -940,7 +1100,7 @@ else
 				'default'		=> '\'\''
 			),
 			'search_data'	=> array(
-				'datatype'		=> 'TEXT',
+				'datatype'		=> 'MEDIUMTEXT',
 				'allow_null'	=> true
 			)
 		),
@@ -953,7 +1113,7 @@ else
 	if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
 		$schema['INDEXES']['ident_idx'] = array('ident(8)');
 
-	$db->create_table('search_cache', $schema);
+	$db->create_table('search_cache', $schema) or error('Unable to create search_cache table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -980,7 +1140,7 @@ else
 		)
 	);
 
-	$db->create_table('search_matches', $schema);
+	$db->create_table('search_matches', $schema) or error('Unable to create search_matches table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -1008,7 +1168,7 @@ else
 		$schema['UNIQUE KEYS'] = array('word_idx'	=> array('word'));
 	}
 
-	$db->create_table('search_words', $schema);
+	$db->create_table('search_words', $schema) or error('Unable to create search_words table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -1027,7 +1187,7 @@ else
 		'PRIMARY KEY'	=> array('user_id', 'topic_id')
 	);
 
-	$db->create_table('subscriptions', $schema);
+	$db->create_table('subscriptions', $schema) or error('Unable to create subscriptions table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -1109,7 +1269,7 @@ else
 		)
 	);
 
-	$db->create_table('topics', $schema);
+	$db->create_table('topics', $schema) or error('Unable to create topics table', __FILE__, __LINE__, $db->error());
 
 
 	$schema = array(
@@ -1237,12 +1397,12 @@ else
 				'default'		=> '0'
 			),
 			'time_format'		=> array(
-				'datatype'		=> 'INT(10) UNSIGNED',
+				'datatype'		=> 'TINYINT(1)',
 				'allow_null'	=> false,
 				'default'		=> '0'
 			),
 			'date_format'		=> array(
-				'datatype'		=> 'INT(10) UNSIGNED',
+				'datatype'		=> 'TINYINT(1)',
 				'allow_null'	=> false,
 				'default'		=> '0'
 			),
@@ -1254,7 +1414,7 @@ else
 			'style'				=> array(
 				'datatype'		=> 'VARCHAR(25)',
 				'allow_null'	=> false,
-				'default'		=> '\'Oxygen\''
+				'default'		=> '\''.$db->escape($default_style).'\''
 			),
 			'num_posts'			=> array(
 				'datatype'		=> 'INT(10) UNSIGNED',
@@ -1302,32 +1462,37 @@ else
 			),
 		),
 		'PRIMARY KEY'	=> array('id'),
-		'INDEXES'		=> array(
-			'registered_idx'	=> array('registered'),
+		'UNIQUE KEYS'	=> array(
 			'username_idx'		=> array('username')
+		),
+		'INDEXES'		=> array(
+			'registered_idx'	=> array('registered')
 		)
 	);
 
 	if ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb')
-		$schema['INDEXES']['username_idx'] = array('username(8)');
+		$schema['UNIQUE KEYS']['username_idx'] = array('username(25)');
 
-	$db->create_table('users', $schema);
+	$db->create_table('users', $schema) or error('Unable to create users table', __FILE__, __LINE__, $db->error());
 
 
 	$now = time();
 
 	// Insert the four preset groups
-	$db->query('INSERT INTO '.$db->prefix."groups (g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('Administrators', 'Administrator', 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
-	$db->query('INSERT INTO '.$db->prefix."groups (g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('Moderators', 'Moderator', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
-	$db->query('INSERT INTO '.$db->prefix."groups (g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('Guest', NULL, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 60, 30, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
-	$db->query('INSERT INTO '.$db->prefix."groups (g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('Members', NULL, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 60, 30, 60)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
+	$db->query('INSERT INTO '.$db->prefix.'groups ('.($db_type != 'pgsql' ? 'g_id, ' : '').'g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('.($db_type != 'pgsql' ? '1, ' : '')."'Administrators', 'Administrator', 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
+
+	$db->query('INSERT INTO '.$db->prefix.'groups ('.($db_type != 'pgsql' ? 'g_id, ' : '').'g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('.($db_type != 'pgsql' ? '2, ' : '')."'Moderators', 'Moderator', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
+
+	$db->query('INSERT INTO '.$db->prefix.'groups ('.($db_type != 'pgsql' ? 'g_id, ' : '').'g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('.($db_type != 'pgsql' ? '3, ' : '')."'Guest', NULL, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 60, 30, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
+
+	$db->query('INSERT INTO '.$db->prefix.'groups ('.($db_type != 'pgsql' ? 'g_id, ' : '').'g_title, g_user_title, g_moderator, g_mod_edit_users, g_mod_rename_users, g_mod_change_passwords, g_mod_ban_users, g_read_board, g_view_users, g_post_replies, g_post_topics, g_edit_posts, g_delete_posts, g_delete_topics, g_set_title, g_search, g_search_users, g_send_email, g_post_flood, g_search_flood, g_email_flood) VALUES('.($db_type != 'pgsql' ? '4, ' : '')."'Members', NULL, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 60, 30, 60)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
 
 	// Insert guest and first admin user
 	$db->query('INSERT INTO '.$db_prefix."users (group_id, username, password, email) VALUES(3, 'Guest', 'Guest', 'Guest')")
-		or error('Unable to add guest user. Please check your configuration and try again.');
+		or error('Unable to add guest user. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
 	$db->query('INSERT INTO '.$db_prefix."users (group_id, username, password, email, num_posts, last_post, registered, registration_ip, last_visit) VALUES(1, '".$db->escape($username)."', '".pun_hash($password1)."', '$email', 1, ".$now.", ".$now.", '127.0.0.1', ".$now.')')
-		or error('Unable to add administrator user. Please check your configuration and try again.');
+		or error('Unable to add administrator user. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
 	// Enable/disable avatars depending on file_uploads setting in PHP configuration
 	$avatars = in_array(strtolower(@ini_get('file_uploads')), array('on', 'true', '1')) ? 1 : 0;
@@ -1336,8 +1501,8 @@ else
 	$config = array(
 		'o_cur_version'				=> "'".FORUM_VERSION."'",
 		'o_database_revision'		=> "'".FORUM_DB_REVISION."'",
-		'o_board_title'				=> "'My FluxBB forum'",
-		'o_board_desc'				=> "'Unfortunately no one can be told what FluxBB is - you have to see it for yourself.'",
+		'o_board_title'				=> "'".$db->escape($title)."'",
+		'o_board_desc'				=> "'".$db->escape($description)."'",
 		'o_default_timezone'		=> "'0'",
 		'o_time_format'				=> "'H:i:s'",
 		'o_date_format'				=> "'Y-m-d'",
@@ -1351,13 +1516,14 @@ else
 		'o_smilies'					=> "'1'",
 		'o_smilies_sig'				=> "'1'",
 		'o_make_links'				=> "'1'",
-		'o_default_lang'			=> "'English'",
-		'o_default_style'			=> "'Oxygen'",
+		'o_default_lang'			=> "'".$db->escape($default_lang)."'",
+		'o_default_style'			=> "'".$db->escape($default_style)."'",
 		'o_default_user_group'		=> "'4'",
 		'o_topic_review'			=> "'15'",
 		'o_disp_topics_default'		=> "'30'",
 		'o_disp_posts_default'		=> "'25'",
 		'o_indent_num_spaces'		=> "'4'",
+		'o_quote_depth'				=> "'3'",
 		'o_quickpost'				=> "'1'",
 		'o_users_online'			=> "'1'",
 		'o_censoring'				=> "'0'",
@@ -1370,16 +1536,16 @@ else
 		'o_report_method'			=> "'0'",
 		'o_regs_report'				=> "'0'",
 		'o_default_email_setting'	=> "'1'",
-		'o_mailing_list'			=> "'$email'",
-		'o_avatars'					=> "'$avatars'",
+		'o_mailing_list'			=> "'".$email."'",
+		'o_avatars'					=> "'".$avatars."'",
 		'o_avatars_dir'				=> "'img/avatars'",
 		'o_avatars_width'			=> "'60'",
 		'o_avatars_height'			=> "'60'",
 		'o_avatars_size'			=> "'10240'",
 		'o_search_all_forums'		=> "'1'",
-		'o_base_url'				=> "'$base_url'",
-		'o_admin_email'				=> "'$email'",
-		'o_webmaster_email'			=> "'$email'",
+		'o_base_url'				=> "'".$db->escape($base_url)."'",
+		'o_admin_email'				=> "'".$email."'",
+		'o_webmaster_email'			=> "'".$email."'",
 		'o_subscriptions'			=> "'1'",
 		'o_smtp_host'				=> "NULL",
 		'o_smtp_user'				=> "NULL",
@@ -1394,6 +1560,7 @@ else
 		'o_maintenance'				=> "'0'",
 		'o_maintenance_message'		=> "'The forums are temporarily down for maintenance. Please try again in a few minutes.<br />\\n<br />\\n/Administrator'",
 		'o_default_dst'				=> "'0'",
+		'o_feed_type'				=> "'2'",
 		'p_message_bbcode'			=> "'1'",
 		'p_message_img_tag'			=> "'1'",
 		'p_message_all_caps'		=> "'1'",
@@ -1408,52 +1575,59 @@ else
 		'p_force_guest_email'		=> "'1'"
 	);
 
-	while (list($conf_name, $conf_value) = @each($config))
+	foreach ($config as $conf_name => $conf_value)
 	{
 		$db->query('INSERT INTO '.$db_prefix."config (conf_name, conf_value) VALUES('$conf_name', $conf_value)")
-			or error('Unable to insert into table '.$db_prefix.'config. Please check your configuration and try again.');
+			or error('Unable to insert into table '.$db_prefix.'config. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 	}
 
 	// Insert some other default data
-	$db->query('INSERT INTO '.$db_prefix."categories (cat_name, disp_position) VALUES('Test category', 1)")
-		or error('Unable to insert into table '.$db_prefix.'categories. Please check your configuration and try again.');
+	$subject = 'Test post';
+	$message = 'If you are looking at this (which I guess you are), the install of FluxBB appears to have worked! Now log in and head over to the administration control panel to configure your forum.';
 
-	$db->query('INSERT INTO '.$db_prefix."forums (forum_name, forum_desc, num_topics, num_posts, last_post, last_post_id, last_poster, disp_position, cat_id) VALUES('Test forum', 'This is just a test forum', 1, 1, ".$now.", 1, '".$db->escape($username)."', 1, 1)")
-		or error('Unable to insert into table '.$db_prefix.'forums. Please check your configuration and try again.');
+	$db->query('INSERT INTO '.$db_prefix."ranks (rank, min_posts) VALUES('New member', 0)")
+		or error('Unable to insert into table '.$db_prefix.'ranks. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
-	$db->query('INSERT INTO '.$db_prefix."topics (poster, subject, posted, first_post_id, last_post, last_post_id, last_poster, forum_id) VALUES('".$db->escape($username)."', 'Test post', ".$now.", 1, ".$now.", 1, '".$db->escape($username)."', 1)")
-		or error('Unable to insert into table '.$db_prefix.'topics. Please check your configuration and try again.');
+	$db->query('INSERT INTO '.$db_prefix."ranks (rank, min_posts) VALUES('Member', 10)")
+		or error('Unable to insert into table '.$db_prefix.'ranks. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
-	$db->query('INSERT INTO '.$db_prefix."posts (poster, poster_id, poster_ip, message, posted, topic_id) VALUES('".$db->escape($username)."', 2, '127.0.0.1', 'If you are looking at this (which I guess you are), the install of FluxBB appears to have worked! Now log in and head over to the administration control panel to configure your forum.', ".$now.', 1)')
-		or error('Unable to insert into table '.$db_prefix.'posts. Please check your configuration and try again.');
+	$db->query('INSERT INTO '.$db_prefix."categories (cat_name, disp_position) VALUES('Test category', 1)")
+		or error('Unable to insert into table '.$db_prefix.'categories. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
-	$db->query('INSERT INTO '.$db_prefix."ranks (rank, min_posts) VALUES('New member', 0)")
-		or error('Unable to insert into table '.$db_prefix.'ranks. Please check your configuration and try again.');
+	$db->query('INSERT INTO '.$db_prefix."forums (forum_name, forum_desc, num_topics, num_posts, last_post, last_post_id, last_poster, disp_position, cat_id) VALUES('Test forum', 'This is just a test forum', 1, 1, ".$now.", 1, '".$db->escape($username)."', 1, 1)")
+		or error('Unable to insert into table '.$db_prefix.'forums. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
-	$db->query('INSERT INTO '.$db_prefix."ranks (rank, min_posts) VALUES('Member', 10)")
-		or error('Unable to insert into table '.$db_prefix.'ranks. Please check your configuration and try again.');
+	$db->query('INSERT INTO '.$db_prefix."topics (poster, subject, posted, first_post_id, last_post, last_post_id, last_poster, forum_id) VALUES('".$db->escape($username)."', '".$db->escape($subject)."', ".$now.", 1, ".$now.", 1, '".$db->escape($username)."', 1)")
+		or error('Unable to insert into table '.$db_prefix.'topics. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
+
+	$db->query('INSERT INTO '.$db_prefix."posts (poster, poster_id, poster_ip, message, posted, topic_id) VALUES('".$db->escape($username)."', 2, '127.0.0.1', '".$db->escape($message)."', ".$now.', 1)')
+		or error('Unable to insert into table '.$db_prefix.'posts. Please check your configuration and try again', __FILE__, __LINE__, $db->error());
 
+	// Index the test post so searching for it works
+	require PUN_ROOT.'include/search_idx.php';
+	$pun_config['o_default_lang'] = $default_lang;
+	update_search_index('post', 1, $message, $subject);
 
 	$db->end_transaction();
 
 
-	$alerts = '';
+	$alerts = array();
 	// Check if the cache directory is writable
 	if (!@is_writable('./cache/'))
-		$alerts .= '<p style="font-size: 1.1em"><span style="color: #C03000"><strong>The cache directory is currently not writable!</strong></span> In order for FluxBB to function properly, the directory named <em>cache</em> must be writable by PHP. Use chmod to set the appropriate directory permissions. If in doubt, chmod to 0777.</p>';
+		$alerts[] = '<strong>The cache directory is currently not writable!</strong> In order for FluxBB to function properly, the directory named <em>cache</em> must be writable by PHP. Use chmod to set the appropriate directory permissions. If in doubt, chmod to 0777.';
 
 	// Check if default avatar directory is writable
 	if (!@is_writable('./img/avatars/'))
-		$alerts .= '<p style="font-size: 1.1em"><span style="color: #C03000"><strong>The avatar directory is currently not writable!</strong></span> If you want users to be able to upload their own avatar images you must see to it that the directory named <em>img/avatars</em> is writable by PHP. You can later choose to save avatar images in a different directory (see Admin/Options). Use chmod to set the appropriate directory permissions. If in doubt, chmod to 0777.</p>';
+		$alerts[] = '<strong>The avatar directory is currently not writable!</strong> If you want users to be able to upload their own avatar images you must see to it that the directory named <em>img/avatars</em> is writable by PHP. You can later choose to save avatar images in a different directory (see Admin/Options). Use chmod to set the appropriate directory permissions. If in doubt, chmod to 0777.';
 
 	// Check if we disabled uploading avatars because file_uploads was disabled
 	if ($avatars == '0')
-		$alerts .= '<p style="font-size: 1.1em"><span style="color: #C03000"><strong>File uploads appear to be disallowed on this server!</strong></span> If you want users to be able to upload their own avatar images you must enable the file_uploads configuration setting in PHP. Once file uploads have been enabled, avatar uploads can be enabled in Administration/Options/Features.</p>';
+		$alerts[] = '<strong>File uploads appear to be disallowed on this server!</strong> If you want users to be able to upload their own avatar images you must enable the file_uploads configuration setting in PHP. Once file uploads have been enabled, avatar uploads can be enabled in Administration/Options/Features.';
 
 	// Add some random bytes at the end of the cookie name to prevent collisions
 	$cookie_name = 'pun_cookie_'.random_key(6, false, true);
 
-	/// Generate the config.php file data
+	// Generate the config.php file data
 	$config = generate_config_file();
 
 	// Attempt to write config.php and serve it up for download if writing fails
@@ -1478,29 +1652,48 @@ else
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>FluxBB Installation</title>
-<link rel="stylesheet" type="text/css" href="style/Oxygen.css" />
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
+<style type="text/css">
+<!--
+#punwrap {
+	margin: 20px 10%;
+	}
+-->
+</style>
 </head>
 <body>
 
-<div id="puninstall" style="margin: auto 10% auto 10%">
-<div class="pun">
+<div id="punwrap">
+<div id="puninstall" class="pun">
+
+<div class="top-box"><div><!-- Top Corners --></div></div>
+
+<div id="brdheader" class="block">
+	<div class="box">
+		<div id="brdtitle" class="inbox">
+			<h1><span>FluxBB Installation</span></h1>
+			<div id="brddesc"><p>FluxBB has been installed. To finalize the installation please follow the instructions below.</p></div>
+		</div>
+	</div>
+</div>
+
+<div id="brdmain">
 
 <div class="blockform">
-	<h2>Final instructions</h2>
+	<h2><span>Final instructions</span></h2>
 	<div class="box">
-		<div class="fakeform">
 <?php
 
 if (!$written)
 {
 
 ?>
+		<form method="post" action="install.php">
 			<div class="inform">
 				<div class="forminfo">
-					<p>Important! To finalize the installation, you need to click on the button below to download a file called config.php. You then need to upload this file to the root directory of your FluxBB installation.</p>
-<?php if ($alerts != ''): ?>					<?php echo $alerts."\n" ?>
-<?php endif; ?>				</div>
-				<form method="post" action="install.php">
+					<p>To finalize the installation, you need to click on the button below to download a file called config.php. You then need to upload this file to the root directory of your FluxBB installation.</p>
+					<p>Once you have uploaded config.php, FluxBB will be fully installed! At that point, you may <a href="index.php">go to the forum index</a>.</p>
+				</div>
 				<input type="hidden" name="generate_config" value="1" />
 				<input type="hidden" name="db_type" value="<?php echo $db_type; ?>" />
 				<input type="hidden" name="db_host" value="<?php echo $db_host; ?>" />
@@ -1510,14 +1703,19 @@ if (!$written)
 				<input type="hidden" name="db_prefix" value="<?php echo pun_htmlspecialchars($db_prefix); ?>" />
 				<input type="hidden" name="cookie_name" value="<?php echo pun_htmlspecialchars($cookie_name); ?>" />
 				<input type="hidden" name="cookie_seed" value="<?php echo pun_htmlspecialchars($cookie_seed); ?>" />
-				<p><input type="submit" value="Download config.php file" /></p>
-				</form>
-			</div>
-			<div class="inform">
-				<div class="forminfo">
-					<p>Once you have uploaded config.php, FluxBB will be fully installed! At that point, you may <a href="index.php">go to the forum index</a>.</p>
+
+<?php if (!empty($alerts)): ?>				<div class="forminfo error-info">
+					<ul class="error-list">
+<?php
+
+foreach ($alerts as $cur_alert)
+	echo "\t\t\t\t\t".'<li>'.$cur_alert.'</li>'."\n";
+?>
 				</div>
-			</div>
+<?php endif; ?>			</div>
+			<p class="buttons"><input type="submit" value="Download config.php file" /></p>
+		</form>
+
 <?php
 
 }
@@ -1525,21 +1723,26 @@ else
 {
 
 ?>
+		<div class="fakeform">
 			<div class="inform">
 				<div class="forminfo">
-					<p>FluxBB has been fully installed! You may now <a href="index.php">go to the forum index</a></p>
+					<p>FluxBB has been fully installed! You may now <a href="index.php">go to the forum index</a>.</p>
 				</div>
 			</div>
+		</div>
 <?php
 
 }
 
 ?>
-		</div>
 	</div>
 </div>
 
 </div>
+
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+
+</div>
 </div>
 
 </body>
diff --git a/upload/lang/English/admin_bans.php b/upload/lang/English/admin_bans.php
new file mode 100644
index 0000000..b2c7631
--- /dev/null
+++ b/upload/lang/English/admin_bans.php
@@ -0,0 +1,68 @@
+<?php
+
+// Language definitions used in admin_bans.php
+$lang_admin_bans = array(
+
+'No user message'			=>	'No user by that username registered. If you want to add a ban not tied to a specific username just leave the username blank.',
+'No user ID message'		=>	'No user by that ID registered.',
+'User is admin message'		=>	'The user %s is an administrator and can\'t be banned. If you want to ban an administrator, you must first demote him/her to moderator or user.',
+'Must enter message'		=>	'You must enter either a username, an IP address or an email address (at least).',
+'Cannot ban guest message'	=>	'The guest user cannot be banned.',
+'Invalid IP message'		=>	'You entered an invalid IP/IP-range.',
+'Invalid e-mail message'	=>	'The email address (e.g. user@domain.com) or partial email address domain (e.g. domain.com) you entered is invalid.',
+'Invalid date message'		=>	'You entered an invalid expire date.',
+'Invalid date reasons'		=>	'The format should be YYYY-MM-DD and the date must be at least one day in the future.',
+'Ban added redirect'		=>	'Ban added. Redirecting …' ,
+'Ban edited redirect'		=>	'Ban edited. Redirecting …',
+'Ban removed redirect'		=>	'Ban removed. Redirecting …',
+
+'New ban head'				=>	'New ban',
+'Add ban subhead'			=>	'Add ban',
+'Username label'			=>	'Username',
+'Username help'				=>	'The username to ban (case-insensitive).',
+'Username advanced help'	=>	'The username to ban (case-insensitive). The next page will let you enter a custom IP and email. If you just want to ban a specific IP/IP-range or email just leave it blank.',
+
+'Ban search head'			=>	'Ban search',
+'Ban search subhead'		=>	'Enter search criteria',
+'Ban search info'			=>	'Search for bans in the database. You can enter one or more terms to search for. Wildcards in the form of asterisks (*) are accepted.',
+'Date help'					=>	'(yyyy-mm-dd)',
+'Message label'				=>	'Message',
+'Expire after label'		=>	'Expire after',
+'Expire before label'		=>	'Expire before',
+'Order by label'			=>	'Order by',
+'Order by username'			=>	'Username',
+'Order by ip'				=>	'IP',
+'Order by e-mail'			=>	'Email',
+'Order by expire'			=>	'Expire date',
+'Ascending'					=>	'Ascending',
+'Descending'				=>	'Descending',
+'Submit search'				=>	'Submit search',
+
+'E-mail label'				=>	'Email',
+'E-mail help'				=>	'The email or email domain you wish to ban (e.g. someone@somewhere.com or somewhere.com). See "Allow banned email addresses" in Permissions for more info.',
+'IP label'					=>	'IP address/IP-ranges',
+'IP help'					=>	'The IP address or IP-ranges you wish to ban (e.g. 150.11.110.1 or 150.11.110). Separate addresses with spaces. If an IP is entered already it is the last known IP of this user in the database.',
+'IP help link'				=>	'Click %s to see IP statistics for this user.',
+'Reason label'				=>	'Reason',
+'Banned by label'			=>	'Banned by',
+'Ban advanced head'			=>	'Ban advanced settings',
+'Ban advanced subhead'		=>	'Supplement ban with IP and email',
+'Ban message label'			=>	'Ban message',
+'Ban message help'			=>	'A message that will be displayed to the banned user when he/she visits the board.',
+'Message expiry subhead'	=>	'Ban message and expiry',
+'Ban IP range info'			=>	'You should be very careful when banning an IP-range because of the possibility of multiple users matching the same partial IP.',
+'Expire date label'			=>	'Expire date',
+'Expire date help'			=>	'The date when this ban should be automatically removed (format: yyyy-mm-dd). Leave blank to remove manually.',
+
+'Results head'				=>	'Search Results',
+'Results username head'		=>	'Username',
+'Results e-mail head'		=>	'Email',
+'Results IP address head'	=>	'IP/IP-ranges',
+'Results expire head'		=>	'Expires',
+'Results message head'		=>	'Message',
+'Results banned by head'	=>	'Banned by',
+'Results actions head'		=>	'Actions',
+'No match'					=>	'No match',
+'Unknown'					=>	'Unknown',
+
+);
diff --git a/upload/lang/English/admin_categories.php b/upload/lang/English/admin_categories.php
new file mode 100644
index 0000000..311a5af
--- /dev/null
+++ b/upload/lang/English/admin_categories.php
@@ -0,0 +1,29 @@
+<?php
+
+// Language definitions used in admin-categories.php
+$lang_admin_categories = array(
+
+'Must enter name message'		=>	'You must enter a name for the category',
+'Category added redirect'		=>	'Category added. Redirecting …',
+'Category deleted redirect'		=>	'Category deleted. Redirecting …',
+'Delete category head'			=>	'Delete category (together with all forums and posts it contains)',
+'Confirm delete subhead'		=>	'Confirm delete category',
+'Confirm delete info'			=>	'Are you sure that you want to delete the category <strong>%s</strong>?',
+'Delete category warn'			=>	'<strong>WARNING!</strong> Deleting a category will delete all forums and posts (if any) in this category!',
+'Must enter integer message'	=>	'Position must be a positive integer value.',
+'Categories updated redirect'	=>	'Categories updated. Redirecting …',
+'Add categories head'			=>	'Add categories',
+'Add categories subhead'		=>	'Add categories',
+'Add category label'			=>	'Add a new category',
+'Add new submit'				=>	'Add new',
+'Add category help'				=>	'The name of the new category you want to add. You can edit the name of the category later (see below). Go to %s to add forums to your new category.',
+'Delete categories head'		=>	'Delete categories',
+'Delete categories subhead'		=>	'Delete categories',
+'Delete category label'			=>	'Delete a category',
+'Delete category help'			=>	'Select the name of the category you want to delete. You will be asked to confirm your choice of category for deletion before it is deleted.',
+'Edit categories head'			=>	'Edit categories',
+'Edit categories subhead'		=>	'Edit categories',
+'Category position label'		=>	'Position',
+'Category name label'			=>	'Name',
+
+);
diff --git a/upload/lang/English/admin_censoring.php b/upload/lang/English/admin_censoring.php
new file mode 100644
index 0000000..f112ba1
--- /dev/null
+++ b/upload/lang/English/admin_censoring.php
@@ -0,0 +1,20 @@
+<?php
+
+// Language definitions used in admin_censoring.php
+$lang_admin_censoring = array(
+
+'Must enter both message'	=>	'You must enter both a word to censor and text to replace it with.',
+'Must search both message'	=>	'You must enter both text to search for and text to replace with.',
+'Word updated redirect'		=>	'Censor word updated. Redirecting …',
+'Word added redirect'		=>	'Censor word added. Redirecting …',
+'Word removed redirect'		=>	'Censor word removed. Redirecting …',
+'Censoring head'			=>	'Censoring',
+'Add word subhead'			=>	'Add word',
+'Add word info'				=>	'Enter a word that you want to censor and the replacement text for this word. Wildcards are accepted (i.e. *some* would match somewhere and lonesome). Censor words also affect usernames. New users will not be able to register with usernames containing any censored words. The search is case insensitive. <strong>Censor words must be enabled in %s for this to have any effect.</strong>',
+'Censored word label'		=>	'Censored word',
+'Replacement label'			=>	'Replacement word(s)',
+'Action label'				=>	'Action',
+'Edit remove subhead'		=>	'Edit or remove words',
+'No words in list'			=>	'No censor words in list.',
+
+);
diff --git a/upload/lang/English/admin_common.php b/upload/lang/English/admin_common.php
new file mode 100644
index 0000000..a87616c
--- /dev/null
+++ b/upload/lang/English/admin_common.php
@@ -0,0 +1,44 @@
+<?php
+
+// Language definitions used in admin_common
+$lang_admin_common = array(
+
+// The menu
+'Admin menu'			=>	'Admin menu',
+'Plugins menu'			=>	'Plugins menu',
+'Moderator menu'		=>	'Moderator menu',
+'Index'					=>	'Index',
+'Categories'			=>	'Categories',
+'Forums'				=>	'Forums',
+'Users'					=>	'Users',
+'User groups'			=>	'User groups',
+'Options'				=>	'Options',
+'Permissions'			=>	'Permissions',
+'Censoring'				=>	'Censoring',
+'Ranks'					=>	'Ranks',
+'Bans'					=>	'Bans',
+'Prune'					=>	'Prune',
+'Maintenance'			=>	'Maintenance',
+'Reports'				=>	'Reports',
+
+'Admin'					=>	'Admin',
+'Go back'				=>	'Go back',
+'Delete'				=>	'Delete',
+'Update'				=>	'Update',
+'Add'					=>	'Add',
+'Edit'					=>	'Edit',
+'Remove'				=>	'Remove',
+'Yes'					=>	'Yes',
+'No'					=>	'No',
+'Save changes'			=>	'Save changes',
+'Save'					=>	'Save',
+'here'					=>	'here',
+'Action'				=>	'Action',
+'None'					=>	'None',
+'Maintenance mode'		=>	'maintenance mode', // Used for link text in more than one file
+
+// Admin loader
+'No plugin message'		=>	'There is no plugin called %s in the plugin directory.',
+'Plugin failed message'	=>	'Loading of the plugin - <strong>%s</strong> - failed.',
+
+);
diff --git a/upload/lang/English/admin_forums.php b/upload/lang/English/admin_forums.php
new file mode 100644
index 0000000..f13876d
--- /dev/null
+++ b/upload/lang/English/admin_forums.php
@@ -0,0 +1,51 @@
+<?php
+
+// Language definitions used in admin-forums.php
+$lang_admin_forums = array(
+
+'Forum added redirect'		=>	'Forum added. Redirecting …',
+'Forum deleted redirect'	=>	'Forum deleted. Redirecting …',
+'Forums updated redirect'	=>	'Forums updated. Redirecting …',
+'Forum updated redirect'	=>	'Forum updated. Redirecting …',
+'Perms reverted redirect'	=>	'Permissions reverted to defaults. Redirecting …',
+'Must enter name message'	=>	'You must enter a forum name.',
+'Must be integer message'	=>	'Position must be a positive integer value.',
+
+// Entry page
+'Add forum head'			=>	'Add forum',
+'Create new subhead'		=>	'Create a new forum',
+'Add forum label'			=>	'Add forum to category',
+'Add forum help'			=>	'Select the category to which you wish to add a new forum.',
+'Add forum'					=>	'Add forum',
+'No categories exist'		=>	'No categories exist',
+'Edit forums head'			=>	'Edit forums',
+'Category subhead'			=>	'Category:',
+'Forum label'				=>	'Forum',
+'Edit link'					=>	'Edit',
+'Delete link'				=>	'Delete',
+'Position label'			=>	'Position',
+'Update positions'			=>	'Update positions',
+'Confirm delete head'		=>	'Confirm delete forum',
+'Confirm delete subhead'	=>	'Important! Read before deleting',
+'Confirm delete info'		=>	'Are you sure that you want to delete the forum <strong>%s</strong>?',
+'Confirm delete warn'		=>	'WARNING! Deleting a forum will delete all posts (if any) in that forum!',
+
+// Detailed edit page
+'Edit forum head'			=>	'Edit forum',
+'Edit details subhead'		=>	'Edit forum details',
+'Forum name label'			=>	'Forum name',
+'Forum description label'	=>	'Description (HTML)',
+'Category label'			=>	'Category',
+'Sort by label'				=>	'Sort topics by',
+'Last post'					=>	'Last post',
+'Topic start'				=>	'Topic start',
+'Redirect label'			=>	'Redirect URL',
+'Redirect help'				=>	'Only available in empty forums',
+'Group permissions subhead'	=>	'Edit group permissions for this forum',
+'Group permissions info'	=>	'In this form, you can set the forum specific permissions for the different user groups. If you haven\'t made any changes to this forum\'s group permissions, what you see below is the default based on settings in %s. Administrators always have full permissions and are thus excluded. Permission settings that differ from the default permissions for the user group are marked red. The "Read forum" permission checkbox will be disabled if the group in question lacks the "Read board" permission. For redirect forums, only the "Read forum" permission is editable.',
+'Read forum label'			=>	'Read forum',
+'Post replies label'		=>	'Post replies',
+'Post topics label'			=>	'Post topics',
+'Revert to default'			=>	'Revert to default',
+
+);
diff --git a/upload/lang/English/admin_groups.php b/upload/lang/English/admin_groups.php
new file mode 100644
index 0000000..dd6ad56
--- /dev/null
+++ b/upload/lang/English/admin_groups.php
@@ -0,0 +1,82 @@
+<?php
+
+// Language definitions used in admin-groups.php
+$lang_admin_groups = array(
+
+'Must enter title message'		=>	'You must enter a group title.',
+'Title already exists message'	=>	'There is already a group with the title <strong>%s</strong>.',
+'Default group redirect'		=>	'Default group set. Redirecting …',
+'Cannot remove default message'	=>	'The default group cannot be removed. In order to delete this group, you must first setup a different group as the default.',
+'Group removed redirect'		=>	'Group removed. Redirecting …',
+'Group added redirect'			=>	'Group added. Redirecting …',
+'Group edited redirect'			=>	'Group edited. Redirecting …',
+
+'Add groups head'				=>	'Add/setup groups',
+'Add group subhead'				=>	'Add new group',
+'New group label'				=>	'Base new group on',
+'New group help'				=>	'Select a user group from which the new group will inherit its permission settings. The next page will let you fine-tune its settings.',
+'Default group subhead'			=>	'Set default group',
+'Default group label'			=>	'Default group',
+'Default group help'			=>	'This is the default user group, e.g. the group users are placed in when they register. For security reasons, users can\'t be placed in either the moderator or administrator user groups by default.',
+'Existing groups head'			=>	'Existing groups',
+'Edit groups subhead'			=>	'Edit/delete groups',
+'Edit groups info'				=>	'The pre-defined groups Guests, Administrators, Moderators and Members cannot be removed. However, they can be edited. Please note that in some groups, some options are unavailable (e.g. the <em>edit posts</em> permission for guests). Administrators always have full permissions.',
+'Edit link'						=>	'Edit',
+'Delete link'					=>	'Delete',
+'Group delete head'				=>	'Group delete',
+'Confirm delete subhead'		=>	'Confirm delete group',
+'Confirm delete info'			=>	'Are you sure that you want to delete the group <strong>%s</strong>?',
+'Confirm delete warn'			=>	'WARNING! After you deleted a group you can not restore it.',
+'Delete group head'				=>	'Delete group',
+'Move users subhead'			=>	'Move users currently in group',
+'Move users info'				=>	'The group <strong>%s</strong> currently has <strong>%s</strong> members. Please select a group to which these members will be assigned upon deletion.',
+'Move users label'				=>	'Move users to',
+'Delete group'					=>	'Delete group',
+
+'Group settings head'			=>	'Group settings',
+'Group settings subhead'		=>	'Setup group options and permissions',
+'Group settings info'			=>	'Below options and permissions are the default permissions for the user group. These options apply if no forum specific permissions are in effect.',
+'Group title label'				=>	'Group title',
+'User title label'				=>	'User title',
+'User title help'				=>	'This title will override any rank users in this group have attained. Leave blank to use default title or rank.',
+'Mod privileges label'			=>	'Allow users moderator privileges',
+'Mod privileges help'			=>	'In order for a user in this group to have moderator abilities, he/she must be assigned to moderate one or more forums. This is done via the user administration page of the user\'s profile.',
+'Edit profile label'			=>	'Allow moderators to edit user profiles',
+'Edit profile help'				=>	'If moderator privileges are enabled, allow users in this group to edit user profiles.',
+'Rename users label'			=>	'Allow moderators to rename users',
+'Rename users help'				=>	'If moderator privileges are enabled, allow users in this group to rename users.',
+'Change passwords label'		=>	'Allow moderators to change passwords',
+'Change passwords help'			=>	'If moderator privileges are enabled, allow users in this group to change user passwords.',
+'Ban users label'				=>	'Allow moderators to ban users',
+'Ban users help'				=>	'If moderator privileges are enabled, allow users in this group to ban users.',
+'Read board label'				=>	'Read board',
+'Read board help'				=>	'Allow users in this group to view the board. This setting applies to every aspect of the board and can therefore not be overridden by forum specific settings. If this is set to "No", users in this group will only be able to login/logout and register.',
+'View user info label'			=>	'View user information',
+'View user info help'			=>	'Allow users to view the user list and user profiles.',
+'Post replies label'			=>	'Post replies',
+'Post replies help'				=>	'Allow users in this group to post replies in topics.',
+'Post topics label'				=>	'Post topics',
+'Post topics help'				=>	'Allow users in this group to post new topics.',
+'Edit posts label'				=>	'Edit posts',
+'Edit posts help'				=>	'Allow users in this group to edit their own posts.',
+'Delete posts label'			=>	'Delete posts',
+'Delete posts help'				=>	'Allow users in this group to delete their own posts.',
+'Delete topics label'			=>	'Delete topics',
+'Delete topics help'			=>	'Allow users in this group to delete their own topics (including any replies).',
+'Set own title label'			=>	'Set own user title',
+'Set own title help'			=>	'Allow users in this group to set their own user title.',
+'User search label'				=>	'Use search',
+'User search help'				=>	'Allow users in this group to use the search feature.',
+'User list search label'		=>	'Search user list',
+'User list search help'			=>	'Allow users in this group to freetext search for users in the user list.',
+'Send e-mails label'			=>	'Send e-mails',
+'Send e-mails help'				=>	'Allow users in this group to send e-mails to other users.',
+'Post flood label'				=>	'Post flood interval',
+'Post flood help'				=>	'Number of seconds that users in this group have to wait between posts. Set to 0 to disable.',
+'Search flood label'			=>	'Search flood interval',
+'Search flood help'				=>	'Number of seconds that users in this group have to wait between searches. Set to 0 to disable.',
+'E-mail flood label'			=>	'Email flood interval',
+'E-mail flood help'				=>	'Number of seconds that users in this group have to wait between emails. Set to 0 to disable.',
+'Moderator info'				=>	'Please note that in order for a user in this group to have moderator abilities, he/she must be assigned to moderate one or more forums. This is done via the user administration page of the user\'s profile.',
+
+);
diff --git a/upload/lang/English/admin_index.php b/upload/lang/English/admin_index.php
new file mode 100644
index 0000000..9f9cdc7
--- /dev/null
+++ b/upload/lang/English/admin_index.php
@@ -0,0 +1,51 @@
+<?php
+
+// Language definitions used in admin_index.php
+$lang_admin_index = array(
+
+'fopen disabled message'			=>	'Unable to check for upgrade since \'allow_url_fopen\' is disabled on this system.',
+'Upgrade check failed message'		=>	'Check for upgrade failed for unknown reasons.',
+'Running latest version message'	=>	'You are running the latest version of FluxBB.',
+'New version available message'		=>	'A new version of FluxBB has been released. You can download the latest version at %s.',
+'PHPinfo disabled message'			=>	'The PHP function phpinfo() has been disabled on this server.',
+'Not available'						=>	'Not available',
+'Forum admin head'					=>	'Forum administration',
+'NA'								=>	'N/A',
+'Welcome to admin'					=>	'Welcome to the FluxBB administration control panel. From here you can control vital aspects of the board. Depending on whether you are an administrator or a moderator you can:',
+'Welcome 1'							=>	'Organize categories and forums.',
+'Welcome 2'							=>	'Set forum-wide options and preferences.',
+'Welcome 3'							=>	'Control permissions for users and guests.',
+'Welcome 4'							=>	'View IP statistics for users.',
+'Welcome 5'							=>	'Ban users.',
+'Welcome 6'							=>	'Censor words.',
+'Welcome 7'							=>	'Set up user ranks.',
+'Welcome 8'							=>	'Prune old posts.',
+'Welcome 9'							=>	'Handle post reports.',
+'Statistics head'					=>	'Statistics',
+'FluxBB version label'				=>	'FluxBB version',
+'Check for upgrade'					=>	'Check for upgrade',
+'FluxBB version data'				=>	'v%s - %s',
+'Server load label'					=>	'Server load',
+'Server load data'					=>	'%s - %s user(s) online',
+'Environment label'					=>	'Environment',
+'Environment data OS'				=>	'Operating system: %s',
+'Show info'							=>	'Show info',
+'Environment data version'			=>	'PHP: %s - %s',
+'Environment data acc'				=>	'Accelerator: %s',
+'Turck MMCache'						=>	'Turk MMCache',
+'Turck MMCache link'				=>	'turck-mmcache.sourceforge.net',
+'ionCube PHP Accelerator'			=>	'ionCube PHP Accelerator',
+'ionCube PHP Accelerator link'		=>	'www.php-accelerator.co.uk/',
+'Alternative PHP Cache (APC)'		=>	'Alternative PHP Cache (APC)',
+'Alternative PHP Cache (APC) link'	=>	'www.php.net/apc/',
+'Zend Optimizer'					=>	'Zend Optimizer',
+'Zend Optimizer link'				=>	'www.zend.com/products/guard/zend-optimizer',
+'eAccelerator'						=>	'eAccelerator',
+'eAccelerator link'					=>	'www.eaccelerator.net/',
+'XCache'							=>	'XCache',
+'XCache link'						=>	'xcache.lighttpd.net/',
+'Database label'					=>	'Database',
+'Database data rows'				=>	'Rows: %s',
+'Database data size'				=>	'Size: %s',
+
+);
diff --git a/upload/lang/English/admin_maintenance.php b/upload/lang/English/admin_maintenance.php
new file mode 100644
index 0000000..a0e62b3
--- /dev/null
+++ b/upload/lang/English/admin_maintenance.php
@@ -0,0 +1,23 @@
+<?php
+
+// Language definitions used in admin_maintenance.php
+$lang_admin_maintenance = array(
+
+'Maintenance head'				=>	'Forum maintenance',
+'Rebuild index subhead'			=>	'Rebuild search index',
+'Rebuild index info'			=>	'If you\'ve added, edited or removed posts manually in the database or if you\'re having problems searching, you should rebuild the search index. For best performance, you should put the forum in %s during rebuilding. <strong>Rebuilding the search index can take a long time and will increase server load during the rebuild process!</strong>',
+'Posts per cycle label'			=>	'Posts per cycle',
+'Posts per cycle help'			=>	'The number of posts to process per pageview. E.g. if you were to enter 300, three hundred posts would be processed and then the page would refresh. This is to prevent the script from timing out during the rebuild process.',
+'Starting post label'			=>	'Starting post ID',
+'Starting post help'			=>	'The post ID to start rebuilding at. The default value is the first available ID in the database. Normally you wouldn\'t want to change this.',
+'Empty index label'				=>	'Empty index',
+'Empty index help'				=>	'Select this if you want the search index to be emptied before rebuilding (see below).',
+'Rebuild completed info'		=>	'Once the process has completed, you will be redirected back to this page. It is highly recommended that you have JavaScript enabled in your browser during rebuilding (for automatic redirect when a cycle has completed). If you are forced to abort the rebuild process, make a note of the last processed post ID and enter that ID+1 in "Starting post ID" when/if you want to continue ("Empty index" must not be selected).',
+'Rebuild index'					=>	'Rebuild index',
+'Rebuilding search index'		=>	'Rebuilding search index',
+'Rebuilding index info'			=>	'Rebuilding index. This might be a good time to put on some coffee :-)',
+'Processing post'				=>	'Processing post <strong>%s</strong> …',
+'Click here'					=>	'Click here',
+'Javascript redirect failed'	=>	'JavaScript redirect unsuccessful. %s to continue …',
+
+);
diff --git a/upload/lang/English/admin_options.php b/upload/lang/English/admin_options.php
new file mode 100644
index 0000000..e701917
--- /dev/null
+++ b/upload/lang/English/admin_options.php
@@ -0,0 +1,217 @@
+<?php
+
+// Language definitions used in admin-options.php
+$lang_admin_options = array(
+
+'Bad HTTP Referer message'			=>	'Bad HTTP_REFERER. If you have moved these forums from one location to another or switched domains, you need to update the Base URL manually in the database (look for o_base_url in the config table) and then clear the cache by deleting all .php files in the /cache directory.',
+'Must enter title message'			=>	'You must enter a board title.',
+'Invalid e-mail message'			=>	'The admin email address you entered is invalid.',
+'Invalid webmaster e-mail message'	=>	'The webmaster email address you entered is invalid.',
+'Enter announcement here'			=>	'Enter your announcement here.',
+'Enter rules here'					=>	'Enter your rules here.',
+'Default maintenance message'		=>	'The forums are temporarily down for maintenance. Please try again in a few minutes.',
+'Timeout error message'				=>	'The value of "Timeout online" must be smaller than the value of "Timeout visit".',
+'Options updated redirect'			=>	'Options updated. Redirecting …',
+'Options head'						=>	'Options',
+
+// Essentials section
+'Essentials subhead'				=>	'Essentials',
+'Board title label'					=>	'Board title',
+'Board title help'					=>	'The title of this bulletin board (shown at the top of every page). This field may <strong>not</strong> contain HTML.',
+'Board desc label'					=>	'Board description',
+'Board desc help'					=>	'A short description of this bulletin board (shown at the top of every page). This field may contain HTML.',
+'Base URL label'					=>	'Base URL',
+'Base URL help'						=>	'The complete URL of the board without trailing slash (i.e. http://www.mydomain.com/forums). This <strong>must</strong> be correct in order for all admin and moderator features to work. If you get "Bad referer" errors, it\'s probably incorrect.',
+'Timezone label'					=>	'Default time zone',
+'Timezone help'						=>	'The default time zone for guests and users attempting to register for the board.',
+'DST label'							=>	'Adjust for DST',
+'DST help'							=>	'Check if daylight savings is in effect (advances times by 1 hour).',
+'Language label'					=>	'Default language',
+'Language help'						=>	'The default language for guests and users who haven\'t changed from the default in their profile. If you remove a language pack, this must be updated.',
+'Default style label'				=>	'Default style',
+'Default style help'				=>	'The default style for guests and users who haven\'t changed from the default in their profile.',
+
+// Essentials section timezone options
+'UTC-12:00'							=>	'(UTC-12:00) International Date Line West',
+'UTC-11:00'							=>	'(UTC-11:00) Niue, Samoa',
+'UTC-10:00'							=>	'(UTC-10:00) Hawaii-Aleutian, Cook Island',
+'UTC-09:30'							=>	'(UTC-09:30) Marquesas Islands',
+'UTC-09:00'							=>	'(UTC-09:00) Alaska, Gambier Island',
+'UTC-08:30'							=>	'(UTC-08:30) Pitcairn Islands',
+'UTC-08:00'							=>	'(UTC-08:00) Pacific',
+'UTC-07:00'							=>	'(UTC-07:00) Mountain',
+'UTC-06:00'							=>	'(UTC-06:00) Central',
+'UTC-05:00'							=>	'(UTC-05:00) Eastern',
+'UTC-04:00'							=>	'(UTC-04:00) Atlantic',
+'UTC-03:30'							=>	'(UTC-03:30) Newfoundland',
+'UTC-03:00'							=>	'(UTC-03:00) Amazon, Central Greenland',
+'UTC-02:00'							=>	'(UTC-02:00) Mid-Atlantic',
+'UTC-01:00'							=>	'(UTC-01:00) Azores, Cape Verde, Eastern Greenland',
+'UTC'								=>	'(UTC) Western European, Greenwich',
+'UTC+01:00'							=>	'(UTC+01:00) Central European, West African',
+'UTC+02:00'							=>	'(UTC+02:00) Eastern European, Central African',
+'UTC+03:00'							=>	'(UTC+03:00) Moscow, Eastern African',
+'UTC+03:30'							=>	'(UTC+03:30) Iran',
+'UTC+04:00'							=>	'(UTC+04:00) Gulf, Samara',
+'UTC+04:30'							=>	'(UTC+04:30) Afghanistan',
+'UTC+05:00'							=>	'(UTC+05:00) Pakistan, Yekaterinburg',
+'UTC+05:30'							=>	'(UTC+05:30) India, Sri Lanka',
+'UTC+05:45'							=>	'(UTC+05:45) Nepal',
+'UTC+06:00'							=>	'(UTC+06:00) Bangladesh, Bhutan, Novosibirsk',
+'UTC+06:30'							=>	'(UTC+06:30) Cocos Islands, Myanmar',
+'UTC+07:00'							=>	'(UTC+07:00) Indochina, Krasnoyarsk',
+'UTC+08:00'							=>	'(UTC+08:00) Greater China, Australian Western, Irkutsk',
+'UTC+08:45'							=>	'(UTC+08:45) Southeastern Western Australia',
+'UTC+09:00'							=>	'(UTC+09:00) Japan, Korea, Chita',
+'UTC+09:30'							=>	'(UTC+09:30) Australian Central',
+'UTC+10:00'							=>	'(UTC+10:00) Australian Eastern, Vladivostok',
+'UTC+10:30'							=>	'(UTC+10:30) Lord Howe',
+'UTC+11:00'							=>	'(UTC+11:00) Solomon Island, Magadan',
+'UTC+11:30'							=>	'(UTC+11:30) Norfolk Island',
+'UTC+12:00'							=>	'(UTC+12:00) New Zealand, Fiji, Kamchatka',
+'UTC+12:45'							=>	'(UTC+12:45) Chatham Islands',
+'UTC+13:00'							=>	'(UTC+13:00) Tonga, Phoenix Islands',
+'UTC+14:00'							=>	'(UTC+14:00) Line Islands',
+
+// Timeout Section
+'Timeouts subhead'					=>	'Time and timeouts',
+'Time format label'					=>	'Time format',
+'PHP manual'						=>	'PHP manual',
+'Time format help'					=>	'[Current format: %s]. See %s for formatting options.',
+'Date format label'					=>	'Date format',
+'Date format help'					=>	'[Current format: %s]. See %s for formatting options.',
+'Visit timeout label'				=>	'Visit timeout',
+'Visit timeout help'				=>	'Number of seconds a user must be idle before his/hers last visit data is updated (primarily affects new message indicators).',
+'Online timeout label'				=>	'Online timeout',
+'Online timeout help'				=>	'Number of seconds a user must be idle before being removed from the online users list.',
+'Redirect time label'				=>	'Redirect time',
+'Redirect time help'				=>	'Number of seconds to wait when redirecting. If set to 0, no redirect page will be displayed (not recommended).',
+
+// Display Section
+'Display subhead'					=>	'Display',
+'Version number label'				=>	'Version number',
+'Version number help'				=>	'Show FluxBB version number in footer.',
+'Info in posts label'				=>	'User info in posts',
+'Info in posts help'				=>	'Show information about the poster under the username in topic view. The information affected is location, register date, post count and the contact links (email and URL).',
+'Post count label'					=>	'User post count',
+'Post count help'					=>	'Show the number of posts a user has made (affects topic view, profile and user list).',
+'Smilies label'						=>	'Smilies in posts',
+'Smilies help'						=>	'Convert smilies to small graphic icons.',
+'Smilies sigs label'				=>	'Smilies in signatures',
+'Smilies sigs help'					=>	'Convert smilies to small graphic icons in user signatures.',
+'Clickable links label'				=>	'Make clickable links',
+'Clickable links help'				=>	'When enabled, FluxBB will automatically detect any URLs in posts and make them clickable hyperlinks.',
+'Topic review label'				=>	'Topic review',
+'Topic review help'					=>	'Maximum number of posts to display when posting (newest first). Set to 0 to disable.',
+'Topics per page label'				=>	'Topics per page',
+'Topics per page help'				=>	'The default number of topics to display per page in a forum. Users can personalize this setting.',
+'Posts per page label'				=>	'Posts per page',
+'Posts per page help'				=>	'The default number of posts to display per page in a topic. Users can personalize this setting.',
+'Indent label'						=>	'Indent size',
+'Indent help'						=>	'If set to 8, a regular tab will be used when displaying text within the [code][/code] tag. Otherwise this many spaces will be used to indent the text.',
+'Quote depth label'					=>	'Maximum [quote] depth',
+'Quote depth help'					=>	'The maximum times a [quote] tag can go inside other [quote] tags, any tags deeper than this will be discarded.',
+
+// Features section
+'Features subhead'					=>	'Features',
+'Quick post label'					=>	'Quick post',
+'Quick post help'					=>	'When enabled, FluxBB will add a quick post form at the bottom of topics. This way users can post directly from the topic view.',
+'Users online label'				=>	'Users online',
+'Users online help'					=>	'Display info on the index page about guests and registered users currently browsing the board.',
+'Censor words label'				=>	'Censor words',
+'Censor words help'					=>	'Enable this to censor specific words in the board. See %s for more info.',
+'Signatures label'					=>	'Signatures',
+'Signatures help'					=>	'Allow users to attach a signature to their posts.',
+'User ranks label'					=>	'User ranks',
+'User ranks help'					=>	'Enable this to use user ranks. See %s for more info.',
+'User has posted label'				=>	'User has posted earlier',
+'User has posted help'				=>	'This feature displays a dot in front of topics in viewforum.php in case the currently logged in user has posted in that topic earlier. Disable if you are experiencing high server load.',
+'Topic views label'					=>	'Topic views',
+'Topic views help'					=>	'Keep track of the number of views a topic has. Disable if you are experiencing high server load in a busy forum.',
+'Quick jump label'					=>	'Quick jump',
+'Quick jump help'					=>	'Enable the quick jump (jump to forum) drop list.',
+'GZip label'						=>	'GZip output',
+'GZip help'							=>	'If enabled, FluxBB will gzip the output sent to browsers. This will reduce bandwidth usage, but use a little more CPU. This feature requires that PHP is configured with zlib (--with-zlib). Note: If you already have one of the Apache modules mod_gzip or mod_deflate set up to compress PHP scripts, you should disable this feature.',
+'Search all label'					=>	'Search all forums',
+'Search all help'					=>	'When disabled, searches will only be allowed in one forum at a time. Disable if server load is high due to excessive searching.',
+'Menu items label'					=>	'Additional menu items',
+'Menu items help'					=>	'By entering HTML hyperlinks into this textbox, any number of items can be added to the navigation menu at the top of all pages. The format for adding new links is X = &lt;a href="URL"&gt;LINK&lt;/a&gt; where X is the position at which the link should be inserted (e.g. 0 to insert at the beginning and 2 to insert after "User list"). Separate entries with a linebreak.',
+'Default feed label'				=>	'Default feed type',
+'Default feed help'					=>	'Select the type of syndication feed to display. Note: Choosing none will not disable feeds, only hide them by default.',
+'None'								=>	'None',
+'RSS'								=>	'RSS',
+'Atom'								=>	'Atom',
+
+// Reports section
+'Reports subhead'					=>	'Reports',
+'Reporting method label'			=>	'Reporting method',
+'Internal'							=>	'Internal',
+'By e-mail'							=>	'Email',
+'Both'								=>	'Both',
+'Reporting method help'				=>	'Select the method for handling topic/post reports. You can choose whether topic/post reports should be handled by the internal report system, emailed to the addresses on the mailing list (see below) or both.',
+'Mailing list label'				=>	'Mailing list',
+'Mailing list help'					=>	'A comma separated list of subscribers. The people on this list are the recipients of reports.',
+
+// Avatars section
+'Avatars subhead'					=>	'Avatars',
+'Use avatars label'					=>	'Use avatars',
+'Use avatars help'					=>	'When enabled, users will be able to upload an avatar which will be displayed under their title/rank.',
+'Upload directory label'			=>	'Upload directory',
+'Upload directory help'				=>	'The upload directory for avatars (relative to the FluxBB root directory). PHP must have write permissions to this directory.',
+'Max width label'					=>	'Max width',
+'Max width help'					=>	'The maximum allowed width of avatars in pixels (60 is recommended).',
+'Max height label'					=>	'Max height',
+'Max height help'					=>	'The maximum allowed height of avatars in pixels (60 is recommended).',
+'Max size label'					=>	'Max size',
+'Max size help'						=>	'The maximum allowed size of avatars in bytes (10240 is recommended).',
+
+// E-mail section
+'E-mail subhead'					=>	'Email',
+'Admin e-mail label'				=>	'Admin email',
+'Admin e-mail help'					=>	'The email address of the board administrator.',
+'Webmaster e-mail label'			=>	'Webmaster email',
+'Webmaster e-mail help'				=>	'This is the address that all emails sent by the board will be addressed from.',
+'Subscriptions label'				=>	'Subscriptions',
+'Subscriptions help'				=>	'Enable users to subscribe to topics (receive email when someone replies).',
+'SMTP address label'				=>	'SMTP server address',
+'SMTP address help'					=>	'The address of an external SMTP server to send emails with. You can specify a custom port number if the SMTP server doesn\'t run on the default port 25 (example: mail.myhost.com:3580). Leave blank to use the local mail program.',
+'SMTP username label'				=>	'SMTP username',
+'SMTP username help'				=>	'Username for SMTP server. Only enter a username if it is required by the SMTP server (most servers <strong>do not</strong> require authentication).',
+'SMTP password label'				=>	'SMTP password',
+'SMTP password help'				=>	'Password for SMTP server. Only enter a password if it is required by the SMTP server (most servers <strong>do not</strong> require authentication).',
+'SMTP SSL label'					=>	'Encrypt SMTP using SSL',
+'SMTP SSL help'						=>	'Encrypts the connection to the SMTP server using SSL. Should only be used if your SMTP server requires it and your version of PHP supports SSL.',
+
+// Registration Section
+'Registration subhead'				=>	'Registration',
+'Allow new label'					=>	'Allow new registrations',
+'Allow new help'					=>	'Controls whether this board accepts new registrations. Disable only under special circumstances.',
+'Verify label'						=>	'Verify registrations',
+'Verify help'						=>	'When enabled, users are emailed a random password when they register. They can then log in and change the password in their profile if they see fit. This feature also requires users to verify new email addresses if they choose to change from the one they registered with. This is an effective way of avoiding registration abuse and making sure that all users have "correct" email addresses in their profiles.',
+'Report new label'					=>	'Report new registrations',
+'Report new help'					=>	'If enabled, FluxBB will notify users on the mailing list (see above) when a new user registers in the forums.',
+'Use rules label'					=>	'User forum rules',
+'Use rules help'					=>	'When enabled, users must agree to a set of rules when registering (enter text below). The rules will always be available through a link in the navigation table at the top of every page.',
+'Rules label'						=>	'Enter your rules here',
+'Rules help'						=>	'Here you can enter any rules or other information that the user must review and accept when registering. If you enabled rules above you have to enter something here, otherwise it will be disabled. This text will not be parsed like regular posts and thus may contain HTML.',
+'E-mail default label'				=>	'Default email setting',
+'E-mail default help'				=>	'Choose the default privacy setting for new user registrations.',
+'Display e-mail label'				=>	'Display email address to other users.',
+'Hide allow form label'				=>	'Hide email address but allow form e-mail.',
+'Hide both label'					=>	'Hide email address and disallow form email.',
+
+// Announcement Section
+'Announcement subhead'				=>	'Announcements',
+'Display announcement label'		=>	'Display announcement',
+'Display announcement help'			=>	'Enable this to display the below message in the board.',
+'Announcement message label'		=>	'Announcement message',
+'Announcement message help'			=>	'This text will not be parsed like regular posts and thus may contain HTML.',
+
+// Maintenance Section
+'Maintenance subhead'				=>	'Maintenance',
+'Maintenance mode label'			=>	'Maintenance mode',
+'Maintenance mode help'				=>	'When enabled, the board will only be available to administrators. This should be used if the board needs to be taken down temporarily for maintenance. <strong>WARNING! Do not log out when the board is in maintenance mode.</strong> You will not be able to login again.',
+'Maintenance message label'			=>	'Maintenance message',
+'Maintenance message help'			=>	'The message that will be displayed to users when the board is in maintenance mode. If left blank, a default message will be used. This text will not be parsed like regular posts and thus may contain HTML.',
+
+);
diff --git a/upload/lang/English/admin_permissions.php b/upload/lang/English/admin_permissions.php
new file mode 100644
index 0000000..3c3600c
--- /dev/null
+++ b/upload/lang/English/admin_permissions.php
@@ -0,0 +1,36 @@
+<?php
+
+// Language definitions used in admin-permissions.php
+$lang_admin_permissions = array(
+
+'Perms updated redirect'	=>	'Permissions updated. Redirecting …',
+'Permissions head'			=>	'Permissions',
+'Posting subhead'			=>	'Posting',
+'BBCode label'				=>	'BBCode',
+'BBCode help'				=>	'Allow BBCode in posts (recommended).',
+'Image tag label'			=>	'Image tag',
+'Image tag help'			=>	'Allow the BBCode [img][/img] tag in posts.',
+'All caps message label'	=>	'All caps message',
+'All caps message help'		=>	'Allow a message to contain only capital letters.',
+'All caps subject label'	=>	'All caps subject',
+'All caps subject help'		=>	'Allow a subject to contain only capital letters.',
+'Require e-mail label'		=>	'Require guest email',
+'Require e-mail help'		=>	'Require guests to supply an email address when posting.',
+'Signatures subhead'		=>	'Signatures',
+'BBCode sigs label'			=>	'BBCodes in signatures',
+'BBCode sigs help'			=>	'Allow BBCodes in user signatures.',
+'Image tag sigs label'		=>	'Image tag in signatures',
+'Image tag sigs help'		=>	'Allow the BBCode [img][/img] tag in user signatures (not recommended).',
+'All caps sigs label'		=>	'All caps signature',
+'All caps sigs help'		=>	'Allow a signature to contain only capital letters.',
+'Max sig length label'		=>	'Maximum signature length',
+'Max sig length help'		=>	'The maximum number of characters a user signature may contain.',
+'Max sig lines label'		=>	'Maximum signature lines',
+'Max sig lines help'		=>	'The maximum number of lines a user signature may contain.',
+'Registration subhead'		=>	'Registration',
+'Banned e-mail label'		=>	'Allow banned email addresses',
+'Banned e-mail help'		=>	'Allow users to register with or change to a banned email address/domain. If left at its default setting (yes), this action will be allowed, but an alert email will be sent to the mailing list (an effective way of detecting multiple registrations).',
+'Duplicate e-mail label'	=>	'Allow duplicate email addresses',
+'Duplicate e-mail help'		=>	'Controls whether users should be allowed to register with an email address that another user already has. If allowed, an alert email will be sent to the mailing list if a duplicate is detected.',
+
+);
diff --git a/upload/lang/English/admin_plugin_example.php b/upload/lang/English/admin_plugin_example.php
new file mode 100644
index 0000000..b06158d
--- /dev/null
+++ b/upload/lang/English/admin_plugin_example.php
@@ -0,0 +1,17 @@
+<?php
+
+// Language definitions used in example Plugin
+$lang_admin_plugin_example = array(
+
+'No text'				=>	'You didn\'t enter anything!',
+'Example plugin title'	=>	'Example plugin',
+'You said'				=>	'You said "%s". Great stuff.',
+'Explanation 1'			=>	'This plugin doesn\'t do anything useful. Hence the name "Example".',
+'Explanation 2'			=>	'This would be a good spot to talk a little about your plugin. Describe what it does and how it should be used. Be brief, but informative.',
+'Example form title'	=>	'An example form',
+'Legend text'			=>	'Enter a piece of text and hit "Show text"!',
+'Text to show'			=>	'Text to show',
+'Show text button'		=>	'Show text',
+'Input content'			=>	'The text you want to display.',
+
+);
diff --git a/upload/lang/English/admin_prune.php b/upload/lang/English/admin_prune.php
new file mode 100644
index 0000000..b7f9030
--- /dev/null
+++ b/upload/lang/English/admin_prune.php
@@ -0,0 +1,23 @@
+<?php
+
+// Language definitions used in admin_prune.php
+$lang_admin_prune = array(
+
+'Must be integer message'	=>	'Days to prune must be a positive integer value.',
+'No old topics message'		=>	'There are no topics that are %s days old. Please decrease the value of "Days old" and try again.',
+'Posts pruned redirect'		=>	'Posts pruned. Redirecting …',
+'Prune head'				=>	'Prune',
+'Prune subhead'				=>	'Prune old posts',
+'Days old label'			=>	'Days old',
+'Days old help'				=>	'The number of days "old" a topic must be to be pruned. E.g. if you were to enter 30, every topic that didn\'t contain a post dated less than 30 days old would be deleted.',
+'Prune sticky label'		=>	'Prune sticky topics',
+'Prune sticky help'			=>	'When enabled sticky topics will also be pruned.',
+'Prune from label'			=>	'Prune from forum',
+'All forums'				=>	'All forums',
+'Prune from help'			=>	'The forum from which you want to prune posts.',
+'Prune info'				=>	'Use this feature with caution. <strong>Pruned posts can never be recovered.</strong> For best performance, you should put the forum in %s during pruning.',
+'Confirm prune subhead'		=>	'Confirm prune posts',
+'Confirm prune info'		=>	'Are you sure that you want to prune all topics older than %s days from %s (%s topics).',
+'Confirm prune warn'		=>	'WARNING! Pruning posts deletes them permanently.',
+
+);
diff --git a/upload/lang/English/admin_ranks.php b/upload/lang/English/admin_ranks.php
new file mode 100644
index 0000000..7dca408
--- /dev/null
+++ b/upload/lang/English/admin_ranks.php
@@ -0,0 +1,21 @@
+<?php
+
+// Language definitions used in admin_ranks.php
+$lang_admin_ranks = array(
+
+'Must be integer message'	=>	'Minimum posts must be a positive integer value.',
+'Dupe min posts message'	=>	'There is already a rank with a minimun posts value of %s.',
+'Must enter title message'	=>	'You must enter a rank title.',
+'Rank added redirect'		=>	'Rank added. Redirecting …',
+'Rank updated redirect'		=>	'Rank updated. Redirecting …',
+'Rank removed redirect'		=>	'Rank removed. Redirecting …',
+'Ranks head'				=>	'Ranks',
+'Add rank subhead'			=>	'Add rank',
+'Add rank info'				=>	'Enter a rank and the minimum number of posts a user must have made to attain the rank. Different ranks cannot have the same value for minimum posts. If a title is set for a user, the title will be displayed instead of any rank. <strong>User ranks must be enabled in %s for this to have any effect</strong>.',
+'Rank title label'			=>	'Rank title',
+'Minimum posts label'		=>	'Minimum posts',
+'Actions label'				=>	'Actions',
+'Edit remove subhead'		=>	'Edit/remove ranks',
+'No ranks in list'			=>	'No ranks in list',
+
+);
diff --git a/upload/lang/English/admin_reports.php b/upload/lang/English/admin_reports.php
new file mode 100644
index 0000000..f954fff
--- /dev/null
+++ b/upload/lang/English/admin_reports.php
@@ -0,0 +1,21 @@
+<?php
+
+// Language definitions used in admin_reports.php
+$lang_admin_reports = array(
+
+'Report zapped redirect'	=>	'Report zapped. Redirecting …',
+'New reports head'			=>	'New reports',
+'Deleted user'				=>	'Deleted user',
+'Deleted'					=>	'Deleted',
+'Report subhead'			=>	'Reported %s',
+'Location seperator'		=>	' » ',
+'Reported by'				=>	'Reported by %s',
+'Reason'					=>	'Reason',
+'Zap'						=>	'Zap',
+'No new reports'			=>	'There are no new reports.',
+'Last 10 head'				=>	'10 last zapped reports',
+'NA'						=>	'N/A',
+'Zapped subhead'			=>	'Zapped %s by %s',
+'No zapped reports'			=>	'There are no zapped reports.',
+
+);
diff --git a/upload/lang/English/admin_users.php b/upload/lang/English/admin_users.php
new file mode 100644
index 0000000..1e21a34
--- /dev/null
+++ b/upload/lang/English/admin_users.php
@@ -0,0 +1,70 @@
+<?php
+
+// Language definitions used in admin-users.php
+$lang_admin_users = array(
+
+'Non numeric message'		=>	'You entered a non-numeric value into a numeric only column.',
+'Invalid date time message'	=>	'You entered an invalid date/time.',
+'Not verified'				=>	'Not verified',
+'User search head'			=>	'User search',
+'User search subhead'		=>	'Enter search criteria',
+'User search info'			=>	'Search for users in the database. You can enter one or more terms to search for. Wildcards in the form of asterisks (*) are accepted.',
+'Username label'			=>	'Username',
+'E-mail address label'		=>	'Email address',
+'Title label'				=>	'Title',
+'Real name label'			=>	'Real name',
+'Website label'				=>	'Website',
+'Jabber label'				=>	'Jabber',
+'ICQ label'					=>	'ICQ',
+'MSN label'					=>	'MSN Messenger',
+'AOL label'					=>	'AOL IM',
+'Yahoo label'				=>	'Yahoo Messenger',
+'Location label'			=>	'Location',
+'Signature label'			=>	'Signature',
+'Admin note label'			=>	'Admin note',
+'Posts more than label'		=>	'Number of posts greater than',
+'Posts less than label'		=>	'Number of posts less than',
+'Last post after label'		=>	'Last post is after',
+'Date help'					=>	'(yyyy-mm-dd hh:mm:ss)',
+'Last post before label'	=>	'Last post is before',
+'Registered after label'	=>	'Registered after',
+'Registered before label'	=>	'Registered before',
+'Order by label'			=>	'Order by',
+'Order by username'			=>	'Username',
+'Order by e-mail'			=>	'Email',
+'Order by posts'			=>	'Number of posts',
+'Order by last post'		=>	'Last post',
+'Order by registered'		=>	'Registered',
+'Ascending'					=>	'Ascending',
+'Descending'				=>	'Descending',
+'User group label'			=>	'User group',
+'All groups'				=>	'All groups',
+'Unverified users'			=>	'Unverified users',
+'Submit search'				=>	'Submit search',
+'IP search head'			=>	'IP search',
+'IP search subhead'			=>	'Enter IP to search for',
+'IP address label'			=>	'IP address',
+'IP address help'			=>	'The IP address to search for in the post database.',
+'Find IP address'			=>	'Find IP address',
+
+'Results head'				=>	'Search Results',
+'Results username head'		=>	'Username',
+'Results e-mail head'		=>	'Email',
+'Results title head'		=>	'Title/Status',
+'Results posts head'		=>	'Posts',
+'Results admin note head'	=>	'Admin note',
+'Results actions head'		=>	'Actions',
+'Results IP address head'	=>	'IP address',
+'Results last used head'	=>	'Last used',
+'Results times found head'	=>	'Times found',
+'Results action head'		=>	'Action',
+'Results find more link'	=>	'Find more users for this ip',
+'Results no posts found'	=>	'There are currently no posts by that user in the forum.',
+'Bad IP message'			=>	'The supplied IP address is not correctly formatted.',
+'Results view IP link'		=>	'View IP stats',
+'Results show posts link'	=>	'Show posts',
+'Results guest'				=>	'Guest',
+'Results no IP found'		=>	'The supplied IP address could not be found in the database.',
+'No match'					=>	'No match'
+
+);
diff --git a/upload/lang/English/common.php b/upload/lang/English/common.php
index 676380e..aaade9a 100644
--- a/upload/lang/English/common.php
+++ b/upload/lang/English/common.php
@@ -28,145 +28,164 @@ setlocale(LC_CTYPE, $locale);
 $lang_common = array(
 
 // Text orientation and encoding
-'lang_direction'		=>	'ltr',	// ltr (Left-To-Right) or rtl (Right-To-Left)
+'lang_direction'					=>	'ltr', // ltr (Left-To-Right) or rtl (Right-To-Left)
+'lang_identifier'					=>	'en',
 
 // Number formatting
 'lang_decimal_point'				=>	'.',
 'lang_thousands_sep'				=>	',',
 
 // Notices
-'Bad request'			=>	'Bad request. The link you followed is incorrect or outdated.',
-'No view'				=>	'You do not have permission to view these forums.',
-'No permission'			=>	'You do not have permission to access this page.',
-'Bad referrer'			=>	'Bad HTTP_REFERER. You were referred to this page from an unauthorized source. If the problem persists please make sure that \'Base URL\' is correctly set in Admin/Options and that you are visiting the forum by navigating to that URL. More information regarding the referrer check can be found in the FluxBB documentation.',
-
-// Topic/forum indicators
-'New icon'				=>	'There are new posts',
-'Normal icon'			=>	'<!-- -->',
-'Closed icon'			=>	'This topic is closed',
-'Redirect icon'			=>	'Redirected forum',
+'Bad request'						=>	'Bad request. The link you followed is incorrect or outdated.',
+'No view'							=>	'You do not have permission to view these forums.',
+'No permission'						=>	'You do not have permission to access this page.',
+'Bad referrer'						=>	'Bad HTTP_REFERER. You were referred to this page from an unauthorized source. If the problem persists please make sure that \'Base URL\' is correctly set in Admin/Options and that you are visiting the forum by navigating to that URL. More information regarding the referrer check can be found in the FluxBB documentation.',
+'No cookie'							=>	'You appear to have logged in successfully, however a cookie has not been set. Please check your settings and if applicable, enable cookies for this website.',
+'Pun include error'					=>	'Unable to process user include %s from template %s. There is no such file in %s.',
 
 // Miscellaneous
-'Announcement'			=>	'Announcement',
-'Options'				=>	'Options',
-'Actions'				=>	'Actions',
-'Submit'				=>	'Submit',	// "name" of submit buttons
-'Ban message'			=>	'You are banned from this forum.',
-'Ban message 2'			=>	'The ban expires at the end of',
-'Ban message 3'			=>	'The administrator or moderator that banned you left the following message:',
-'Ban message 4'			=>	'Please direct any inquiries to the forum administrator at',
-'Never'					=>	'Never',
-'Today'					=>	'Today',
-'Yesterday'				=>	'Yesterday',
-'Info'					=>	'Info',		// a common table header
-'Go back'				=>	'Go back',
-'Maintenance'			=>	'Maintenance',
-'Redirecting'			=>	'Redirecting',
-'Click redirect'		=>	'Click here if you do not want to wait any longer (or if your browser does not automatically forward you)',
-'on'					=>	'on',		// as in "BBCode is on"
-'off'					=>	'off',
-'Invalid e-mail'		=>	'The e-mail address you entered is invalid.',
-'required field'		=>	'is a required field in this form.',	// for javascript form validation
-'Last post'				=>	'Last post',
-'by'					=>	'by',	// as in last post by someuser
-'New posts'				=>	'New&nbsp;posts',	// the link that leads to the first new post (use &nbsp; for spaces)
-'New posts info'		=>	'Go to the first new post in this topic.',	// the popup text for new posts links
-'Username'				=>	'Username',
-'Password'				=>	'Password',
-'E-mail'				=>	'E-mail',
-'Send e-mail'			=>	'Send e-mail',
-'Moderated by'			=>	'Moderated by',
-'Registered'			=>	'Registered',
-'Subject'				=>	'Subject',
-'Message'				=>	'Message',
-'Topic'					=>	'Topic',
-'Forum'					=>	'Forum',
-'Posts'					=>	'Posts',
-'Replies'				=>	'Replies',
-'Author'				=>	'Author',
-'Pages'					=>	'Pages',
-'BBCode'				=>	'BBCode',	// You probably shouldn't change this
-'img tag'				=>	'[img] tag',
-'Smilies'				=>	'Smilies',
-'and'					=>	'and',
-'Image link'			=>	'image',	// This is displayed (i.e. <image>) instead of images when "Show images" is disabled in the profile
-'wrote'					=>	'wrote',	// For [quote]'s
-'Code'					=>	'Code',		// For [code]'s
-'Mailer'				=>	'Mailer',	// As in "MyForums Mailer" in the signature of outgoing e-mails
-'Important information'	=>	'Important information',
-'Write message legend'	=>	'Write your message and submit',
+'Announcement'						=>	'Announcement',
+'Options'							=>	'Options',
+'Submit'							=>	'Submit', // "Name" of submit buttons
+'Ban message'						=>	'You are banned from this forum.',
+'Ban message 2'						=>	'The ban expires at the end of',
+'Ban message 3'						=>	'The administrator or moderator that banned you left the following message:',
+'Ban message 4'						=>	'Please direct any inquiries to the forum administrator at',
+'Never'								=>	'Never',
+'Today'								=>	'Today',
+'Yesterday'							=>	'Yesterday',
+'Info'								=>	'Info', // A common table header
+'Go back'							=>	'Go back',
+'Maintenance'						=>	'Maintenance',
+'Redirecting'						=>	'Redirecting',
+'Click redirect'					=>	'Click here if you do not want to wait any longer (or if your browser does not automatically forward you)',
+'on'								=>	'on', // As in "BBCode is on"
+'off'								=>	'off',
+'Invalid email'						=>	'The email address you entered is invalid.',
+'Required'							=>	'(Required)',
+'required field'					=>	'is a required field in this form.', // For javascript form validation
+'Last post'							=>	'Last post',
+'by'								=>	'by', // As in last post by someuser
+'New posts'							=>	'New posts', // The link that leads to the first new post
+'New posts info'					=>	'Go to the first new post in this topic.', // The popup text for new posts links
+'Username'							=>	'Username',
+'Password'							=>	'Password',
+'Email'								=>	'Email',
+'Send email'						=>	'Send email',
+'Moderated by'						=>	'Moderated by',
+'Registered'						=>	'Registered',
+'Subject'							=>	'Subject',
+'Message'							=>	'Message',
+'Topic'								=>	'Topic',
+'Forum'								=>	'Forum',
+'Posts'								=>	'Posts',
+'Replies'							=>	'Replies',
+'Pages'								=>	'Pages:',
+'Page'								=>	'Page %s',
+'BBCode'							=>	'BBCode:', // You probably shouldn't change this
+'img tag'							=>	'[img] tag:',
+'Smilies'							=>	'Smilies:',
+'and'								=>	'and',
+'Image link'						=>	'image', // This is displayed (i.e. <image>) instead of images when "Show images" is disabled in the profile
+'wrote'								=>	'wrote:', // For [quote]'s
+'Mailer'							=>	'Mailer', // As in "MyForums Mailer" in the signature of outgoing emails
+'Important information'				=>	'Important information',
+'Write message legend'				=>	'Write your message and submit',
+'Previous'							=>	'Previous',
+'Next'								=>	'Next',
+'Spacer'							=>	'…', // Ellipsis for paginate
 
 // Title
-'Title'					=>	'Title',
-'Member'				=>	'Member',	// Default title
-'Moderator'				=>	'Moderator',
-'Administrator'			=>	'Administrator',
-'Banned'				=>	'Banned',
-'Guest'					=>	'Guest',
+'Title'								=>	'Title',
+'Member'							=>	'Member', // Default title
+'Moderator'							=>	'Moderator',
+'Administrator'						=>	'Administrator',
+'Banned'							=>	'Banned',
+'Guest'								=>	'Guest',
 
 // Stuff for include/parser.php
-'BBCode error'			=>	'The BBCode syntax in the message is incorrect.',
-'BBCode error 1'		=>	'Missing start tag for [/quote].',
-'BBCode error 2'		=>	'Missing end tag for [code].',
-'BBCode error 3'		=>	'Missing start tag for [/code].',
-'BBCode error 4'		=>	'Missing one or more end tags for [quote].',
-'BBCode error 5'		=>	'Missing one or more start tags for [/quote].',
+'BBCode error no opening tag'		=>	'[/%1$s] was found without a matching [%1$s]',
+'BBCode error invalid nesting'		=>	'[%1$s] was opened within [%2$s], this is not allowed',
+'BBCode error invalid self-nesting'	=>	'[%s] was opened within itself, this is not allowed',
+'BBCode error no closing tag'		=>	'[%1$s] was found without a matching [/%1$s]',
+'BBCode error empty attribute'		=>	'[%s] tag had an empty attribute section',
+'BBCode code problem'				=>	'There is a problem with your [code] tags',
+'BBCode list size error'			=>	'Your list was too long to parse, please make it smaller!',
 
 // Stuff for the navigator (top of every page)
-'Index'					=>	'Index',
-'User list'				=>	'User list',
-'Rules'					=>  'Rules',
-'Search'				=>  'Search',
-'Register'				=>  'Register',
-'Login'					=>  'Login',
-'Not logged in'			=>  'You are not logged in.',
-'Profile'				=>	'Profile',
-'Logout'				=>	'Logout',
-'Logged in as'			=>	'Logged in as',
-'Admin'					=>	'Administration',
-'Last visit'			=>	'Last visit',
-'Show new posts'		=>	'Show new posts since last visit',
-'Mark all as read'		=>	'Mark all topics as read',
-'Link separator'		=>	'',	// The text that separates links in the navigator
+'Index'								=>	'Index',
+'User list'							=>	'User list',
+'Rules'								=>	'Rules',
+'Search'							=>	'Search',
+'Register'							=>	'Register',
+'Login'								=>	'Login',
+'Not logged in'						=>	'You are not logged in.',
+'Profile'							=>	'Profile',
+'Logout'							=>	'Logout',
+'Logged in as'						=>	'Logged in as',
+'Admin'								=>	'Administration',
+'Last visit'						=>	'Last visit: %s',
+'Show new posts'					=>	'Show new posts since last visit',
+'Mark all as read'					=>	'Mark all topics as read',
+'Mark forum read'					=>	'Mark this forum as read',
+'Title separator'					=>	' / ',
 
 // Stuff for the page footer
-'Board footer'			=>	'Board footer',
-'Search links'			=>	'Search links',
-'Show recent posts'		=>	'Show recent posts',
-'Show unanswered posts'	=>	'Show unanswered posts',
-'Show your posts'		=>	'Show your posts',
-'Show subscriptions'	=>	'Show your subscribed topics',
-'Jump to'				=>	'Jump to',
-'Go'					=>	' Go ',		// submit button in forum jump
-'Moderate topic'		=>	'Moderate topic',
-'Move topic'			=>  'Move topic',
-'Open topic'			=>  'Open topic',
-'Close topic'			=>  'Close topic',
-'Unstick topic'			=>  'Unstick topic',
-'Stick topic'			=>  'Stick topic',
-'Moderate forum'		=>	'Moderate forum',
-'Delete posts'			=>	'Delete multiple posts', // Depreciated
-'Debug table'			=>	'Debug information',
+'Board footer'						=>	'Board footer',
+'Search links'						=>	'Search links',
+'Show recent posts'					=>	'Show recent posts',
+'Show unanswered posts'				=>	'Show unanswered posts',
+'Show your posts'					=>	'Show your posts',
+'Show subscriptions'				=>	'Show your subscribed topics',
+'Jump to'							=>	'Jump to',
+'Go'								=>	' Go ', // Submit button in forum jump
+'Moderate topic'					=>	'Moderate topic',
+'Move topic'						=>	'Move topic',
+'Open topic'						=>	'Open topic',
+'Close topic'						=>	'Close topic',
+'Unstick topic'						=>	'Unstick topic',
+'Stick topic'						=>	'Stick topic',
+'Moderate forum'					=>	'Moderate forum',
+'Powered by'						=>	'Powered by %s',
+
+// Debug information
+'Debug table'						=>	'Debug information',
+'Querytime'							=>	'Generated in %1$s seconds, %2$s queries executed',
+'Query times'						=>	'Time (s)',
+'Query'								=>	'Query',
+'Total query time'					=>	'Total query time: %s',
 
 // Email related notifications
-'New user notification'					=>	'Alert - New registration',
+'New user notification'				=>	'Alert - New registration',
 'New user message'					=>	'User \'%s\' registered in the forums at %s',
-'Banned email notification'				=>	'Alert - Banned e-mail detected',
-'Banned email register message'				=>	'User \'%s\' registered with banned e-mail address: %s',
-'Banned email change message'				=>	'User \'%s\' changed to banned e-mail address: %s',
-'Duplicate email notification'				=>	'Alert - Duplicate e-mail detected',
-'Duplicate email register message'			=>	'User \'%s\' registered with an e-mail address that also belongs to: %s',
-'Duplicate email change message'			=>	'User \'%s\' changed to an e-mail address that also belongs to: %s',
-'Report notification'					=>	'Report(%d) - \'%s\'',
+'Banned email notification'			=>	'Alert - Banned email detected',
+'Banned email register message'		=>	'User \'%s\' registered with banned email address: %s',
+'Banned email change message'		=>	'User \'%s\' changed to banned email address: %s',
+'Banned email post message'			=>	'User \'%s\' posted with banned email address: %s',
+'Duplicate email notification'		=>	'Alert - Duplicate email detected',
+'Duplicate email register message'	=>	'User \'%s\' registered with an email address that also belongs to: %s',
+'Duplicate email change message'	=>	'User \'%s\' changed to an email address that also belongs to: %s',
+'Report notification'				=>	'Report(%d) - \'%s\'',
 'Report message 1'					=>	'User \'%s\' has reported the following message: %s',
 'Report message 2'					=>	'Reason: %s',
 
 'User profile'						=>	'User profile: %s',
+'Post URL'							=>	'Post URL: %s',
 'Email signature'					=>	'Forum Mailer'."\n".'(Do not reply to this message)',
 
 // For extern.php RSS feed
-'RSS Desc Active'		=>	'The most recently active topics at',	// board_title will be appended to this string
-'RSS Desc New'			=>	'The newest topics at',					// board_title will be appended to this string
-'Posted'				=>	'Posted'	// The date/time a topic was started
+'RSS description'					=>	'The most recent topics at %s.',
+'RSS description topic'				=>	'The most recent posts in %s.',
+'RSS reply'							=>	'Re: ', // The topic subject will be appended to this string (to signify a reply)
+'RSS active topics feed'			=>	'RSS active topics feed',
+'Atom active topics feed'			=>	'Atom active topics feed',
+'RSS forum feed'					=>	'RSS forum feed',
+'Atom forum feed'					=>	'Atom forum feed',
+'RSS topic feed'					=>	'RSS topic feed',
+'Atom topic feed'					=>	'Atom topic feed',
+
+// Admin related stuff in the header
+'New reports'						=>	'There are new reports',
+'Maintenance mode enabled'			=>	'Maintenance mode is enabled!',
 
 );
diff --git a/upload/lang/English/delete.php b/upload/lang/English/delete.php
index 7318889..29f358b 100644
--- a/upload/lang/English/delete.php
+++ b/upload/lang/English/delete.php
@@ -5,8 +5,9 @@ $lang_delete = array(
 
 'Delete post'			=>	'Delete post',
 'Warning'				=>	'Warning! If this is the first post in the topic, the whole topic will be deleted.',
-'Delete'				=>	'Delete',	// The submit button
-'Post del redirect'		=>	'Post deleted. Redirecting &hellip;',
-'Topic del redirect'	=>	'Topic deleted. Redirecting &hellip;'
+'Author'				=>	'Author: %s',
+'Delete'				=>	'Delete', // The submit button
+'Post del redirect'		=>	'Post deleted. Redirecting …',
+'Topic del redirect'	=>	'Topic deleted. Redirecting …'
 
 );
diff --git a/upload/lang/English/forum.php b/upload/lang/English/forum.php
index cb2e06c..241677f 100644
--- a/upload/lang/English/forum.php
+++ b/upload/lang/English/forum.php
@@ -5,8 +5,9 @@ $lang_forum = array(
 
 'Post topic'	=>	'Post new topic',
 'Views'			=>	'Views',
-'Moved'			=>	'Moved',
-'Sticky'		=>	'Sticky',
+'Moved'			=>	'Moved:',
+'Sticky'		=>	'Sticky:',
+'Closed'		=>	'Closed:',
 'Empty forum'	=>	'Forum is empty.'
 
 );
diff --git a/upload/lang/English/help.php b/upload/lang/English/help.php
index f3e2ed8..2f39682 100644
--- a/upload/lang/English/help.php
+++ b/upload/lang/English/help.php
@@ -6,6 +6,7 @@ $lang_help = array(
 'Help'					=>	'Help',
 'produces'				=>	'produces',
 
+'BBCode'				=>	'BBCode',
 'BBCode info 1'			=>	'BBCode is a collection of formatting tags that are used to change the look of text in this forum. BBCode is based on the same principal as, and is very similar to, HTML. Below is a list of all the available BBCodes and instructions on how to use them.',
 'BBCode info 2'			=>	'Administrators have the ability to enable or disable BBCode. You can tell if BBCode is enabled or disabled out in the left margin whenever you post a message or edit your signature.',
 
@@ -16,17 +17,19 @@ $lang_help = array(
 'Italic text'			=>	'Italic text',
 'Red text'				=>	'Red text',
 'Blue text'				=>	'Blue text',
+'Heading text'			=>	'Heading text',
 
 'Links and images'		=>	'Links and images',
-'Links info'			=>	'You can create links to other documents or to e-mail addresses using the following tags:',
-'My e-mail address'		=>	'My e-mail address',
-'Images info'			=>	'If you want to display an image you can use the img tag.',
+'Links info'			=>	'You can create links to other documents or to email addresses using the following tags:',
+'My email address'		=>	'My email address',
+'Images info'			=>	'If you want to display an image you can use the img tag. The text appearing after the "=" sign in the opening tag is used for the alt attribute and should be included whenever possible.',
 
 'Quotes'				=>	'Quotes',
 'Quotes info'			=>	'If you want to quote someone, you should use the quote tag.',
 'Quotes info 2'			=>	'If you don\'t want to quote anyone in particular, you can use the quote tag without specifying a name.',
 'Quote text'			=>	'This is the text i want to quote.',
 'produces quote box'	=>	'produces a quote box like this:',
+'quote note'			=>	'Note: If a username contains the characters [ or ] you can enclose it in quote marks.',
 
 'Code'					=>	'Code',
 'Code info'				=>	'When displaying source code you should make sure that you use the code tag. Text displayed with the code tag will use a monospaced font and will not be affected by other tags.',
@@ -37,6 +40,16 @@ $lang_help = array(
 'Nested tags info'		=>	'BBCode can be nested to create more advanced formatting. For example:',
 'Bold, underlined text'	=>	'Bold, underlined text',
 
+'Lists'					=>	'Lists',
+'List info'				=>	'To create a list you can use the list tag. You can create 3 types of lists using the list tag.',
+'List text 1'			=>	'Example list item 1.',
+'List text 2'			=>	'Example list item 2.',
+'List text 3'			=>	'Example list item 3.',
+'produces list'			=>	'produces a bulleted list.',
+'produces decimal list'	=>	'produces a numbered list.',
+'produces alpha list'	=>	'produces an alphabetically labelled list.',
+
+'Smilies'				=>	'Smilies',
 'Smilies info'			=>	'If you like (and if it is enabled), the forum can convert a series of smilies to images representations of that smiley. This forum recognizes the following smilies and replaces them with images:'
 
 );
diff --git a/upload/lang/English/index.html b/upload/lang/English/index.html
index 2db9a3c..89337b2 100644
--- a/upload/lang/English/index.html
+++ b/upload/lang/English/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/lang/English/index.php b/upload/lang/English/index.php
index fc46f68..0ed222a 100644
--- a/upload/lang/English/index.php
+++ b/upload/lang/English/index.php
@@ -3,19 +3,18 @@
 // Language definitions used in index.php
 $lang_index = array(
 
-'Topics'				=>  'Topics',
-'Moderators'			=>  'Moderators',
-'Link to'				=>	'Link to',	// As in "Link to http://fluxbb.org/"
-'Empty board'			=>	'Board is empty.',
-'Newest user'			=>	'Newest registered user',
-'Users online'			=>	'Registered users online',
-'Guests online'			=>	'Guests online',
-'No of users'			=>	'Total number of registered users',
-'No of topics'			=>	'Total number of topics',
-'No of posts'			=>	'Total number of posts',
-'Online'				=>	'Online',	// As in "Online: User A, User B etc."
-'Board info'			=>	'Board information',
-'Board stats'			=>	'Board statistics',
-'User info'				=>	'User information'
+'Topics'		=>	'Topics',
+'Link to'		=>	'Link to:', // As in "Link to: http://fluxbb.org/"
+'Empty board'	=>	'Board is empty.',
+'Newest user'	=>	'Newest registered user: %s',
+'Users online'	=>	'Registered users online: %s',
+'Guests online'	=>	'Guests online: %s',
+'No of users'	=>	'Total number of registered users: %s',
+'No of topics'	=>	'Total number of topics: %s',
+'No of posts'	=>	'Total number of posts: %s',
+'Online'		=>	'Online:', // As in "Online: User A, User B etc."
+'Board info'	=>	'Board information',
+'Board stats'	=>	'Board statistics',
+'User info'		=>	'User information'
 
 );
diff --git a/upload/lang/English/login.php b/upload/lang/English/login.php
index 9ba3782..244ee06 100644
--- a/upload/lang/English/login.php
+++ b/upload/lang/English/login.php
@@ -1,24 +1,26 @@
 <?php
 
-// Language definitions used in delete.php
+// Language definitions used in login.php
 $lang_login = array(
 
 // Miscellaneous
-'Wrong user/pass'		=>	'Wrong username and/or password.',
-'Forgotten pass'		=>	'Forgotten your password?',
-'Login redirect'		=>	'Logged in successfully. Redirecting &hellip;',
-'Logout redirect'		=>	'Logged out. Redirecting &hellip;',
-'No e-mail match'		=>	'There is no user registered with the e-mail address',
-'Request pass'			=>	'Request password',
-'Request pass legend'	=>	'Enter the e-mail address with which you registered',
-'Request pass info'		=>	'A new password together with a link to activate the new password will be sent to that address.',
-'Not registered'		=>	'Not registered yet?',
-'Login legend'			=>	'Enter your username and password below',
-'Remember me'			=>	'Log me in automatically each time I visit.',
-'Login info'			=>	'If you have not registered or have forgotten your password click on the appropriate link below.',
+'Wrong user/pass'			=>	'Wrong username and/or password.',
+'Forgotten pass'			=>	'Forgotten your password?',
+'Login redirect'			=>	'Logged in successfully. Redirecting …',
+'Logout redirect'			=>	'Logged out. Redirecting …',
+'No email match'			=>	'There is no user registered with the email address',
+'Request pass'				=>	'Request password',
+'Request pass legend'		=>	'Enter the email address with which you registered',
+'Request pass info'			=>	'A new password together with a link to activate the new password will be sent to that address.',
+'Not registered'			=>	'Not registered yet?',
+'Login legend'				=>	'Enter your username and password below',
+'Remember me'				=>	'Log me in automatically each time I visit.',
+'Login info'				=>	'If you have not registered or have forgotten your password click on the appropriate link below.',
+'New password errors'		=>	'Password request error',
+'New passworderrors info'	=>	'The following error needs to be corrected before a new password can be sent:',
 
 // Forget password mail stuff
-'Forget mail'			=>	'An e-mail has been sent to the specified address with instructions on how to change your password. If it does not arrive you can contact the forum administrator at',
-'Email flood'			=>	'This account has already requested a password reset in the past hour. Please wait a while before requesting a new password again.'
+'Forget mail'				=>	'An email has been sent to the specified address with instructions on how to change your password. If it does not arrive you can contact the forum administrator at',
+'Email flood'				=>	'This account has already requested a password reset in the past hour. Please wait a while before requesting a new password again.'
 
 );
diff --git a/upload/lang/English/mail_templates/activate_email.tpl b/upload/lang/English/mail_templates/activate_email.tpl
index ebcbb03..f17066f 100644
--- a/upload/lang/English/mail_templates/activate_email.tpl
+++ b/upload/lang/English/mail_templates/activate_email.tpl
@@ -1,12 +1,12 @@
-Subject: Change e-mail address requested
+Subject: Change email address requested
 
 Hello <username>,
 
-You have requested to have a new e-mail address assigned to your account in the discussion forum at <base_url>. If you didn't request this or if you don't want to change your e-mail address you should just ignore this message. Only if you visit the activation page below will your e-mail address be changed. In order for the activation page to work, you must be logged in to the forum.
+You have requested to have a new email address assigned to your account in the discussion forum at <base_url>. If you didn't request this or if you don't want to change your email address you should just ignore this message. Only if you visit the activation page below will your email address be changed. In order for the activation page to work, you must be logged in to the forum.
 
-To change your e-mail address, please visit the following page:
+To change your email address, please visit the following page:
 <activation_url>
 
--- 
+--
 <board_mailer>
-(Do not reply to this message)
\ No newline at end of file
+(Do not reply to this message)
diff --git a/upload/lang/English/mail_templates/activate_password.tpl b/upload/lang/English/mail_templates/activate_password.tpl
index 1c0d708..33b2b3e 100644
--- a/upload/lang/English/mail_templates/activate_password.tpl
+++ b/upload/lang/English/mail_templates/activate_password.tpl
@@ -9,6 +9,6 @@ Your new password is: <new_password>
 To change your password, please visit the following page:
 <activation_url>
 
--- 
+--
 <board_mailer>
-(Do not reply to this message)
\ No newline at end of file
+(Do not reply to this message)
diff --git a/upload/lang/English/mail_templates/form_email.tpl b/upload/lang/English/mail_templates/form_email.tpl
index f721e02..b862422 100644
--- a/upload/lang/English/mail_templates/form_email.tpl
+++ b/upload/lang/English/mail_templates/form_email.tpl
@@ -1,6 +1,6 @@
 Subject: <mail_subject>
 
-<sender> from <board_title> has sent you a message. You can reply to <sender> by replying to this e-mail.
+<sender> from <board_title> has sent you a message. You can reply to <sender> by replying to this email.
 
 The message reads as follows:
 -----------------------------------------------------------------------
@@ -9,5 +9,5 @@ The message reads as follows:
 
 -----------------------------------------------------------------------
 
--- 
-<board_mailer>
\ No newline at end of file
+--
+<board_mailer>
diff --git a/upload/lang/English/mail_templates/index.html b/upload/lang/English/mail_templates/index.html
index 2db9a3c..89337b2 100644
--- a/upload/lang/English/mail_templates/index.html
+++ b/upload/lang/English/mail_templates/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/lang/English/mail_templates/new_reply.tpl b/upload/lang/English/mail_templates/new_reply.tpl
index 5acffc3..e9dab0b 100644
--- a/upload/lang/English/mail_templates/new_reply.tpl
+++ b/upload/lang/English/mail_templates/new_reply.tpl
@@ -6,6 +6,6 @@ The post is located at <post_url>
 
 You can unsubscribe by going to <unsubscribe_url>
 
--- 
+--
 <board_mailer>
-(Do not reply to this message)
\ No newline at end of file
+(Do not reply to this message)
diff --git a/upload/lang/English/mail_templates/new_reply_full.tpl b/upload/lang/English/mail_templates/new_reply_full.tpl
index 3820152..7231145 100644
--- a/upload/lang/English/mail_templates/new_reply_full.tpl
+++ b/upload/lang/English/mail_templates/new_reply_full.tpl
@@ -13,6 +13,6 @@ The post is located at <post_url>
 
 You can unsubscribe by going to <unsubscribe_url>
 
--- 
+--
 <board_mailer>
-(Do not reply to this message)
\ No newline at end of file
+(Do not reply to this message)
diff --git a/upload/lang/English/mail_templates/welcome.tpl b/upload/lang/English/mail_templates/welcome.tpl
index 768e460..0110042 100644
--- a/upload/lang/English/mail_templates/welcome.tpl
+++ b/upload/lang/English/mail_templates/welcome.tpl
@@ -9,4 +9,4 @@ Login at <login_url> to activate the account.
 
 --
 <board_mailer>
-(Do not reply to this message)
\ No newline at end of file
+(Do not reply to this message)
diff --git a/upload/lang/English/misc.php b/upload/lang/English/misc.php
index 3f416cf..9ccd4b2 100644
--- a/upload/lang/English/misc.php
+++ b/upload/lang/English/misc.php
@@ -3,81 +3,88 @@
 // Language definitions used in various scripts
 $lang_misc = array(
 
-'Mark read redirect'		=>	'All topics and forums have been marked as read. Redirecting &hellip;',
-'Mark forum read redirect'	=>	'All topics in the specified forum have been marked as read. Redirecting &hellip;',
+'Mark read redirect'			=>	'All topics and forums have been marked as read. Redirecting …',
+'Mark forum read redirect'		=>	'All topics in the specified forum have been marked as read. Redirecting …',
 
-// Send e-mail
-'Form e-mail disabled'		=>	'The user you are trying to send an e-mail to has disabled form e-mail.',
-'No e-mail subject'			=>	'You must enter a subject.',
-'No e-mail message'			=>	'You must enter a message.',
-'Too long e-mail message'	=>	'Messages cannot be longer than 65535 characters (64 KB).',
-'Email flood'				=>	'At least %s seconds have to pass between sent emails. Please wait a while and try sending again.',
-'E-mail sent redirect'		=>	'E-mail sent. Redirecting &hellip;',
-'Send e-mail to'			=>	'Send e-mail to',
-'E-mail subject'			=>	'Subject',
-'E-mail message'			=>	'Message',
-'E-mail disclosure note'	=>	'Please note that by using this form, your e-mail address will be disclosed to the recipient.',
-'Write e-mail'				=>	'Write and submit your e-mail message',
+// Send email
+'Form email disabled'			=>	'The user you are trying to send an email to has disabled form email.',
+'No email subject'				=>	'You must enter a subject.',
+'No email message'				=>	'You must enter a message.',
+'Too long email message'		=>	'Messages cannot be longer than 65535 characters (64 KB).',
+'Email flood'					=>	'At least %s seconds have to pass between sent emails. Please wait a while and try sending again.',
+'Email sent redirect'			=>	'Email sent. Redirecting …',
+'Send email to'					=>	'Send email to',
+'Email subject'					=>	'Subject',
+'Email message'					=>	'Message',
+'Email disclosure note'			=>	'Please note that by using this form, your email address will be disclosed to the recipient.',
+'Write email'					=>	'Write and submit your email message',
 
 // Report
-'No reason'					=>	'You must enter a reason.',
-'Report flood'				=>	'At least %s seconds have to pass between reports. Please wait a while and try sending again.',
-'Report redirect'			=>	'Post reported. Redirecting &hellip;',
-'Report post'				=>	'Report post',
-'Reason'					=>	'Reason',
-'Reason desc'				=>	'Please enter a short reason why you are reporting this post',
+'No reason'						=>	'You must enter a reason.',
+'Report flood'					=>	'At least %s seconds have to pass between reports. Please wait a while and try sending again.',
+'Report redirect'				=>	'Post reported. Redirecting …',
+'Report post'					=>	'Report post',
+'Reason'						=>	'Reason',
+'Reason desc'					=>	'Please enter a short reason why you are reporting this post',
 
 // Subscriptions
-'Already subscribed'		=>	'You are already subscribed to this topic.',
-'Subscribe redirect'		=>	'Your subscription has been added. Redirecting &hellip;',
-'Not subscribed'			=>	'You are not subscribed to this topic.',
-'Unsubscribe redirect'		=>	'Your subscription has been removed. Redirecting &hellip;',
+'Already subscribed'			=>	'You are already subscribed to this topic.',
+'Subscribe redirect'			=>	'Your subscription has been added. Redirecting …',
+'Not subscribed'				=>	'You are not subscribed to this topic.',
+'Unsubscribe redirect'			=>	'Your subscription has been removed. Redirecting …',
 
 // General forum and topic moderation
-'Moderate'					=>	'Moderate',
-'Select'					=>	'Select',	// the header of a column of checkboxes
-'Move'						=>	'Move',
-'Split'						=>	'Split',
-'Delete'					=>	'Delete',
-'Merge'						=>	'Merge',
+'Moderate'						=>	'Moderate',
+'Select'						=>	'Select', // the header of a column of checkboxes
+'Move'							=>	'Move',
+'Split'							=>	'Split',
+'Delete'						=>	'Delete',
+'Merge'							=>	'Merge',
 
 // Moderate forum
-'Open'						=>	'Open',
-'Close'						=>	'Close',
-'Move topic'				=>	'Move topic',
-'Move topics'				=>	'Move topics',
-'Move legend'				=>	'Select destination of move',
-'Move to'					=>	'Move to',
-'Leave redirect'			=>	'Leave redirect topic(s)',
-'Move topic redirect'		=>	'Topic moved. Redirecting &hellip;',
-'Move topics redirect'		=>	'Topics moved. Redirecting &hellip;',
-'Confirm delete legend'		=>	'Please confirm deletion',
-'Delete topics'			=>	'Delete topics',
-'Delete topics comply'		=>	'Are you sure you want to delete the selected topics?',
-'Delete topics redirect'	=>	'Topics deleted. Redirecting &hellip;',
-'Open topic redirect'		=>	'Topic opened. Redirecting &hellip;',
-'Open topics redirect'		=>	'Topics opened. Redirecting &hellip;',
-'Close topic redirect'		=>	'Topic closed. Redirecting &hellip;',
-'Close topics redirect'		=>	'Topics closed. Redirecting &hellip;',
-'No topics selected'		=>	'You must select at least one topic for move/delete/open/close.',
+'Open'							=>	'Open',
+'Close'							=>	'Close',
+'Move topic'					=>	'Move topic',
+'Move topics'					=>	'Move topics',
+'Move legend'					=>	'Select destination of move',
+'Move to'						=>	'Move to',
+'Nowhere to move'				=>	'There are no forums into which you can move topics.',
+'Leave redirect'				=>	'Leave redirect topic(s)',
+'Move topic redirect'			=>	'Topic moved. Redirecting …',
+'Move topics redirect'			=>	'Topics moved. Redirecting …',
+'Confirm delete legend'			=>	'Please confirm deletion',
+'Delete topics'					=>	'Delete topics',
+'Delete topics comply'			=>	'Are you sure you want to delete the selected topics?',
+'Delete topics redirect'		=>	'Topics deleted. Redirecting …',
+'Open topic redirect'			=>	'Topic opened. Redirecting …',
+'Open topics redirect'			=>	'Topics opened. Redirecting …',
+'Close topic redirect'			=>	'Topic closed. Redirecting …',
+'Close topics redirect'			=>	'Topics closed. Redirecting …',
+'No topics selected'			=>	'You must select at least one topic for move/delete/open/close.',
 'Not enough topics selected'	=>	'You must select at least two topics for merge.',
-'Stick topic redirect'		=>	'Topic sticked. Redirecting &hellip;',
-'Unstick topic redirect'	=>	'Topic unsticked. Redirecting &hellip;',
-'Merge topics'			=>	'Merge topics',
-'Merge topics redirect'		=>	'Topics merged. Redirecting &hellip;',
-'Confirm merge legend'		=>	'Please confirm merge',
-'New subject'			=>	'New subject',
+'Stick topic redirect'			=>	'Topic sticked. Redirecting …',
+'Unstick topic redirect'		=>	'Topic unsticked. Redirecting …',
+'Merge topics'					=>	'Merge topics',
+'Merge topics redirect'			=>	'Topics merged. Redirecting …',
+'Confirm merge legend'			=>	'Please confirm merge',
+'New subject'					=>	'New subject',
 
 // Split multiple posts in topic
-'Confirm split legend'		=>	'Please confirm split of selected posts.',
-'Split posts'			=>	'Split posts',
-'Split posts comply'		=>	'Are you sure you want to split the selected posts?',
-'Split posts redirect'		=>	'Posts have been split. Redirecting &hellip;',
+'Confirm split legend'			=>	'Please confirm split of selected posts.',
+'Split posts'					=>	'Split posts',
+'Split posts comply'			=>	'Are you sure you want to split the selected posts?',
+'Split posts redirect'			=>	'Posts have been split. Redirecting …',
 
 // Delete multiple posts in topic
-'Delete posts'				=>	'Delete posts',
-'Delete posts comply'		=>	'Are you sure you want to delete the selected posts?',
-'Delete posts redirect'		=>	'Posts deleted. Redirecting &hellip;',
-'No posts selected'			=>	'You must select at least one post to be deleted.'
+'Delete posts'					=>	'Delete posts',
+'Cannot select first'			=>	'First post cannot be selected for split/delete.',
+'Delete posts comply'			=>	'Are you sure you want to delete the selected posts?',
+'Delete posts redirect'			=>	'Posts deleted. Redirecting …',
+'No posts selected'				=>	'You must select at least one post for split/delete.',
+
+// Get host
+'Host info 1'					=>	'The IP address is: %s',
+'Host info 2'					=>	'The host name is: %s',
+'Show more users'				=>	'Show more users for this IP',
 
 );
diff --git a/upload/lang/English/post.php b/upload/lang/English/post.php
index d7087ed..5c8ea37 100644
--- a/upload/lang/English/post.php
+++ b/upload/lang/English/post.php
@@ -4,30 +4,33 @@
 $lang_post = array(
 
 // Post validation stuff (many are similiar to those in edit.php)
-'No subject'			=>	'Topics must contain a subject.',
-'Too long subject'		=>	'Subjects cannot be longer than 70 characters.',
-'No message'			=>	'You must enter a message.',
-'Too long message'		=>	'Posts cannot be longer that 65535 characters (64 KB).',
+'No subject'		=>	'Topics must contain a subject.',
+'Too long subject'	=>	'Subjects cannot be longer than 70 characters.',
+'No message'		=>	'You must enter a message.',
+'Too long message'	=>	'Posts cannot be longer that 65535 characters (64 KB).',
+'All caps subject'	=>	'Subjects cannot contain only capital letters.',
+'All caps message'	=>	'Posts cannot contain only capital letters.',
 
 // Posting
-'Post errors'			=>	'Post errors',
-'Post errors info'		=>	'The following errors need to be corrected before the message can be posted:',
-'Post preview'			=>	'Post preview',
-'Guest name'			=>	'Name',	// For guests (instead of Username)
-'Post redirect'			=>	'Post entered. Redirecting &hellip;',
-'Post a reply'			=>	'Post a reply',
-'Post new topic'		=>	'Post new topic',
-'Hide smilies'			=>	'Never show smilies as icons for this post',
-'Subscribe'				=>	'Subscribe to this topic',
-'Topic review'			=>	'Topic review (newest first)',
-'Flood start'			=>	'At least',
-'flood end'				=>	'seconds have to pass between posts. Please wait a little while and try posting again.',
-'Preview'				=>	'Preview',	// submit button to preview message
+'Post errors'		=>	'Post errors',
+'Post errors info'	=>	'The following errors need to be corrected before the message can be posted:',
+'Post preview'		=>	'Post preview',
+'Guest name'		=>	'Name', // For guests (instead of Username)
+'Post redirect'		=>	'Post entered. Redirecting …',
+'Post a reply'		=>	'Post a reply',
+'Post new topic'	=>	'Post new topic',
+'Hide smilies'		=>	'Never show smilies as icons for this post',
+'Subscribe'			=>	'Subscribe to this topic',
+'Stay subscribed'	=>	'Stay subscribed to this topic',
+'Topic review'		=>	'Topic review (newest first)',
+'Flood start'		=>	'At least',
+'flood end'			=>	'seconds have to pass between posts. Please wait a little while and try posting again.',
+'Preview'			=>	'Preview', // submit button to preview message
 
 // Edit post
-'Edit post legend'		=>	'Edit the post and submit changes',
-'Silent edit'			=>	'Silent edit (don\'t display "Edited by ..." in topic view)',
-'Edit post'				=>	'Edit post',
-'Edit redirect'			=>	'Post updated. Redirecting &hellip;'
+'Edit post legend'	=>	'Edit the post and submit changes',
+'Silent edit'		=>	'Silent edit (don\'t display "Edited by ..." in topic view)',
+'Edit post'			=>	'Edit post',
+'Edit redirect'		=>	'Post updated. Redirecting …'
 
 );
diff --git a/upload/lang/English/prof_reg.php b/upload/lang/English/prof_reg.php
index 7efc980..9a69b41 100644
--- a/upload/lang/English/prof_reg.php
+++ b/upload/lang/English/prof_reg.php
@@ -3,40 +3,79 @@
 // Language definitions used in both profile.php and register.php
 $lang_prof_reg = array(
 
-'E-mail legend'				=>	'Enter a valid e-mail address',
-'E-mail legend 2'			=>	'Enter and confirm a valid e-mail address',
+'Email legend'				=>	'Enter a valid email address',
+'Email legend 2'			=>	'Enter and confirm a valid email address',
 'Localisation legend'		=>	'Set your localisation options',
-'Timezone'					=>	'Timezone',
-'Timezone info'				=>	'For the forum to display times correctly you must select your local timezone.',
-'DST'						=>	'Adjust for DST: This box should be checked properly so that the forum can display the correct time.',
-'DST info'					=>	'Daylight savings is in effect (advance times by 1 hour).',
+'Time zone'					=>	'Time zone',
+'Time zone info'			=>	'For the forum to display times correctly you must select your local time zone. If Daylight Savings Time is in effect you should also check the option provided which will advance times by 1 hour.',
+'DST'						=>	'Daylight Savings Time is in effect (advance time by 1 hour).',
 'Time format'				=>	'Time format',
 'Date format'				=>	'Date format',
 'Default'					=>	'Default',
 'Language'					=>	'Language',
-'Language info'				=>	'You can choose which language you wish to use to view the forum.',
-'E-mail setting info'		=>	'Select whether you want your e-mail address to be viewable to other users or not and if you want other users to be able to send you e-mail via the forum (form e-mail) or not.',
-'E-mail setting 1'			=>	'Display your e-mail address.',
-'E-mail setting 2'			=>	'Hide your e-mail address but allow form e-mail.',
-'E-mail setting 3'			=>	'Hide your e-mail address and disallow form e-mail.',
+'Email setting info'		=>	'Select whether you want your email address to be viewable to other users or not and if you want other users to be able to send you email via the forum (form email) or not.',
+'Email setting 1'			=>	'Display your email address.',
+'Email setting 2'			=>	'Hide your email address but allow form email.',
+'Email setting 3'			=>	'Hide your email address and disallow form email.',
 'Privacy options legend'	=>	'Set your privacy options',
 'Confirm pass'				=>	'Confirm password',
 
 'Username too short'		=>	'Usernames must be at least 2 characters long. Please choose another (longer) username.',
+'Username too long'			=>	'Usernames must not be more than 25 characters long. Please choose another (shorter) username.',
 'Username guest'			=>	'The username guest is reserved. Please choose another username.',
 'Username IP'				=>	'Usernames may not be in the form of an IP address. Please choose another username.',
 'Username reserved chars'	=>	'Usernames may not contain all the characters \', " and [ or ] at once. Please choose another username.',
 'Username BBCode'			=>	'Usernames may not contain any of the text formatting tags (BBCode) that the forum uses. Please choose another username.',
-'Dupe username'				=>	'Someone else has already registered with that username. Please choose another username.',
+'Banned username'			=>	'The username you entered is banned in this forum. Please choose another username.',
 'Pass too short'			=>	'Passwords must be at least 4 characters long. Please choose another (longer) password.',
-'Pass not match'			=>	'Passwords do not match. Please go back and correct.',
-'Banned e-mail'				=>	'The e-mail address you entered is banned in this forum. Please choose another e-mail address.',
-'Dupe e-mail'				=>	'Someone else is already registered with that e-mail address. Please choose another e-mail address.',
+'Pass not match'			=>	'Passwords do not match.',
+'Banned email'				=>	'The email address you entered is banned in this forum. Please choose another email address.',
+'Dupe email'				=>	'Someone else is already registered with that email address. Please choose another email address.',
 'Sig too long'				=>	'Signatures cannot be longer than',
 'characters'				=>	'characters',
 'Sig too many lines'		=>	'Signatures cannot have more than',
 'lines'						=>	'lines',
-'Signature quote/code'		=>	'The quote and code BBCodes are not allowed in signatures. Please go back and correct.',
-'Bad ICQ'					=>	'You entered an invalid ICQ UIN. Please go back and correct.'
+'Bad ICQ'					=>	'You entered an invalid ICQ UIN. Please go back and correct.',
+
+'UTC-12:00'					=>	'(UTC-12:00) International Date Line West',
+'UTC-11:00'					=>	'(UTC-11:00) Niue, Samoa',
+'UTC-10:00'					=>	'(UTC-10:00) Hawaii-Aleutian, Cook Island',
+'UTC-09:30'					=>	'(UTC-09:30) Marquesas Islands',
+'UTC-09:00'					=>	'(UTC-09:00) Alaska, Gambier Island',
+'UTC-08:30'					=>	'(UTC-08:30) Pitcairn Islands',
+'UTC-08:00'					=>	'(UTC-08:00) Pacific',
+'UTC-07:00'					=>	'(UTC-07:00) Mountain',
+'UTC-06:00'					=>	'(UTC-06:00) Central',
+'UTC-05:00'					=>	'(UTC-05:00) Eastern',
+'UTC-04:00'					=>	'(UTC-04:00) Atlantic',
+'UTC-03:30'					=>	'(UTC-03:30) Newfoundland',
+'UTC-03:00'					=>	'(UTC-03:00) Amazon, Central Greenland',
+'UTC-02:00'					=>	'(UTC-02:00) Mid-Atlantic',
+'UTC-01:00'					=>	'(UTC-01:00) Azores, Cape Verde, Eastern Greenland',
+'UTC'						=>	'(UTC) Western European, Greenwich',
+'UTC+01:00'					=>	'(UTC+01:00) Central European, West African',
+'UTC+02:00'					=>	'(UTC+02:00) Eastern European, Central African',
+'UTC+03:00'					=>	'(UTC+03:00) Moscow, Eastern African',
+'UTC+03:30'					=>	'(UTC+03:30) Iran',
+'UTC+04:00'					=>	'(UTC+04:00) Gulf, Samara',
+'UTC+04:30'					=>	'(UTC+04:30) Afghanistan',
+'UTC+05:00'					=>	'(UTC+05:00) Pakistan, Yekaterinburg',
+'UTC+05:30'					=>	'(UTC+05:30) India, Sri Lanka',
+'UTC+05:45'					=>	'(UTC+05:45) Nepal',
+'UTC+06:00'					=>	'(UTC+06:00) Bangladesh, Bhutan, Novosibirsk',
+'UTC+06:30'					=>	'(UTC+06:30) Cocos Islands, Myanmar',
+'UTC+07:00'					=>	'(UTC+07:00) Indochina, Krasnoyarsk',
+'UTC+08:00'					=>	'(UTC+08:00) Greater China, Australian Western, Irkutsk',
+'UTC+08:45'					=>	'(UTC+08:45) Southeastern Western Australia',
+'UTC+09:00'					=>	'(UTC+09:00) Japan, Korea, Chita',
+'UTC+09:30'					=>	'(UTC+09:30) Australian Central',
+'UTC+10:00'					=>	'(UTC+10:00) Australian Eastern, Vladivostok',
+'UTC+10:30'					=>	'(UTC+10:30) Lord Howe',
+'UTC+11:00'					=>	'(UTC+11:00) Solomon Island, Magadan',
+'UTC+11:30'					=>	'(UTC+11:30) Norfolk Island',
+'UTC+12:00'					=>	'(UTC+12:00) New Zealand, Fiji, Kamchatka',
+'UTC+12:45'					=>	'(UTC+12:45) Chatham Islands',
+'UTC+13:00'					=>	'(UTC+13:00) Tonga, Phoenix Islands',
+'UTC+14:00'					=>	'(UTC+14:00) Line Islands'
 
 );
diff --git a/upload/lang/English/profile.php b/upload/lang/English/profile.php
index ec6a55c..ef6a98c 100644
--- a/upload/lang/English/profile.php
+++ b/upload/lang/English/profile.php
@@ -4,143 +4,137 @@
 $lang_profile = array(
 
 // Navigation and sections
-'Profile menu'				=>	'Profile menu',
-'Section essentials'		=>	'Essentials',
-'Section personal'			=>	'Personal',
-'Section messaging'			=>	'Messaging',
-'Section personality'		=>	'Personality',
-'Section display'			=>	'Display',
-'Section privacy'			=>	'Privacy',
-'Section admin'				=>	'Administration',
+'Profile menu'					=>	'Profile menu',
+'Section essentials'			=>	'Essentials',
+'Section personal'				=>	'Personal',
+'Section messaging'				=>	'Messaging',
+'Section personality'			=>	'Personality',
+'Section display'				=>	'Display',
+'Section privacy'				=>	'Privacy',
+'Section admin'					=>	'Administration',
 
 // Miscellaneous
-'Username and pass legend'	=>	'Enter your username and password',
-'Personal details legend'	=>	'Enter your personal details',
-'Contact details legend'	=>	'Enter your messaging details',
-'Options display'			=>	'Set your display options',
-'Options post'				=>	'Set your post viewing options',
-'User activity'				=>	'User activity',
-'Paginate info'				=>	'Enter the number of topics and posts you wish to view on each page.',
+'Username and pass legend'		=>	'Enter your username and password',
+'Personal details legend'		=>	'Enter your personal details',
+'Contact details legend'		=>	'Enter your messaging details',
+'User activity'					=>	'User activity',
+'Paginate info'					=>	'Enter the number of topics and posts you wish to view on each page.',
 
 // Password stuff
-'Pass key bad'				=>	'The specified password activation key was incorrect or has expired. Please re-request a new password. If that fails, contact the forum administrator at',
-'Pass updated'				=>	'Your password has been updated. You can now login with your new password.',
-'Pass updated redirect'		=>	'Password updated. Redirecting &hellip;',
-'Wrong pass'				=>	'Wrong old password.',
-'Change pass'				=>	'Change password',
-'Change pass legend'		=>	'Enter and confirm your new password',
-'Old pass'					=>	'Old password',
-'New pass'					=>	'New password',
-'Confirm new pass'			=>	'Confirm new password',
+'Pass key bad'					=>	'The specified password activation key was incorrect or has expired. Please re-request a new password. If that fails, contact the forum administrator at',
+'Pass updated'					=>	'Your password has been updated. You can now login with your new password.',
+'Pass updated redirect'			=>	'Password updated. Redirecting …',
+'Wrong pass'					=>	'Wrong old password.',
+'Change pass'					=>	'Change password',
+'Change pass legend'			=>	'Enter and confirm your new password',
+'Old pass'						=>	'Old password',
+'New pass'						=>	'New password',
+'Confirm new pass'				=>	'Confirm new password',
+'Pass info'						=>	'Passwords must be at least 4 characters long. Passwords are case sensitive.',
 
-// E-mail stuff
-'E-mail key bad'			=>	'The specified e-mail activation key was incorrect or has expired. Please re-request change of e-mail address. If that fails, contact the forum administrator at',
-'E-mail updated'			=>	'Your e-mail address has been updated.',
-'Activate e-mail sent'		=>	'An email has been sent to the specified address with instructions on how to activate the new e-mail address. If it doesn\'t arrive you can contact the forum administrator at',
-'E-mail legend'				=>	'Enter your new e-mail address',
-'E-mail instructions'		=>	'An e-mail will be sent to your new address with an activation link. You must click the link in the e-mail you receive to activate the new address.',
-'Change e-mail'				=>	'Change e-mail address',
-'New e-mail'				=>	'New e-mail',
+// Email stuff
+'Email key bad'					=>	'The specified email activation key was incorrect or has expired. Please re-request change of email address. If that fails, contact the forum administrator at',
+'Email updated'					=>	'Your email address has been updated.',
+'Activate email sent'			=>	'An email has been sent to the specified address with instructions on how to activate the new email address. If it doesn\'t arrive you can contact the forum administrator at',
+'Email legend'					=>	'Enter your new email address',
+'Email instructions'			=>	'An email will be sent to your new address with an activation link. You must click the link in the email you receive to activate the new address.',
+'Change email'					=>	'Change email address',
+'New email'						=>	'New email',
 
 // Avatar upload stuff
-'Avatars disabled'			=>	'The administrator has disabled avatar support.',
-'Too large ini'				=>	'The selected file was too large to upload. The server didn\'t allow the upload.',
-'Partial upload'			=>	'The selected file was only partially uploaded. Please try again.',
-'No tmp directory'			=>	'PHP was unable to save the uploaded file to a temporary location.',
-'No file'					=>	'You did not select a file for upload.',
-'Bad type'					=>	'The file you tried to upload is not of an allowed type. Allowed types are gif, jpeg and png.',
-'Too wide or high'			=>	'The file you tried to upload is wider and/or higher than the maximum allowed',
-'Too large'					=>	'The file you tried to upload is larger than the maximum allowed',
-'pixels'					=>	'pixels',
-'bytes'						=>	'bytes',
-'Move failed'				=>	'The server was unable to save the uploaded file. Please contact the forum administrator at',
-'Unknown failure'			=>	'An unknown error occurred. Please try again.',
-'Avatar upload redirect'	=>	'Avatar uploaded. Redirecting &hellip;',
-'Avatar deleted redirect'	=>	'Avatar deleted. Redirecting &hellip;',
-'Avatar desc'				=>	'An avatar is a small image that will be displayed under your username in your posts. It must not be any bigger than',
-'Upload avatar'				=>	'Upload avatar',
-'Upload avatar legend'		=>	'Enter an avatar file to upload',
-'Delete avatar'				=>	'Delete avatar',	// only for admins
-'File'						=>	'File',
-'Upload'					=>	'Upload',	// submit button
+'Avatars disabled'				=>	'The administrator has disabled avatar support.',
+'Too large ini'					=>	'The selected file was too large to upload. The server didn\'t allow the upload.',
+'Partial upload'				=>	'The selected file was only partially uploaded. Please try again.',
+'No tmp directory'				=>	'PHP was unable to save the uploaded file to a temporary location.',
+'No file'						=>	'You did not select a file for upload.',
+'Bad type'						=>	'The file you tried to upload is not of an allowed type. Allowed types are gif, jpeg and png.',
+'Too wide or high'				=>	'The file you tried to upload is wider and/or higher than the maximum allowed',
+'Too large'						=>	'The file you tried to upload is larger than the maximum allowed',
+'pixels'						=>	'pixels',
+'bytes'							=>	'bytes',
+'Move failed'					=>	'The server was unable to save the uploaded file. Please contact the forum administrator at',
+'Unknown failure'				=>	'An unknown error occurred. Please try again.',
+'Avatar upload redirect'		=>	'Avatar uploaded. Redirecting …',
+'Avatar deleted redirect'		=>	'Avatar deleted. Redirecting …',
+'Avatar desc'					=>	'An avatar is a small image that will be displayed under your username in your posts. It must not be any bigger than',
+'Upload avatar'					=>	'Upload avatar',
+'Upload avatar legend'			=>	'Enter an avatar file to upload',
+'Delete avatar'					=>	'Delete avatar', // only for admins
+'File'							=>	'File',
+'Upload'						=>	'Upload', // submit button
 
 // Form validation stuff
-'Dupe username'				=>	'Someone else has already registered with that username. Please go back and try a different username.',
-'Forbidden title'			=>	'The title you entered contains a forbidden word. You must choose a different title.',
-'Profile redirect'			=>	'Profile updated. Redirecting &hellip;',
+'Forbidden title'				=>	'The title you entered contains a forbidden word. You must choose a different title.',
+'Profile redirect'				=>	'Profile updated. Redirecting …',
 
 // Profile display stuff
-'Not activated'				=>	'This user hasn\'t activated his/her account yet. The account is activated when he/she logs in the first time.',
-'Unknown'					=>	'(Unknown)',	// This is displayed when a user hasn't filled out profile field (e.g. Location)
-'Private'					=>	'(Private)',	// This is displayed when a user does not want to receive e-mails
-'No avatar'					=>	'(No avatar)',
-'Show posts'				=>	'Show all posts',
-'Realname'					=>	'Real name',
-'Location'					=>	'Location',
-'Website'					=>	'Website',
-'Jabber'					=>	'Jabber',
-'ICQ'						=>	'ICQ',
-'MSN'						=>	'MSN Messenger',
-'AOL IM'					=>	'AOL IM',
-'Yahoo'						=>	'Yahoo! Messenger',
-'Avatar'					=>	'Avatar',
-'Signature'					=>	'Signature',
-'Sig max length'			=>	'Max length',
-'Sig max lines'				=>	'Max lines',
-'Avatar legend'				=>	'Set your avatar display options',
-'Avatar info'				=>	'An avatar is a small image that will be displayed with all your posts. You can upload an avatar by clicking the link below.',
-'Change avatar'				=>	'Change avatar',
-'Use avatar'				=>	'Use avatar.',
-'Signature legend'			=>	'Compose your signature',
-'Signature info'			=>	'A signature is a small piece of text that is attached to your posts. In it, you can enter just about anything you like. Perhaps you would like to enter your favourite quote or your star sign. It\'s up to you! In your signature you can use BBCode if it is allowed in this particular forum. You can see the features that are allowed/enabled listed below whenever you edit your signature.',
-'Sig preview'				=>	'Current signature preview:',
-'No sig'					=>	'No signature currently stored in profile.',
-'Topics per page'			=>	'Topics',
-'Topics per page info'		=>	'This setting controls how many topics are displayed per page when you view a forum. If you are uncertain about what to use, you can just leave it blank and the forum default will be used.',
-'Posts per page'			=>	'Posts',
-'Posts per page info'		=>	'This setting controls how many posts are displayed per page when you view a topic. If you are uncertain about what to use, you can just leave it blank and the forum default will be used.',
-'Leave blank'				=>	'Leave blank to use forum default.',
-'Notify full'				=>	'Include post in subscription e-mails.',
-'Notify full info'			=>	'With this enabled, a plain text version of the new post will be included in subscription notification e-mails.',
-'Auto notify full'			=>	'Automatically subscribe to topics when posting.',
-'Auto notify full info'		=>	'With this enabled, you will automatically be subscribed to every topic you post in.',
-'Show smilies'				=>	'Show smilies as graphic icons',
-'Show smilies info'			=>	'If you enable this option, small images will be displayed instead of text smilies.',
-'Show images'				=>	'Show images in posts.',
-'Show images info'			=>	'Disable this if you don\'t want to see images in posts (i.e. images displayed with the [img]-tag).',
-'Show images sigs'			=>	'Show images in user signatures.',
-'Show images sigs info'		=>	'Disable this if you don\'t want to see images in signatures (i.e. images displayed with the [img]-tag).',
-'Show avatars'				=>	'Show user avatars in posts.',
-'Show avatars info'			=>	'This option toggles whether user avatar images will be displayed in posts or not.',
-'Show sigs'					=>	'Show user signatures.',
-'Show sigs info'			=>	'Enable if you would like to see user signatures.',
-'Style legend'				=>	'Select your preferred style',
-'Style info'				=>	'If you like you can use a different visual style for this forum.',
-'Admin note'				=>	'Admin note',
-'Pagination legend'			=>	'Enter your pagination options',
-'Post display legend'		=>	'Set your options for viewing posts',
-'Post display info'			=>	'If you are on a slow connection, disabling these options, particularly showing images in posts and signatures, will make pages load faster.',
-'Instructions'				=>	'When you update your profile, you will be redirected back to this page.',
+'Users profile'					=>	'%s\'s profile',
+'Unknown'						=>	'(Unknown)', // This is displayed when a user hasn't filled out profile field (e.g. Location)
+'Private'						=>	'(Private)', // This is displayed when a user does not want to receive emails
+'No avatar'						=>	'(No avatar)',
+'Username info'					=>	'Username: %s',
+'Email info'					=>	'Email: %s',
+'Posts info'					=>	'Posts: %s',
+'Registered info'				=>	'Registered: %s',
+'Last post info'				=>	'Last post: %s',
+'Show posts'					=>	'Show all posts',
+'Realname'						=>	'Real name',
+'Location'						=>	'Location',
+'Website'						=>	'Website',
+'Jabber'						=>	'Jabber',
+'ICQ'							=>	'ICQ',
+'MSN'							=>	'MSN Messenger',
+'AOL IM'						=>	'AOL IM',
+'Yahoo'							=>	'Yahoo! Messenger',
+'Avatar'						=>	'Avatar',
+'Signature'						=>	'Signature',
+'Sig max size'					=>	'Max length: %s characters / Max lines: %s',
+'Avatar legend'					=>	'Set your avatar display options',
+'Avatar info'					=>	'An avatar is a small image that will be displayed with all your posts. You can upload an avatar by clicking the link below.',
+'Change avatar'					=>	'Change avatar',
+'Signature legend'				=>	'Compose your signature',
+'Signature info'				=>	'A signature is a small piece of text that is attached to your posts. In it, you can enter just about anything you like. Perhaps you would like to enter your favourite quote or your star sign. It\'s up to you! In your signature you can use BBCode if it is allowed in this particular forum. You can see the features that are allowed/enabled listed below whenever you edit your signature.',
+'Sig preview'					=>	'Current signature preview:',
+'No sig'						=>	'No signature currently stored in profile.',
+'Signature quote/code/list/h'	=>	'The quote, code, list, and heading BBCodes are not allowed in signatures.',
+'Topics per page'				=>	'Topics',
+'Posts per page'				=>	'Posts',
+'Leave blank'					=>	'Leave blank to use forum default.',
+'Subscription legend'			=>	'Set your subscription options',
+'Notify full'					=>	'Include a plain text version of new posts in subscription notification emails.',
+'Auto notify full'				=>	'Automatically subscribe to every topic you post in.',
+'Show smilies'					=>	'Show smilies as graphic icons.',
+'Show images'					=>	'Show images in posts.',
+'Show images sigs'				=>	'Show images in user signatures.',
+'Show avatars'					=>	'Show user avatars in posts.',
+'Show sigs'						=>	'Show user signatures.',
+'Style legend'					=>	'Select your preferred style',
+'Styles'						=>	'Styles',
+'Admin note'					=>	'Admin note',
+'Pagination legend'				=>	'Enter your pagination options',
+'Post display legend'			=>	'Set your options for viewing posts',
+'Post display info'				=>	'If you are on a slow connection, disabling these options, particularly showing images in posts and signatures, will make pages load faster.',
+'Instructions'					=>	'When you update your profile, you will be redirected back to this page.',
 
 // Administration stuff
-'Group membership legend'	=>	'Choose user group',
-'Save'						=>	'Save',
-'Set mods legend'			=>	'Set moderator access',
-'Moderator in'				=>	'Moderator in',
-'Moderator in info'			=>	'Choose what forums this user should be allowed to moderate. Note: This only applies to moderators. Administrators always have full permissions in all forums.',
-'Update forums'				=>	'Update forums',
-'Delete ban legend'			=>	'Delete (administrators only) or ban user',
-'Delete user'				=>	'Delete user',
-'Ban user'					=>	'Ban user',
-'Confirm delete legend'		=>	'Important: read before deleting user',
-'Confirm delete user'		=>	'Confirm delete user',
-'Confirmation info'			=>	'Please confirm that you want to delete the user',	// the username will be appended to this string
-'Delete warning'			=>	'Warning! Deleted users and/or posts cannot be restored. If you choose not to delete the posts made by this user, the posts can only be deleted manually at a later time.',
-'Delete posts'				=>	'Delete any posts and topics this user has made.',
-'Delete'					=>	'Delete',		// submit button (confirm user delete)
-'User delete redirect'		=>	'User deleted. Redirecting &hellip;',
-'Group membership redirect'	=>	'Group membership saved. Redirecting &hellip;',
-'Update forums redirect'	=>	'Forum moderator rights updated. Redirecting &hellip;',
-'Ban redirect'				=>	'Redirecting &hellip;'
+'Group membership legend'		=>	'Choose user group',
+'Save'							=>	'Save',
+'Set mods legend'				=>	'Set moderator access',
+'Moderator in info'				=>	'Choose which forums this user should be allowed to moderate. Note: This only applies to moderators. Administrators always have full permissions in all forums.',
+'Update forums'					=>	'Update forums',
+'Delete ban legend'				=>	'Delete (administrators only) or ban user',
+'Delete user'					=>	'Delete user',
+'Ban user'						=>	'Ban user',
+'Confirm delete legend'			=>	'Important: read before deleting user',
+'Confirm delete user'			=>	'Confirm delete user',
+'Confirmation info'				=>	'Please confirm that you want to delete the user', // the username will be appended to this string
+'Delete warning'				=>	'Warning! Deleted users and/or posts cannot be restored. If you choose not to delete the posts made by this user, the posts can only be deleted manually at a later time.',
+'Delete posts'					=>	'Delete any posts and topics this user has made.',
+'Delete'						=>	'Delete', // submit button (confirm user delete)
+'User delete redirect'			=>	'User deleted. Redirecting …',
+'Group membership redirect'		=>	'Group membership saved. Redirecting …',
+'Update forums redirect'		=>	'Forum moderator rights updated. Redirecting …',
+'Ban redirect'					=>	'Redirecting …',
+'No delete admin message'		=>	'Administrators cannot be deleted. In order to delete this user, you must first move him/her to a different user group.',
 
 );
diff --git a/upload/lang/English/register.php b/upload/lang/English/register.php
index 28addb3..c3e24df 100644
--- a/upload/lang/English/register.php
+++ b/upload/lang/English/register.php
@@ -5,7 +5,7 @@ $lang_register = array(
 
 // Miscellaneous
 'No new regs'				=>	'This forum is not accepting new registrations.',
-'Reg cancel redirect'		=>	'Registration cancelled. Redirecting &hellip;',
+'Reg cancel redirect'		=>	'Registration cancelled. Redirecting …',
 'Forum rules'				=>	'Forum rules',
 'Rules legend'				=>	'You must agree to the following in order to register',
 'Registration flood'		=>	'A new user was registered with the same IP address as you within the last hour. To prevent registration flooding, at least an hour has to pass between registrations from the same IP. Sorry for the inconvenience.',
@@ -14,23 +14,24 @@ $lang_register = array(
 'Register'					=>	'Register',
 
 // Form validation stuff (some of these are also used in post.php)
+'Registration errors'		=>	'Registration errors',
+'Registration errors info'	=>	'The following errors need to be corrected before you can register:',
 'Username censor'			=>	'The username you entered contains one or more censored words. Please choose a different username.',
 'Username dupe 1'			=>	'Someone is already registered with the username',
 'Username dupe 2'			=>	'The username you entered is too similar. The username must differ from that by at least one alphanumerical character (a-z or 0-9). Please choose a different username.',
-'E-mail not match'			=>	'E-mail addresses do not match. Please go back and correct.',
+'Email not match'			=>	'Email addresses do not match.',
 
-// Registration e-mail stuff
-'Reg e-mail'				=>	'Thank you for registering. Your password has been sent to the specified address. If it doesn\'t arrive you can contact the forum administrator at',
-'Reg complete'				=>	'Registration complete. Logging in and redirecting &hellip;',
+// Registration email stuff
+'Reg email'					=>	'Thank you for registering. Your password has been sent to the specified address. If it doesn\'t arrive you can contact the forum administrator at',
+'Reg complete'				=>	'Registration complete. Logging in and redirecting …',
 
 // Register info
 'Desc 1'					=>	'Registration will grant you access to a number of features and capabilities otherwise unavailable. These functions include the ability to edit and delete posts, design your own signature that accompanies your posts and much more. If you have any questions regarding this forum you should ask an administrator.',
 'Desc 2'					=>	'Below is a form you must fill out in order to register. Once you are registered you should visit your profile and review the different settings you can change. The fields below only make up a small part of all the settings you can alter in your profile.',
 'Username legend'			=>	'Please enter a username between 2 and 25 characters long',
-'Pass legend 1'				=>	'Please enter and confirm your chosen password',
-'Pass legend 2'				=>	'Please read the instructions below',
-'Pass info'					=>	'Passwords can be between 4 and 16 characters long. Passwords are case sensitive.',
-'E-mail info'				=>	'You must enter a valid e-mail address as your randomly generated password will be sent to that address.',
-'Confirm e-mail'			=>	'Confirm e-mail address',
+'Pass legend'				=>	'Please enter and confirm your chosen password',
+'Pass info'					=>	'Passwords must be at least 4 characters long. Passwords are case sensitive.',
+'Email info'				=>	'You must enter a valid email address as your randomly generated password will be sent to that address.',
+'Confirm email'				=>	'Confirm email address',
 
 );
diff --git a/upload/lang/English/search.php b/upload/lang/English/search.php
index bea0731..d6a5081 100644
--- a/upload/lang/English/search.php
+++ b/upload/lang/English/search.php
@@ -43,6 +43,7 @@ $lang_search = array(
 'No new posts'				=>	'There are no topics with new posts since your last visit.',
 'No recent posts'			=>	'No new posts have been made within the last 24 hours.',
 'No unanswered'				=>	'There are no unanswered posts in this forum.',
-'Go to post'				=>	'Go to post'
+'Go to post'				=>	'Go to post',
+'Go to topic'				=>	'Go to topic'
 
 );
diff --git a/upload/lang/English/stopwords.txt b/upload/lang/English/stopwords.txt
index baee28b..907a260 100644
--- a/upload/lang/English/stopwords.txt
+++ b/upload/lang/English/stopwords.txt
@@ -10,6 +10,7 @@ anybody
 anywhere
 are
 arent
+aren't
 around
 ask
 been
@@ -20,14 +21,19 @@ but
 came
 can
 cant
+can't
 come
 could
 couldnt
+couldn't
 did
 didnt
+didn't
 does
 doesnt
+doesn't
 dont
+don't
 each
 either
 else
@@ -46,6 +52,7 @@ had
 has
 have
 havent
+haven't
 having
 her
 here
@@ -54,10 +61,17 @@ him
 his
 how
 ill
+i'll
+i'm
 into
 isnt
+isn't
+itll
+it'll
 its
+it's
 ive
+i've
 just
 know
 less
@@ -82,6 +96,7 @@ only
 other
 our
 ours
+our's
 out
 over
 please
@@ -102,6 +117,7 @@ thank
 thanks
 that
 thats
+that's
 the
 their
 theirs
@@ -147,4 +163,13 @@ yes
 yet
 you
 your
-yours
\ No newline at end of file
+youre
+you're
+yours
+http
+https
+ftp
+www
+com
+net
+org
diff --git a/upload/lang/English/topic.php b/upload/lang/English/topic.php
index e8513ae..e5317e9 100644
--- a/upload/lang/English/topic.php
+++ b/upload/lang/English/topic.php
@@ -3,25 +3,29 @@
 // Language definitions used in viewtopic.php
 $lang_topic = array(
 
-'Post reply'		=>	'Post reply',
-'Topic closed'		=>	'Topic closed',
-'From'				=>	'From',				// User location
-'Note'				=>	'Note',				// Admin note
-'Website'			=>	'Website',
-'Guest'				=>	'Guest',
-'Online'			=>	'Online',
-'Offline'			=>	'Offline',
-'Last edit'			=>	'Last edited by',
-'Report'			=>	'Report',
-'Delete'			=>	'Delete',
-'Edit'				=>	'Edit',
-'Quote'				=>	'Quote',
-'Is subscribed'		=>	'You are currently subscribed to this topic',
-'Unsubscribe'		=>	'Unsubscribe',
-'Subscribe'			=>	'Subscribe to this topic',
-'Quick post'		=>	'Quick post',
-
-'Link separator'	=>	' | ',	// The text that separates links in posts (website, e-mail, report, edit etc.)
-'Mod controls'		=>	'Moderator controls'
+'Post reply'	=>	'Post reply',
+'Topic closed'	=>	'Topic closed',
+'From'			=>	'From:', // User location
+'IP'			=>	'IP:',
+'Note'			=>	'Note:', // Admin note
+'Posts'			=>	'Posts:',
+'Registered'	=>	'Registered:',
+'Replies'		=>	'Replies:',
+'Website'		=>	'Website',
+'Guest'			=>	'Guest',
+'Online'		=>	'Online',
+'Offline'		=>	'Offline',
+'Last edit'		=>	'Last edited by',
+'Report'		=>	'Report',
+'Delete'		=>	'Delete',
+'Edit'			=>	'Edit',
+'Quote'			=>	'Quote',
+'Is subscribed'	=>	'You are currently subscribed to this topic',
+'Unsubscribe'	=>	'Unsubscribe',
+'Subscribe'		=>	'Subscribe to this topic',
+'Quick post'	=>	'Quick post',
+'Mod controls'	=>	'Moderator controls',
+'New icon'		=>	'New post',
+'Re'			=>	'Re:'
 
 );
diff --git a/upload/lang/English/userlist.php b/upload/lang/English/userlist.php
index 77e94e8..1b39920 100644
--- a/upload/lang/English/userlist.php
+++ b/upload/lang/English/userlist.php
@@ -3,10 +3,10 @@
 // Language definitions used in userlist.php
 $lang_ul = array(
 
-'User find legend'		=>	'Find and sort users',
-'User search info'		=>	'Enter a username to search for and/or a user group to filter by. The username field can be left blank. Use the wildcard character * for partial matches. Sort users by name, date registered or number of posts and in ascending/descending order.',
-'User group'			=>	'User group',
-'No of posts'			=>	'No. of posts',
-'All users'				=>	'All'
+'User find legend'	=>	'Find and sort users',
+'User search info'	=>	'Enter a username to search for and/or a user group to filter by. The username field can be left blank. Use the wildcard character * for partial matches. Sort users by name, date registered or number of posts and in ascending/descending order.',
+'User group'		=>	'User group',
+'No of posts'		=>	'Number of posts',
+'All users'			=>	'All'
 
 );
diff --git a/upload/lang/index.html b/upload/lang/index.html
index 2db9a3c..89337b2 100644
--- a/upload/lang/index.html
+++ b/upload/lang/index.html
@@ -1,8 +1 @@
-<html>
-<head>
-<title>.</title>
-</head>
-<body>
-.
-</body>
-</html>
\ No newline at end of file
+<html><head><title>.</title></head><body>.</body></html>
diff --git a/upload/login.php b/upload/login.php
index ff4b614..0f899c4 100644
--- a/upload/login.php
+++ b/upload/login.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 if (isset($_GET['action']))
 	define('PUN_QUIET_VISIT', 1);
@@ -37,47 +20,58 @@ $action = isset($_GET['action']) ? $_GET['action'] : null;
 
 if (isset($_POST['form_sent']) && $action == 'in')
 {
-	$form_username = trim($_POST['req_username']);
-	$form_password = trim($_POST['req_password']);
+	$form_username = pun_trim($_POST['req_username']);
+	$form_password = pun_trim($_POST['req_password']);
 	$save_pass = isset($_POST['save_pass']);
 
 	$username_sql = ($db_type == 'mysql' || $db_type == 'mysqli' || $db_type == 'mysql_innodb' || $db_type == 'mysqli_innodb') ? 'username=\''.$db->escape($form_username).'\'' : 'LOWER(username)=LOWER(\''.$db->escape($form_username).'\')';
 
-	$result = $db->query('SELECT id, group_id, password FROM '.$db->prefix.'users WHERE '.$username_sql) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
-	list($user_id, $group_id, $db_password_hash) = $db->fetch_row($result);
+	$result = $db->query('SELECT * FROM '.$db->prefix.'users WHERE '.$username_sql) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+	$cur_user = $db->fetch_assoc($result);
 
 	$authorized = false;
 
-	if (!empty($db_password_hash))
+	if (!empty($cur_user['password']))
 	{
-		$sha1_in_db = (strlen($db_password_hash) == 40) ? true : false;
-		$sha1_available = (function_exists('sha1') || function_exists('mhash')) ? true : false;
+		$form_password_hash = pun_hash($form_password); // Will result in a SHA-1 hash
 
-		$form_password_hash = pun_hash($form_password);	// This could result in either an SHA-1 or an MD5 hash (depends on $sha1_available)
+		// If there is a salt in the database we have upgraded from 1.3-legacy though havent yet logged in
+		if (!empty($cur_user['salt']))
+		{
+			if (sha1($cur_user['salt'].sha1($form_password)) == $cur_user['password']) // 1.3 used sha1(salt.sha1(pass))
+			{
+				$authorized = true;
 
-		if ($sha1_in_db && $sha1_available && $db_password_hash == $form_password_hash)
-			$authorized = true;
-		else if (!$sha1_in_db && $db_password_hash == md5($form_password))
+				$db->query('UPDATE '.$db->prefix.'users SET password=\''.$form_password_hash.'\', salt=NULL WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
+			}
+		}
+		// If the length isn't 40 then the password isn't using sha1, so it must be md5 from 1.2
+		else if (strlen($cur_user['password']) != 40)
 		{
-			$authorized = true;
+			if (md5($form_password) == $cur_user['password'])
+			{
+				$authorized = true;
 
-			if ($sha1_available)	// There's an MD5 hash in the database, but SHA1 hashing is available, so we update the DB
-				$db->query('UPDATE '.$db->prefix.'users SET password=\''.$form_password_hash.'\' WHERE id='.$user_id) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
+				$db->query('UPDATE '.$db->prefix.'users SET password=\''.$form_password_hash.'\' WHERE id='.$cur_user['id']) or error('Unable to update user password', __FILE__, __LINE__, $db->error());
+			}
 		}
+		// Otherwise we should have a normal sha1 password
+		else
+			$authorized = ($cur_user['password'] == $form_password_hash);
 	}
 
 	if (!$authorized)
 		message($lang_login['Wrong user/pass'].' <a href="login.php?action=forget">'.$lang_login['Forgotten pass'].'</a>');
 
 	// Update the status if this is the first time the user logged in
-	if ($group_id == PUN_UNVERIFIED)
-		$db->query('UPDATE '.$db->prefix.'users SET group_id='.$pun_config['o_default_user_group'].' WHERE id='.$user_id) or error('Unable to update user status', __FILE__, __LINE__, $db->error());
+	if ($cur_user['group_id'] == PUN_UNVERIFIED)
+		$db->query('UPDATE '.$db->prefix.'users SET group_id='.$pun_config['o_default_user_group'].' WHERE id='.$cur_user['id']) or error('Unable to update user status', __FILE__, __LINE__, $db->error());
 
 	// Remove this users guest entry from the online list
 	$db->query('DELETE FROM '.$db->prefix.'online WHERE ident=\''.$db->escape(get_remote_address()).'\'') or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
 
 	$expire = ($save_pass == '1') ? time() + 1209600 : time() + $pun_config['o_timeout_visit'];
-	pun_setcookie($user_id, $form_password_hash, $expire);
+	pun_setcookie($cur_user['id'], $form_password_hash, $expire);
 
 	// Reset tracked topics
 	set_tracked_topics(null);
@@ -94,7 +88,7 @@ else if ($action == 'out')
 		exit;
 	}
 
-	// Remove user from "users online" list.
+	// Remove user from "users online" list
 	$db->query('DELETE FROM '.$db->prefix.'online WHERE user_id='.$pun_user['id']) or error('Unable to delete from online list', __FILE__, __LINE__, $db->error());
 
 	// Update last_visit (make sure there's something to update it with)
@@ -114,61 +108,92 @@ else if ($action == 'forget' || $action == 'forget_2')
 
 	if (isset($_POST['form_sent']))
 	{
+		// Start with a clean slate
+		$errors = array();
+
 		require PUN_ROOT.'include/email.php';
 
-		// Validate the email-address
+		// Validate the email address
 		$email = strtolower(trim($_POST['req_email']));
 		if (!is_valid_email($email))
-			message($lang_common['Invalid e-mail']);
+			$errors[] = $lang_common['Invalid email'];
 
-		$result = $db->query('SELECT id, username, last_email_sent FROM '.$db->prefix.'users WHERE email=\''.$db->escape($email).'\'') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
-
-		if ($db->num_rows($result))
+		// Did everything go according to plan?
+		if (empty($errors))
 		{
-			// Load the "activate password" template
-			$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/activate_password.tpl'));
+			$result = $db->query('SELECT id, username, last_email_sent FROM '.$db->prefix.'users WHERE email=\''.$db->escape($email).'\'') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
 
-			// The first row contains the subject
-			$first_crlf = strpos($mail_tpl, "\n");
-			$mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8));
-			$mail_message = trim(substr($mail_tpl, $first_crlf));
+			if ($db->num_rows($result))
+			{
+				// Load the "activate password" template
+				$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/activate_password.tpl'));
 
-			// Do the generic replacements first (they apply to all e-mails sent out here)
-			$mail_message = str_replace('<base_url>', $pun_config['o_base_url'].'/', $mail_message);
-			$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message);
+				// The first row contains the subject
+				$first_crlf = strpos($mail_tpl, "\n");
+				$mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8));
+				$mail_message = trim(substr($mail_tpl, $first_crlf));
 
-			// Loop through users we found
-			while ($cur_hit = $db->fetch_assoc($result))
-			{
-				if ($cur_hit['last_email_sent'] != '' && (time() - $cur_hit['last_email_sent']) < 3600 && (time() - $cur_hit['last_email_sent']) >= 0)
-					message($lang_login['Email flood']);
+				// Do the generic replacements first (they apply to all emails sent out here)
+				$mail_message = str_replace('<base_url>', $pun_config['o_base_url'].'/', $mail_message);
+				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message);
 
-				// Generate a new password and a new password activation code
-				$new_password = random_pass(8);
-				$new_password_key = random_pass(8);
+				// Loop through users we found
+				while ($cur_hit = $db->fetch_assoc($result))
+				{
+					if ($cur_hit['last_email_sent'] != '' && (time() - $cur_hit['last_email_sent']) < 3600 && (time() - $cur_hit['last_email_sent']) >= 0)
+						message($lang_login['Email flood'], true);
 
-				$db->query('UPDATE '.$db->prefix.'users SET activate_string=\''.pun_hash($new_password).'\', activate_key=\''.$new_password_key.'\', last_email_sent = '.time().' WHERE id='.$cur_hit['id']) or error('Unable to update activation data', __FILE__, __LINE__, $db->error());
+					// Generate a new password and a new password activation code
+					$new_password = random_pass(8);
+					$new_password_key = random_pass(8);
 
-				// Do the user specific replacements to the template
-				$cur_mail_message = str_replace('<username>', $cur_hit['username'], $mail_message);
-				$cur_mail_message = str_replace('<activation_url>', $pun_config['o_base_url'].'/profile.php?id='.$cur_hit['id'].'&action=change_pass&key='.$new_password_key, $cur_mail_message);
-				$cur_mail_message = str_replace('<new_password>', $new_password, $cur_mail_message);
+					$db->query('UPDATE '.$db->prefix.'users SET activate_string=\''.pun_hash($new_password).'\', activate_key=\''.$new_password_key.'\', last_email_sent = '.time().' WHERE id='.$cur_hit['id']) or error('Unable to update activation data', __FILE__, __LINE__, $db->error());
 
-				pun_mail($email, $mail_subject, $cur_mail_message);
-			}
+					// Do the user specific replacements to the template
+					$cur_mail_message = str_replace('<username>', $cur_hit['username'], $mail_message);
+					$cur_mail_message = str_replace('<activation_url>', $pun_config['o_base_url'].'/profile.php?id='.$cur_hit['id'].'&action=change_pass&key='.$new_password_key, $cur_mail_message);
+					$cur_mail_message = str_replace('<new_password>', $new_password, $cur_mail_message);
 
-			message($lang_login['Forget mail'].' <a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>.');
-		}
-		else
-			message($lang_login['No e-mail match'].' '.htmlspecialchars($email).'.');
-	}
+					pun_mail($email, $mail_subject, $cur_mail_message);
+				}
 
+				message($lang_login['Forget mail'].' <a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>.', true);
+			}
+			else
+				$errors[] = $lang_login['No email match'].' '.htmlspecialchars($email).'.';
+			}
+		}
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_login['Request pass'];
-	$required_fields = array('req_email' => $lang_common['E-mail']);
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_login['Request pass']);
+	$required_fields = array('req_email' => $lang_common['Email']);
 	$focus_element = array('request_pass', 'req_email');
+	define ('PUN_ACTIVE_PAGE', 'login');
 	require PUN_ROOT.'header.php';
 
+// If there are errors, we display them
+if (!empty($errors))
+{
+
+?>
+<div id="posterror" class="block">
+	<h2><span><?php echo $lang_login['New password errors'] ?></span></h2>
+	<div class="box">
+		<div class="inbox error-info">
+			<p><?php echo $lang_login['New passworderrors info'] ?></p>
+			<ul class="error-list">
+<?php
+
+	foreach ($errors as $cur_error)
+		echo "\t\t\t\t".'<li><strong>'.$cur_error.'</strong></li>'."\n";
+?>
+			</ul>
+		</div>
+	</div>
+</div>
+
+<?php
+
+}
 ?>
 <div class="blockform">
 	<h2><span><?php echo $lang_login['Request pass'] ?></span></h2>
@@ -179,12 +204,12 @@ else if ($action == 'forget' || $action == 'forget_2')
 					<legend><?php echo $lang_login['Request pass legend'] ?></legend>
 					<div class="infldset">
 						<input type="hidden" name="form_sent" value="1" />
-						<input id="req_email" type="text" name="req_email" size="50" maxlength="50" />
+						<label class="required"><strong><?php echo $lang_common['Email'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br /><input id="req_email" type="text" name="req_email" size="50" maxlength="80" /><br /></label>
 						<p><?php echo $lang_login['Request pass info'] ?></p>
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="request_pass" value="<?php echo $lang_common['Submit'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="request_pass" value="<?php echo $lang_common['Submit'] ?>" /><?php if (empty($errors)): ?> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a><?php endif; ?></p>
 		</form>
 	</div>
 </div>
@@ -198,11 +223,12 @@ if (!$pun_user['is_guest'])
 	header('Location: index.php');
 
 // Try to determine if the data in HTTP_REFERER is valid (if not, we redirect to index.php after login)
-$redirect_url = (isset($_SERVER['HTTP_REFERER']) && preg_match('#^'.preg_quote($pun_config['o_base_url']).'/(.*?)\.php#i', $_SERVER['HTTP_REFERER'])) ? htmlspecialchars($_SERVER['HTTP_REFERER']) : 'index.php';
+$redirect_url = (isset($_SERVER['HTTP_REFERER']) && preg_match('#^'.preg_quote($pun_config['o_base_url']).'/(.*?)\.php#i', $_SERVER['HTTP_REFERER'])) ? htmlspecialchars($_SERVER['HTTP_REFERER']) : $pun_config['o_base_url'].'/index.php';
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_common['Login'];
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_common['Login']);
 $required_fields = array('req_username' => $lang_common['Username'], 'req_password' => $lang_common['Password']);
 $focus_element = array('login', 'req_username');
+define('PUN_ACTIVE_PAGE', 'login');
 require PUN_ROOT.'header.php';
 
 ?>
@@ -213,23 +239,22 @@ require PUN_ROOT.'header.php';
 			<div class="inform">
 				<fieldset>
 					<legend><?php echo $lang_login['Login legend'] ?></legend>
-						<div class="infldset">
-							<input type="hidden" name="form_sent" value="1" />
-							<input type="hidden" name="redirect_url" value="<?php echo $redirect_url ?>" />
-							<label class="conl"><strong><?php echo $lang_common['Username'] ?></strong><br /><input type="text" name="req_username" size="25" maxlength="25" tabindex="1" /><br /></label>
-							<label class="conl"><strong><?php echo $lang_common['Password'] ?></strong><br /><input type="password" name="req_password" size="16" maxlength="16" tabindex="2" /><br /></label>
-
-							<div class="rbox clearb">
-								<label><input type="checkbox" name="save_pass" value="1" tabindex="3" /><?php echo $lang_login['Remember me'] ?> <br /></label>
-							</div>
-
-							<p class="clearb"><?php echo $lang_login['Login info'] ?></p>
-							<p><a href="register.php" tabindex="4"><?php echo $lang_login['Not registered'] ?></a>&nbsp;&nbsp;
-							<a href="login.php?action=forget" tabindex="5"><?php echo $lang_login['Forgotten pass'] ?></a></p>
+					<div class="infldset">
+						<input type="hidden" name="form_sent" value="1" />
+						<input type="hidden" name="redirect_url" value="<?php echo $redirect_url ?>" />
+						<label class="conl required"><strong><?php echo $lang_common['Username'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br /><input type="text" name="req_username" size="25" maxlength="25" tabindex="1" /><br /></label>
+						<label class="conl required"><strong><?php echo $lang_common['Password'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br /><input type="password" name="req_password" size="25" tabindex="2" /><br /></label>
+
+						<div class="rbox clearb">
+							<label><input type="checkbox" name="save_pass" value="1" tabindex="3" /><?php echo $lang_login['Remember me'] ?><br /></label>
 						</div>
+
+						<p class="clearb"><?php echo $lang_login['Login info'] ?></p>
+						<p class="actions"><span><a href="register.php" tabindex="4"><?php echo $lang_login['Not registered'] ?></a></span> <span><a href="login.php?action=forget" tabindex="5"><?php echo $lang_login['Forgotten pass'] ?></a></span></p>
+					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="login" value="<?php echo $lang_common['Login'] ?>" tabindex="3" /></p>
+			<p class="buttons"><input type="submit" name="login" value="<?php echo $lang_common['Login'] ?>" tabindex="3" /></p>
 		</form>
 	</div>
 </div>
diff --git a/upload/misc.php b/upload/misc.php
index 1dc3ec8..31a82b3 100644
--- a/upload/misc.php
+++ b/upload/misc.php
@@ -1,27 +1,10 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 if (isset($_GET['action']))
 	define('PUN_QUIET_VISIT', 1);
@@ -44,15 +27,16 @@ if ($action == 'rules')
 	// Load the register.php language file
 	require PUN_ROOT.'lang/'.$pun_user['language'].'/register.php';
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_register['Forum rules'];
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_register['Forum rules']);
+	define('PUN_ACTIVE_PAGE', 'rules');
 	require PUN_ROOT.'header.php';
 
 ?>
-<div class="block">
-	<h2><span><?php echo $lang_register['Forum rules'] ?></span></h2>
+<div id="rules" class="block">
+	<div class="hd"><h2><span><?php echo $lang_register['Forum rules'] ?></span></h2></div>
 	<div class="box">
-		<div class="inbox">
-			<p><?php echo $pun_config['o_rules_message'] ?></p>
+		<div id="rules-block" class="inbox">
+			<div class="usercontent"><?php echo $pun_config['o_rules_message'] ?></div>
 		</div>
 	</div>
 </div>
@@ -82,7 +66,7 @@ else if ($action == 'markforumread')
 	if ($pun_user['is_guest'])
 		message($lang_common['No permission']);
 
-	$fid = intval($_GET['fid']);
+	$fid = isset($_GET['fid']) ? intval($_GET['fid']) : 0;
 	if ($fid < 1)
 		message($lang_common['Bad request']);
 
@@ -110,7 +94,7 @@ else if (isset($_GET['email']))
 	list($recipient, $recipient_email, $email_setting) = $db->fetch_row($result);
 
 	if ($email_setting == 2 && !$pun_user['is_admmod'])
-		message($lang_misc['Form e-mail disabled']);
+		message($lang_misc['Form email disabled']);
 
 
 	if (isset($_POST['form_sent']))
@@ -120,22 +104,22 @@ else if (isset($_GET['email']))
 		$message = pun_trim($_POST['req_message']);
 
 		if ($subject == '')
-			message($lang_misc['No e-mail subject']);
+			message($lang_misc['No email subject']);
 		else if ($message == '')
-			message($lang_misc['No e-mail message']);
-		else if (strlen($message) > 65535)
-			message($lang_misc['Too long e-mail message']);
+			message($lang_misc['No email message']);
+		else if (pun_strlen($message) > PUN_MAX_POSTSIZE)
+			message($lang_misc['Too long email message']);
 
 		if ($pun_user['last_email_sent'] != '' && (time() - $pun_user['last_email_sent']) < $pun_user['g_email_flood'] && (time() - $pun_user['last_email_sent']) >= 0)
 			message(sprintf($lang_misc['Email flood'], $pun_user['g_email_flood']));
 
-		// Load the "form e-mail" template
+		// Load the "form email" template
 		$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/form_email.tpl'));
 
 		// The first row contains the subject
 		$first_crlf = strpos($mail_tpl, "\n");
-		$mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8));
-		$mail_message = trim(substr($mail_tpl, $first_crlf));
+		$mail_subject = pun_trim(substr($mail_tpl, 8, $first_crlf-8));
+		$mail_message = pun_trim(substr($mail_tpl, $first_crlf));
 
 		$mail_subject = str_replace('<mail_subject>', $subject, $mail_subject);
 		$mail_message = str_replace('<sender>', $pun_user['username'], $mail_message);
@@ -149,38 +133,39 @@ else if (isset($_GET['email']))
 
 		$db->query('UPDATE '.$db->prefix.'users SET last_email_sent='.time().' WHERE id='.$pun_user['id']) or error('Unable to update user', __FILE__, __LINE__, $db->error());
 
-		redirect(htmlspecialchars($_POST['redirect_url']), $lang_misc['E-mail sent redirect']);
+		redirect(htmlspecialchars($_POST['redirect_url']), $lang_misc['Email sent redirect']);
 	}
 
 
-	// Try to determine if the data in HTTP_REFERER is valid (if not, we redirect to the users profile after the e-mail is sent)
+	// Try to determine if the data in HTTP_REFERER is valid (if not, we redirect to the users profile after the email is sent)
 	$redirect_url = (isset($_SERVER['HTTP_REFERER']) && preg_match('#^'.preg_quote($pun_config['o_base_url']).'/(.*?)\.php#i', $_SERVER['HTTP_REFERER'])) ? htmlspecialchars($_SERVER['HTTP_REFERER']) : 'index.php';
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_misc['Send e-mail to'].' '.pun_htmlspecialchars($recipient);
-	$required_fields = array('req_subject' => $lang_misc['E-mail subject'], 'req_message' => $lang_misc['E-mail message']);
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_misc['Send email to'].' '.pun_htmlspecialchars($recipient));
+	$required_fields = array('req_subject' => $lang_misc['Email subject'], 'req_message' => $lang_misc['Email message']);
 	$focus_element = array('email', 'req_subject');
+	define('PUN_ACTIVE_PAGE', 'index');
 	require PUN_ROOT.'header.php';
 
 ?>
-<div class="blockform">
-	<h2><span><?php echo $lang_misc['Send e-mail to'] ?> <?php echo pun_htmlspecialchars($recipient) ?></span></h2>
+<div id="emailform" class="blockform">
+	<h2><span><?php echo $lang_misc['Send email to'] ?> <?php echo pun_htmlspecialchars($recipient) ?></span></h2>
 	<div class="box">
 		<form id="email" method="post" action="misc.php?email=<?php echo $recipient_id ?>" onsubmit="this.submit.disabled=true;if(process_form(this)){return true;}else{this.submit.disabled=false;return false;}">
 			<div class="inform">
 				<fieldset>
-					<legend><?php echo $lang_misc['Write e-mail'] ?></legend>
+					<legend><?php echo $lang_misc['Write email'] ?></legend>
 					<div class="infldset txtarea">
 						<input type="hidden" name="form_sent" value="1" />
 						<input type="hidden" name="redirect_url" value="<?php echo $redirect_url ?>" />
-						<label><strong><?php echo $lang_misc['E-mail subject'] ?></strong><br />
+						<label class="required"><strong><?php echo $lang_misc['Email subject'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br />
 						<input class="longinput" type="text" name="req_subject" size="75" maxlength="70" tabindex="1" /><br /></label>
-						<label><strong><?php echo $lang_misc['E-mail message'] ?></strong><br />
+						<label class="required"><strong><?php echo $lang_misc['Email message'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br />
 						<textarea name="req_message" rows="10" cols="75" tabindex="2"></textarea><br /></label>
-						<p><?php echo $lang_misc['E-mail disclosure note'] ?></p>
+						<p><?php echo $lang_misc['Email disclosure note'] ?></p>
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" tabindex="3" accesskey="s" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" tabindex="3" accesskey="s" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
@@ -205,7 +190,7 @@ else if (isset($_GET['report']))
 		$reason = pun_linebreaks(pun_trim($_POST['req_reason']));
 		if ($reason == '')
 			message($lang_misc['No reason']);
-			
+
 		if ($pun_user['last_email_sent'] != '' && (time() - $pun_user['last_email_sent']) < $pun_user['g_email_flood'] && (time() - $pun_user['last_email_sent']) >= 0)
 			message(sprintf($lang_misc['Report flood'], $pun_user['g_email_flood']));
 
@@ -224,15 +209,15 @@ else if (isset($_GET['report']))
 		list($subject, $forum_id) = $db->fetch_row($result);
 
 		// Should we use the internal report handling?
-		if ($pun_config['o_report_method'] == 0 || $pun_config['o_report_method'] == 2)
+		if ($pun_config['o_report_method'] == '0' || $pun_config['o_report_method'] == '2')
 			$db->query('INSERT INTO '.$db->prefix.'reports (post_id, topic_id, forum_id, reported_by, created, message) VALUES('.$post_id.', '.$topic_id.', '.$forum_id.', '.$pun_user['id'].', '.time().', \''.$db->escape($reason).'\')' ) or error('Unable to create report', __FILE__, __LINE__, $db->error());
 
-		// Should we e-mail the report?
-		if ($pun_config['o_report_method'] == 1 || $pun_config['o_report_method'] == 2)
+		// Should we email the report?
+		if ($pun_config['o_report_method'] == '1' || $pun_config['o_report_method'] == '2')
 		{
 			// We send it to the complete mailing-list in one swoop
 			if ($pun_config['o_mailing_list'] != '')
-			{			
+			{
 				$mail_subject = sprintf($lang_common['Report notification'], $forum_id, $subject);
 				$mail_message = sprintf($lang_common['Report message 1'], $pun_user['username'], $pun_config['o_base_url'].'/viewtopic.php?pid='.$post_id.'#p'.$post_id)."\n";
 				$mail_message .= sprintf($lang_common['Report message 2'], $reason)."\n";
@@ -243,20 +228,38 @@ else if (isset($_GET['report']))
 				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
 			}
 		}
-		
+
 		$db->query('UPDATE '.$db->prefix.'users SET last_email_sent='.time().' WHERE id='.$pun_user['id']) or error('Unable to update user', __FILE__, __LINE__, $db->error());
 
 		redirect('viewtopic.php?pid='.$post_id.'#p'.$post_id, $lang_misc['Report redirect']);
 	}
 
+	// Fetch some info about the post, the topic and the forum
+	$result = $db->query('SELECT f.id AS fid, f.forum_name, t.id AS tid, t.subject FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND p.id='.$post_id) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
+	if (!$db->num_rows($result))
+		message($lang_common['Bad request']);
+
+	$cur_post = $db->fetch_assoc($result);
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_misc['Report post'];
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_misc['Report post']);
 	$required_fields = array('req_reason' => $lang_misc['Reason']);
 	$focus_element = array('report', 'req_reason');
+	define('PUN_ACTIVE_PAGE', 'index');
 	require PUN_ROOT.'header.php';
 
 ?>
-<div class="blockform">
+<div class="linkst">
+	<div class="inbox">
+		<ul class="crumbs">
+			<li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewforum.php?id=<?php echo $cur_post['fid'] ?>"><?php echo pun_htmlspecialchars($cur_post['forum_name']) ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewtopic.php?pid=<?php echo $post_id ?>#p<?php echo $post_id ?>"><?php echo pun_htmlspecialchars($cur_post['subject']) ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_misc['Report post'] ?></strong></li>
+		</ul>
+	</div>
+</div>
+
+<div id="reportform" class="blockform">
 	<h2><span><?php echo $lang_misc['Report post'] ?></span></h2>
 	<div class="box">
 		<form id="report" method="post" action="misc.php?report=<?php echo $post_id ?>" onsubmit="this.submit.disabled=true;if(process_form(this)){return true;}else{this.submit.disabled=false;return false;}">
@@ -265,11 +268,11 @@ else if (isset($_GET['report']))
 					<legend><?php echo $lang_misc['Reason desc'] ?></legend>
 					<div class="infldset txtarea">
 						<input type="hidden" name="form_sent" value="1" />
-						<label><strong><?php echo $lang_misc['Reason'] ?></strong><br /><textarea name="req_reason" rows="5" cols="60"></textarea><br /></label>
+						<label class="required"><strong><?php echo $lang_misc['Reason'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br /><textarea name="req_reason" rows="5" cols="60"></textarea><br /></label>
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" accesskey="s" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" accesskey="s" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
diff --git a/upload/moderate.php b/upload/moderate.php
index cc5b286..ea909f6 100644
--- a/upload/moderate.php
+++ b/upload/moderate.php
@@ -1,34 +1,17 @@
 <?php
-/***********************************************************************
-
-  Copyright (C) 2002-2005  Rickard Andersson (rickard@punbb.org)
-
-  This file is part of PunBB.
-
-  PunBB 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.
-
-  PunBB 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., 59 Temple Place, Suite 330, Boston,
-  MA  02111-1307  USA
-
-************************************************************************/
 
+/**
+ * Copyright (C) 2008-2010 FluxBB
+ * based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
+ * License: http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
+ */
 
 define('PUN_ROOT', './');
 require PUN_ROOT.'include/common.php';
 
 
 // This particular function doesn't require forum-based moderator access. It can be used
-// by all moderators and admins.
+// by all moderators and admins
 if (isset($_GET['get_host']))
 {
 	if (!$pun_user['is_admmod'])
@@ -50,7 +33,10 @@ if (isset($_GET['get_host']))
 		$ip = $db->result($result);
 	}
 
-	message('The IP address is: '.$ip.'<br />The host name is: '.@gethostbyaddr($ip).'<br /><br /><a href="admin_users.php?show_users='.$ip.'">Show more users for this IP</a>');
+	// Load the misc.php language file
+	require PUN_ROOT.'lang/'.$pun_user['language'].'/misc.php';
+
+	message(sprintf($lang_misc['Host info 1'], $ip).'<br />'.sprintf($lang_misc['Host info 2'], @gethostbyaddr($ip)).'<br /><br /><a href="admin_users.php?show_users='.$ip.'">'.$lang_misc['Show more users'].'</a>');
 }
 
 
@@ -75,7 +61,7 @@ if (!$pun_user['is_guest'])
 require PUN_ROOT.'lang/'.$pun_user['language'].'/misc.php';
 
 
-// All other topic moderation features require a topic id in GET
+// All other topic moderation features require a topic ID in GET
 if (isset($_GET['tid']))
 {
 	$tid = intval($_GET['tid']);
@@ -83,7 +69,7 @@ if (isset($_GET['tid']))
 		message($lang_common['Bad request']);
 
 	// Fetch some info about the topic
-	$result = $db->query('SELECT t.subject, t.num_replies, f.id AS forum_id, forum_name FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'subscriptions AS s ON (t.id=s.topic_id AND s.user_id='.$pun_user['id'].') LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$fid.' AND t.id='.$tid.' AND t.moved_to IS NULL') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
+	$result = $db->query('SELECT t.subject, t.num_replies, t.first_post_id, f.id AS forum_id, forum_name FROM '.$db->prefix.'topics AS t INNER JOIN '.$db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$db->prefix.'subscriptions AS s ON (t.id=s.topic_id AND s.user_id='.$pun_user['id'].') LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$fid.' AND t.id='.$tid.' AND t.moved_to IS NULL') or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
 	if (!$db->num_rows($result))
 		message($lang_common['Bad request']);
 
@@ -92,7 +78,7 @@ if (isset($_GET['tid']))
 	// Delete one or more posts
 	if (isset($_POST['delete_posts']) || isset($_POST['delete_posts_comply']))
 	{
-		$posts = $_POST['posts'];
+		$posts = isset($_POST['posts']) ? $_POST['posts'] : array();
 		if (empty($posts))
 			message($lang_misc['No posts selected']);
 
@@ -131,7 +117,8 @@ if (isset($_GET['tid']))
 		}
 
 
-		$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_misc['Moderate'];
+		$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_misc['Moderate']);
+		define('PUN_ACTIVE_PAGE', 'index');
 		require PUN_ROOT.'header.php';
 
 ?>
@@ -148,7 +135,7 @@ if (isset($_GET['tid']))
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="delete_posts_comply" value="<?php echo $lang_misc['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="delete_posts_comply" value="<?php echo $lang_misc['Delete'] ?>" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
@@ -158,7 +145,7 @@ if (isset($_GET['tid']))
 	}
 	else if (isset($_POST['split_posts']) || isset($_POST['split_posts_comply']))
 	{
-		$posts = $_POST['posts'];
+		$posts = isset($_POST['posts']) ? $_POST['posts'] : array();
 		if (empty($posts))
 			message($lang_misc['No posts selected']);
 
@@ -215,25 +202,27 @@ if (isset($_GET['tid']))
 			redirect('viewtopic.php?id='.$new_tid, $lang_misc['Split posts redirect']);
 		}
 
-		$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_misc['Moderate'];
+		$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_misc['Moderate']);
+		$focus_element = array('subject','new_subject');
+		define('PUN_ACTIVE_PAGE', 'index');
 		require PUN_ROOT.'header.php';
 
 ?>
 <div class="blockform">
 	<h2><span><?php echo $lang_misc['Split posts'] ?></span></h2>
 	<div class="box">
-		<form method="post" action="moderate.php?fid=<?php echo $fid ?>&amp;tid=<?php echo $tid ?>">
+		<form id="subject" method="post" action="moderate.php?fid=<?php echo $fid ?>&amp;tid=<?php echo $tid ?>">
 			<div class="inform">
 				<fieldset>
 					<legend><?php echo $lang_misc['Confirm split legend'] ?></legend>
 					<div class="infldset">
 						<input type="hidden" name="posts" value="<?php echo implode(',', array_map('intval', array_keys($posts))) ?>" />
-						<label><strong><?php echo $lang_misc['New subject'] ?></strong><br /><input type="text" name="new_subject" size="80" maxlength="70" /><br /></label>
+						<label class="required"><strong><?php echo $lang_misc['New subject'] ?> <span><?php echo $lang_common['Required'] ?></span></strong><br /><input type="text" name="new_subject" size="80" maxlength="70" /><br /></label>
 						<p><?php echo $lang_misc['Split posts comply'] ?></p>
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="split_posts_comply" value="<?php echo $lang_misc['Split'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="split_posts_comply" value="<?php echo $lang_misc['Split'] ?>" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
@@ -249,31 +238,37 @@ if (isset($_GET['tid']))
 	require PUN_ROOT.'lang/'.$pun_user['language'].'/topic.php';
 
 	// Used to disable the Move and Delete buttons if there are no replies to this topic
-	$button_status = ($cur_topic['num_replies'] == 0) ? ' disabled' : '';
+	$button_status = ($cur_topic['num_replies'] == 0) ? ' disabled="disabled"' : '';
 
 
 	// Determine the post offset (based on $_GET['p'])
 	$num_pages = ceil(($cur_topic['num_replies'] + 1) / $pun_user['disp_posts']);
 
-	$p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : $_GET['p'];
+	$p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
 	$start_from = $pun_user['disp_posts'] * ($p - 1);
 
 	// Generate paging links
-	$paging_links = $lang_common['Pages'].': '.paginate($num_pages, $p, 'moderate.php?fid='.$fid.'&amp;tid='.$tid);
+	$paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'moderate.php?fid='.$fid.'&amp;tid='.$tid);
 
 
 	if ($pun_config['o_censoring'] == '1')
 		$cur_topic['subject'] = censor_words($cur_topic['subject']);
 
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$cur_topic['subject'];
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), pun_htmlspecialchars($cur_topic['forum_name']), pun_htmlspecialchars($cur_topic['subject']));
+	define('PUN_ACTIVE_PAGE', 'index');
 	require PUN_ROOT.'header.php';
 
 ?>
 <div class="linkst">
-	<div class="inbox">
+	<div class="inbox crumbsplus">
+		<ul class="crumbs">
+			<li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewforum.php?id=<?php echo $fid ?>"><?php echo pun_htmlspecialchars($cur_topic['forum_name']) ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewtopic.php?id=<?php echo $tid ?>"><?php echo pun_htmlspecialchars($cur_topic['subject']) ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_misc['Moderate'] ?></strong></li>
+		</ul>
 		<p class="pagelink conl"><?php echo $paging_links ?></p>
-		<ul><li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li><li>&nbsp;&raquo;&nbsp;<a href="viewforum.php?id=<?php echo $fid ?>"><?php echo pun_htmlspecialchars($cur_topic['forum_name']) ?></a></li><li>&nbsp;&raquo;&nbsp;<?php echo pun_htmlspecialchars($cur_topic['subject']) ?></li></ul>
 		<div class="clearer"></div>
 	</div>
 </div>
@@ -283,8 +278,7 @@ if (isset($_GET['tid']))
 
 	require PUN_ROOT.'include/parser.php';
 
-	$bg_switch = true;	// Used for switching background color in posts
-	$post_count = 0;	// Keep track of post numbers
+	$post_count = 0; // Keep track of post numbers
 
 	// Retrieve the posts (and their respective poster)
 	$result = $db->query('SELECT u.title, u.num_posts, g.g_id, g.g_user_title, p.id, p.poster, p.poster_id, p.message, p.hide_smilies, p.posted, p.edited, p.edited_by FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'users AS u ON u.id=p.poster_id INNER JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE p.topic_id='.$tid.' ORDER BY p.id LIMIT '.$start_from.','.$pun_user['disp_posts'], true) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
@@ -293,7 +287,7 @@ if (isset($_GET['tid']))
 	{
 		$post_count++;
 
-		// If the poster is a registered user.
+		// If the poster is a registered user
 		if ($cur_post['poster_id'] > 1)
 		{
 			if ($pun_user['g_view_users'] == '1')
@@ -315,35 +309,35 @@ if (isset($_GET['tid']))
 			$user_title = $lang_topic['Guest'];
 		}
 
-		// Switch the background color for every message.
-		$bg_switch = ($bg_switch) ? $bg_switch = false : $bg_switch = true;
-		$vtbg = ($bg_switch) ? ' roweven' : ' rowodd';
-
 		// Perform the main parsing of the message (BBCode, smilies, censor words etc)
 		$cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
 
 ?>
 
-<div class="blockpost<?php echo $vtbg ?>">
-	<a name="<?php echo $cur_post['id'] ?>"></a>
-	<h2><span><span class="conr">#<?php echo ($start_from + $post_count) ?>&nbsp;</span><a href="viewtopic.php?pid=<?php echo $cur_post['id'].'#p'.$cur_post['id'] ?>"><?php echo format_time($cur_post['posted']) ?></a></span></h2>
+<div id="p<?php echo $cur_post['id'] ?>" class="blockpost<?php if($cur_post['id'] == $cur_topic['first_post_id']) echo ' firstpost' ?><?php echo ($post_count % 2 == 0) ? ' roweven' : ' rowodd' ?><?php if ($post_count == 1) echo ' blockpost1' ?>">
+	<h2><span><span class="conr">#<?php echo ($start_from + $post_count) ?></span> <a href="viewtopic.php?pid=<?php echo $cur_post['id'].'#p'.$cur_post['id'] ?>"><?php echo format_time($cur_post['posted']) ?></a></span></h2>
 	<div class="box">
 		<div class="inbox">
-			<div class="postleft">
-				<dl>
-					<dt><strong><?php echo $poster ?></strong></dt>
-					<dd><strong><?php echo $user_title ?></strong></dd>
-				</dl>
-			</div>
-			<div class="postright">
-				<h3 class="nosize"><?php echo $lang_common['Message'] ?></h3>
-				<div class="postmsg">
-					<?php echo $cur_post['message']."\n" ?>
-<?php if ($cur_post['edited'] != '') echo "\t\t\t\t\t".'<p class="postedit"><em>'.$lang_topic['Last edit'].' '.pun_htmlspecialchars($cur_post['edited_by']).' ('.format_time($cur_post['edited']).')</em></p>'."\n"; ?>
+			<div class="postbody">
+				<div class="postleft">
+					<dl>
+						<dt><strong><?php echo $poster ?></strong></dt>
+						<dd class="usertitle"><strong><?php echo $user_title ?></strong></dd>
+					</dl>
+				</div>
+				<div class="postright">
+					<h3 class="nosize"><?php echo $lang_common['Message'] ?></h3>
+					<div class="postmsg">
+						<?php echo $cur_post['message']."\n" ?>
+<?php if ($cur_post['edited'] != '') echo "\t\t\t\t\t\t".'<p class="postedit"><em>'.$lang_topic['Last edit'].' '.pun_htmlspecialchars($cur_post['edited_by']).' ('.format_time($cur_post['edited']).')</em></p>'."\n"; ?>
+					</div>
 				</div>
-				<?php if ($start_from + $post_count > 1) echo '<p class="multidelete"><label><strong>'.$lang_misc['Select'].'</strong>&nbsp;&nbsp;<input type="checkbox" name="posts['.$cur_post['id'].']" value="1" /></label></p>'."\n" ?>
 			</div>
-			<div class="clearer"></div>
+		</div>
+		<div class="inbox">
+			<div class="postfoot clearb">
+				<div class="postfootright"><?php echo ($cur_post['id'] != $cur_topic['first_post_id']) ? '<p class="multidelete"><label><strong>'.$lang_misc['Select'].'</strong>&#160;<input type="checkbox" name="posts['.$cur_post['id'].']" value="1" /></label></p>' : '<p>'.$lang_misc['Cannot select first'].'</p>' ?></div>
+			</div>
 		</div>
 	</div>
 </div>
@@ -356,10 +350,7 @@ if (isset($_GET['tid']))
 <div class="postlinksb">
 	<div class="inbox">
 		<p class="pagelink conl"><?php echo $paging_links ?></p>
-		<p class="conr">
-			<input type="submit" name="split_posts" value="<?php echo $lang_misc['Split'] ?>"<?php echo $button_status ?> />
-			<input type="submit" name="delete_posts" value="<?php echo $lang_misc['Delete'] ?>"<?php echo $button_status ?> />
-		</p>
+		<p class="conr modbuttons"><input type="submit" name="split_posts" value="<?php echo $lang_misc['Split'] ?>"<?php echo $button_status ?> /> <input type="submit" name="delete_posts" value="<?php echo $lang_misc['Delete'] ?>"<?php echo $button_status ?> /></p>
 		<div class="clearer"></div>
 	</div>
 </div>
@@ -371,7 +362,7 @@ if (isset($_GET['tid']))
 
 
 // Move one or more topics
-if (isset($_POST['move_topics']) || isset($_POST['move_topics_to']))
+if (isset($_REQUEST['move_topics']) || isset($_POST['move_topics_to']))
 {
 	if (isset($_POST['move_topics_to']))
 	{
@@ -391,7 +382,7 @@ if (isset($_POST['move_topics']) || isset($_POST['move_topics_to']))
 		if ($db->num_rows($result) != count($topics))
 			message($lang_common['Bad request']);
 
-		// Delete any redirect topics if there are any (only if we moved/copied the topic back to where it where it was once moved from)
+		// Delete any redirect topics if there are any (only if we moved/copied the topic back to where it was once moved from)
 		$db->query('DELETE FROM '.$db->prefix.'topics WHERE forum_id='.$move_to_forum.' AND moved_to IN('.implode(',',$topics).')') or error('Unable to delete redirect topics', __FILE__, __LINE__, $db->error());
 
 		// Move the topic(s)
@@ -400,7 +391,7 @@ if (isset($_POST['move_topics']) || isset($_POST['move_topics_to']))
 		// Should we create redirect topics?
 		if (isset($_POST['with_redirect']))
 		{
-			while (list(, $cur_topic) = @each($topics))
+			foreach ($topics as $cur_topic)
 			{
 				// Fetch info for the redirect topic
 				$result = $db->query('SELECT poster, subject, posted, last_post FROM '.$db->prefix.'topics WHERE id='.$cur_topic) or error('Unable to fetch topic info', __FILE__, __LINE__, $db->error());
@@ -411,8 +402,8 @@ if (isset($_POST['move_topics']) || isset($_POST['move_topics_to']))
 			}
 		}
 
-		update_forum($fid);				// Update the forum FROM which the topic was moved
-		update_forum($move_to_forum);	// Update the forum TO which the topic was moved
+		update_forum($fid); // Update the forum FROM which the topic was moved
+		update_forum($move_to_forum); // Update the forum TO which the topic was moved
 
 		$redirect_msg = (count($topics) > 1) ? $lang_misc['Move topics redirect'] : $lang_misc['Move topic redirect'];
 		redirect('viewforum.php?id='.$move_to_forum, $redirect_msg);
@@ -436,7 +427,12 @@ if (isset($_POST['move_topics']) || isset($_POST['move_topics_to']))
 		$action = 'single';
 	}
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / Moderate';
+	$result = $db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name FROM '.$db->prefix.'categories AS c INNER JOIN '.$db->prefix.'forums AS f ON c.id=f.cat_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND f.redirect_url IS NULL ORDER BY c.disp_position, c.id, f.disp_position') or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());
+	if ($db->num_rows($result) < 2)
+		message($lang_misc['Nowhere to move']);
+
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_misc['Moderate']);
+	define('PUN_ACTIVE_PAGE', 'index');
 	require PUN_ROOT.'header.php';
 
 ?>
@@ -453,12 +449,10 @@ if (isset($_POST['move_topics']) || isset($_POST['move_topics_to']))
 						<br /><select name="move_to_forum">
 <?php
 
-	$result = $db->query('SELECT c.id AS cid, c.cat_name, f.id AS fid, f.forum_name FROM '.$db->prefix.'categories AS c INNER JOIN '.$db->prefix.'forums AS f ON c.id=f.cat_id LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND f.redirect_url IS NULL ORDER BY c.disp_position, c.id, f.disp_position', true) or error('Unable to fetch category/forum list', __FILE__, __LINE__, $db->error());
-
 	$cur_category = 0;
 	while ($cur_forum = $db->fetch_assoc($result))
 	{
-		if ($cur_forum['cid'] != $cur_category)	// A new category since last iteration?
+		if ($cur_forum['cid'] != $cur_category) // A new category since last iteration?
 		{
 			if ($cur_category)
 				echo "\t\t\t\t\t\t\t".'</optgroup>'."\n";
@@ -481,7 +475,7 @@ if (isset($_POST['move_topics']) || isset($_POST['move_topics_to']))
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="move_topics_to" value="<?php echo $lang_misc['Move'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="move_topics_to" value="<?php echo $lang_misc['Move'] ?>" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
@@ -495,9 +489,13 @@ else if (isset($_POST['merge_topics']) || isset($_POST['merge_topics_comply']))
 {
 	if (isset($_POST['merge_topics_comply']))
 	{
-		if (isset($_POST['topics']))
-			$topics = array_map('intval', explode(',', $_POST['topics']));
-		else
+		confirm_referrer('moderate.php');
+
+		if (@preg_match('/[^0-9,]/', $_POST['topics']))
+			message($lang_common['Bad request']);
+
+		$topics = explode(',', $_POST['topics']);
+		if (count($topics) < 2)
 			message($lang_misc['Not enough topics selected']);
 
 		// Verify that the topic IDs are valid (moved topics can not be merged?)
@@ -544,34 +542,32 @@ else if (isset($_POST['merge_topics']) || isset($_POST['merge_topics_comply']))
 		update_forum($fid);
 		redirect('viewforum.php?id='.$fid, $lang_misc['Merge topics redirect']);
 	}
-	else
-	{
-		if (isset($_POST['topics']) && count($_POST['topics']) > 1)
-			$topics = array_map('intval', array_keys($_POST['topics']));
-		else
-			message($lang_misc['Not enough topics selected']);
-	}
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_misc['Moderate'];
+	$topics = isset($_POST['topics']) ? $_POST['topics'] : array();
+	if (count($topics) < 2)
+		message($lang_misc['Not enough topics selected']);
+
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_misc['Moderate']);
+	define('PUN_ACTIVE_PAGE', 'index');
 	require PUN_ROOT.'header.php';
 
 ?>
 <div class="blockform">
-	<h2><?php echo $lang_misc['Merge topics'] ?></h2>
+	<h2><span><?php echo $lang_misc['Merge topics'] ?></span></h2>
 	<div class="box">
 		<form method="post" action="moderate.php?fid=<?php echo $fid ?>">
-			<input type="hidden" name="topics" value="<?php echo implode(',', $topics); ?>" />
+			<input type="hidden" name="topics" value="<?php echo implode(',', array_map('intval', array_keys($topics))) ?>" />
 			<div class="inform">
 				<fieldset>
 					<legend><?php echo $lang_misc['Confirm merge legend'] ?></legend>
 					<div class="infldset">
 						<div class="rbox">
-							<label><input type="checkbox" name="with_redirect" value="1"<?php if ($action == 'single') echo ' checked="checked"' ?> /><?php echo $lang_misc['Leave redirect'] ?><br /></label>
+							<label><input type="checkbox" name="with_redirect" value="1" /><?php echo $lang_misc['Leave redirect'] ?><br /></label>
 						</div>
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="merge_topics_comply" value="<?php echo $lang_misc['Merge'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="merge_topics_comply" value="<?php echo $lang_misc['Merge'] ?>" /> <a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
@@ -608,14 +604,14 @@ else if (isset($_POST['delete_topics']) || isset($_POST['delete_topics_comply'])
 		// Delete any subscriptions
 		$db->query('DELETE FROM '.$db->prefix.'subscriptions WHERE topic_id IN('.$topics.')') or error('Unable to delete subscriptions', __FILE__, __LINE__, $db->error());
 
-		// Create a list of the post ID's in this topic and then strip the search index
+		// Create a list of the post IDs in this topic and then strip the search index
 		$result = $db->query('SELECT id FROM '.$db->prefix.'posts WHERE topic_id IN('.$topics.')') or error('Unable to fetch posts', __FILE__, __LINE__, $db->error());
 
 		$post_ids = '';
 		while ($row = $db->fetch_row($result))
 			$post_ids .= ($post_ids != '') ? ','.$row[0] : $row[0];
 
-		// We have to check that we actually have a list of post ID's since we could be deleting just a redirect topic
+		// We have to check that we actually have a list of post IDs since we could be deleting just a redirect topic
 		if ($post_ids != '')
 			strip_search_index($post_ids);
 
@@ -628,12 +624,13 @@ else if (isset($_POST['delete_topics']) || isset($_POST['delete_topics_comply'])
 	}
 
 
-	$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.$lang_misc['Moderate'];
+	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_misc['Moderate']);
+	define('PUN_ACTIVE_PAGE', 'index');
 	require PUN_ROOT.'header.php';
 
 ?>
 <div class="blockform">
-	<h2><?php echo $lang_misc['Delete topics'] ?></h2>
+	<h2><span><?php echo $lang_misc['Delete topics'] ?></span></h2>
 	<div class="box">
 		<form method="post" action="moderate.php?fid=<?php echo $fid ?>">
 			<input type="hidden" name="topics" value="<?php echo implode(',', array_map('intval', array_keys($topics))) ?>" />
@@ -645,7 +642,7 @@ else if (isset($_POST['delete_topics']) || isset($_POST['delete_topics_comply'])
 					</div>
 				</fieldset>
 			</div>
-			<p><input type="submit" name="delete_topics_comply" value="<?php echo $lang_misc['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
+			<p class="buttons"><input type="submit" name="delete_topics_comply" value="<?php echo $lang_misc['Delete'] ?>" /><a href="javascript:history.go(-1)"><?php echo $lang_common['Go back'] ?></a></p>
 		</form>
 	</div>
 </div>
@@ -656,11 +653,11 @@ else if (isset($_POST['delete_topics']) || isset($_POST['delete_topics_comply'])
 
 
 // Open or close one or more topics
-else if (isset($_POST['open']) || isset($_POST['close']))
+else if (isset($_REQUEST['open']) || isset($_REQUEST['close']))
 {
-	$action = (isset($_POST['open'])) ? 0 : 1;
+	$action = (isset($_REQUEST['open'])) ? 0 : 1;
 
-	// There could be an array of topic ID's in $_POST
+	// There could be an array of topic IDs in $_POST
 	if (isset($_POST['open']) || isset($_POST['close']))
 	{
 		confirm_referrer('moderate.php');
@@ -727,7 +724,7 @@ else if (isset($_GET['unstick']))
 require PUN_ROOT.'lang/'.$pun_user['language'].'/forum.php';
 
 // Fetch some info about the forum
-$result = $db->query('SELECT f.forum_name, f.redirect_url, f.num_topics FROM '.$db->prefix.'forums AS f LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$fid) or error('Unable to fetch forum info', __FILE__, __LINE__, $db->error());
+$result = $db->query('SELECT f.forum_name, f.redirect_url, f.num_topics, f.sort_by FROM '.$db->prefix.'forums AS f LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$fid) or error('Unable to fetch forum info', __FILE__, __LINE__, $db->error());
 if (!$db->num_rows($result))
 	message($lang_common['Bad request']);
 
@@ -737,23 +734,28 @@ $cur_forum = $db->fetch_assoc($result);
 if ($cur_forum['redirect_url'] != '')
 	message($lang_common['Bad request']);
 
-$page_title = pun_htmlspecialchars($pun_config['o_board_title']).' / '.pun_htmlspecialchars($cur_forum['forum_name']);
-require PUN_ROOT.'header.php';
-
 // Determine the topic offset (based on $_GET['p'])
 $num_pages = ceil($cur_forum['num_topics'] / $pun_user['disp_topics']);
 
-$p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : $_GET['p'];
+$p = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $num_pages) ? 1 : intval($_GET['p']);
 $start_from = $pun_user['disp_topics'] * ($p - 1);
 
 // Generate paging links
-$paging_links = $lang_common['Pages'].': '.paginate($num_pages, $p, 'moderate.php?fid='.$fid)
+$paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'moderate.php?fid='.$fid);
+
+$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), pun_htmlspecialchars($cur_forum['forum_name']));
+define('PUN_ACTIVE_PAGE', 'index');
+require PUN_ROOT.'header.php';
 
 ?>
 <div class="linkst">
-	<div class="inbox">
+	<div class="inbox crumbsplus">
+		<ul class="crumbs">
+			<li><a href="index.php"><?php echo $lang_common['Index'] ?></a></li>
+			<li><span>&raquo;&#160;</span><a href="viewforum.php?id=<?php echo $fid ?>"><?php echo pun_htmlspecialchars($cur_forum['forum_name']) ?></a></li>
+			<li><span>&raquo;&#160;</span><strong><?php echo $lang_misc['Moderate'] ?></strong></li>
+		</ul>
 		<p class="pagelink conl"><?php echo $paging_links ?></p>
-		<ul><li><a href="index.php"><?php echo $lang_common['Index'] ?></a>&nbsp;</li><li>&raquo;&nbsp;<?php echo pun_htmlspecialchars($cur_forum['forum_name']) ?></li></ul>
 		<div class="clearer"></div>
 	</div>
 </div>
@@ -777,91 +779,95 @@ $paging_links = $lang_common['Pages'].': '.paginate($num_pages, $p, 'moderate.ph
 <?php
 
 // Select topics
-$result = $db->query('SELECT id, poster, subject, posted, last_post, last_post_id, last_poster, num_views, num_replies, closed, sticky, moved_to FROM '.$db->prefix.'topics WHERE forum_id='.$fid.' ORDER BY sticky DESC, last_post DESC LIMIT '.$start_from.', '.$pun_user['disp_topics']) or error('Unable to fetch topic list for forum', __FILE__, __LINE__, $db->error());
+$result = $db->query('SELECT id, poster, subject, posted, last_post, last_post_id, last_poster, num_views, num_replies, closed, sticky, moved_to FROM '.$db->prefix.'topics WHERE forum_id='.$fid.' ORDER BY sticky DESC, '.(($cur_forum['sort_by'] == '1') ? 'posted' : 'last_post').' DESC LIMIT '.$start_from.', '.$pun_user['disp_topics']) or error('Unable to fetch topic list for forum', __FILE__, __LINE__, $db->error());
 
-// If there are topics in this forum.
+// If there are topics in this forum
 if ($db->num_rows($result))
 {
 	$button_status = '';
-
+	$topic_count = 0;
 	while ($cur_topic = $db->fetch_assoc($result))
 	{
 
-		$icon_text = $lang_common['Normal icon'];
-		$item_status = '';
+		++$topic_count;
+		$status_text = array();
+		$item_status = ($topic_count % 2 == 0) ? 'roweven' : 'rowodd';
 		$icon_type = 'icon';
 
 		if ($cur_topic['moved_to'] == null)
 		{
-			$last_post = '<a href="viewtopic.php?pid='.$cur_topic['last_post_id'].'#p'.$cur_topic['last_post_id'].'">'.format_time($cur_topic['last_post']).'</a> '.$lang_common['by'].' '.pun_htmlspecialchars($cur_topic['last_poster']);
+			$last_post = '<a href="viewtopic.php?pid='.$cur_topic['last_post_id'].'#p'.$cur_topic['last_post_id'].'">'.format_time($cur_topic['last_post']).'</a> <span class="byuser">'.$lang_common['by'].' '.pun_htmlspecialchars($cur_topic['last_poster']).'</span>';
 			$ghost_topic = false;
 		}
 		else
 		{
-			$last_post = '&nbsp;';
+			$last_post = '- - -';
 			$ghost_topic = true;
 		}
 
 		if ($pun_config['o_censoring'] == '1')
 			$cur_topic['subject'] = censor_words($cur_topic['subject']);
 
+		if ($cur_topic['sticky'] == '1')
+		{
+			$item_status .= ' isticky';
+			$status_text[] = '<span class="stickytext">'.$lang_forum['Sticky'].'</span>';
+		}
+
 		if ($cur_topic['moved_to'] != 0)
-			$subject = $lang_forum['Moved'].': <a href="viewtopic.php?id='.$cur_topic['moved_to'].'">'.pun_htmlspecialchars($cur_topic['subject']).'</a> <span class="byuser">'.$lang_common['by'].' '.pun_htmlspecialchars($cur_topic['poster']).'</span>';
+		{
+			$subject = '<a href="viewtopic.php?id='.$cur_topic['moved_to'].'">'.pun_htmlspecialchars($cur_topic['subject']).'</a> <span class="byuser">'.$lang_common['by'].' '.pun_htmlspecialchars($cur_topic['poster']).'</span>';
+			$status_text[] = '<span class="movedtext">'.$lang_forum['Moved'].'</span>';
+			$item_status .= ' imoved';
+		}
 		else if ($cur_topic['closed'] == '0')
-			$subject = '<a href="viewtopic.php?id='.$cur_topic['id'].'">'.pun_htmlspecialchars($cur_topic['subject']).'</a> <span>'.$lang_common['by'].'&nbsp;'.pun_htmlspecialchars($cur_topic['poster']).'</span>';
+			$subject = '<a href="viewtopic.php?id='.$cur_topic['id'].'">'.pun_htmlspecialchars($cur_topic['subject']).'</a> <span class="byuser">'.$lang_common['by'].' '.pun_htmlspecialchars($cur_topic['poster']).'</span>';
 		else
 		{
 			$subject = '<a href="viewtopic.php?id='.$cur_topic['id'].'">'.pun_htmlspecialchars($cur_topic['subject']).'</a> <span class="byuser">'.$lang_common['by'].' '.pun_htmlspecialchars($cur_topic['poster']).'</span>';
-			$icon_text = $lang_common['Closed icon'];
-			$item_status = 'iclosed';
+			$status_text[] = '<span class="closedtext">'.$lang_forum['Closed'].'</span>';
+			$item_status .= ' iclosed';
 		}
 
 		if (!$ghost_topic && $cur_topic['last_post'] > $pun_user['last_visit'] && (!isset($tracked_topics['topics'][$cur_topic['id']]) || $tracked_topics['topics'][$cur_topic['id']] < $cur_topic['last_post']) && (!isset($tracked_topics['forums'][$fid]) || $tracked_topics['forums'][$fid] < $cur_topic['last_post']))
 		{
-			$icon_text .= ' '.$lang_common['New icon'];
 			$item_status .= ' inew';
-			$icon_type = 'icon inew';
+			$icon_type = 'icon icon-new';
 			$subject = '<strong>'.$subject.'</strong>';
-			$subject_new_posts = '<span class="newtext">[&nbsp;<a href="viewtopic.php?id='.$cur_topic['id'].'&amp;action=new" title="'.$lang_common['New posts info'].'">'.$lang_common['New posts'].'</a>&nbsp;]</span>';
+			$subject_new_posts = '<span class="newtext">[ <a href="viewtopic.php?id='.$cur_topic['id'].'&amp;action=new" title="'.$lang_common['New posts info'].'">'.$lang_common['New posts'].'</a> ]</span>';
 		}
 		else
 			$subject_new_posts = null;
 
-		// We won't display "the dot", but we add the spaces anyway
-		if ($pun_config['o_show_dot'] == '1')
-			$subject = '&nbsp;&nbsp;'.$subject;
-
-		if ($cur_topic['sticky'] == '1')
-		{
-			$subject = '<span class="stickytext">'.$lang_forum['Sticky'].': </span>'.$subject;
-			$item_status .= ' isticky';
-			$icon_text .= ' '.$lang_forum['Sticky'];
-		}
+		// Insert the status text before the subject
+		$subject = implode(' ', $status_text).' '.$subject;
 
 		$num_pages_topic = ceil(($cur_topic['num_replies'] + 1) / $pun_user['disp_posts']);
 
 		if ($num_pages_topic > 1)
-			$subject_multipage = '[ '.paginate($num_pages_topic, -1, 'viewtopic.php?id='.$cur_topic['id']).' ]';
+			$subject_multipage = '<span class="pagestext">[ '.paginate($num_pages_topic, -1, 'viewtopic.php?id='.$cur_topic['id']).' ]</span>';
 		else
 			$subject_multipage = null;
 
 		// Should we show the "New posts" and/or the multipage links?
 		if (!empty($subject_new_posts) || !empty($subject_multipage))
 		{
-			$subject .= '&nbsp; '.(!empty($subject_new_posts) ? $subject_new_posts : '');
+			$subject .= !empty($subject_new_posts) ? ' '.$subject_new_posts : '';
 			$subject .= !empty($subject_multipage) ? ' '.$subject_multipage : '';
 		}
 
 ?>
-				<tr<?php if ($item_status != '') echo ' class="'.trim($item_status).'"'; ?>>
+				<tr class="<?php echo $item_status ?>">
 					<td class="tcl">
-						<div class="<?php echo $icon_type ?>"><div class="nosize"><?php echo trim($icon_text) ?></div></div>
+						<div class="<?php echo $icon_type ?>"><div class="nosize"><?php echo forum_number_format($topic_count + $start_from) ?></div></div>
 						<div class="tclcon">
-							<?php echo $subject."\n" ?>
+							<div>
+								<?php echo $subject."\n" ?>
+							</div>
 						</div>
 					</td>
-					<td class="tc2"><?php echo (!$ghost_topic) ? forum_number_format($cur_topic['num_replies']) : '&nbsp;' ?></td>
-<?php if ($pun_config['o_topic_views'] == '1'): ?>					<td class="tc3"><?php echo (!$ghost_topic) ? forum_number_format($cur_topic['num_views']) : '&nbsp;' ?></td>
+					<td class="tc2"><?php echo (!$ghost_topic) ? forum_number_format($cur_topic['num_replies']) : '-' ?></td>
+<?php if ($pun_config['o_topic_views'] == '1'): ?>					<td class="tc3"><?php echo (!$ghost_topic) ? forum_number_format($cur_topic['num_views']) : '-' ?></td>
 <?php endif; ?>					<td class="tcr"><?php echo $last_post ?></td>
 					<td class="tcmod"><input type="checkbox" name="topics[<?php echo $cur_topic['id'] ?>]" value="1" /></td>
 				</tr>
@@ -886,7 +892,7 @@ else
 <div class="linksb">
 	<div class="inbox">
 		<p class="pagelink conl"><?php echo $paging_links ?></p>
-		<p class="conr"><input type="submit" name="move_topics" value="<?php echo $lang_misc['Move'] ?>"<?php echo $button_status ?> />&nbsp;&nbsp;<input type="submit" name="delete_topics" value="<?php echo $lang_misc['Delete'] ?>"<?php echo $button_status ?> />&nbsp;&nbsp;<input type="submit