diff -urN punbb-1.2.14/upload/admin_categories.php punbb-1.2.15/upload/admin_categories.php
--- punbb-1.2.14/upload/admin_categories.php	Sun Apr  3 20:48:32 2005
+++ punbb-1.2.15/upload/admin_categories.php	Tue Apr 10 23:37:36 2007
@@ -118,7 +118,7 @@
 					<fieldset>
 						<legend>Confirm delete category</legend>
 						<div class="infldset">
-							<p>Are you sure that you want to delete the category "<?php echo $cat_name ?>"?</p>
+							<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>
 						</div>
 					</fieldset>
@@ -151,7 +151,7 @@
 		if ($cat_name[$i] == '')
 			message('You must enter a category name.');
 
-		if (!preg_match('#^\d+$#', $cat_order[$i]))
+		if (!@preg_match('#^\d+$#', $cat_order[$i]))
 			message('Position must be an integer value.');
 
 		list($cat_id, $position) = $db->fetch_row($result);
diff -urN punbb-1.2.14/upload/admin_forums.php punbb-1.2.15/upload/admin_forums.php
--- punbb-1.2.14/upload/admin_forums.php	Sun Oct 15 18:27:14 2006
+++ punbb-1.2.15/upload/admin_forums.php	Tue Apr 10 23:37:36 2007
@@ -137,7 +137,7 @@
 
 	while (list($forum_id, $disp_position) = @each($_POST['position']))
 	{
-		if (!preg_match('#^\d+$#', $disp_position))
+		if (!@preg_match('#^\d+$#', $disp_position))
 			message('Position must be a positive integer value.');
 
 		$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());
diff -urN punbb-1.2.14/upload/admin_loader.php punbb-1.2.15/upload/admin_loader.php
--- punbb-1.2.14/upload/admin_loader.php	Thu Feb 24 23:15:56 2005
+++ punbb-1.2.15/upload/admin_loader.php	Tue Apr 10 23:37:36 2007
@@ -37,7 +37,7 @@
 
 // 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
diff -urN punbb-1.2.14/upload/admin_maintenance.php punbb-1.2.15/upload/admin_maintenance.php
--- punbb-1.2.14/upload/admin_maintenance.php	Sun Jan 30 13:58:06 2005
+++ punbb-1.2.15/upload/admin_maintenance.php	Wed Jan 31 00:31:44 2007
@@ -52,7 +52,7 @@
 		// 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') ? 'TRUNCATE TABLE ' : 'DELETE FROM ';
+		$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());
 
@@ -65,7 +65,7 @@
 				break;
 
 			case 'pgsql';
-				$result = $db->query('SELECT setval(\'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error());
+				$result = $db->query('SELECT setval(\''.$db->prefix.'search_words_id_seq\', 1, false)') or error('Unable to update sequence', __FILE__, __LINE__, $db->error());
 		}
 	}
 
diff -urN punbb-1.2.14/upload/admin_options.php punbb-1.2.15/upload/admin_options.php
--- punbb-1.2.14/upload/admin_options.php	Sun Oct 15 18:31:20 2006
+++ punbb-1.2.15/upload/admin_options.php	Wed Apr 11 13:35:46 2007
@@ -37,9 +37,9 @@
 
 if (isset($_POST['form_sent']))
 {
-	// Lazy referer check (in case base_url isn't correct)
-	if (!isset($_SERVER['HTTP_REFERER']) || !preg_match('#/admin_options\.php#i', $_SERVER['HTTP_REFERER']))
-		message($lang_common['Bad referrer']);
+	// 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']);
 
diff -urN punbb-1.2.14/upload/admin_prune.php punbb-1.2.15/upload/admin_prune.php
--- punbb-1.2.14/upload/admin_prune.php	Thu Jul  7 19:31:56 2005
+++ punbb-1.2.15/upload/admin_prune.php	Tue Apr 10 23:37:36 2007
@@ -84,7 +84,7 @@
 
 
 	$prune_days = $_POST['req_prune_days'];
-	if (!preg_match('#^\d+$#', $prune_days))
+	if (!@preg_match('#^\d+$#', $prune_days))
 		message('Days to prune must be a positive integer.');
 
 	$prune_date = time() - ($prune_days*86400);
diff -urN punbb-1.2.14/upload/admin_ranks.php punbb-1.2.15/upload/admin_ranks.php
--- punbb-1.2.14/upload/admin_ranks.php	Fri Mar 11 20:17:28 2005
+++ punbb-1.2.15/upload/admin_ranks.php	Tue Apr 10 23:37:36 2007
@@ -46,7 +46,7 @@
 	if ($rank == '')
 		message('You must enter a rank title.');
 
-	if (!preg_match('#^\d+$#', $min_posts))
+	if (!@preg_match('#^\d+$#', $min_posts))
 		message('Minimum posts must be a positive integer value.');
 
 	// Make sure there isn't already a rank with the same min_posts value
@@ -77,11 +77,11 @@
 	if ($rank == '')
 		message('You must enter a rank title.');
 
-	if (!preg_match('#^\d+$#', $min_posts))
+	if (!@preg_match('#^\d+$#', $min_posts))
 		message('Minimum posts must be a positive integer value.');
 
 	// 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.' && min_posts='.$min_posts) or error('Unable to fetch rank info', __FILE__, __LINE__, $db->error());
+	$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.'.');
 
diff -urN punbb-1.2.14/upload/admin_users.php punbb-1.2.15/upload/admin_users.php
--- punbb-1.2.14/upload/admin_users.php	Sun Oct 15 18:27:14 2006
+++ punbb-1.2.15/upload/admin_users.php	Tue Apr 10 23:37:36 2007
@@ -111,7 +111,7 @@
 {
 	$ip = $_GET['show_users'];
 
-	if (!preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $ip))
+	if (!@preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $ip))
 		message('The supplied IP address is not correctly formatted.');
 
 
diff -urN punbb-1.2.14/upload/extern.php punbb-1.2.15/upload/extern.php
--- punbb-1.2.14/upload/extern.php	Wed Jul 27 23:25:16 2005
+++ punbb-1.2.15/upload/extern.php	Mon Jan 15 02:51:06 2007
@@ -149,6 +149,10 @@
 if (!isset($lang_common))
 	exit('There is no valid language pack \''.$pun_config['o_default_lang'].'\' installed. Please reinstall a language of that name.');
 
+// Check if we are to display a maintenance message
+if ($pun_config['o_maintenance'] && !defined('PUN_TURN_OFF_MAINT'))
+	maintenance_message();
+
 if (!isset($_GET['action']))
 	exit('No parameters supplied. See extern.php for instructions.');
 
diff -urN punbb-1.2.14/upload/footer.php punbb-1.2.15/upload/footer.php
--- punbb-1.2.14/upload/footer.php	Thu Jul  7 18:44:42 2005
+++ punbb-1.2.15/upload/footer.php	Tue Apr 10 18:19:26 2007
@@ -139,21 +139,6 @@
 // END SUBST - <pun_footer>
 
 
-// START SUBST - <pun_include "*">
-while (preg_match('#<pun_include "([^/\\\\]*?)">#', $tpl_main, $cur_include))
-{
-	if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1]))
-		error('Unable to process user include &lt;pun_include "'.htmlspecialchars($cur_include[1]).'"&gt; from template main.tpl. There is no such file in folder /include/user/');
-
-	ob_start();
-	include PUN_ROOT.'include/user/'.$cur_include[1];
-	$tpl_temp = ob_get_contents();
-	$tpl_main = str_replace($cur_include[0], $tpl_temp, $tpl_main);
-    ob_end_clean();
-}
-// END SUBST - <pun_include "*">
-
-
 // Close the db connection (and free up any result data)
 $db->close();
 
diff -urN punbb-1.2.14/upload/header.php punbb-1.2.15/upload/header.php
--- punbb-1.2.14/upload/header.php	Tue Feb 28 20:20:28 2006
+++ punbb-1.2.15/upload/header.php	Tue Apr 10 18:19:26 2007
@@ -43,6 +43,21 @@
 	$tpl_main = file_get_contents(PUN_ROOT.'include/template/main.tpl');
 
 
+// START SUBST - <pun_include "*">
+while (preg_match('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_main, $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/');
+
+	ob_start();
+	include PUN_ROOT.'include/user/'.$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();
+}
+// END SUBST - <pun_include "*">
+
+
 // START SUBST - <pun_content_direction>
 $tpl_main = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_main);
 // END SUBST - <pun_content_direction>
diff -urN punbb-1.2.14/upload/include/common.php punbb-1.2.15/upload/include/common.php
--- punbb-1.2.14/upload/include/common.php	Tue Nov  1 01:06:56 2005
+++ punbb-1.2.15/upload/include/common.php	Mon Apr  9 16:15:22 2007
@@ -37,8 +37,7 @@
 require PUN_ROOT.'include/functions.php';
 
 // Reverse the effect of register_globals
-if (@ini_get('register_globals'))
-	unregister_globals();
+unregister_globals();
 
 
 @include PUN_ROOT.'config.php';
diff -urN punbb-1.2.14/upload/include/dblayer/mysql.php punbb-1.2.15/upload/include/dblayer/mysql.php
--- punbb-1.2.14/upload/include/dblayer/mysql.php	Tue Jan 11 21:41:16 2005
+++ punbb-1.2.15/upload/include/dblayer/mysql.php	Tue Apr 10 23:37:36 2007
@@ -156,7 +156,9 @@
 
 	function escape($str)
 	{
-		if (function_exists('mysql_real_escape_string'))
+		if (is_array($str))
+			return '';
+		else if (function_exists('mysql_real_escape_string'))
 			return mysql_real_escape_string($str, $this->link_id);
 		else
 			return mysql_escape_string($str);
diff -urN punbb-1.2.14/upload/include/dblayer/mysqli.php punbb-1.2.15/upload/include/dblayer/mysqli.php
--- punbb-1.2.14/upload/include/dblayer/mysqli.php	Tue Jan 11 21:41:16 2005
+++ punbb-1.2.15/upload/include/dblayer/mysqli.php	Tue Apr 10 23:37:36 2007
@@ -159,7 +159,7 @@
 
 	function escape($str)
 	{
-		return mysqli_real_escape_string($this->link_id, $str);
+		return is_array($str) ? '' : mysqli_real_escape_string($this->link_id, $str);
 	}
 
 
diff -urN punbb-1.2.14/upload/include/dblayer/pgsql.php punbb-1.2.15/upload/include/dblayer/pgsql.php
--- punbb-1.2.14/upload/include/dblayer/pgsql.php	Fri Jan 28 23:16:46 2005
+++ punbb-1.2.15/upload/include/dblayer/pgsql.php	Tue Apr 10 23:37:36 2007
@@ -217,7 +217,7 @@
 
 	function escape($str)
 	{
-		return pg_escape_string($str);
+		return is_array($str) ? '' : pg_escape_string($str);
 	}
 
 
diff -urN punbb-1.2.14/upload/include/dblayer/sqlite.php punbb-1.2.15/upload/include/dblayer/sqlite.php
--- punbb-1.2.14/upload/include/dblayer/sqlite.php	Fri Jan 28 23:16:46 2005
+++ punbb-1.2.15/upload/include/dblayer/sqlite.php	Tue Apr 10 23:37:36 2007
@@ -219,7 +219,7 @@
 
 	function escape($str)
 	{
-		return sqlite_escape_string($str);
+		return is_array($str) ? '' : sqlite_escape_string($str);
 	}
 
 
diff -urN punbb-1.2.14/upload/include/email.php punbb-1.2.15/upload/include/email.php
--- punbb-1.2.14/upload/include/email.php	Thu Sep 22 00:35:06 2005
+++ punbb-1.2.15/upload/include/email.php	Mon Apr  9 18:41:04 2007
@@ -77,8 +77,8 @@
 
 	$headers = 'From: '.$from."\r\n".'Date: '.date('r')."\r\n".'MIME-Version: 1.0'."\r\n".'Content-transfer-encoding: 8bit'."\r\n".'Content-type: text/plain; charset='.$lang_common['lang_encoding']."\r\n".'X-Mailer: PunBB Mailer';
 
-	// Make sure all linebreaks are CRLF in message
-	$message = str_replace("\n", "\r\n", pun_linebreaks($message));
+	// Make sure all linebreaks are CRLF in message (and strip out any NULL bytes)
+	$message = str_replace(array("\n", "\0"), array("\r\n", ''), pun_linebreaks($message));
 
 	if ($pun_config['o_smtp_host'] != '')
 		smtp_mail($to, $subject, $message, $headers);
diff -urN punbb-1.2.14/upload/include/functions.php punbb-1.2.15/upload/include/functions.php
--- punbb-1.2.14/upload/include/functions.php	Sun Oct 15 18:36:14 2006
+++ punbb-1.2.15/upload/include/functions.php	Tue Apr 10 18:19:26 2007
@@ -27,7 +27,7 @@
 //
 function check_cookie(&$pun_user)
 {
-	global $db, $pun_config, $cookie_name, $cookie_seed;
+	global $db, $db_type, $pun_config, $cookie_name, $cookie_seed;
 
 	$now = time();
 	$expire = $now + 31536000;	// The cookie expires after a year
@@ -75,7 +75,22 @@
 		{
 			// Update the online list
 			if (!$pun_user['logged'])
-				$db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) VALUES('.$pun_user['id'].', \''.$db->escape($pun_user['username']).'\', '.$now.')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
+			{
+				$pun_user['logged'] = $now;
+
+				// With MySQL/MySQLi, REPLACE INTO avoids a user having two rows in the online table
+				switch ($db_type)
+				{
+					case 'mysql':
+					case 'mysqli':
+						$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());
+						break;
+				}
+			}
 			else
 			{
 				// Special case: We've timed out, but no other user has browsed the forums since we timed out
@@ -102,7 +117,7 @@
 //
 function set_default_user()
 {
-	global $db, $pun_user, $pun_config;
+	global $db, $db_type, $pun_user, $pun_config;
 
 	$remote_addr = get_remote_address();
 
@@ -115,7 +130,22 @@
 
 	// Update online list
 	if (!$pun_user['logged'])
-		$db->query('INSERT INTO '.$db->prefix.'online (user_id, ident, logged) VALUES(1, \''.$db->escape($remote_addr).'\', '.time().')') or error('Unable to insert into online list', __FILE__, __LINE__, $db->error());
+	{
+		$pun_user['logged'] = time();
+
+		// With MySQL/MySQLi, REPLACE INTO avoids a user having two rows in the online table
+		switch ($db_type)
+		{
+			case 'mysql':
+			case 'mysqli':
+				$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());
+				break;
+		}
+	}
 	else
 		$db->query('UPDATE '.$db->prefix.'online SET logged='.time().' WHERE ident=\''.$db->escape($remote_addr).'\'') or error('Unable to update online list', __FILE__, __LINE__, $db->error());
 
@@ -752,6 +782,21 @@
 	$tpl_maint = trim(file_get_contents(PUN_ROOT.'include/template/maintenance.tpl'));
 
 
+	// START SUBST - <pun_include "*">
+	while (preg_match('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_maint, $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/');
+
+		ob_start();
+		include PUN_ROOT.'include/user/'.$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();
+	}
+	// END SUBST - <pun_include "*">
+
+
 	// START SUBST - <pun_content_direction>
 	$tpl_maint = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_maint);
 	// END SUBST - <pun_content_direction>
@@ -790,21 +835,6 @@
 	$db->end_transaction();
 
 
-	// START SUBST - <pun_include "*">
-	while (preg_match('#<pun_include "([^/\\\\]*?)">#', $tpl_maint, $cur_include))
-	{
-		if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1]))
-			error('Unable to process user include &lt;pun_include "'.htmlspecialchars($cur_include[1]).'"&gt; from template maintenance.tpl. There is no such file in folder /include/user/');
-
-		ob_start();
-		include PUN_ROOT.'include/user/'.$cur_include[1];
-		$tpl_temp = ob_get_contents();
-		$tpl_maint = str_replace($cur_include[0], $tpl_temp, $tpl_maint);
-	    ob_end_clean();
-	}
-	// END SUBST - <pun_include "*">
-
-
 	// Close the db connection (and free up any result data)
 	$db->close();
 
@@ -831,6 +861,21 @@
 	$tpl_redir = trim(file_get_contents(PUN_ROOT.'include/template/redirect.tpl'));
 
 
+	// START SUBST - <pun_include "*">
+	while (preg_match('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_redir, $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/');
+
+		ob_start();
+		include PUN_ROOT.'include/user/'.$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();
+	}
+	// END SUBST - <pun_include "*">
+
+
 	// START SUBST - <pun_content_direction>
 	$tpl_redir = str_replace('<pun_content_direction>', $lang_common['lang_direction'], $tpl_redir);
 	// END SUBST - <pun_content_direction>
@@ -883,21 +928,6 @@
 	// END SUBST - <pun_footer>
 
 
-	// START SUBST - <pun_include "*">
-	while (preg_match('#<pun_include "([^/\\\\]*?)">#', $tpl_redir, $cur_include))
-	{
-		if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1]))
-			error('Unable to process user include &lt;pun_include "'.htmlspecialchars($cur_include[1]).'"&gt; from template redirect.tpl. There is no such file in folder /include/user/');
-
-		ob_start();
-		include PUN_ROOT.'include/user/'.$cur_include[1];
-		$tpl_temp = ob_get_contents();
-		$tpl_redir = str_replace($cur_include[0], $tpl_temp, $tpl_redir);
-	    ob_end_clean();
-	}
-	// END SUBST - <pun_include "*">
-
-
 	// Close the db connection (and free up any result data)
 	$db->close();
 
@@ -925,7 +955,7 @@
 
 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html dir="ltr">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
 <title><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?> / Error</title>
@@ -1036,6 +1066,10 @@
 //
 function unregister_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.');
diff -urN punbb-1.2.14/upload/include/template/admin.tpl punbb-1.2.15/upload/include/template/admin.tpl
--- punbb-1.2.14/upload/include/template/admin.tpl	Tue Jan 11 21:41:16 2005
+++ punbb-1.2.15/upload/include/template/admin.tpl	Sun Apr  8 19:30:40 2007
@@ -1,6 +1,6 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
-<html dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=<pun_char_encoding>" />
 <pun_head>
diff -urN punbb-1.2.14/upload/include/template/help.tpl punbb-1.2.15/upload/include/template/help.tpl
--- punbb-1.2.14/upload/include/template/help.tpl	Tue Jan 11 21:41:16 2005
+++ punbb-1.2.15/upload/include/template/help.tpl	Sun Apr  8 19:30:40 2007
@@ -1,6 +1,6 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
-<html dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=<pun_char_encoding>" />
 <pun_head>
diff -urN punbb-1.2.14/upload/include/template/main.tpl punbb-1.2.15/upload/include/template/main.tpl
--- punbb-1.2.14/upload/include/template/main.tpl	Tue Jan 11 21:41:16 2005
+++ punbb-1.2.15/upload/include/template/main.tpl	Sun Apr  8 19:30:40 2007
@@ -1,6 +1,6 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
-<html dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=<pun_char_encoding>" />
 <pun_head>
diff -urN punbb-1.2.14/upload/include/template/maintenance.tpl punbb-1.2.15/upload/include/template/maintenance.tpl
--- punbb-1.2.14/upload/include/template/maintenance.tpl	Tue Jan 11 21:41:16 2005
+++ punbb-1.2.15/upload/include/template/maintenance.tpl	Sun Apr  8 19:30:40 2007
@@ -1,6 +1,6 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
-<html dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=<pun_char_encoding>" />
 <pun_head>
diff -urN punbb-1.2.14/upload/include/template/redirect.tpl punbb-1.2.15/upload/include/template/redirect.tpl
--- punbb-1.2.14/upload/include/template/redirect.tpl	Tue Jan 11 21:41:16 2005
+++ punbb-1.2.15/upload/include/template/redirect.tpl	Sun Apr  8 19:30:40 2007
@@ -1,6 +1,6 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 
-<html dir="<pun_content_direction>">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="<pun_content_direction>">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=<pun_char_encoding>" />
 <pun_head>
diff -urN punbb-1.2.14/upload/install.php punbb-1.2.15/upload/install.php
--- punbb-1.2.14/upload/install.php	Sun Oct 15 18:40:20 2006
+++ punbb-1.2.15/upload/install.php	Wed Apr 11 13:39:52 2007
@@ -24,7 +24,7 @@
 
 
 // The PunBB version this script installs
-$punbb_version = '1.2.14';
+$punbb_version = '1.2.15';
 
 
 define('PUN_ROOT', './');
@@ -1234,6 +1234,7 @@
 		case 'mysql':
 		case 'mysqli':
 			// We use MySQL's ALTER TABLE ... ADD INDEX syntax instead of CREATE INDEX to avoid problems with users lacking the INDEX privilege
+			$queries[] = 'ALTER TABLE '.$db_prefix.'online ADD UNIQUE INDEX '.$db_prefix.'online_user_id_ident_idx(user_id,ident)';
 			$queries[] = 'ALTER TABLE '.$db_prefix.'online ADD INDEX '.$db_prefix.'online_user_id_idx(user_id)';
 			$queries[] = 'ALTER TABLE '.$db_prefix.'posts ADD INDEX '.$db_prefix.'posts_topic_id_idx(topic_id)';
 			$queries[] = 'ALTER TABLE '.$db_prefix.'posts ADD INDEX '.$db_prefix.'posts_multi_idx(poster_id, topic_id)';
diff -urN punbb-1.2.14/upload/misc.php punbb-1.2.15/upload/misc.php
--- punbb-1.2.14/upload/misc.php	Sat May 20 17:52:04 2006
+++ punbb-1.2.15/upload/misc.php	Tue Apr 10 18:42:56 2007
@@ -125,7 +125,7 @@
 
 
 	// 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)
-	$redirect_url = (isset($_SERVER['HTTP_REFERER']) && preg_match('#^'.preg_quote($pun_config['o_base_url']).'/(.*?)\.php#i', $_SERVER['HTTP_REFERER'])) ? $_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']) : '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']);
diff -urN punbb-1.2.14/upload/moderate.php punbb-1.2.15/upload/moderate.php
--- punbb-1.2.14/upload/moderate.php	Thu May  5 01:13:34 2005
+++ punbb-1.2.15/upload/moderate.php	Tue Apr 10 23:37:36 2007
@@ -35,7 +35,7 @@
 		message($lang_common['No permission']);
 
 	// Is get_host an IP address or a post ID?
-	if (preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $_GET['get_host']))
+	if (@preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $_GET['get_host']))
 		$ip = $_GET['get_host'];
 	else
 	{
@@ -98,7 +98,13 @@
 		{
 			confirm_referrer('moderate.php');
 
-			if (preg_match('/[^0-9,]/', $posts))
+			if (@preg_match('/[^0-9,]/', $posts))
+				message($lang_common['Bad request']);
+
+			// Verify that the post IDs are valid
+			$result = $db->query('SELECT 1 FROM '.$db->prefix.'posts WHERE id IN('.$posts.') AND topic_id='.$tid) or error('Unable to check posts', __FILE__, __LINE__, $db->error());
+
+			if ($db->num_rows($result) != substr_count($posts, ',') + 1)
 				message($lang_common['Bad request']);
 
 			// Delete the posts
@@ -281,7 +287,7 @@
 	{
 		confirm_referrer('moderate.php');
 
-		if (preg_match('/[^0-9,]/', $_POST['topics']))
+		if (@preg_match('/[^0-9,]/', $_POST['topics']))
 			message($lang_common['Bad request']);
 
 		$topics = explode(',', $_POST['topics']);
@@ -289,6 +295,12 @@
 		if (empty($topics) || $move_to_forum < 1)
 			message($lang_common['Bad request']);
 
+		// Verify that the topic IDs are valid
+		$result = $db->query('SELECT 1 FROM '.$db->prefix.'topics WHERE id IN('.implode(',',$topics).') AND forum_id='.$fid) or error('Unable to check topics', __FILE__, __LINE__, $db->error());
+
+		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)
 		$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());
 
@@ -400,11 +412,17 @@
 	{
 		confirm_referrer('moderate.php');
 
-		if (preg_match('/[^0-9,]/', $topics))
+		if (@preg_match('/[^0-9,]/', $topics))
 			message($lang_common['Bad request']);
 
 		require PUN_ROOT.'include/search_idx.php';
 
+		// Verify that the topic IDs are valid
+		$result = $db->query('SELECT 1 FROM '.$db->prefix.'topics WHERE id IN('.$topics.') AND forum_id='.$fid) or error('Unable to check topics', __FILE__, __LINE__, $db->error());
+
+		if ($db->num_rows($result) != substr_count($topics, ',') + 1)
+			message($lang_common['Bad request']);
+
 		// Delete the topics and any redirect topics
 		$db->query('DELETE FROM '.$db->prefix.'topics WHERE id IN('.$topics.') OR moved_to IN('.$topics.')') or error('Unable to delete topic', __FILE__, __LINE__, $db->error());
 
@@ -472,7 +490,7 @@
 		if (empty($topics))
 			message($lang_misc['No topics selected']);
 
-		$db->query('UPDATE '.$db->prefix.'topics SET closed='.$action.' WHERE id IN('.implode(',', $topics).')') or error('Unable to close topics', __FILE__, __LINE__, $db->error());
+		$db->query('UPDATE '.$db->prefix.'topics SET closed='.$action.' WHERE id IN('.implode(',', $topics).') AND forum_id='.$fid) or error('Unable to close topics', __FILE__, __LINE__, $db->error());
 
 		$redirect_msg = ($action) ? $lang_misc['Close topics redirect'] : $lang_misc['Open topics redirect'];
 		redirect('moderate.php?fid='.$fid, $redirect_msg);
@@ -486,7 +504,7 @@
 		if ($topic_id < 1)
 			message($lang_common['Bad request']);
 
-		$db->query('UPDATE '.$db->prefix.'topics SET closed='.$action.' WHERE id='.$topic_id) or error('Unable to close topic', __FILE__, __LINE__, $db->error());
+		$db->query('UPDATE '.$db->prefix.'topics SET closed='.$action.' WHERE id='.$topic_id.' AND forum_id='.$fid) or error('Unable to close topic', __FILE__, __LINE__, $db->error());
 
 		$redirect_msg = ($action) ? $lang_misc['Close topic redirect'] : $lang_misc['Open topic redirect'];
 		redirect('viewtopic.php?id='.$topic_id, $redirect_msg);
@@ -503,7 +521,7 @@
 	if ($stick < 1)
 		message($lang_common['Bad request']);
 
-	$db->query('UPDATE '.$db->prefix.'topics SET sticky=\'1\' WHERE id='.$stick) or error('Unable to stick topic', __FILE__, __LINE__, $db->error());
+	$db->query('UPDATE '.$db->prefix.'topics SET sticky=\'1\' WHERE id='.$stick.' AND forum_id='.$fid) or error('Unable to stick topic', __FILE__, __LINE__, $db->error());
 
 	redirect('viewtopic.php?id='.$stick, $lang_misc['Stick topic redirect']);
 }
@@ -518,7 +536,7 @@
 	if ($unstick < 1)
 		message($lang_common['Bad request']);
 
-	$db->query('UPDATE '.$db->prefix.'topics SET sticky=\'0\' WHERE id='.$unstick) or error('Unable to unstick topic', __FILE__, __LINE__, $db->error());
+	$db->query('UPDATE '.$db->prefix.'topics SET sticky=\'0\' WHERE id='.$unstick.' AND forum_id='.$fid) or error('Unable to unstick topic', __FILE__, __LINE__, $db->error());
 
 	redirect('viewtopic.php?id='.$unstick, $lang_misc['Unstick topic redirect']);
 }
diff -urN punbb-1.2.14/upload/post.php punbb-1.2.15/upload/post.php
--- punbb-1.2.14/upload/post.php	Mon Oct 31 23:26:14 2005
+++ punbb-1.2.15/upload/post.php	Mon Jan 15 15:59:04 2007
@@ -128,7 +128,7 @@
 			$errors[] = $lang_register['Username censor'];
 
 		// Check that the username (or a too similar username) is not already registered
-		$result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE username=\''.$db->escape($username).'\' OR username=\''.$db->escape(preg_replace('/[^\w]/', '', $username)).'\'') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+		$result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE (username=\''.$db->escape($username).'\' OR username=\''.$db->escape(preg_replace('/[^\w]/', '', $username)).'\') AND id>1') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
 		if ($db->num_rows($result))
 		{
 			$busy = $db->result($result);
diff -urN punbb-1.2.14/upload/profile.php punbb-1.2.15/upload/profile.php
--- punbb-1.2.14/upload/profile.php	Tue Nov  1 01:27:30 2005
+++ punbb-1.2.15/upload/profile.php	Tue Apr 10 23:37:36 2007
@@ -190,7 +190,7 @@
 		$result = $db->query('SELECT activate_string, activate_key FROM '.$db->prefix.'users WHERE id='.$id) or error('Unable to fetch activation data', __FILE__, __LINE__, $db->error());
 		list($new_email, $new_email_key) = $db->fetch_row($result);
 
-		if ($key != $new_email_key)
+		if ($key == '' || $key != $new_email_key)
 			message($lang_profile['E-mail key bad'].' <a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>.');
 		else
 		{
@@ -752,7 +752,7 @@
 			}
 
 			// Add http:// if the URL doesn't contain it already
-			if ($form['url'] != '' && !stristr($form['url'], 'http://'))
+			if ($form['url'] != '' && strpos(strtolower($form['url']), 'http://') !== 0)
 				$form['url'] = 'http://'.$form['url'];
 
 			break;
@@ -763,7 +763,7 @@
 			$form = extract_elements(array('jabber', 'icq', 'msn', 'aim', 'yahoo'));
 
 			// If the ICQ UIN contains anything other than digits it's invalid
-			if ($form['icq'] != '' && preg_match('/[^0-9]/', $form['icq']))
+			if ($form['icq'] != '' && @preg_match('/[^0-9]/', $form['icq']))
 				message($lang_prof_reg['Bad ICQ']);
 
 			break;
diff -urN punbb-1.2.14/upload/register.php punbb-1.2.15/upload/register.php
--- punbb-1.2.14/upload/register.php	Sun Oct 15 18:31:20 2006
+++ punbb-1.2.15/upload/register.php	Mon Jan 15 00:58:18 2007
@@ -183,7 +183,7 @@
 	else
 		$language = $pun_config['o_default_lang'];
 
-	$timezone = intval($_POST['timezone']);
+	$timezone = round($_POST['timezone'], 1);
 	$save_pass = (!isset($_POST['save_pass']) || $_POST['save_pass'] != '1') ? '0' : '1';
 
 	$email_setting = intval($_POST['email_setting']);
diff -urN punbb-1.2.14/upload/search.php punbb-1.2.15/upload/search.php
--- punbb-1.2.14/upload/search.php	Sun Oct 15 18:36:14 2006
+++ punbb-1.2.15/upload/search.php	Wed Apr 11 09:28:00 2007
@@ -122,7 +122,7 @@
 		$keyword_results = $author_results = array();
 
 		// Search a specific forum?
-		$forum_sql = ($forum != -1) ? ' AND t.forum_id = '.$forum : '';
+		$forum_sql = ($forum != -1 || ($forum == -1 && $pun_config['o_search_all_forums'] == '0')) ? ' AND t.forum_id = '.$forum : '';
 
 		if (!empty($author) || !empty($keywords))
 		{
@@ -326,7 +326,7 @@
 				if ($pun_user['is_guest'])
 					message($lang_common['No permission']);
 
-				$result = $db->query('SELECT t.id 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='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.last_post>'.$pun_user['last_visit']) or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
+				$result = $db->query('SELECT t.id 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='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.last_post>'.$pun_user['last_visit'].' AND t.moved_to IS NULL') or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
 				$num_hits = $db->num_rows($result);
 
 				if (!$num_hits)
@@ -335,7 +335,7 @@
 			// If it's a search for todays posts
 			else if ($action == 'show_24h')
 			{
-				$result = $db->query('SELECT t.id 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='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.last_post>'.(time() - 86400)) or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
+				$result = $db->query('SELECT t.id 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='.$pun_user['g_id'].') WHERE (fp.read_forum IS NULL OR fp.read_forum=1) AND t.last_post>'.(time() - 86400).' AND t.moved_to IS NULL') or error('Unable to fetch topic list', __FILE__, __LINE__, $db->error());
 				$num_hits = $db->num_rows($result);
 
 				if (!$num_hits)
@@ -430,7 +430,6 @@
 	// Fetch results to display
 	if ($search_results != '')
 	{
-		$group_by_sql = '';
 		switch ($sort_by)
 		{
 			case 1:
@@ -450,14 +449,8 @@
 				break;
 
 			default:
-			{
 				$sort_by_sql = ($show_as == 'topics') ? 't.posted' : 'p.posted';
-
-				if ($show_as == 'topics')
-					$group_by_sql = ', t.posted';
-
 				break;
-			}
 		}
 
 		if ($show_as == 'posts')
@@ -466,7 +459,7 @@
 			$sql = 'SELECT p.id AS pid, p.poster AS pposter, p.posted AS pposted, p.poster_id, '.$substr_sql.'(p.message, 1, 1000) AS message, t.id AS tid, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.forum_id FROM '.$db->prefix.'posts AS p INNER JOIN '.$db->prefix.'topics AS t ON t.id=p.topic_id WHERE p.id IN('.$search_results.') ORDER BY '.$sort_by_sql;
 		}
 		else
-			$sql = 'SELECT t.id AS tid, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id FROM '.$db->prefix.'topics AS t WHERE t.id IN('.$search_results.') GROUP BY t.id, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id'.$group_by_sql.' ORDER BY '.$sort_by_sql;
+			$sql = 'SELECT t.id AS tid, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id FROM '.$db->prefix.'topics AS t WHERE t.id IN('.$search_results.') ORDER BY '.$sort_by_sql;
 
 
 		// Determine the topic or post offset (based on $_GET['p'])
diff -urN punbb-1.2.14/upload/style/imports/base.css punbb-1.2.15/upload/style/imports/base.css
--- punbb-1.2.14/upload/style/imports/base.css	Tue Oct 10 17:48:32 2006
+++ punbb-1.2.15/upload/style/imports/base.css	Mon Jan 15 00:52:30 2007
@@ -175,7 +175,8 @@
 DIV.postleft, DIV.postfootleft {
 	FLOAT:left;
 	WIDTH: 18em;
-	OVERFLOW: hidden
+	OVERFLOW: hidden;
+	POSITION: relative;
 }
 	
 DIV.postright, DIV.postfootright {
diff -urN punbb-1.2.14/upload/userlist.php punbb-1.2.15/upload/userlist.php
--- punbb-1.2.14/upload/userlist.php	Sat May 20 17:53:30 2006
+++ punbb-1.2.15/upload/userlist.php	Tue Apr 10 23:37:36 2007
@@ -41,7 +41,7 @@
 // Determine if we are allowed to view post counts
 $show_post_count = ($pun_config['o_show_post_count'] == '1' || $pun_user['g_id'] < PUN_GUEST) ? true : false;
 
-$username = (isset($_GET['username']) && $pun_user['g_search_users'] == '1') ? $_GET['username'] : '';
+$username = (isset($_GET['username']) && $pun_user['g_search_users'] == '1') ? pun_trim($_GET['username']) : '';
 $show_group = (!isset($_GET['show_group']) || intval($_GET['show_group']) < -1 && intval($_GET['show_group']) > 2) ? -1 : intval($_GET['show_group']);
 $sort_by = (!isset($_GET['sort_by']) || $_GET['sort_by'] != 'username' && $_GET['sort_by'] != 'registered' && ($_GET['sort_by'] != 'num_posts' || !$show_post_count)) ? 'username' : $_GET['sort_by'];
 $sort_dir = (!isset($_GET['sort_dir']) || $_GET['sort_dir'] != 'ASC' && $_GET['sort_dir'] != 'DESC') ? 'ASC' : strtoupper($_GET['sort_dir']);
