[Xfce4-commits] <forum:master> Update to fluxbb 1.4.6.

Nick Schermer noreply at xfce.org
Sat Aug 13 10:20:01 CEST 2011


Updating branch refs/heads/master
         to 55fb12bac325e2cb544a42a688811c36097313d7 (commit)
       from 402e40219adb4887f56ba58aa19fabd54973e497 (commit)

commit 55fb12bac325e2cb544a42a688811c36097313d7
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Aug 13 09:36:53 2011 +0200

    Update to fluxbb 1.4.6.

 admin_bans.php                                     |   14 +-
 admin_categories.php                               |    2 +-
 admin_forums.php                                   |   23 +-
 admin_groups.php                                   |   54 +++--
 admin_index.php                                    |   15 +-
 admin_loader.php                                   |    2 +-
 admin_maintenance.php                              |    2 +-
 admin_options.php                                  |    2 +-
 admin_prune.php                                    |  217 --------------------
 admin_ranks.php                                    |    4 +-
 admin_users.php                                    |  141 ++++++++-----
 common.js                                          |   32 +++
 db_update.php                                      |  109 +++++++++--
 header.php                                         |   20 +-
 help.php                                           |   11 +-
 img/smilies/big_smile.png                          |  Bin 544 -> 451 bytes
 img/smilies/cool.png                               |  Bin 560 -> 493 bytes
 img/smilies/hmm.png                                |  Bin 564 -> 495 bytes
 img/smilies/lol.png                                |  Bin 538 -> 461 bytes
 img/smilies/mad.png                                |  Bin 560 -> 500 bytes
 img/smilies/neutral.png                            |  Bin 565 -> 482 bytes
 img/smilies/roll.png                               |  Bin 559 -> 510 bytes
 img/smilies/sad.png                                |  Bin 568 -> 487 bytes
 img/smilies/smile.png                              |  Bin 598 -> 513 bytes
 img/smilies/tongue.png                             |  Bin 563 -> 503 bytes
 img/smilies/wink.png                               |  Bin 642 -> 530 bytes
 img/smilies/yikes.png                              |  Bin 554 -> 467 bytes
 img/test.png                                       |  Bin 6369 -> 3680 bytes
 include/cache.php                                  |    2 +-
 include/common.php                                 |   24 +--
 include/common_admin.php                           |    6 +-
 include/dblayer/common_db.php                      |   12 +-
 include/dblayer/mysql.php                          |    4 +-
 include/dblayer/mysql_innodb.php                   |    4 +-
 include/dblayer/mysqli.php                         |    4 +-
 include/dblayer/mysqli_innodb.php                  |    4 +-
 include/dblayer/pgsql.php                          |   18 +-
 include/dblayer/sqlite.php                         |   22 +-
 include/email.php                                  |  188 +++++++++++++++--
 include/functions.php                              |  108 ++++++++---
 include/parser.php                                 |  184 +++++++++--------
 include/search_idx.php                             |   16 +-
 lang/English/admin_groups.php                      |    4 +-
 lang/English/admin_index.php                       |    6 +-
 lang/English/admin_plugin_example.php              |   17 --
 lang/English/admin_prune.php                       |   23 --
 lang/English/admin_users.php                       |    3 +
 lang/English/common.php                            |   30 +--
 lang/English/help.php                              |    6 +
 lang/English/mail_templates/activate_email.tpl     |    2 +-
 lang/English/mail_templates/activate_password.tpl  |    2 +-
 .../English/mail_templates/banned_email_change.tpl |    9 +
 lang/English/mail_templates/banned_email_post.tpl  |    9 +
 .../mail_templates/banned_email_register.tpl       |    9 +
 lang/English/mail_templates/dupe_email_change.tpl  |    9 +
 .../English/mail_templates/dupe_email_register.tpl |    9 +
 lang/English/mail_templates/form_email.tpl         |    2 +-
 lang/English/mail_templates/new_reply.tpl          |    2 +-
 lang/English/mail_templates/new_reply_full.tpl     |    2 +-
 lang/English/mail_templates/new_report.tpl         |    9 +
 lang/English/mail_templates/new_topic.tpl          |    2 +-
 lang/English/mail_templates/new_topic_full.tpl     |    2 +-
 lang/English/mail_templates/new_user.tpl           |    9 +
 lang/English/mail_templates/rename.tpl             |    2 +-
 lang/English/mail_templates/welcome.tpl            |    2 +-
 lang/English/profile.php                           |    1 +
 lang/English/search.php                            |   20 +-
 lang/English/topic.php                             |    9 +-
 lang/English/update.php                            |    7 +-
 login.php                                          |    8 +-
 misc.php                                           |   28 ++-
 moderate.php                                       |   20 +-
 post.php                                           |   56 ++++--
 profile.php                                        |   67 +++++--
 register.php                                       |   57 ++++--
 search.php                                         |   97 ++++++---
 style/Air.css                                      |   64 ++++++-
 style/Air/base_admin.css                           |   26 ++-
 style/Cobalt.css                                   |  132 +++++++++---
 style/Earth.css                                    |   63 ++++++-
 style/Earth/base_admin.css                         |   26 ++-
 style/Fire.css                                     |   63 ++++++-
 style/Fire/base_admin.css                          |   26 ++-
 style/Lithium.css                                  |  132 +++++++++---
 style/Mercury.css                                  |  132 +++++++++---
 style/Oxygen.css                                   |  132 +++++++++---
 style/Radium.css                                   |  132 +++++++++---
 style/Sulfur.css                                   |  132 +++++++++---
 style/Technetium.css                               |   64 ++++++
 style/imports/base_admin.css                       |   11 +-
 userlist.php                                       |    3 +-
 viewforum.php                                      |   23 +--
 viewtopic.php                                      |   32 +--
 93 files changed, 1994 insertions(+), 983 deletions(-)

diff --git a/admin_bans.php b/admin_bans.php
index acd2a6e..d141889 100644
--- a/admin_bans.php
+++ b/admin_bans.php
@@ -192,7 +192,7 @@ else if (isset($_POST['add_edit_ban']))
 		message($lang_admin_bans['Must enter message']);
 	else if (strtolower($ban_user) == 'guest')
 		message($lang_admin_bans['Cannot ban guest message']);
-	
+
 	// Make sure we're not banning an admin or moderator
 	if (!empty($ban_user))
 	{
@@ -200,13 +200,13 @@ else if (isset($_POST['add_edit_ban']))
 		if ($db->num_rows($result))
 		{
 			$group_id = $db->result($result);
-			
+
 			if ($group_id == PUN_ADMIN)
 				message(sprintf($lang_admin_bans['User is admin message'], pun_htmlspecialchars($ban_user)));
-	
+
 			$result = $db->query('SELECT g_moderator FROM '.$db->prefix.'groups WHERE g_id='.$group_id) or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
 			$is_moderator_group = $db->result($result);
-	
+
 			if ($is_moderator_group)
 				message(sprintf($lang_admin_bans['User is mod message'], pun_htmlspecialchars($ban_user)));
 		}
@@ -215,7 +215,7 @@ else if (isset($_POST['add_edit_ban']))
 	// Validate IP/IP range (it's overkill, I know)
 	if ($ban_ip != '')
 	{
-		$ban_ip = preg_replace('/\s{2,}/S', ' ', $ban_ip);
+		$ban_ip = preg_replace('%\s{2,}%S', ' ', $ban_ip);
 		$addresses = explode(' ', $ban_ip);
 		$addresses = array_map('pun_trim', $addresses);
 
@@ -244,7 +244,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)
+					if ($c > 3 || preg_match('%[^0-9]%', $octets[$c]) || intval($octets[$c]) > 255)
 						message($lang_admin_bans['Invalid IP message']);
 				}
 
@@ -259,7 +259,7 @@ else if (isset($_POST['add_edit_ban']))
 	require PUN_ROOT.'include/email.php';
 	if ($ban_email != '' && !is_valid_email($ban_email))
 	{
-		if (!preg_match('/^[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/', $ban_email))
+		if (!preg_match('%^[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$%', $ban_email))
 			message($lang_admin_bans['Invalid e-mail message']);
 	}
 
diff --git a/admin_categories.php b/admin_categories.php
index 2877cd3..7f5ec0f 100644
--- a/admin_categories.php
+++ b/admin_categories.php
@@ -138,7 +138,7 @@ else if (isset($_POST['update'])) // Change position and name of the categories
 		if ($cur_cat['name'] == '')
 			message($lang_admin_categories['Must enter name message']);
 
-		if ($cur_cat['order'] == '' || preg_match('/[^0-9]/', $cur_cat['order']))
+		if ($cur_cat['order'] == '' || preg_match('%[^0-9]%', $cur_cat['order']))
 			message($lang_admin_categories['Must enter integer message']);
 
 		$db->query('UPDATE '.$db->prefix.'categories SET cat_name=\''.$db->escape($cur_cat['name']).'\', disp_position='.$cur_cat['order'].' WHERE id='.intval($cat_id)) or error('Unable to update category', __FILE__, __LINE__, $db->error());
diff --git a/admin_forums.php b/admin_forums.php
index 9fe2adc..1d15a2a 100644
--- a/admin_forums.php
+++ b/admin_forums.php
@@ -128,7 +128,7 @@ else if (isset($_POST['update_positions']))
 	foreach ($_POST['position'] as $forum_id => $disp_position)
 	{
 		$disp_position = trim($disp_position);
-		if ($disp_position == '' || preg_match('/[^0-9]/', $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());
@@ -308,6 +308,8 @@ else if (isset($_GET['edit_forum']))
 
 	$result = $db->query('SELECT g.g_id, g.g_title, g.g_read_board, g.g_post_replies, g.g_post_topics, fp.read_forum, fp.post_replies, fp.post_topics FROM '.$db->prefix.'groups AS g LEFT JOIN '.$db->prefix.'forum_perms AS fp ON (g.g_id=fp.group_id AND fp.forum_id='.$forum_id.') WHERE g.g_id!='.PUN_ADMIN.' ORDER BY g.g_id') or error('Unable to fetch group forum permission list', __FILE__, __LINE__, $db->error());
 
+	$cur_index = 7;
+
 	while ($cur_perm = $db->fetch_assoc($result))
 	{
 		$read_forum = ($cur_perm['read_forum'] != '0') ? true : false;
@@ -324,15 +326,15 @@ else if (isset($_GET['edit_forum']))
 									<th class="atcl"><?php echo pun_htmlspecialchars($cur_perm['g_title']) ?></th>
 									<td<?php if (!$read_forum_def) echo ' class="nodefault"'; ?>>
 										<input type="hidden" name="read_forum_old[<?php echo $cur_perm['g_id'] ?>]" value="<?php echo ($read_forum) ? '1' : '0'; ?>" />
-										<input type="checkbox" name="read_forum_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($read_forum) ? ' checked="checked"' : ''; ?><?php echo ($cur_perm['g_read_board'] == '0') ? ' disabled="disabled"' : ''; ?> />
+										<input type="checkbox" name="read_forum_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($read_forum) ? ' checked="checked"' : ''; ?><?php echo ($cur_perm['g_read_board'] == '0') ? ' disabled="disabled"' : ''; ?> tabindex="<?php echo $cur_index++ ?>" />
 									</td>
 									<td<?php if (!$post_replies_def && $cur_forum['redirect_url'] == '') echo ' class="nodefault"'; ?>>
 										<input type="hidden" name="post_replies_old[<?php echo $cur_perm['g_id'] ?>]" value="<?php echo ($post_replies) ? '1' : '0'; ?>" />
-										<input type="checkbox" name="post_replies_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($post_replies) ? ' checked="checked"' : ''; ?><?php echo ($cur_forum['redirect_url'] != '') ? ' disabled="disabled"' : ''; ?> />
+										<input type="checkbox" name="post_replies_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($post_replies) ? ' checked="checked"' : ''; ?><?php echo ($cur_forum['redirect_url'] != '') ? ' disabled="disabled"' : ''; ?> tabindex="<?php echo $cur_index++ ?>" />
 									</td>
 									<td<?php if (!$post_topics_def && $cur_forum['redirect_url'] == '') echo ' class="nodefault"'; ?>>
 										<input type="hidden" name="post_topics_old[<?php echo $cur_perm['g_id'] ?>]" value="<?php echo ($post_topics) ? '1' : '0'; ?>" />
-										<input type="checkbox" name="post_topics_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($post_topics) ? ' checked="checked"' : ''; ?><?php echo ($cur_forum['redirect_url'] != '') ? ' disabled="disabled"' : ''; ?> />
+										<input type="checkbox" name="post_topics_new[<?php echo $cur_perm['g_id'] ?>]" value="1"<?php echo ($post_topics) ? ' checked="checked"' : ''; ?><?php echo ($cur_forum['redirect_url'] != '') ? ' disabled="disabled"' : ''; ?> tabindex="<?php echo $cur_index++ ?>" />
 									</td>
 								</tr>
 <?php
@@ -342,11 +344,11 @@ else if (isset($_GET['edit_forum']))
 ?>
 							</tbody>
 							</table>
-							<div class="fsetsubmit"><input type="submit" name="revert_perms" value="<?php echo $lang_admin_forums['Revert to default'] ?>" /></div>
+							<div class="fsetsubmit"><input type="submit" name="revert_perms" value="<?php echo $lang_admin_forums['Revert to default'] ?>" tabindex="<?php echo $cur_index++ ?>" /></div>
 						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" /></p>
+				<p class="submitend"><input type="submit" name="save" value="<?php echo $lang_admin_common['Save changes'] ?>" tabindex="<?php echo $cur_index++ ?>" /></p>
 			</form>
 		</div>
 	</div>
@@ -415,7 +417,7 @@ if ($db->num_rows($result) > 0)
 				<p class="submittop"><input type="submit" name="update_positions" value="<?php echo $lang_admin_forums['Update positions'] ?>" tabindex="3" /></p>
 <?php
 
-$tabindex_count = 4;
+$cur_index = 4;
 
 $cur_category = 0;
 while ($cur_forum = $db->fetch_assoc($result))
@@ -446,13 +448,12 @@ while ($cur_forum = $db->fetch_assoc($result))
 
 ?>
 								<tr>
-									<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="tcl"><a href="admin_forums.php?edit_forum=<?php echo $cur_forum['fid'] ?>" tabindex="<?php echo $cur_index++ ?>"><?php echo $lang_admin_forums['Edit link'] ?></a> | <a href="admin_forums.php?del_forum=<?php echo $cur_forum['fid'] ?>" tabindex="<?php echo $cur_index++ ?>"><?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 $cur_index++ ?>" /></td>
 									<td class="tcr"><strong><?php echo pun_htmlspecialchars($cur_forum['forum_name']) ?></strong></td>
 								</tr>
 <?php
 
-	$tabindex_count += 2;
 }
 
 ?>
@@ -461,7 +462,7 @@ while ($cur_forum = $db->fetch_assoc($result))
 						</div>
 					</fieldset>
 				</div>
-				<p class="submitend"><input type="submit" name="update_positions" value="<?php echo $lang_admin_forums['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 $cur_index++ ?>" /></p>
 			</form>
 		</div>
 <?php
diff --git a/admin_groups.php b/admin_groups.php
index 1e1e9bd..7852e79 100644
--- a/admin_groups.php
+++ b/admin_groups.php
@@ -101,128 +101,135 @@ if (isset($_POST['add_group']) || isset($_GET['edit_group']))
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="mod_rename_users" value="0"<?php if ($group['g_mod_rename_users'] == '0') echo ' checked="checked"' ?> tabindex="6" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="mod_rename_users" value="1"<?php if ($group['g_mod_rename_users'] == '1') echo ' checked="checked"' ?> tabindex="7" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="mod_rename_users" value="0"<?php if ($group['g_mod_rename_users'] == '0') echo ' checked="checked"' ?> tabindex="8" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
 										<span><?php echo $lang_admin_groups['Rename users help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="mod_change_passwords" value="0"<?php if ($group['g_mod_change_passwords'] == '0') echo ' checked="checked"' ?> tabindex="6" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="mod_change_passwords" value="1"<?php if ($group['g_mod_change_passwords'] == '1') echo ' checked="checked"' ?> tabindex="9" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="mod_change_passwords" value="0"<?php if ($group['g_mod_change_passwords'] == '0') echo ' checked="checked"' ?> tabindex="10" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
 										<span><?php echo $lang_admin_groups['Change passwords help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="mod_ban_users" value="0"<?php if ($group['g_mod_ban_users'] == '0') echo ' checked="checked"' ?> tabindex="6" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="mod_ban_users" value="1"<?php if ($group['g_mod_ban_users'] == '1') echo ' checked="checked"' ?> tabindex="11" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="mod_ban_users" value="0"<?php if ($group['g_mod_ban_users'] == '0') echo ' checked="checked"' ?> tabindex="12" /> <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"><?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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="read_board" value="0"<?php if ($group['g_read_board'] == '0') echo ' checked="checked"' ?> tabindex="4" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="read_board" value="1"<?php if ($group['g_read_board'] == '1') echo ' checked="checked"' ?> tabindex="13" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="read_board" value="0"<?php if ($group['g_read_board'] == '0') echo ' checked="checked"' ?> tabindex="14" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
 										<span><?php echo $lang_admin_groups['Read board help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="view_users" value="0"<?php if ($group['g_view_users'] == '0') echo ' checked="checked"' ?> tabindex="4" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="view_users" value="1"<?php if ($group['g_view_users'] == '1') echo ' checked="checked"' ?> tabindex="15" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="view_users" value="0"<?php if ($group['g_view_users'] == '0') echo ' checked="checked"' ?> tabindex="16" /> <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"><?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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="post_replies" value="0"<?php if ($group['g_post_replies'] == '0') echo ' checked="checked"' ?> tabindex="6" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="post_replies" value="1"<?php if ($group['g_post_replies'] == '1') echo ' checked="checked"' ?> tabindex="17" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="post_replies" value="0"<?php if ($group['g_post_replies'] == '0') echo ' checked="checked"' ?> tabindex="18" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
 										<span><?php echo $lang_admin_groups['Post replies help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="post_topics" value="0"<?php if ($group['g_post_topics'] == '0') echo ' checked="checked"' ?> tabindex="8" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="post_topics" value="1"<?php if ($group['g_post_topics'] == '1') echo ' checked="checked"' ?> tabindex="19" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="post_topics" value="0"<?php if ($group['g_post_topics'] == '0') echo ' checked="checked"' ?> tabindex="20" /> <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"><?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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="edit_posts" value="0"<?php if ($group['g_edit_posts'] == '0') echo ' checked="checked"' ?> tabindex="12" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="edit_posts" value="1"<?php if ($group['g_edit_posts'] == '1') echo ' checked="checked"' ?> tabindex="21" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="edit_posts" value="0"<?php if ($group['g_edit_posts'] == '0') echo ' checked="checked"' ?> tabindex="22" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
 										<span><?php echo $lang_admin_groups['Edit posts help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="delete_posts" value="0"<?php if ($group['g_delete_posts'] == '0') echo ' checked="checked"' ?> tabindex="14" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="delete_posts" value="1"<?php if ($group['g_delete_posts'] == '1') echo ' checked="checked"' ?> tabindex="23" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="delete_posts" value="0"<?php if ($group['g_delete_posts'] == '0') echo ' checked="checked"' ?> tabindex="24" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
 										<span><?php echo $lang_admin_groups['Delete posts help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="delete_topics" value="0"<?php if ($group['g_delete_topics'] == '0') echo ' checked="checked"' ?> tabindex="16" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="delete_topics" value="1"<?php if ($group['g_delete_topics'] == '1') echo ' checked="checked"' ?> tabindex="25" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="delete_topics" value="0"<?php if ($group['g_delete_topics'] == '0') echo ' checked="checked"' ?> tabindex="26" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
 										<span><?php echo $lang_admin_groups['Delete topics help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="set_title" value="0"<?php if ($group['g_set_title'] == '0') echo ' checked="checked"' ?> tabindex="18" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="set_title" value="1"<?php if ($group['g_set_title'] == '1') echo ' checked="checked"' ?> tabindex="27" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="set_title" value="0"<?php if ($group['g_set_title'] == '0') echo ' checked="checked"' ?> tabindex="28" /> <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"><?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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="search" value="0"<?php if ($group['g_search'] == '0') echo ' checked="checked"' ?> tabindex="20" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="search" value="1"<?php if ($group['g_search'] == '1') echo ' checked="checked"' ?> tabindex="29" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="search" value="0"<?php if ($group['g_search'] == '0') echo ' checked="checked"' ?> tabindex="30" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
 										<span><?php echo $lang_admin_groups['User search help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="search_users" value="0"<?php if ($group['g_search_users'] == '0') echo ' checked="checked"' ?> tabindex="22" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="search_users" value="1"<?php if ($group['g_search_users'] == '1') echo ' checked="checked"' ?> tabindex="31" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="search_users" value="0"<?php if ($group['g_search_users'] == '0') echo ' checked="checked"' ?> tabindex="32" /> <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"><?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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="send_email" value="0"<?php if ($group['g_send_email'] == '0') echo ' checked="checked"' ?> tabindex="22" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
+										<input type="radio" name="send_email" value="1"<?php if ($group['g_send_email'] == '1') echo ' checked="checked"' ?> tabindex="33" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="send_email" value="0"<?php if ($group['g_send_email'] == '0') echo ' checked="checked"' ?> tabindex="34" /> <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"><?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" />
+										<input type="text" name="post_flood" size="5" maxlength="4" value="<?php echo $group['g_post_flood'] ?>" tabindex="35" />
 										<span><?php echo $lang_admin_groups['Post flood help'] ?></span>
 									</td>
 								</tr>
 								<tr>
 									<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" />
+										<input type="text" name="search_flood" size="5" maxlength="4" value="<?php echo $group['g_search_flood'] ?>" tabindex="36" />
 										<span><?php echo $lang_admin_groups['Search flood help'] ?></span>
 									</td>
 								</tr>
 <?php if ($group['g_id'] != PUN_GUEST): ?>								<tr>
 									<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" />
+										<input type="text" name="email_flood" size="5" maxlength="4" value="<?php echo $group['g_email_flood'] ?>" tabindex="37" />
 										<span><?php echo $lang_admin_groups['E-mail flood help'] ?></span>
 									</td>
 								</tr>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_groups['Report flood label'] ?></th>
+									<td>
+										<input type="text" name="report_flood" size="5" maxlength="4" value="<?php echo $group['g_report_flood'] ?>" tabindex="38" />
+										<span><?php echo $lang_admin_groups['Report flood help'] ?></span>
+									</td>
+								</tr>
 <?php endif; endif; ?>							</table>
 <?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="<?php echo $lang_admin_common['Save'] ?>" tabindex="26" /></p>
+				<p class="submitend"><input type="submit" name="add_edit_group" value="<?php echo $lang_admin_common['Save'] ?>" tabindex="39" /></p>
 			</form>
 		</div>
 	</div>
@@ -263,6 +270,7 @@ else if (isset($_POST['add_edit_group']))
 	$post_flood = isset($_POST['post_flood']) ? intval($_POST['post_flood']) : '0';
 	$search_flood = isset($_POST['search_flood']) ? intval($_POST['search_flood']) : '0';
 	$email_flood = isset($_POST['email_flood']) ? intval($_POST['email_flood']) : '0';
+	$report_flood = isset($_POST['report_flood']) ? intval($_POST['report_flood']) : '0';
 
 	if ($title == '')
 		message($lang_admin_groups['Must enter title message']);
@@ -275,7 +283,7 @@ else if (isset($_POST['add_edit_group']))
 		if ($db->num_rows($result))
 			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());
+		$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, g_report_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.', '.$report_flood.')') or error('Unable to add group', __FILE__, __LINE__, $db->error());
 		$new_group_id = $db->insert_id();
 
 		// Now lets copy the forum specific permissions from the group which this group is based on
@@ -289,7 +297,7 @@ else if (isset($_POST['add_edit_group']))
 		if ($db->num_rows($result))
 			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());
+		$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.', g_report_flood='.$report_flood.' WHERE g_id='.intval($_POST['group_id'])) or error('Unable to update group', __FILE__, __LINE__, $db->error());
 	}
 
 	// Regenerate the quick jump cache
@@ -393,7 +401,7 @@ else if (isset($_GET['del_group']))
 						</div>
 					</fieldset>
 				</div>
-				<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>
+				<p class="buttons"><input type="submit" name="del_group_comply" value="<?php echo $lang_admin_common['Delete'] ?>" tabindex="1" /><a href="javascript:history.go(-1)" tabindex="2"><?php echo $lang_admin_common['Go back'] ?></a></p>
 			</form>
 		</div>
 	</div>
@@ -540,10 +548,12 @@ while ($cur_group = $db->fetch_assoc($result))
 							<table cellspacing="0">
 <?php
 
+$cur_index = 5;
+
 $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'].'">'.$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";
+	echo "\t\t\t\t\t\t\t\t".'<tr><th scope="row"><a href="admin_groups.php?edit_group='.$cur_group['g_id'].'" tabindex="'.$cur_index++.'">'.$lang_admin_groups['Edit link'].'</a>'.(($cur_group['g_id'] > PUN_MEMBER) ? ' | <a href="admin_groups.php?del_group='.$cur_group['g_id'].'" tabindex="'.$cur_index++.'">'.$lang_admin_groups['Delete link'].'</a>' : '').'</th><td>'.pun_htmlspecialchars($cur_group['g_title']).'</td></tr>'."\n";
 
 ?>
 							</table>
diff --git a/admin_index.php b/admin_index.php
index 0064f6a..e4f6023 100644
--- a/admin_index.php
+++ b/admin_index.php
@@ -70,7 +70,7 @@ if (@file_exists('/proc/loadavg') && is_readable('/proc/loadavg'))
 	$load_averages = @explode(' ', $load_averages);
 	$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 = $lang_admin_index['Not available'];
@@ -147,24 +147,25 @@ generate_admin_menu('index');
 				<dl>
 					<dt><?php echo $lang_admin_index['FluxBB version label'] ?></dt>
 					<dd>
-						<?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>') ?>
+						<?php printf($lang_admin_index['FluxBB version data']."\n", $pun_config['o_cur_version'], '<a href="admin_index.php?action=check_upgrade">'.$lang_admin_index['Check for upgrade'].'</a>') ?>
 					</dd>
 					<dt><?php echo $lang_admin_index['Server load label'] ?></dt>
 					<dd>
-						<?php printf($lang_admin_index['Server load data'], $server_load, $num_online) ?>
+						<?php printf($lang_admin_index['Server load data']."\n", $server_load, $num_online) ?>
 					</dd>
 <?php if ($pun_user['g_id'] == PUN_ADMIN): ?>					<dt><?php echo $lang_admin_index['Environment label'] ?></dt>
 					<dd>
 						<?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) ?>
+						<?php printf($lang_admin_index['Environment data acc']."\n", $php_accelerator) ?>
 					</dd>
 					<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 /><?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; ?>					</dd><?php endif; ?>
+<?php if (isset($total_records) && isset($total_size)): ?>						<br /><?php printf($lang_admin_index['Database data rows']."\n", forum_number_format($total_records)) ?>
+						<br /><?php printf($lang_admin_index['Database data size']."\n", $total_size) ?>
+<?php endif; ?>					</dd>
+<?php endif; ?>
 				</dl>
 			</div>
 		</div>
diff --git a/admin_loader.php b/admin_loader.php
index ceaf51c..7e753cd 100644
--- a/admin_loader.php
+++ b/admin_loader.php
@@ -19,7 +19,7 @@ if (!$pun_user['is_admmod'])
 
 // 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 --git a/admin_maintenance.php b/admin_maintenance.php
index fe58efe..60cb957 100644
--- a/admin_maintenance.php
+++ b/admin_maintenance.php
@@ -173,7 +173,7 @@ if ($action == 'prune')
 	}
 
 	$prune_days = trim($_POST['req_prune_days']);
-	if ($prune_days == '' || preg_match('/[^0-9]/', $prune_days))
+	if ($prune_days == '' || preg_match('%[^0-9]%', $prune_days))
 		message($lang_admin_maintenance['Days must be integer message']);
 
 	$prune_date = time() - ($prune_days * 86400);
diff --git a/admin_options.php b/admin_options.php
index fb4396c..fdabe2b 100644
--- a/admin_options.php
+++ b/admin_options.php
@@ -118,7 +118,7 @@ if (isset($_POST['form_sent']))
 		message($lang_admin_options['Invalid webmaster e-mail message']);
 
 	if ($form['mailing_list'] != '')
-		$form['mailing_list'] = strtolower(preg_replace('/\s/S', '', $form['mailing_list']));
+		$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) == '/')
diff --git a/admin_prune.php b/admin_prune.php
deleted file mode 100644
index 8d80c87..0000000
--- a/admin_prune.php
+++ /dev/null
@@ -1,217 +0,0 @@
-<?php
-
-/**
- * Copyright (C) 2008-2011 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);
-
-define('PUN_ROOT', dirname(__FILE__).'/');
-require PUN_ROOT.'include/common.php';
-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']))
-{
-	$prune_from = trim($_POST['prune_from']);
-	$prune_sticky = intval($_POST['prune_sticky']);
-
-	if (isset($_POST['prune_comply']))
-	{
-		confirm_referrer('admin_prune.php');
-
-		$prune_days = intval($_POST['prune_days']);
-		$prune_date = ($prune_days) ? time() - ($prune_days * 86400) : -1;
-
-		@set_time_limit(0);
-
-		if ($prune_from == 'all')
-		{
-			$result = $db->query('SELECT id FROM '.$db->prefix.'forums') or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
-			$num_forums = $db->num_rows($result);
-
-			for ($i = 0; $i < $num_forums; ++$i)
-			{
-				$fid = $db->result($result, $i);
-
-				prune($fid, $prune_sticky, $prune_date);
-				update_forum($fid);
-			}
-		}
-		else
-		{
-			$prune_from = intval($prune_from);
-			prune($prune_from, $prune_sticky, $prune_date);
-			update_forum($prune_from);
-		}
-
-		// Locate any "orphaned redirect topics" and delete them
-		$result = $db->query('SELECT t1.id FROM '.$db->prefix.'topics AS t1 LEFT JOIN '.$db->prefix.'topics AS t2 ON t1.moved_to=t2.id WHERE t2.id IS NULL AND t1.moved_to IS NOT NULL') or error('Unable to fetch redirect topics', __FILE__, __LINE__, $db->error());
-		$num_orphans = $db->num_rows($result);
-
-		if ($num_orphans)
-		{
-			for ($i = 0; $i < $num_orphans; ++$i)
-				$orphans[] = $db->result($result, $i);
-
-			$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', $lang_admin_prune['Posts pruned redirect']);
-	}
-
-	$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);
-
-	// 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 ($prune_sticky == '0')
-		$sql .= ' AND sticky=\'0\'';
-
-	if ($prune_from != 'all')
-	{
-		$prune_from = intval($prune_from);
-		$sql .= ' AND forum_id='.$prune_from;
-
-		// Fetch the forum name (just for cosmetic reasons)
-		$result = $db->query('SELECT forum_name FROM '.$db->prefix.'forums WHERE id='.$prune_from) or error('Unable to fetch forum name', __FILE__, __LINE__, $db->error());
-		$forum = '"'.pun_htmlspecialchars($db->result($result)).'"';
-	}
-	else
-		$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(sprintf($lang_admin_prune['No old topics message'], $prune_days));
-
-
-	$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><?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 $prune_sticky ?>" />
-					<input type="hidden" name="prune_from" value="<?php echo $prune_from ?>" />
-					<fieldset>
-						<legend><?php echo $lang_admin_prune['Confirm prune subhead'] ?></legend>
-						<div class="infldset">
-							<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 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>
-	<div class="clearer"></div>
-</div>
-<?php
-
-	require PUN_ROOT.'footer.php';
-}
-
-
-else
-{
-	$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><?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" />
-					<fieldset>
-						<legend><?php echo $lang_admin_prune['Prune subhead'] ?></legend>
-						<div class="infldset">
-							<table class="aligntop" cellspacing="0">
-								<tr>
-									<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><?php echo $lang_admin_prune['Days old help'] ?></span>
-									</td>
-								</tr>
-								<tr>
-									<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" /> <strong><?php echo $lang_admin_common['Yes'] ?></strong>   <input type="radio" name="prune_sticky" value="0" /> <strong><?php echo $lang_admin_common['No'] ?></strong>
-										<span><?php echo $lang_admin_prune['Prune sticky help'] ?></span>
-									</td>
-								</tr>
-								<tr>
-									<th scope="row"><?php echo $lang_admin_prune['Prune from label'] ?></th>
-									<td>
-										<select name="prune_from" tabindex="3">
-											<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());
-
-	$cur_category = 0;
-	while ($forum = $db->fetch_assoc($result))
-	{
-		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";
-
-			echo "\t\t\t\t\t\t\t\t\t\t\t".'<optgroup label="'.pun_htmlspecialchars($forum['cat_name']).'">'."\n";
-			$cur_category = $forum['cid'];
-		}
-
-		echo "\t\t\t\t\t\t\t\t\t\t\t\t".'<option value="'.$forum['fid'].'">'.pun_htmlspecialchars($forum['forum_name']).'</option>'."\n";
-	}
-
-?>
-											</optgroup>
-										</select>
-										<span><?php echo $lang_admin_prune['Prune from help'] ?></span>
-									</td>
-								</tr>
-							</table>
-							<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>
-			</form>
-		</div>
-	</div>
-	<div class="clearer"></div>
-</div>
-<?php
-
-	require PUN_ROOT.'footer.php';
-}
diff --git a/admin_ranks.php b/admin_ranks.php
index 421e812..fb5f7c1 100644
--- a/admin_ranks.php
+++ b/admin_ranks.php
@@ -31,7 +31,7 @@ if (isset($_POST['add_rank']))
 	if ($rank == '')
 		message($lang_admin_ranks['Must enter title message']);
 
-	if ($min_posts == '' || preg_match('/[^0-9]/', $min_posts))
+	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
@@ -64,7 +64,7 @@ else if (isset($_POST['update']))
 	if ($rank == '')
 		message($lang_admin_ranks['Must enter title message']);
 
-	if ($min_posts == '' || preg_match('/[^0-9]/', $min_posts))
+	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
diff --git a/admin_users.php b/admin_users.php
index d9c74d9..d393d24 100644
--- a/admin_users.php
+++ b/admin_users.php
@@ -125,7 +125,7 @@ if (isset($_GET['show_users']))
 {
 	$ip = trim($_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))
+	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($lang_admin_users['Bad IP message']);
 
 	// Fetch user count
@@ -260,26 +260,26 @@ else if (isset($_POST['move_users']) || isset($_POST['move_users_comply']))
 		message($lang_common['No permission']);
 
 	confirm_referrer('admin_users.php');
-	
+
 	if (isset($_POST['users']))
 	{
 		$user_ids = is_array($_POST['users']) ? array_keys($_POST['users']) : explode(',', $_POST['users']);
 		$user_ids = array_map('intval', $user_ids);
-		
+
 		// Delete invalid IDs
 		$user_ids = array_diff($user_ids, array(0, 1));
 	}
 	else
 		$user_ids = array();
-	
+
 	if (empty($user_ids))
 		message($lang_admin_users['No users selected']);
-	
+
 	// Are we trying to batch move any admins?
 	$result = $db->query('SELECT COUNT(*) FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).') AND group_id='.PUN_ADMIN) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
 	if ($db->result($result) > 0)
 		message($lang_admin_users['No move admins message']);
-	
+
 	// Fetch all user groups
 	$all_groups = array();
 	$result = $db->query('SELECT g_id, g_title FROM '.$db->prefix.'groups WHERE g_id NOT IN ('.PUN_GUEST.','.PUN_ADMIN.') ORDER BY g_title ASC') or error('Unable to fetch groups', __FILE__, __LINE__, $db->error());
@@ -289,11 +289,11 @@ else if (isset($_POST['move_users']) || isset($_POST['move_users_comply']))
 	if (isset($_POST['move_users_comply']))
 	{
 		$new_group = isset($_POST['new_group']) && isset($all_groups[$_POST['new_group']]) ? $_POST['new_group'] : message($lang_admin_users['Invalid group message']);
-		
+
 		// Is the new group a moderator group?
 		$result = $db->query('SELECT g_moderator FROM '.$db->prefix.'groups WHERE g_id='.$new_group) or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
 		$new_group_mod = $db->result($result);
-		
+
 		// Fetch user groups
 		$user_groups = array();
 		$result = $db->query('SELECT id, group_id FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).')') or error('Unable to fetch user groups', __FILE__, __LINE__, $db->error());
@@ -301,10 +301,10 @@ else if (isset($_POST['move_users']) || isset($_POST['move_users_comply']))
 		{
 			if (!isset($user_groups[$cur_user['group_id']]))
 				$user_groups[$cur_user['group_id']] = array();
-			
+
 			$user_groups[$cur_user['group_id']][] = $cur_user['id'];
 		}
-		
+
 		// Are any users moderators?
 		$group_ids = array_keys($user_groups);
 		$result = $db->query('SELECT g_id, g_moderator FROM '.$db->prefix.'groups WHERE g_id IN ('.implode(',', $group_ids).')') or error('Unable to fetch group moderators', __FILE__, __LINE__, $db->error());
@@ -313,7 +313,7 @@ else if (isset($_POST['move_users']) || isset($_POST['move_users_comply']))
 			if ($cur_group['g_moderator'] == '0')
 				unset($user_groups[$cur_group['g_id']]);
 		}
-		
+
 		if (!empty($user_groups) && $new_group != PUN_ADMIN && $new_group_mod != '1')
 		{
 			// Fetch forum list and clean up their moderator list
@@ -321,25 +321,25 @@ else if (isset($_POST['move_users']) || isset($_POST['move_users_comply']))
 			while ($cur_forum = $db->fetch_assoc($result))
 			{
 				$cur_moderators = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array();
-	
+
 				foreach ($user_groups as $group_users)
 					$cur_moderators = array_diff($cur_moderators, $group_users);
-				
+
 				$cur_moderators = (!empty($cur_moderators)) ? '\''.$db->escape(serialize($cur_moderators)).'\'' : 'NULL';
 				$db->query('UPDATE '.$db->prefix.'forums SET moderators='.$cur_moderators.' WHERE id='.$cur_forum['id']) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
 			}
 		}
-		
+
 		// Change user group
 		$db->query('UPDATE '.$db->prefix.'users SET group_id='.$new_group.' WHERE id IN ('.implode(',', $user_ids).')') or error('Unable to change user group', __FILE__, __LINE__, $db->error());
-		
+
 		redirect('admin_users.php', $lang_admin_users['Users move redirect']);
 	}
 
 	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Move users']);
 	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
-	
+
 	generate_admin_menu('users');
 
 ?>
@@ -386,21 +386,21 @@ else if (isset($_POST['delete_users']) || isset($_POST['delete_users_comply']))
 		message($lang_common['No permission']);
 
 	confirm_referrer('admin_users.php');
-	
+
 	if (isset($_POST['users']))
 	{
 		$user_ids = is_array($_POST['users']) ? array_keys($_POST['users']) : explode(',', $_POST['users']);
 		$user_ids = array_map('intval', $user_ids);
-		
+
 		// Delete invalid IDs
 		$user_ids = array_diff($user_ids, array(0, 1));
 	}
 	else
 		$user_ids = array();
-	
+
 	if (empty($user_ids))
 		message($lang_admin_users['No users selected']);
-	
+
 	// Are we trying to delete any admins?
 	$result = $db->query('SELECT COUNT(*) FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).') AND group_id='.PUN_ADMIN) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
 	if ($db->result($result) > 0)
@@ -415,10 +415,10 @@ else if (isset($_POST['delete_users']) || isset($_POST['delete_users_comply']))
 		{
 			if (!isset($user_groups[$cur_user['group_id']]))
 				$user_groups[$cur_user['group_id']] = array();
-			
+
 			$user_groups[$cur_user['group_id']][] = $cur_user['id'];
 		}
-		
+
 		// Are any users moderators?
 		$group_ids = array_keys($user_groups);
 		$result = $db->query('SELECT g_id, g_moderator FROM '.$db->prefix.'groups WHERE g_id IN ('.implode(',', $group_ids).')') or error('Unable to fetch group moderators', __FILE__, __LINE__, $db->error());
@@ -427,7 +427,7 @@ else if (isset($_POST['delete_users']) || isset($_POST['delete_users_comply']))
 			if ($cur_group['g_moderator'] == '0')
 				unset($user_groups[$cur_group['g_id']]);
 		}
-		
+
 		// Fetch forum list and clean up their moderator list
 		$result = $db->query('SELECT id, moderators FROM '.$db->prefix.'forums') or error('Unable to fetch forum list', __FILE__, __LINE__, $db->error());
 		while ($cur_forum = $db->fetch_assoc($result))
@@ -436,18 +436,18 @@ else if (isset($_POST['delete_users']) || isset($_POST['delete_users_comply']))
 
 			foreach ($user_groups as $group_users)
 				$cur_moderators = array_diff($cur_moderators, $group_users);
-			
+
 			$cur_moderators = (!empty($cur_moderators)) ? '\''.$db->escape(serialize($cur_moderators)).'\'' : 'NULL';
 			$db->query('UPDATE '.$db->prefix.'forums SET moderators='.$cur_moderators.' WHERE id='.$cur_forum['id']) or error('Unable to update forum', __FILE__, __LINE__, $db->error());
 		}
-		
+
 		// Delete any subscriptions
 		$db->query('DELETE FROM '.$db->prefix.'topic_subscriptions WHERE user_id IN ('.implode(',', $user_ids).')') or error('Unable to delete topic subscriptions', __FILE__, __LINE__, $db->error());
 		$db->query('DELETE FROM '.$db->prefix.'forum_subscriptions WHERE user_id IN ('.implode(',', $user_ids).')') or error('Unable to delete forum subscriptions', __FILE__, __LINE__, $db->error());
-		
+
 		// Remove them from the online list (if they happen to be logged in)
 		$db->query('DELETE FROM '.$db->prefix.'online WHERE user_id IN ('.implode(',', $user_ids).')') or error('Unable to remove users from online list', __FILE__, __LINE__, $db->error());
-		
+
 		// Should we delete all posts made by these users?
 		if (isset($_POST['delete_posts']))
 		{
@@ -482,14 +482,20 @@ else if (isset($_POST['delete_users']) || isset($_POST['delete_users_comply']))
 		// Delete user avatars
 		foreach ($user_ids as $user_id)
 			delete_avatar($user_id);
-		
+
+		// Regenerate the users info cache
+		if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+			require PUN_ROOT.'include/cache.php';
+
+		generate_users_info_cache();
+
 		redirect('admin_users.php', $lang_admin_users['Users delete redirect']);
 	}
 
 	$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_admin_common['Admin'], $lang_admin_common['Users'], $lang_admin_users['Delete users']);
 	define('PUN_ACTIVE_PAGE', 'admin');
 	require PUN_ROOT.'header.php';
-	
+
 	generate_admin_menu('users');
 
 ?>
@@ -529,61 +535,61 @@ else if (isset($_POST['ban_users']) || isset($_POST['ban_users_comply']))
 		message($lang_common['No permission']);
 
 	confirm_referrer('admin_users.php');
-	
+
 	if (isset($_POST['users']))
 	{
 		$user_ids = is_array($_POST['users']) ? array_keys($_POST['users']) : explode(',', $_POST['users']);
 		$user_ids = array_map('intval', $user_ids);
-		
+
 		// Delete invalid IDs
 		$user_ids = array_diff($user_ids, array(0, 1));
 	}
 	else
 		$user_ids = array();
-	
+
 	if (empty($user_ids))
 		message($lang_admin_users['No users selected']);
-	
+
 	// Are we trying to ban any admins?
 	$result = $db->query('SELECT COUNT(*) FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).') AND group_id='.PUN_ADMIN) or error('Unable to fetch group info', __FILE__, __LINE__, $db->error());
 	if ($db->result($result) > 0)
 		message($lang_admin_users['No ban admins message']);
-	
+
 	// Also, we cannot ban moderators
 	$result = $db->query('SELECT COUNT(*) FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id WHERE g.g_moderator=1 AND u.id IN ('.implode(',', $user_ids).')') or error('Unable to fetch moderator group info', __FILE__, __LINE__, $db->error());
 	if ($db->result($result) > 0)
 		message($lang_admin_users['No ban mods message']);
-	
+
 	if (isset($_POST['ban_users_comply']))
 	{
 		$ban_message = pun_trim($_POST['ban_message']);
 		$ban_expire = pun_trim($_POST['ban_expire']);
 		$ban_the_ip = isset($_POST['ban_the_ip']) ? intval($_POST['ban_the_ip']) : 0;
-		
+
 		if ($ban_expire != '' && $ban_expire != 'Never')
 		{
 			$ban_expire = strtotime($ban_expire.' GMT');
-	
+
 			if ($ban_expire == -1 || !$ban_expire)
 				message($lang_admin_users['Invalid date message'].' '.$lang_admin_users['Invalid date reasons']);
-	
+
 			$diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600;
 			$ban_expire -= $diff;
-	
+
 			if ($ban_expire <= time())
 				message($lang_admin_users['Invalid date message'].' '.$lang_admin_users['Invalid date reasons']);
 		}
 		else
 			$ban_expire = 'NULL';
-	
+
 		$ban_message = ($ban_message != '') ? '\''.$db->escape($ban_message).'\'' : 'NULL';
-		
+
 		// Fetch user information
 		$user_info = array();
 		$result = $db->query('SELECT id, username, email, registration_ip FROM '.$db->prefix.'users WHERE id IN ('.implode(',', $user_ids).')') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
 		while ($cur_user = $db->fetch_assoc($result))
 			$user_info[$cur_user['id']] = array('username' => $cur_user['username'], 'email' => $cur_user['email'], 'ip' => $cur_user['registration_ip']);
-		
+
 		// Overwrite the registration IP with one from the last post (if it exists)
 		if ($ban_the_ip != 0)
 		{
@@ -591,23 +597,23 @@ else if (isset($_POST['ban_users']) || isset($_POST['ban_users_comply']))
 			while ($cur_address = $db->fetch_assoc($result))
 				$user_info[$cur_address['poster_id']]['ip'] = $cur_address['poster_ip'];
 		}
-		
+
 		// And insert the bans!
 		foreach ($user_ids as $user_id)
 		{
 			$ban_username = '\''.$db->escape($user_info[$user_id]['username']).'\'';
 			$ban_email = '\''.$db->escape($user_info[$user_id]['email']).'\'';
 			$ban_ip = ($ban_the_ip != 0) ? '\''.$db->escape($user_info[$user_id]['ip']).'\'' : 'NULL';
-			
+
 			$db->query('INSERT INTO '.$db->prefix.'bans (username, ip, email, message, expire, ban_creator) VALUES('.$ban_username.', '.$ban_ip.', '.$ban_email.', '.$ban_message.', '.$ban_expire.', '.$pun_user['id'].')') or error('Unable to add ban', __FILE__, __LINE__, $db->error());
 		}
-		
+
 		// Regenerate the bans cache
 		if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
 			require PUN_ROOT.'include/cache.php';
-	
+
 		generate_bans_cache();
-	
+
 		redirect('admin_users.php', $lang_admin_users['Users banned redirect']);
 	}
 
@@ -678,9 +684,11 @@ else if (isset($_GET['find_user']))
 	$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']) : '';
+	$last_visit_after = isset($_GET['last_visit_after']) ? trim($_GET['last_visit_after']) : '';
+	$last_visit_before = isset($_GET['last_visit_before']) ? trim($_GET['last_visit_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';
+	$order_by = isset($_GET['order_by']) && in_array($_GET['order_by'], array('username', 'email', 'num_posts', 'last_post', 'last_visit', '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;
 
@@ -688,7 +696,7 @@ else if (isset($_GET['find_user']))
 	$query_str[] = 'direction='.$direction;
 	$query_str[] = 'user_group='.$user_group;
 
-	if (preg_match('/[^0-9]/', $posts_greater.$posts_less))
+	if (preg_match('%[^0-9]%', $posts_greater.$posts_less))
 		message($lang_admin_users['Non numeric message']);
 
 	// Try to convert date/time to timestamps
@@ -712,6 +720,26 @@ else if (isset($_GET['find_user']))
 
 		$conditions[] = 'u.last_post<'.$last_post_before;
 	}
+	if ($last_visit_after != '')
+	{
+		$query_str[] = 'last_visit_after='.$last_visit_after;
+
+		$last_visit_after = strtotime($last_visit_after);
+		if ($last_visit_after === false || $last_visit_after == -1)
+			message($lang_admin_users['Invalid date time message']);
+
+		$conditions[] = 'u.last_visit>'.$last_visit_after;
+	}
+	if ($last_visit_before != '')
+	{
+		$query_str[] = 'last_visit_before='.$last_visit_before;
+
+		$last_visit_before = strtotime($last_visit_before);
+		if ($last_visit_before === false || $last_visit_before == -1)
+			message($lang_admin_users['Invalid date time message']);
+
+		$conditions[] = 'u.last_visit<'.$last_visit_before;
+	}
 	if ($registered_after != '')
 	{
 		$query_str[] = 'registered_after='.$registered_after;
@@ -769,7 +797,7 @@ else if (isset($_GET['find_user']))
 
 	// Generate paging links
 	$paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'admin_users.php?find_user=&'.implode('&', $query_str));
-	
+
 	// Some helper variables for permissions
 	$can_delete = $can_move = $pun_user['g_id'] == PUN_ADMIN;
 	$can_ban = $pun_user['g_id'] == PUN_ADMIN || ($pun_user['g_moderator'] == '1' && $pun_user['g_mod_ban_users'] == '1');
@@ -839,7 +867,7 @@ else if (isset($_GET['find_user']))
 					<td class="tc5"><?php echo ($user_data['admin_note'] != '') ? pun_htmlspecialchars($user_data['admin_note']) : ' ' ?></td>
 					<td class="tcr"><?php echo $actions ?></td>
 <?php if ($can_action): ?>					<td class="tcmod"><input type="checkbox" name="users[<?php echo $user_data['id'] ?>]" value="1" /></td>
-<?php endif; ?> 
+<?php endif; ?>
 				</tr>
 <?php
 
@@ -969,6 +997,16 @@ else
 									<span><?php echo $lang_admin_users['Date help'] ?></span></td>
 								</tr>
 								<tr>
+									<th scope="row"><?php echo $lang_admin_users['Last visit after label'] ?></th>
+									<td><input type="text" name="last_visit_after" size="24" maxlength="19" tabindex="17" />
+									<span><?php echo $lang_admin_users['Date help'] ?></span></td>
+								</tr>
+								<tr>
+									<th scope="row"><?php echo $lang_admin_users['Last visit before label'] ?></th>
+									<td><input type="text" name="last_visit_before" size="24" maxlength="19" tabindex="18" />
+									<span><?php echo $lang_admin_users['Date help'] ?></span></td>
+								</tr>
+								<tr>
 									<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>
@@ -986,6 +1024,7 @@ else
 											<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="last_visit"><?php echo $lang_admin_users['Order by last visit'] ?></option>
 											<option value="registered"><?php echo $lang_admin_users['Order by registered'] ?></option>
 										</select>   <select name="direction" tabindex="22">
 											<option value="ASC" selected="selected"><?php echo $lang_admin_users['Ascending'] ?></option>
diff --git a/common.js b/common.js
new file mode 100644
index 0000000..b7ff12f
--- /dev/null
+++ b/common.js
@@ -0,0 +1,32 @@
+
+function select_checkboxes(curFormId, link, new_string)
+{
+	var curForm = document.getElementById(curFormId);
+	var inputlist = curForm.getElementsByTagName("input");
+	for (i = 0; i < inputlist.length; i++)
+	{
+		if (inputlist[i].getAttribute("type") == 'checkbox' && inputlist[i].disabled == false)
+			inputlist[i].checked = true;
+	}
+	
+	link.setAttribute('onclick', 'return unselect_checkboxes(\'' + curFormId + '\', this, \'' + link.innerHTML + '\')');
+	link.innerHTML = new_string;
+
+	return false;
+}
+
+function unselect_checkboxes(curFormId, link, new_string)
+{
+	var curForm = document.getElementById(curFormId);
+	var inputlist = curForm.getElementsByTagName("input");
+	for (i = 0; i < inputlist.length; i++)
+	{
+		if (inputlist[i].getAttribute("type") == 'checkbox' && inputlist[i].disabled == false)
+			inputlist[i].checked = false;
+	}
+	
+	link.setAttribute('onclick', 'return select_checkboxes(\'' + curFormId + '\', this, \'' + link.innerHTML + '\')');
+	link.innerHTML = new_string;
+
+	return false;
+}
\ No newline at end of file
diff --git a/db_update.php b/db_update.php
index b15b777..ce6273d 100644
--- a/db_update.php
+++ b/db_update.php
@@ -7,9 +7,9 @@
  */
 
 // The FluxBB version this script updates to
-define('UPDATE_TO', '1.4.5');
+define('UPDATE_TO', '1.4.6');
 
-define('UPDATE_TO_DB_REVISION', 11);
+define('UPDATE_TO_DB_REVISION', 15);
 define('UPDATE_TO_SI_REVISION', 2);
 define('UPDATE_TO_PARSER_REVISION', 2);
 
@@ -277,8 +277,8 @@ function convert_to_utf8(&$str, $old_charset)
 		$str = html_entity_decode($str, ENT_QUOTES, 'UTF-8');
 
 	// Replace numeric entities
-	$str = preg_replace_callback('/&#([0-9]+);/', 'utf8_callback_1', $str);
-	$str = preg_replace_callback('/&#x([a-f0-9]+);/i', 'utf8_callback_2', $str);
+	$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);
@@ -339,7 +339,7 @@ function alter_table_utf8($table)
 			$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'], 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());
 		}
 	}
@@ -459,6 +459,48 @@ $query_str = '';
 // Show form
 if (empty($stage))
 {
+	if (file_exists(FORUM_CACHE_DIR.'db_update.lock'))
+	{
+		// Deal with newlines, tabs and multiple spaces
+		$pattern = array("\t", '  ', '  ');
+		$replace = array('    ', '  ', '  ');
+		$message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']);
+
+?>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title><?php echo $lang_update['Maintenance'] ?></title>
+<link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
+</head>
+<body>
+
+<div id="punmaint" class="pun">
+<div class="top-box"><div><!-- Top Corners --></div></div>
+<div class="punwrap">
+
+<div id="brdmain">
+<div class="block">
+	<h2><?php echo $lang_update['Maintenance'] ?></h2>
+	<div class="box">
+		<div class="inbox">
+			<p><?php echo $message ?></p>
+		</div>
+	</div>
+</div>
+</div>
+
+</div>
+<div class="end-box"><div><!-- Bottom Corners --></div></div>
+</div>
+
+</body>
+</html>
+<?php
+
+	}
+	else
+	{
 
 ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
@@ -469,7 +511,7 @@ if (empty($stage))
 <title><?php echo $lang_update['Update'] ?></title>
 <link rel="stylesheet" type="text/css" href="style/<?php echo $default_style ?>.css" />
 </head>
-<body onload="document.getElementById('install').req_db_type.focus();document.getElementById('install').start.disabled=false;">
+<body onload="document.getElementById('install').req_db_pass.focus();document.getElementById('install').start.disabled=false;">
 
 <div id="pundb_update" class="pun">
 <div class="top-box"><div><!-- Top Corners --></div></div>
@@ -488,7 +530,7 @@ if (empty($stage))
 <div class="blockform">
 	<h2><span><?php echo $lang_update['Update'] ?></span></h2>
 	<div class="box">
-		<form method="post" action="db_update.php">
+		<form id="install" method="post" action="db_update.php">
 			<input type="hidden" name="stage" value="start" />
 			<div class="inform">
 				<fieldset>
@@ -497,6 +539,11 @@ if (empty($stage))
 						<p><?php echo $lang_update['Database password info'] ?></p>
 						<p><strong><?php echo $lang_update['Note']; ?></strong> <?php echo $lang_update['Database password note'] ?></p>
 						<label class="required"><strong><?php echo $lang_update['Database password'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br /><input type="password" id="req_db_pass" name="req_db_pass" /><br /></label>
+						<p><?php echo $lang_update['Maintenance message info'] ?></p>
+						<div class="txtarea">
+							<label class="required"><strong><?php echo $lang_update['Maintenance message'] ?> <span><?php echo $lang_update['Required'] ?></span></strong><br />
+							<textarea name="req_maintenance_message" rows="4" cols="65"><?php echo pun_htmlspecialchars($pun_config['o_maintenance_message']) ?></textarea><br /></label>
+						</div>
 					</div>
 				</fieldset>
 			</div>
@@ -559,6 +606,7 @@ if (empty($stage))
 </html>
 <?php
 
+	}
 	$db->end_transaction();
 	$db->close();
 	exit;
@@ -602,6 +650,25 @@ if (isset($_POST['req_db_pass']))
 
 		fwrite($fh, $uid);
 		fclose($fh);
+
+		// Update maintenance message
+		if ($_POST['req_maintenance_message'] != '')
+			$maintenance_message = pun_trim(pun_linebreaks($_POST['req_maintenance_message']));
+		else
+		{
+			// Load the admin_options.php language file
+			require PUN_ROOT.'lang/'.$default_lang.'/admin_options.php';
+
+			$maintenance_message = $lang_admin_options['Default maintenance message'];
+		}
+
+		$db->query('UPDATE '.$db->prefix.'config SET conf_value=\''.$db->escape($maintenance_message).'\' WHERE conf_name=\'o_maintenance_message\'') or error('Unable to update board config', __FILE__, __LINE__, $db->error());
+
+		// Regenerate the config cache
+		if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+			require PUN_ROOT.'include/cache.php';
+
+		generate_config_cache();
 	}
 }
 else if (isset($_GET['uid']))
@@ -719,7 +786,7 @@ switch ($stage)
 			{
 				// 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 .= preg_replace('%:(80|443)$%', '', $_SERVER['HTTP_HOST']);							// host[:port]
 				$base_url .= str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));							// path
 			}
 
@@ -753,7 +820,7 @@ switch ($stage)
 				$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());
+				$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, g_report_flood) VALUES('."'Moderators', 'Moderator', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0)") or error('Unable to add group', __FILE__, __LINE__, $db->error());
 				$mod_gid = $db->insert_id();
 			}
 
@@ -916,9 +983,14 @@ switch ($stage)
 		$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
+		// Add the last_report_sent column to the users table and the g_report_flood
+		// column to the groups table
+		$db->add_field('users', 'last_report_sent', 'INT(10) UNSIGNED', true, null, 'last_email_sent') or error('Unable to add last_report_sent field', __FILE__, __LINE__, $db->error());
+		$db->add_field('groups', 'g_report_flood', 'SMALLINT(6)', false, 60, 'g_email_flood') or error('Unable to add g_report_flood field', __FILE__, __LINE__, $db->error());
+
+		// Set non-default g_send_email, g_flood_email and g_flood_report 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());
+		$db->query('UPDATE '.$db->prefix.'groups SET g_email_flood = 0, g_report_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') or error('Unable to add auto_notify field', __FILE__, __LINE__, $db->error());
@@ -1086,6 +1158,10 @@ switch ($stage)
 		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());
 
+		// For MySQL(i) without InnoDB, change the engine of the online table (for performance reasons)
+		if ($db_type == 'mysql' || $db_type == 'mysqli')
+			$db->query('ALTER TABLE '.$db->prefix.'online ENGINE = MyISAM') or error('Unable to change engine type of online table to MyISAM', __FILE__, __LINE__, $db->error());
+
 		// Should we do charset conversion or not?
 		if (strpos($cur_version, '1.2') === 0 && isset($_POST['convert_charset']))
 			$query_str = '?stage=conv_bans&req_old_charset='.$old_charset;
@@ -1458,14 +1534,14 @@ switch ($stage)
 					$errors[$id][] = $lang_update['Username too long error'];
 				else if (!strcasecmp($username, 'Guest'))
 					$errors[$id][] = $lang_update['Username Guest reserved error'];
-				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))
+				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[$id][] = $lang_update['Username IP format error'];
 				else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false)
 					$errors[$id][] = $lang_update['Username bad characters error'];
-				else if (preg_match('/(?:\[\/?(?:b|u|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list|\*)\]|\[(?:img|url|quote|list)=)/i', $username))
+				else if (preg_match('%(?:\[/?(?:b|u|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list|\*)\]|\[(?:img|url|quote|list)=)%i', $username))
 					$errors[$id][] = $lang_update['Username BBCode error'];
 
-				$result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$db->escape($username).'\') OR UPPER(username)=UPPER(\''.$db->escape(ucp_preg_replace('/[^\p{L}\p{N}]/u', '', $username)).'\')) AND id>1') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+				$result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$db->escape($username).'\') OR UPPER(username)=UPPER(\''.$db->escape(ucp_preg_replace('%[^\p{L}\p{N}]%u', '', $username)).'\')) AND id>1') or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
 
 				if ($db->num_rows($result))
 				{
@@ -1535,7 +1611,7 @@ switch ($stage)
 					$mail_message = str_replace('<base_url>', get_base_url().'/', $mail_message);
 					$mail_message = str_replace('<old_username>', $old_username, $mail_message);
 					$mail_message = str_replace('<new_username>', $username, $mail_message);
-					$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' Mailer', $mail_message);
+					$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 					pun_mail($cur_user['email'], $mail_subject, $mail_message);
 
@@ -1828,4 +1904,5 @@ $db->end_transaction();
 $db->close();
 
 if ($query_str != '')
-	exit('<script type="text/javascript">window.location="db_update.php'.$query_str.'&uid='.$uid.'"</script><noscript>'.sprintf($lang_update['JavaScript disabled'], sprintf('<a href="db_update.php'.$query_str.'&uid='.$uid.'">%s</a>', $lang_update['Click here to continue'])).'</noscript>');
+	exit('<script type="text/javascript">window.location="db_update.php'.$query_str.'&uid='.$uid.'"</script><noscript><meta http-equiv="refresh" content="0;url=db_update.php'.$query_str.'&uid='.$uid.'" /></noscript>');
+
diff --git a/header.php b/header.php
index 0f300db..b3a15a1 100644
--- a/header.php
+++ b/header.php
@@ -41,7 +41,7 @@ else
 $tpl_main = file_get_contents($tpl_file);
 
 // START SUBST - <pun_include "*">
-preg_match_all('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_main, $pun_includes, PREG_SET_ORDER);
+preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_main, $pun_includes, PREG_SET_ORDER);
 
 foreach ($pun_includes as $cur_include)
 {
@@ -142,12 +142,8 @@ function process_form(the_form)
 // 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))
-	$page_head = array();
-
-$page_head['top'] = '<link rel="top" href="index.php" title="'.$lang_common['Forum index'].'" />';
-
-echo implode("\n", $page_head)."\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);
@@ -212,7 +208,7 @@ else
 // Are there any additional navlinks we should insert into the array before imploding it?
 if ($pun_user['g_read_board'] == '1' && $pun_config['o_additional_navlinks'] != '')
 {
-	if (preg_match_all('#([0-9]+)\s*=\s*(.*?)\n#s', $pun_config['o_additional_navlinks']."\n", $extra_links))
+	if (preg_match_all('%([0-9]+)\s*=\s*(.*?)\n%s', $pun_config['o_additional_navlinks']."\n", $extra_links))
 	{
 		// Insert any additional links into the $links array (at the correct index)
 		$num_links = count($extra_links[1]);
@@ -230,7 +226,7 @@ $tpl_main = str_replace('<pun_navlinks>', $tpl_temp, $tpl_main);
 $page_statusinfo = $page_topicsearches = array();
 
 if ($pun_user['is_guest'])
-	$page_statusinfo = '<p>'.$lang_common['Not logged in'].'</p>';
+	$page_statusinfo = '<p class="conl">'.$lang_common['Not logged in'].'</p>';
 else
 {
 	$page_statusinfo[] = '<li><span>'.$lang_common['Logged in as'].' <strong>'.pun_htmlspecialchars($pun_user['username']).'</strong></span></li>';
@@ -266,7 +262,7 @@ if ($pun_user['g_read_board'] == '1' && $pun_user['g_search'] == '1')
 
 
 // Generate all that jazz
-$tpl_temp = '<div id="brdwelcome" class="inbox">'."\n\t\t\t";
+$tpl_temp = '<div id="brdwelcome" class="inbox">';
 
 // The status information
 if (is_array($page_statusinfo))
@@ -283,10 +279,10 @@ if (!empty($page_topicsearches))
 {
 	$tpl_temp .= "\n\t\t\t".'<ul class="conr">';
 	$tpl_temp .= "\n\t\t\t\t".'<li><span>'.$lang_common['Topic searches'].' '.implode(' | ', $page_topicsearches).'</span></li>';
-	$tpl_temp .= "\n\t\t\t".'</ul>'."\n\t\t\t".'<div class="clearer"></div>';
+	$tpl_temp .= "\n\t\t\t".'</ul>';
 }
 
-$tpl_temp .= "\n\t\t".'</div>';
+$tpl_temp .= "\n\t\t\t".'<div class="clearer"></div>'."\n\t\t".'</div>';
 
 $tpl_main = str_replace('<pun_status>', $tpl_temp, $tpl_main);
 // END SUBST - <pun_status>
diff --git a/help.php b/help.php
index c1e94ae..0820794 100644
--- a/help.php
+++ b/help.php
@@ -55,12 +55,21 @@ require PUN_ROOT.'header.php';
 		<p><?php echo $lang_help['Links info'] ?></p>
 		<p><code>[url=<?php echo pun_htmlspecialchars(get_base_url(true).'/') ?>]<?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?>[/url]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/') ?>"><?php echo pun_htmlspecialchars($pun_config['o_board_title']) ?></a></samp></p>
 		<p><code>[url]<?php echo pun_htmlspecialchars(get_base_url(true).'/') ?>[/url]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/') ?></a></samp></p>
+		<p><code>[url=/help.php]<?php echo $lang_help['This help page'] ?>[/url]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo get_base_url(true).'/help.php' ?>"><?php echo $lang_help['This help page'] ?></a></samp></p>
 		<p><code>[email]myname at mydomain.com[/email]</code> <?php echo $lang_help['produces'] ?> <samp><a href="mailto:myname at mydomain.com">myname at mydomain.com</a></samp></p>
 		<p><code>[email=myname at mydomain.com]<?php echo $lang_help['My email address'] ?>[/email]</code> <?php echo $lang_help['produces'] ?> <samp><a href="mailto:myname at mydomain.com"><?php echo $lang_help['My email address'] ?></a></samp></p>
+		<p><code>[topic=1]<?php echo $lang_help['Test topic'] ?>[/topic]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?id=1') ?>"><?php echo $lang_help['Test topic'] ?></a></samp></p>
+		<p><code>[topic]1[/topic]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?id=1') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?id=1') ?></a></samp></p>
+		<p><code>[post=1]<?php echo $lang_help['Test post'] ?>[/post]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?pid=1#p1') ?>"><?php echo $lang_help['Test post'] ?></a></samp></p>
+		<p><code>[post]1[/post]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?pid=1#p1') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/viewtopic.php?pid=1#p1') ?></a></samp></p>
+		<p><code>[forum=1]<?php echo $lang_help['Test forum'] ?>[/forum]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewforum.php?id=1') ?>"><?php echo $lang_help['Test forum'] ?></a></samp></p>
+		<p><code>[forum]1[/forum]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/viewforum.php?id=1') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/viewforum.php?id=1') ?></a></samp></p>
+		<p><code>[user=2]<?php echo $lang_help['Test user'] ?>[/user]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/profile.php?id=2') ?>"><?php echo $lang_help['Test user'] ?></a></samp></p>
+		<p><code>[user]2[/user]</code> <?php echo $lang_help['produces'] ?> <samp><a href="<?php echo pun_htmlspecialchars(get_base_url(true).'/profile.php?id=2') ?>"><?php echo pun_htmlspecialchars(get_base_url(true).'/profile.php?id=2') ?></a></samp></p>
 	</div>
 	<div class="inbox">
 		<p><a name="img"></a><?php echo $lang_help['Images info'] ?></p>
-		<p><code>[img=<?php echo $lang_help['FluxBB bbcode test'] ?>]<?php echo pun_htmlspecialchars(get_base_url(true)) ?>/img/test.png[/img]</code> <?php echo $lang_help['produces'] ?> <samp><img src="<?php echo pun_htmlspecialchars(get_base_url(true)) ?>/img/test.png" alt="<?php echo $lang_help['FluxBB bbcode test'] ?>" /></samp></p>
+		<p><code>[img=<?php echo $lang_help['FluxBB bbcode test'] ?>]<?php echo pun_htmlspecialchars(get_base_url(true)) ?>/img/test.png[/img]</code> <?php echo $lang_help['produces'] ?> <samp><img style="height: 21px" src="<?php echo pun_htmlspecialchars(get_base_url(true)) ?>/img/test.png" alt="<?php echo $lang_help['FluxBB bbcode test'] ?>" /></samp></p>
 	</div>
 </div>
 <h2><span><?php echo $lang_help['Quotes'] ?></span></h2>
diff --git a/img/smilies/big_smile.png b/img/smilies/big_smile.png
index b29719b..dad2fe8 100644
Binary files a/img/smilies/big_smile.png and b/img/smilies/big_smile.png differ
diff --git a/img/smilies/cool.png b/img/smilies/cool.png
index a875361..6b74528 100644
Binary files a/img/smilies/cool.png and b/img/smilies/cool.png differ
diff --git a/img/smilies/hmm.png b/img/smilies/hmm.png
index 69e416a..2dbc8aa 100644
Binary files a/img/smilies/hmm.png and b/img/smilies/hmm.png differ
diff --git a/img/smilies/lol.png b/img/smilies/lol.png
index dd9058b..45cb27e 100644
Binary files a/img/smilies/lol.png and b/img/smilies/lol.png differ
diff --git a/img/smilies/mad.png b/img/smilies/mad.png
index 011079d..3a26df0 100644
Binary files a/img/smilies/mad.png and b/img/smilies/mad.png differ
diff --git a/img/smilies/neutral.png b/img/smilies/neutral.png
index 9bc5ca0..2471da5 100644
Binary files a/img/smilies/neutral.png and b/img/smilies/neutral.png differ
diff --git a/img/smilies/roll.png b/img/smilies/roll.png
index e2e8e2a..f0ef64b 100644
Binary files a/img/smilies/roll.png and b/img/smilies/roll.png differ
diff --git a/img/smilies/sad.png b/img/smilies/sad.png
index c14e144..f03ae85 100644
Binary files a/img/smilies/sad.png and b/img/smilies/sad.png differ
diff --git a/img/smilies/smile.png b/img/smilies/smile.png
index 44cc239..27299dc 100644
Binary files a/img/smilies/smile.png and b/img/smilies/smile.png differ
diff --git a/img/smilies/tongue.png b/img/smilies/tongue.png
index 5302c89..5de9741 100644
Binary files a/img/smilies/tongue.png and b/img/smilies/tongue.png differ
diff --git a/img/smilies/wink.png b/img/smilies/wink.png
index 595c1fe..6807feb 100644
Binary files a/img/smilies/wink.png and b/img/smilies/wink.png differ
diff --git a/img/smilies/yikes.png b/img/smilies/yikes.png
index bb4aefd..64a2c70 100644
Binary files a/img/smilies/yikes.png and b/img/smilies/yikes.png differ
diff --git a/img/test.png b/img/test.png
index 7b46d9e..34eb90a 100644
Binary files a/img/test.png and b/img/test.png differ
diff --git a/include/cache.php b/include/cache.php
index 99c2487..2070fb4 100644
--- a/include/cache.php
+++ b/include/cache.php
@@ -183,7 +183,7 @@ function generate_censoring_cache()
 	for ($i = 0; $i < $num_words; $i++)
 	{
 		list($search_for[$i], $replace_with[$i]) = $db->fetch_row($result);
-		$search_for[$i] = '/(?<=[^\p{L}\p{N}])('.str_replace('\*', '[\p{L}\p{N}]*?', preg_quote($search_for[$i], '/')).')(?=[^\p{L}\p{N}])/iu';
+		$search_for[$i] = '%(?<=[^\p{L}\p{N}])('.str_replace('\*', '[\p{L}\p{N}]*?', preg_quote($search_for[$i], '%')).')(?=[^\p{L}\p{N}])%iu';
 	}
 
 	// Output censored words as PHP code
diff --git a/include/common.php b/include/common.php
index 371b972..2c4a2de 100644
--- a/include/common.php
+++ b/include/common.php
@@ -10,9 +10,9 @@ 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.5');
+define('FORUM_VERSION', '1.4.6');
 
-define('FORUM_DB_REVISION', 11);
+define('FORUM_DB_REVISION', 15);
 define('FORUM_SI_REVISION', 2);
 define('FORUM_PARSER_REVISION', 2);
 
@@ -70,7 +70,7 @@ setlocale(LC_CTYPE, 'C');
 if (get_magic_quotes_runtime())
 	set_magic_quotes_runtime(0);
 
-// Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled)
+// Strip slashes from GET/POST/COOKIE/REQUEST/FILES (if magic_quotes_gpc is enabled)
 if (get_magic_quotes_gpc())
 {
 	function stripslashes_array($array)
@@ -82,6 +82,7 @@ if (get_magic_quotes_gpc())
 	$_POST = stripslashes_array($_POST);
 	$_COOKIE = stripslashes_array($_COOKIE);
 	$_REQUEST = stripslashes_array($_REQUEST);
+	$_FILES = stripslashes_array($_FILES);
 }
 
 // If a cookie name is not specified in config.php, we use the default (pun_cookie)
@@ -120,13 +121,13 @@ if (!defined('PUN_CONFIG_LOADED'))
 
 // Verify that we are running the proper database schema revision
 if (!isset($pun_config['o_database_revision']) || $pun_config['o_database_revision'] < FORUM_DB_REVISION ||
-		!isset($pun_config['o_searchindex_revision']) || $pun_config['o_searchindex_revision'] < FORUM_SI_REVISION ||
-		!isset($pun_config['o_parser_revision']) || $pun_config['o_parser_revision'] < FORUM_PARSER_REVISION ||
-		version_compare($pun_config['o_cur_version'], FORUM_VERSION, '<'))
-	{
-		header('Location: db_update.php');
-		exit;
-	}
+	!isset($pun_config['o_searchindex_revision']) || $pun_config['o_searchindex_revision'] < FORUM_SI_REVISION ||
+	!isset($pun_config['o_parser_revision']) || $pun_config['o_parser_revision'] < FORUM_PARSER_REVISION ||
+	version_compare($pun_config['o_cur_version'], FORUM_VERSION, '<'))
+{
+	header('Location: db_update.php');
+	exit;
+}
 
 // Enable output buffering
 if (!defined('PUN_DISABLE_BUFFERING'))
@@ -141,9 +142,6 @@ if (!defined('PUN_DISABLE_BUFFERING'))
 // Define standard date/time formats
 $forum_time_formats = array($pun_config['o_time_format'], 'H:i:s', 'H:i', 'g:i:s a', 'g:i a');
 $forum_date_formats = array($pun_config['o_date_format'], 'Y-m-d', 'Y-d-m', 'd-m-Y', 'm-d-Y', 'M j Y', 'jS M Y');
- 
-// BadBehavior will stop the spammers!
-require PUN_ROOT.'include/bad-behavior-fluxbb.php';
 
 // Check/update/set cookie and fetch user info
 $pun_user = array();
diff --git a/include/common_admin.php b/include/common_admin.php
index 5ce1319..bc353ac 100644
--- a/include/common_admin.php
+++ b/include/common_admin.php
@@ -14,7 +14,7 @@ if (!defined('PUN'))
 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'];
+	$admin_language = $pun_config['o_default_lang'];
 else
 	$admin_language = 'English';
 
@@ -83,8 +83,8 @@ function generate_admin_menu($page = '')
 				<ul>
 <?php
 
-		foreach ($plugins as $cur_plugin)
-			echo "\t\t\t\t\t".'<li'.(($page == $cur_plugin[1]) ? ' class="isactive"' : '').'><a href="admin_loader.php?plugin='.$cur_plugin[1].'">'.str_replace('_', ' ', $cur_plugin[0]).'</a></li>'."\n";
+		foreach ($plugins as $plugin_name => $plugin)
+			echo "\t\t\t\t\t".'<li'.(($page == $plugin_name) ? ' class="isactive"' : '').'><a href="admin_loader.php?plugin='.$plugin_name.'">'.str_replace('_', ' ', $plugin).'</a></li>'."\n";
 
 ?>
 				</ul>
diff --git a/include/dblayer/common_db.php b/include/dblayer/common_db.php
index a832376..be48607 100644
--- a/include/dblayer/common_db.php
+++ b/include/dblayer/common_db.php
@@ -15,27 +15,27 @@ if (!defined('PUN'))
 switch ($db_type)
 {
 	case 'mysql':
-		require PUN_ROOT.'include/dblayer/mysql.php';
+		require_once PUN_ROOT.'include/dblayer/mysql.php';
 		break;
 
 	case 'mysql_innodb':
-		require PUN_ROOT.'include/dblayer/mysql_innodb.php';
+		require_once PUN_ROOT.'include/dblayer/mysql_innodb.php';
 		break;
 
 	case 'mysqli':
-		require PUN_ROOT.'include/dblayer/mysqli.php';
+		require_once PUN_ROOT.'include/dblayer/mysqli.php';
 		break;
 
 	case 'mysqli_innodb':
-		require PUN_ROOT.'include/dblayer/mysqli_innodb.php';
+		require_once PUN_ROOT.'include/dblayer/mysqli_innodb.php';
 		break;
 
 	case 'pgsql':
-		require PUN_ROOT.'include/dblayer/pgsql.php';
+		require_once PUN_ROOT.'include/dblayer/pgsql.php';
 		break;
 
 	case 'sqlite':
-		require PUN_ROOT.'include/dblayer/sqlite.php';
+		require_once PUN_ROOT.'include/dblayer/sqlite.php';
 		break;
 
 	default:
diff --git a/include/dblayer/mysql.php b/include/dblayer/mysql.php
index f35609f..53b37b2 100644
--- a/include/dblayer/mysql.php
+++ b/include/dblayer/mysql.php
@@ -24,7 +24,7 @@ class DBLayer
 	var $error_msg = 'Unknown';
 
 	var $datatype_transformations = array(
-		'/^SERIAL$/'	=>	'INT(10) UNSIGNED AUTO_INCREMENT'
+		'%^SERIAL$%'	=>	'INT(10) UNSIGNED AUTO_INCREMENT'
 	);
 
 
@@ -204,7 +204,7 @@ class DBLayer
 
 		return array(
 			'name'		=> 'MySQL Standard',
-			'version'	=> preg_replace('/^([^-]+).*$/', '\\1', $this->result($result))
+			'version'	=> preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
 		);
 	}
 
diff --git a/include/dblayer/mysql_innodb.php b/include/dblayer/mysql_innodb.php
index 8071a3b..6851309 100644
--- a/include/dblayer/mysql_innodb.php
+++ b/include/dblayer/mysql_innodb.php
@@ -25,7 +25,7 @@ class DBLayer
 	var $error_msg = 'Unknown';
 
 	var $datatype_transformations = array(
-		'/^SERIAL$/'	=>	'INT(10) UNSIGNED AUTO_INCREMENT'
+		'%^SERIAL$%'	=>	'INT(10) UNSIGNED AUTO_INCREMENT'
 	);
 
 
@@ -218,7 +218,7 @@ class DBLayer
 
 		return array(
 			'name'		=> 'MySQL Standard (InnoDB)',
-			'version'	=> preg_replace('/^([^-]+).*$/', '\\1', $this->result($result))
+			'version'	=> preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
 		);
 	}
 
diff --git a/include/dblayer/mysqli.php b/include/dblayer/mysqli.php
index cab2776..c17294d 100644
--- a/include/dblayer/mysqli.php
+++ b/include/dblayer/mysqli.php
@@ -24,7 +24,7 @@ class DBLayer
 	var $error_msg = 'Unknown';
 
 	var $datatype_transformations = array(
-		'/^SERIAL$/'	=>	'INT(10) UNSIGNED AUTO_INCREMENT'
+		'%^SERIAL$%'	=>	'INT(10) UNSIGNED AUTO_INCREMENT'
 	);
 
 
@@ -211,7 +211,7 @@ class DBLayer
 
 		return array(
 			'name'		=> 'MySQL Improved',
-			'version'	=> preg_replace('/^([^-]+).*$/', '\\1', $this->result($result))
+			'version'	=> preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
 		);
 	}
 
diff --git a/include/dblayer/mysqli_innodb.php b/include/dblayer/mysqli_innodb.php
index cefbd73..b9f43db 100644
--- a/include/dblayer/mysqli_innodb.php
+++ b/include/dblayer/mysqli_innodb.php
@@ -25,7 +25,7 @@ class DBLayer
 	var $error_msg = 'Unknown';
 
 	var $datatype_transformations = array(
-		'/^SERIAL$/'	=>	'INT(10) UNSIGNED AUTO_INCREMENT'
+		'%^SERIAL$%'	=>	'INT(10) UNSIGNED AUTO_INCREMENT'
 	);
 
 
@@ -224,7 +224,7 @@ class DBLayer
 
 		return array(
 			'name'		=> 'MySQL Improved (InnoDB)',
-			'version'	=> preg_replace('/^([^-]+).*$/', '\\1', $this->result($result))
+			'version'	=> preg_replace('%^([^-]+).*$%', '\\1', $this->result($result))
 		);
 	}
 
diff --git a/include/dblayer/pgsql.php b/include/dblayer/pgsql.php
index 9d4547e..66b81ca 100644
--- a/include/dblayer/pgsql.php
+++ b/include/dblayer/pgsql.php
@@ -26,12 +26,12 @@ class DBLayer
 	var $error_msg = 'Unknown';
 
 	var $datatype_transformations = array(
-		'/^(TINY|SMALL)INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$/i'			=>	'SMALLINT',
-		'/^(MEDIUM)?INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$/i'				=>	'INTEGER',
-		'/^BIGINT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$/i'						=>	'BIGINT',
-		'/^(TINY|MEDIUM|LONG)?TEXT$/i'										=>	'TEXT',
-		'/^DOUBLE( )?(\\([0-9,]+\\))?( )?(UNSIGNED)?$/i'					=>	'DOUBLE PRECISION',
-		'/^FLOAT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$/i'						=>	'REAL'
+		'%^(TINY|SMALL)INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i'			=>	'SMALLINT',
+		'%^(MEDIUM)?INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i'				=>	'INTEGER',
+		'%^BIGINT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i'						=>	'BIGINT',
+		'%^(TINY|MEDIUM|LONG)?TEXT$%i'										=>	'TEXT',
+		'%^DOUBLE( )?(\\([0-9,]+\\))?( )?(UNSIGNED)?$%i'					=>	'DOUBLE PRECISION',
+		'%^FLOAT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i'						=>	'REAL'
 	);
 
 
@@ -100,7 +100,7 @@ class DBLayer
 	function query($sql, $unbuffered = false) // $unbuffered is ignored since there is no pgsql_unbuffered_query()
 	{
 		if (strrpos($sql, 'LIMIT') !== false)
-			$sql = preg_replace('#LIMIT ([0-9]+),([ 0-9]+)#', 'LIMIT \\2 OFFSET \\1', $sql);
+			$sql = preg_replace('%LIMIT ([0-9]+),([ 0-9]+)%', 'LIMIT \\2 OFFSET \\1', $sql);
 
 		if (defined('PUN_SHOW_QUERIES'))
 			$q_start = get_microtime();
@@ -173,7 +173,7 @@ class DBLayer
 
 		if ($query_id && $this->last_query_text[$query_id] != '')
 		{
-			if (preg_match('/^INSERT INTO ([a-z0-9\_\-]+)/is', $this->last_query_text[$query_id], $table_name))
+			if (preg_match('%^INSERT INTO ([a-z0-9\_\-]+)%is', $this->last_query_text[$query_id], $table_name))
 			{
 				// Hack (don't ask)
 				if (substr($table_name[1], -6) == 'groups')
@@ -266,7 +266,7 @@ class DBLayer
 
 		return array(
 			'name'		=> 'PostgreSQL',
-			'version'	=> preg_replace('/^[^0-9]+([^\s,-]+).*$/', '\\1', $this->result($result))
+			'version'	=> preg_replace('%^[^0-9]+([^\s,-]+).*$%', '\\1', $this->result($result))
 		);
 	}
 
diff --git a/include/dblayer/sqlite.php b/include/dblayer/sqlite.php
index cf6d4c2..e934dc4 100644
--- a/include/dblayer/sqlite.php
+++ b/include/dblayer/sqlite.php
@@ -25,9 +25,9 @@ class DBLayer
 	var $error_msg = 'Unknown';
 
 	var $datatype_transformations = array(
-		'/^SERIAL$/'															=>	'INTEGER',
-		'/^(TINY|SMALL|MEDIUM|BIG)?INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$/i'	=>	'INTEGER',
-		'/^(TINY|MEDIUM|LONG)?TEXT$/i'											=>	'TEXT'
+		'%^SERIAL$%'															=>	'INTEGER',
+		'%^(TINY|SMALL|MEDIUM|BIG)?INT( )?(\\([0-9]+\\))?( )?(UNSIGNED)?$%i'	=>	'INTEGER',
+		'%^(TINY|MEDIUM|LONG)?TEXT$%i'											=>	'TEXT'
 	);
 
 
@@ -279,7 +279,7 @@ class DBLayer
 		if (!$this->num_rows($result))
 			return false;
 
-		return preg_match('/[\r\n]'.preg_quote($field_name).' /', $this->result($result));
+		return preg_match('%[\r\n]'.preg_quote($field_name, '%').' %', $this->result($result));
 	}
 
 
@@ -405,7 +405,7 @@ class DBLayer
 		$table['columns'] = array();
 		foreach ($table_lines as $table_line)
 		{
-			$table_line = pun_trim($table_line);
+			$table_line = trim($table_line, " \t\n\r,"); // trim spaces, tabs, newlines, and commas
 			if (substr($table_line, 0, 12) == 'CREATE TABLE')
 				continue;
 			else if (substr($table_line, 0, 11) == 'PRIMARY KEY')
@@ -413,7 +413,7 @@ class DBLayer
 			else if (substr($table_line, 0, 6) == 'UNIQUE')
 				$table['unique'] = $table_line;
 			else if (substr($table_line, 0, strpos($table_line, ' ')) != '')
-				$table['columns'][substr($table_line, 0, strpos($table_line, ' '))] = pun_trim(substr($table_line, strpos($table_line, ' ')));
+				$table['columns'][substr($table_line, 0, strpos($table_line, ' '))] = trim(substr($table_line, strpos($table_line, ' ')));
 		}
 
 		return $table;
@@ -444,18 +444,18 @@ class DBLayer
 		$query .= ' DEFAULT '.$default_value;
 
 		$old_columns = array_keys($table['columns']);
-		array_insert($table['columns'], $after_field, $query.',', $field_name);
+		array_insert($table['columns'], $after_field, $query, $field_name);
 
 		$new_table = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (';
 
 		foreach ($table['columns'] as $cur_column => $column_details)
-			$new_table .= "\n".$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 .= "\n".$table['primary_key'].',';
 
 		$new_table = trim($new_table, ',')."\n".');';
 
@@ -509,13 +509,13 @@ class DBLayer
 		$new_table = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$this->escape($table_name).' (';
 
 		foreach ($table['columns'] as $cur_column => $column_details)
-			$new_table .= "\n".$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 .= "\n".$table['primary_key'].',';
 
 		$new_table = trim($new_table, ',')."\n".');';
 
diff --git a/include/email.php b/include/email.php
index 376172d..94058d0 100644
--- a/include/email.php
+++ b/include/email.php
@@ -20,7 +20,7 @@ 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);
 }
 
 
@@ -56,6 +56,157 @@ function encode_mail_text($str)
 
 
 //
+// Make a post email safe
+//
+function bbcode2email($text, $wrap_length = 72)
+{
+    static $base_url;
+
+    if (!isset($base_url))
+        $base_url = get_base_url();
+
+    $text = pun_trim($text, "\t\n ");
+
+    $shortcut_urls = array(
+        'topic' => '/viewtopic.php?id=$1',
+        'post' => '/viewtopic.php?pid=$1#p$1',
+        'forum' => '/viewforum.php?id=$1',
+        'user' => '/profile.php?id=$1',
+    );
+
+    // Split code blocks and text so BBcode in codeblocks won't be touched
+    list($code, $text) = extract_blocks($text, '[code]', '[/code]');
+
+    // Strip all bbcodes, except the quote, url, img, email, code and list items bbcodes
+    $text = preg_replace(array(
+        '%\[/?(?!(?:quote|url|topic|post|user|forum|img|email|code|list|\*))[a-z]+(?:=[^\]]+)?\]%i',
+        '%\n\[/?list(?:=[^\]]+)?\]%i' // A separate regex for the list tags to get rid of some whitespace
+    ), '', $text);
+
+    // Match the deepest nested bbcode
+    // An adapted example from Mastering Regular Expressions
+    $match_quote_regex = '%
+        \[(quote|\*|url|img|email|topic|post|user|forum)(?:=([^\]]+))?\]
+        (
+            (?>[^\[]*)
+            (?>
+                (?!\[/?\1(?:=[^\]]+)?\])
+                \[
+                [^\[]*
+            )*
+        )
+        \[/\1\]
+    %ix';
+
+    $url_index = 1;
+    $url_stack = array();
+    while (preg_match($match_quote_regex, $text, $matches))
+    {
+        // Quotes
+        if ($matches[1] == 'quote')
+        {
+            // Put '>' or '> ' at the start of a line
+            $replacement = preg_replace(
+                array('%^(?=\>)%m', '%^(?!\>)%m'),
+                array('>', '> '),
+                $matches[2]." said:\n".$matches[3]);
+        }
+
+        // List items
+        elseif ($matches[1] == '*')
+        {
+            $replacement = ' * '.$matches[3];
+        }
+
+        // URLs and emails
+        elseif (in_array($matches[1], array('url', 'email')))
+        {
+            if (!empty($matches[2]))
+            {
+                $replacement = '['.$matches[3].']['.$url_index.']';
+                $url_stack[$url_index] = $matches[2];
+                $url_index++;
+            }
+            else
+                $replacement = '['.$matches[3].']';
+        }
+
+        // Images
+        elseif ($matches[1] == 'img')
+        {
+            if (!empty($matches[2]))
+                $replacement = '['.$matches[2].']['.$url_index.']';
+            else
+                $replacement = '['.basename($matches[3]).']['.$url_index.']';
+
+            $url_stack[$url_index] = $matches[3];
+            $url_index++;
+        }
+
+        // Topic, post, forum and user URLs
+        elseif (in_array($matches[1], array('topic', 'post', 'forum', 'user')))
+        {
+            $url = isset($shortcut_urls[$matches[1]]) ? $base_url.$shortcut_urls[$matches[1]] : '';
+
+            if (!empty($matches[2]))
+            {
+                $replacement = '['.$matches[3].']['.$url_index.']';
+                $url_stack[$url_index] = str_replace('$1', $matches[2], $url);
+                $url_index++;
+            }
+            else
+                $replacement = '['.str_replace('$1', $matches[3], $url).']';
+        }
+
+        // Update the main text if there is a replacment
+        if (!is_null($replacement))
+        {
+            $text = str_replace($matches[0], $replacement, $text);
+            $replacement = null;
+        }
+    }
+
+    // Put code blocks and text together
+    if (isset($code))
+    {
+        $parts = explode("\1", $text);
+        $text = '';
+        foreach ($parts as $i => $part)
+        {
+            $text .= $part;
+            if (isset($code[$i]))
+                $text .= trim($code[$i], "\n\r");
+        }
+    }
+
+    // Put URLs at the bottom
+    if ($url_stack)
+    {
+        $text .= "\n\n";
+        foreach ($url_stack as $i => $url)
+            $text .= "\n".' ['.$i.']: '.$url;
+    }
+
+    // Wrap lines if $wrap_length is higher than -1
+    if ($wrap_length > -1)
+    {
+        // Split all lines and wrap them individually
+        $parts = explode("\n", $text);
+        foreach ($parts as $k => $part)
+        {
+            preg_match('%^(>+ )?(.*)%', $part, $matches);
+            $parts[$k] = wordwrap($matches[1].$matches[2], $wrap_length -
+                strlen($matches[1]), "\n".$matches[1]);
+        }
+
+        return implode("\n", $parts);
+    }
+    else
+        return $text;
+}
+
+
+//
 // Wrapper for PHP's mail()
 //
 function pun_mail($to, $subject, $message, $reply_to_email = '', $reply_to_name = '')
@@ -63,19 +214,19 @@ function pun_mail($to, $subject, $message, $reply_to_email = '', $reply_to_name
 	global $pun_config, $lang_common;
 
 	// Default sender/return address
-	$from_name = str_replace('"', '', $pun_config['o_board_title'].' '.$lang_common['Mailer']);
+	$from_name = sprintf($lang_common['Mailer'], $pun_config['o_board_title']);
 	$from_email = $pun_config['o_webmaster_email'];
 
 	// Do a little spring cleaning
-	$to = pun_trim(preg_replace('#[\n\r]+#s', '', $to));
-	$subject = pun_trim(preg_replace('#[\n\r]+#s', '', $subject));
-	$from_email = pun_trim(preg_replace('#[\n\r:]+#s', '', $from_email));
-	$from_name = pun_trim(preg_replace('#[\n\r:]+#s', '', str_replace('"', '', $from_name)));
-	$reply_to_email = pun_trim(preg_replace('#[\n\r:]+#s', '', $reply_to_email));
-	$reply_to_name = pun_trim(preg_replace('#[\n\r:]+#s', '', str_replace('"', '', $reply_to_name)));
+	$to = pun_trim(preg_replace('%[\n\r]+%s', '', $to));
+	$subject = pun_trim(preg_replace('%[\n\r]+%s', '', $subject));
+	$from_email = pun_trim(preg_replace('%[\n\r:]+%s', '', $from_email));
+	$from_name = pun_trim(preg_replace('%[\n\r:]+%s', '', str_replace('"', '', $from_name)));
+	$reply_to_email = pun_trim(preg_replace('%[\n\r:]+%s', '', $reply_to_email));
+	$reply_to_name = pun_trim(preg_replace('%[\n\r:]+%s', '', str_replace('"', '', $reply_to_name)));
 
 	// Set up some headers to take advantage of UTF-8
-	$from = encode_mail_text($from_name).' <'.$from_email.'>';
+	$from = '"'.encode_mail_text($from_name).'" <'.$from_email.'>';
 	$subject = encode_mail_text($subject);
 
 	$headers = 'From: '.$from."\r\n".'Date: '.gmdate('r')."\r\n".'MIME-Version: 1.0'."\r\n".'Content-transfer-encoding: 8bit'."\r\n".'Content-type: text/plain; charset=utf-8'."\r\n".'X-Mailer: FluxBB Mailer';
@@ -83,24 +234,25 @@ function pun_mail($to, $subject, $message, $reply_to_email = '', $reply_to_name
 	// If we specified a reply-to email, we deal with it here
 	if (!empty($reply_to_email))
 	{
-		$reply_to = encode_mail_text($reply_to_name).' <'.$reply_to_email.'>';
+		$reply_to = '"'.encode_mail_text($reply_to_name).'" <'.$reply_to_email.'>';
 
 		$headers .= "\r\n".'Reply-To: '.$reply_to;
 	}
 
-	// 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));
+	// Make sure all linebreaks are LF in message (and strip out any NULL bytes)
+	$message = str_replace("\0", '', pun_linebreaks($message));
 
 	if ($pun_config['o_smtp_host'] != '')
+	{
+		// Headers should be \r\n
+		// Message should be ??
+		$message = str_replace("\n", "\r\n", $message);
 		smtp_mail($to, $subject, $message, $headers);
+	}
 	else
 	{
-		// Change the linebreaks used in the headers according to OS
-		if (strtoupper(substr(PHP_OS, 0, 3)) == 'MAC')
-			$headers = str_replace("\r\n", "\r", $headers);
-		else if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN')
-			$headers = str_replace("\r\n", "\n", $headers);
-
+		// Headers should be \r\n
+		// Message should be \n
 		mail($to, $subject, $message, $headers);
 	}
 }
diff --git a/include/functions.php b/include/functions.php
index 7979d4a..7e9cfaa 100644
--- a/include/functions.php
+++ b/include/functions.php
@@ -26,7 +26,7 @@ function check_cookie(&$pun_user)
 	$now = time();
 
 	// If the cookie is set and it matches the correct pattern, then read the values from it
-	if (isset($_COOKIE[$cookie_name]) && preg_match('/^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$/', $_COOKIE[$cookie_name], $matches))
+	if (isset($_COOKIE[$cookie_name]) && preg_match('%^(\d+)\|([0-9a-fA-F]+)\|(\d+)\|([0-9a-fA-F]+)$%', $_COOKIE[$cookie_name], $matches))
 	{
 		$cookie = array(
 			'user_id'			=> intval($matches[1]),
@@ -246,7 +246,7 @@ function set_default_user()
 	// Fetch guest user
 	$result = $db->query('SELECT u.*, g.*, o.logged, o.last_post, o.last_search FROM '.$db->prefix.'users AS u INNER JOIN '.$db->prefix.'groups AS g ON u.group_id=g.g_id LEFT JOIN '.$db->prefix.'online AS o ON o.ident=\''.$remote_addr.'\' WHERE u.id=1') or error('Unable to fetch guest information', __FILE__, __LINE__, $db->error());
 	if (!$db->num_rows($result))
-		exit('Unable to fetch guest information. The table \''.$db->prefix.'users\' must contain an entry with id = 1 that represents anonymous users.');
+		exit('Unable to fetch guest information. Your database must contain both a guest user and a guest user group.');
 
 	$pun_user = $db->fetch_assoc($result);
 
@@ -428,7 +428,7 @@ 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);
+	$username = preg_replace('%\s+%s', ' ', $username);
 
 	// Validate username
 	if (pun_strlen($username) < 2)
@@ -437,11 +437,11 @@ function check_username($username, $exclude_id = null)
 		$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))
+	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|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list|\*)\]|\[(?:img|url|quote|list)=)/i', $username))
+	else if (preg_match('%(?:\[/?(?:b|u|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list|\*|topic|post|forum|user)\]|\[(?:img|url|quote|list)=)%i', $username))
 		$errors[] = $lang_prof_reg['Username BBCode'];
 
 	// Check username for any censored words
@@ -451,7 +451,7 @@ function check_username($username, $exclude_id = null)
 	// 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(ucp_preg_replace('/[^\p{L}\p{N}]/u', '', $username)).'\')) AND id>1'.$query) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
+	$result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE (UPPER(username)=UPPER(\''.$db->escape($username).'\') OR UPPER(username)=UPPER(\''.$db->escape(ucp_preg_replace('%[^\p{L}\p{N}]%u', '', $username)).'\')) AND id>1'.$query) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error());
 
 	if ($db->num_rows($result))
 	{
@@ -1247,7 +1247,7 @@ function maintenance_message()
 	$tpl_maint = file_get_contents($tpl_file);
 
 	// START SUBST - <pun_include "*">
-	preg_match_all('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_maint, $pun_includes, PREG_SET_ORDER);
+	preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_maint, $pun_includes, PREG_SET_ORDER);
 
 	foreach ($pun_includes as $cur_include)
 	{
@@ -1337,7 +1337,7 @@ function redirect($destination_url, $message)
 		$destination_url = get_base_url(true).'/'.$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')
@@ -1366,7 +1366,7 @@ function redirect($destination_url, $message)
 	$tpl_redir = file_get_contents($tpl_file);
 
 	// START SUBST - <pun_include "*">
-	preg_match_all('#<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">#', $tpl_redir, $pun_includes, PREG_SET_ORDER);
+	preg_match_all('%<pun_include "([^/\\\\]*?)\.(php[45]?|inc|html?|txt)">%i', $tpl_redir, $pun_includes, PREG_SET_ORDER);
 
 	foreach ($pun_includes as $cur_include)
 	{
@@ -1650,7 +1650,7 @@ function remove_bad_characters($array)
 	$array = utf8_bad_strip($array);
 
 	// Remove control characters
-	$array = preg_replace('/[\x{00}-\x{08}\x{0b}-\x{0c}\x{0e}-\x{1f}]/', '', $array);
+	$array = preg_replace('%[\x{00}-\x{08}\x{0b}-\x{0c}\x{0e}-\x{1f}]%', '', $array);
 
 	// Replace some "bad" characters
 	$array = str_replace(array_keys($bad_utf8_chars), array_values($bad_utf8_chars), $array);
@@ -1664,12 +1664,14 @@ function remove_bad_characters($array)
 //
 function file_size($size)
 {
+	global $lang_common;
+
 	$units = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB');
 
 	for ($i = 0; $size > 1024; $i++)
 		$size /= 1024;
 
-	return round($size, 2).' '.$units[$i];
+	return sprintf($lang_common['Size unit '.$units[$i]], round($size, 2));;
 }
 
 
@@ -1759,10 +1761,12 @@ function forum_list_plugins($is_admin)
 		$suffix = substr($entry, strlen($entry) - 4);
 
 		if ($suffix == '.php' && ((!$is_admin && $prefix == 'AMP') || ($is_admin && ($prefix == 'AP' || $prefix == 'AMP'))))
-			$plugins[] = array(substr($entry, strpos($entry, '_') + 1, -4), $entry);
+			$plugins[$entry] = substr($entry, strpos($entry, '_') + 1, -4);
 	}
 	$d->close();
 
+	natcasesort($plugins);
+
 	return $plugins;
 }
 
@@ -1774,33 +1778,83 @@ function split_text($text, $start, $end, &$errors, $retab = true)
 {
 	global $pun_config, $lang_common;
 
-	$tokens = explode($start, $text);
+	$result = array(0 => array(), 1 => array()); // 0 = inside, 1 = outside
+
+	// split the text into parts
+	$parts = preg_split('%'.preg_quote($start, '%').'(.*)'.preg_quote($end, '%').'%Us', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
+	$num_parts = count($parts);
 
-	$outside[] = $tokens[0];
+	// preg_split results in outside parts having even indices, inside parts having odd
+	for ($i = 0;$i < $num_parts;$i++)
+		$result[1 - ($i % 2)][] = $parts[$i];
 
-	$num_tokens = count($tokens);
-	for ($i = 1; $i < $num_tokens; ++$i)
+	if ($pun_config['o_indent_num_spaces'] != 8 && $retab)
 	{
-		$temp = explode($end, $tokens[$i]);
+		$spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
+		$result[1] = str_replace("\t", $spaces, $result[1]);
+	}
+
+	return $result;
+}
+
+
+//
+// Extract blocks from a text with a starting and ending string
+// This function always matches the most outer block so nesting is possible
+//
+function extract_blocks($text, $start, $end, &$errors = array(), $retab = true)
+{
+	global $pun_config;
 
-		if (count($temp) != 2)
+	$code = array();
+	$start_len = strlen($start);
+	$end_len = strlen($end);
+	$regex = '%(?:'.preg_quote($start, '%').'|'.preg_quote($end, '%').')%';
+	$matches = array();
+
+	if (preg_match_all($regex, $text, $matches))
+	{
+		$counter = $offset = 0;
+		$start_pos = $end_pos = false;
+
+		foreach ($matches[0] as $match)
 		{
-			$errors[] = $lang_common['BBCode code problem'];
-			return array(null, array($text));
+			if ($match == $start)
+			{
+				if ($counter == 0)
+					$start_pos = strpos($text, $start);
+				$counter++;
+			}
+			elseif ($match == $end)
+			{
+				$counter--;
+				if ($counter == 0)
+					$end_pos = strpos($text, $end, $offset + 1);
+				$offset = strpos($text, $end, $offset + 1);
+			}
+
+			if ($start_pos !== false && $end_pos !== false)
+			{
+				$code[] = substr($text, $start_pos + $start_len,
+					$end_pos - $start_pos - $start_len);
+				$text = substr_replace($text, "\1", $start_pos,
+					$end_pos - $start_pos + $end_len);
+				$start_pos = $end_pos = false;
+				$offset = 0;
+			}
 		}
-		$inside[] = $temp[0];
-		$outside[] = $temp[1];
 	}
 
 	if ($pun_config['o_indent_num_spaces'] != 8 && $retab)
 	{
 		$spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
-		$inside = str_replace("\t", $spaces, $inside);
+		$text = str_replace("\t", $spaces, $text);
 	}
 
-	return array($inside, $outside);
+	return array($code, $text);
 }
 
+
 //
 // function url_valid($url) {
 //
@@ -1920,7 +1974,7 @@ function url_valid($url)
 function ucp_preg_replace($pattern, $replace, $subject)
 {
 	$replaced = preg_replace($pattern, $replace, $subject);
-	
+
 	// If preg_replace() returns false, this probably means unicode support is not built-in, so we need to modify the pattern a little
 	if ($replaced === false)
 	{
@@ -1928,13 +1982,13 @@ function ucp_preg_replace($pattern, $replace, $subject)
 		{
 			foreach ($pattern as $cur_key => $cur_pattern)
 				$pattern[$cur_key] = str_replace('\p{L}\p{N}', '\w', $cur_pattern);
-			
+
 			$replaced = preg_replace($pattern, $replace, $subject);
 		}
 		else
 			$replaced = preg_replace(str_replace('\p{L}\p{N}', '\w', $pattern), $replace, $subject);
 	}
-	
+
 	return $replaced;
 }
 
diff --git a/include/parser.php b/include/parser.php
index 02449b7..0aba148 100644
--- a/include/parser.php
+++ b/include/parser.php
@@ -76,10 +76,7 @@ function preparse_bbcode($text, &$errors, $is_signature = false)
 
 	// 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]', $errors);
-		$text = implode("\1", $outside);
-	}
+		list($inside, $text) = extract_blocks($text, '[code]', '[/code]', $errors);
 
 	// Tidy up lists
 	$temp = preg_replace($re_list, 'preparse_list_tag(\'$2\', \'$1\', $errors)', $text);
@@ -144,13 +141,10 @@ function strip_empty_bbcode($text, &$errors)
 {
 	// If the message contains a code tag we have to split it up (empty tags within [code][/code] are fine)
 	if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
-	{
-		list($inside, $outside) = split_text($text, '[code]', '[/code]', $errors);
-		$text = implode("\1", $outside);
-	}
+		list($inside, $text) = extract_blocks($text, '[code]', '[/code]', $errors);
 
 	// Remove empty tags
-	while (($new_text = preg_replace('/\[(b|u|s|ins|del|em|i|h|colou?r|quote|img|url|email|list)(?:\=[^\]]*)?\]\s*\[\/\1\]/', '', $text)) !== NULL)
+	while (($new_text = preg_replace('%\[(b|u|s|ins|del|em|i|h|colou?r|quote|img|url|email|list|topic|post|forum|user)(?:\=[^\]]*)?\]\s*\[/\1\]%', '', $text)) !== NULL)
 	{
 		if ($new_text != $text)
 			$text = $new_text;
@@ -159,22 +153,19 @@ function strip_empty_bbcode($text, &$errors)
 	}
 
 	// If we split up the message before we have to concatenate it together again (code tags)
-	if (isset($inside))
-	{
-		$outside = explode("\1", $text);
-		$text = '';
-
-		$num_tokens = count($outside);
-		for ($i = 0; $i < $num_tokens; ++$i)
-		{
-			$text .= $outside[$i];
-			if (isset($inside[$i]))
-				$text .= '[code]'.$inside[$i].'[/code]';
-		}
-	}
+    if (isset($inside)) {
+        $parts = explode("\1", $text);
+        $text = '';
+        foreach ($parts as $i => $part)
+        {
+            $text .= $part;
+            if (isset($inside[$i]))
+                $text .= '[code]'.$inside[$i].'[/code]';
+        }
+    }
 
 	// Remove empty code tags
-	while (($new_text = preg_replace('/\[(code)\]\s*\[\/\1\]/', '', $text)) !== NULL)
+	while (($new_text = preg_replace('%\[(code)\]\s*\[/\1\]%', '', $text)) !== NULL)
 	{
 		if ($new_text != $text)
 			$text = $new_text;
@@ -196,7 +187,7 @@ function preparse_tags($text, &$errors, $is_signature = false)
 	// 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', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'img', 'list', '*', 'h');
+	$tags = array('quote', 'code', 'b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'img', 'list', '*', 'h', 'topic', 'post', 'forum', 'user');
 	// 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)
@@ -208,26 +199,30 @@ function preparse_tags($text, &$errors, $is_signature = false)
 	// 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', 's', 'ins', 'del', 'em', 'color', 'colour', 'h');
+	$tags_inline = array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'h', 'topic', 'post', 'forum', 'user');
 	// Tags we trim interior space
 	$tags_trim = array('img');
 	// Tags we remove quotes from the argument
-	$tags_quotes = array('url', 'email', 'img');
+	$tags_quotes = array('url', 'email', 'img', 'topic', 'post', 'forum', 'user');
 	// Tags we limit bbcode in
 	$tags_limit_bbcode = array(
-		'*' 	=> array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'list', 'img', 'code'),
+		'*' 	=> array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'list', 'img', 'code', 'topic', 'post', 'forum', 'user'),
 		'list' 	=> array('*'),
-		'url' 	=> array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'img'),
-		'email' => array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'img'),
+		'url' 	=> array('img'),
+		'email' => array('img'),
+		'topic' => array('img'),
+		'post'  => array('img'),
+		'forum' => array('img'),
+		'user'  => array('img'),
 		'img' 	=> array(),
-		'h'		=> array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email'),
+		'h'		=> array('b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'topic', 'post', 'forum', 'user'),
 	);
 	// Tags we can automatically fix bad nesting
-	$tags_fix = array('quote', 'b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'h');
+	$tags_fix = array('quote', 'b', 'i', 'u', 's', 'ins', 'del', 'em', 'color', 'colour', 'url', 'email', 'h', 'topic', 'post', 'forum', 'user');
 
-	$split_text = preg_split("/(\[[\*a-zA-Z0-9-\/]*?(?:=.*?)?\])/", $text, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
+	$split_text = preg_split('%(\[[\*a-zA-Z0-9-/]*?(?:=.*?)?\])%', $text, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
 
-	$open_tags = array('post');
+	$open_tags = array('fluxbb-bbcode');
 	$open_args = array('');
 	$opened_tag = 0;
 	$new_text = '';
@@ -235,6 +230,7 @@ function preparse_tags($text, &$errors, $is_signature = false)
 	$current_nest = '';
 	$current_depth = array();
 	$limit_bbcode = $tags;
+	$count_ignored = array();
 
 	foreach ($split_text as $current)
 	{
@@ -245,7 +241,6 @@ function preparse_tags($text, &$errors, $is_signature = false)
 		if (substr($current, 0, 1) != '[' || substr($current, -1, 1) != ']')
 		{
 			// It's not a bbcode tag so we put it on the end and continue
-
 			// If we are nested too deeply don't add to the end
 			if ($current_nest)
 				continue;
@@ -255,7 +250,7 @@ function preparse_tags($text, &$errors, $is_signature = false)
 			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);
+				$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
@@ -357,13 +352,29 @@ function preparse_tags($text, &$errors, $is_signature = false)
 			$current = strtolower($current);
 
 		// This is if we are currently in a tag which escapes other bbcode such as code
+		// We keep a cound of ignored bbcodes (code tags) so we can nest them, but
+		// only balanced sets of tags can be nested
 		if ($current_ignore)
 		{
+			// Increase the current ignored tags counter
+			if ('['.$current_ignore.']' == $current)
+			{
+				if (!isset($count_ignored[$current_tag]))
+					$count_ignored[$current_tag] = 2;
+				else
+					$count_ignored[$current_tag]++;
+			}
+
+			// Decrease the current ignored tags counter
 			if ('[/'.$current_ignore.']' == $current)
+				$count_ignored[$current_tag]--;
+
+			if ('[/'.$current_ignore.']' == $current && $count_ignored[$current_tag] == 0)
 			{
 				// We've finished the ignored section
 				$current = '[/'.$current_tag.']';
 				$current_ignore = '';
+				$count_ignored = array();
 			}
 
 			$new_text .= $current;
@@ -398,7 +409,6 @@ function preparse_tags($text, &$errors, $is_signature = false)
 		if (substr($current, 1, 1) == '/')
 		{
 			// This is if we are closing a tag
-
 			if ($opened_tag == 0 || !in_array($current_tag, $open_tags))
 			{
 				// We tried to close a tag which is not open
@@ -552,7 +562,7 @@ function preparse_tags($text, &$errors, $is_signature = false)
 			// 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);
+				$current = preg_replace('%\['.$current_tag.'=("|\'|)(.*?)\\1\]\s*%i', '['.$current_tag.'=$2]', $current);
 			}
 
 			if (in_array($current_tag, array_keys($tags_limit_bbcode)))
@@ -627,6 +637,8 @@ function handle_url_tag($url, $link = '', $bbcode = false)
 		$full_url = 'http://'.$full_url;
 	else if (strpos($url, 'ftp.') === 0) // Else if it starts with ftp, we add ftp://
 		$full_url = 'ftp://'.$full_url;
+	else if (strpos($url, '/') === 0) // Allow for relative URLs that start with a slash
+		$full_url = get_base_url(true).$full_url;
 	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;
 
@@ -713,9 +725,9 @@ function do_bbcode($text, $is_signature = false)
 
 	if (strpos($text, '[quote') !== false)
 	{
-		$text = preg_replace('#\[quote\]\s*#', '</p><div class="quotebox"><blockquote><div><p>', $text);
-		$text = preg_replace('#\[quote=("|&\#039;|"|\'|)(.*?)\\1\]#se', '"</p><div class=\"quotebox\"><cite>".str_replace(array(\'[\', \'\\"\'), array(\'[\', \'"\'), \'$2\')." ".$lang_common[\'wrote\']."</cite><blockquote><div><p>"', $text);
-		$text = preg_replace('#\s*\[\/quote\]#S', '</p></div></blockquote></div><p>', $text);
+		$text = preg_replace('%\[quote\]\s*%', '</p><div class="quotebox"><blockquote><div><p>', $text);
+		$text = preg_replace('%\[quote=("|&\#039;|"|\'|)(.*?)\\1\]%se', '"</p><div class=\"quotebox\"><cite>".str_replace(array(\'[\', \'\\"\'), array(\'[\', \'"\'), \'$2\')." ".$lang_common[\'wrote\']."</cite><blockquote><div><p>"', $text);
+		$text = preg_replace('%\s*\[\/quote\]%S', '</p></div></blockquote></div><p>', $text);
 	}
 
 	if (!$is_signature)
@@ -724,15 +736,15 @@ function do_bbcode($text, $is_signature = false)
 		$replace[] = 'handle_list_tag(\'$2\', \'$1\')';
 	}
 
-	$pattern[] = '#\[b\](.*?)\[/b\]#ms';
-	$pattern[] = '#\[i\](.*?)\[/i\]#ms';
-	$pattern[] = '#\[u\](.*?)\[/u\]#ms';
-	$pattern[] = '#\[s\](.*?)\[/s\]#ms';
-	$pattern[] = '#\[del\](.*?)\[/del\]#ms';
-	$pattern[] = '#\[ins\](.*?)\[/ins\]#ms';
-	$pattern[] = '#\[em\](.*?)\[/em\]#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';
+	$pattern[] = '%\[b\](.*?)\[/b\]%ms';
+	$pattern[] = '%\[i\](.*?)\[/i\]%ms';
+	$pattern[] = '%\[u\](.*?)\[/u\]%ms';
+	$pattern[] = '%\[s\](.*?)\[/s\]%ms';
+	$pattern[] = '%\[del\](.*?)\[/del\]%ms';
+	$pattern[] = '%\[ins\](.*?)\[/ins\]%ms';
+	$pattern[] = '%\[em\](.*?)\[/em\]%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>';
@@ -746,8 +758,8 @@ function do_bbcode($text, $is_signature = false)
 
 	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';
+		$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)';
@@ -760,15 +772,31 @@ function do_bbcode($text, $is_signature = false)
 		}
 	}
 
-	$pattern[] = '#\[url\]([^\[]*?)\[/url\]#e';
-	$pattern[] = '#\[url=([^\[]+?)\](.*?)\[/url\]#e';
-	$pattern[] = '#\[email\]([^\[]*?)\[/email\]#';
-	$pattern[] = '#\[email=([^\[]+?)\](.*?)\[/email\]#';
+	$pattern[] = '%\[url\]([^\[]*?)\[/url\]%e';
+	$pattern[] = '%\[url=([^\[]+?)\](.*?)\[/url\]%e';
+	$pattern[] = '%\[email\]([^\[]*?)\[/email\]%';
+	$pattern[] = '%\[email=([^\[]+?)\](.*?)\[/email\]%';
+	$pattern[] = '%\[topic\]([^\[]*?)\[/topic\]%e';
+	$pattern[] = '%\[topic=([^\[]+?)\](.*?)\[/topic\]%e';
+	$pattern[] = '%\[post\]([^\[]*?)\[/post\]%e';
+	$pattern[] = '%\[post=([^\[]+?)\](.*?)\[/post\]%e';
+	$pattern[] = '%\[forum\]([^\[]*?)\[/forum\]%e';
+	$pattern[] = '%\[forum=([^\[]+?)\](.*?)\[/forum\]%e';
+	$pattern[] = '%\[user\]([^\[]*?)\[/user\]%e';
+	$pattern[] = '%\[user=([^\[]+?)\](.*?)\[/user\]%e';
 
 	$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>';
+	$replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewtopic.php?id=$1\')';
+	$replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewtopic.php?id=$1\', \'$2\')';
+	$replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewtopic.php?pid=$1#p$1\')';
+	$replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewtopic.php?pid=$1#p$1\', \'$2\')';
+	$replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewforum.php?id=$1\')';
+	$replace[] = 'handle_url_tag(\''.get_base_url(true).'/viewforum.php?id=$1\', \'$2\')';
+	$replace[] = 'handle_url_tag(\''.get_base_url(true).'/profile.php?id=$1\')';
+	$replace[] = 'handle_url_tag(\''.get_base_url(true).'/profile.php?id=$1\', \'$2\')';
 
 	// This thing takes a while! :)
 	$text = preg_replace($pattern, $replace, $text);
@@ -784,8 +812,8 @@ function do_clickable($text)
 {
 	$text = ' '.$text;
 
-	$text = ucp_preg_replace('#(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(https?|ftp|news){1}://([\p{L}\p{N}\-]+\.([\p{L}\p{N}\-]+\.)*[\p{L}\p{N}]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])#uie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5://$6\', \'$5://$6\', true).stripslashes(\'$4$10$11$12\')', $text);
-	$text = ucp_preg_replace('#(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(www|ftp)\.(([\p{L}\p{N}\-]+\.)*[\p{L}\p{N}]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])#uie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5.$6\', \'$5.$6\', true).stripslashes(\'$4$10$11$12\')', $text);
+	$text = ucp_preg_replace('%(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(https?|ftp|news){1}://([\p{L}\p{N}\-]+\.([\p{L}\p{N}\-]+\.)*[\p{L}\p{N}]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])%uie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5://$6\', \'$5://$6\', true).stripslashes(\'$4$10$11$12\')', $text);
+	$text = ucp_preg_replace('%(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(www|ftp)\.(([\p{L}\p{N}\-]+\.)*[\p{L}\p{N}]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])%uie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5.$6\', \'$5.$6\', true).stripslashes(\'$4$10$11$12\')', $text);
 
 	return substr($text, 1);
 }
@@ -803,7 +831,7 @@ function do_smilies($text)
 	foreach ($smilies as $smiley_text => $smiley_img)
 	{
 		if (strpos($text, $smiley_text) !== false)
-			$text = ucp_preg_replace('#(?<=[>\s])'.preg_quote($smiley_text, '#').'(?=[^\p{L}\p{N}])#um', '<img src="'.pun_htmlspecialchars(get_base_url(true).'/img/smilies/'.$smiley_img).'" width="15" height="15" alt="'.substr($smiley_img, 0, strrpos($smiley_img, '.')).'" />', $text);
+			$text = ucp_preg_replace('%(?<=[>\s])'.preg_quote($smiley_text, '%').'(?=[^\p{L}\p{N}])%um', '<img src="'.pun_htmlspecialchars(get_base_url(true).'/img/smilies/'.$smiley_img).'" width="15" height="15" alt="'.substr($smiley_img, 0, strrpos($smiley_img, '.')).'" />', $text);
 	}
 
 	return substr($text, 1, -1);
@@ -825,10 +853,7 @@ 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]', $errors);
-		$text = implode("\1", $outside);
-	}
+		list($inside, $text) = extract_blocks($text, '[code]', '[/code]', $errors);
 
 	if ($pun_config['p_message_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
 		$text = do_bbcode($text);
@@ -842,27 +867,22 @@ function parse_message($text, $hide_smilies)
 	$text = str_replace($pattern, $replace, $text);
 
 	// If we split up the message before we have to concatenate it together again (code tags)
-	if (isset($inside))
-	{
-		$outside = explode("\1", $text);
-		$text = '';
-
-		$num_tokens = count($outside);
-
-		for ($i = 0; $i < $num_tokens; ++$i)
-		{
-			$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"));
-				$text .= '</p><div class="codebox"><pre'.(($num_lines > 28) ? ' class="vscroll"' : '').'><code>'.pun_trim($inside[$i], "\n\r").'</code></pre></div><p>';
-			}
-		}
-	}
+    if (isset($inside)) {
+        $parts = explode("\1", $text);
+        $text = '';
+        foreach ($parts as $i => $part)
+        {
+            $text .= $part;
+            if (isset($inside[$i]))
+            {
+                $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 = 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>');
 
@@ -896,7 +916,7 @@ function parse_signature($text)
 	$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 = 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>');
 
diff --git a/include/search_idx.php b/include/search_idx.php
index 7f3a834..210b268 100644
--- a/include/search_idx.php
+++ b/include/search_idx.php
@@ -48,16 +48,16 @@ define('PUN_CJK_HANGUL_REGEX', '['.
 function split_words($text, $idx)
 {
 	// Remove BBCode
-	$text = preg_replace('/\[\/?(b|u|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list)(?:\=[^\]]*)?\]/', ' ', $text);
+	$text = preg_replace('%\[/?(b|u|s|ins|del|em|i|h|colou?r|quote|code|img|url|email|list)(?:\=[^\]]*)?\]%', ' ', $text);
 
 	// Remove any apostrophes or dashes which aren't part of words
-	$text = substr(ucp_preg_replace('/((?<=[^\p{L}\p{N}])[\'\-]|[\'\-](?=[^\p{L}\p{N}]))/u', '', ' '.$text.' '), 1, -1);
+	$text = substr(ucp_preg_replace('%((?<=[^\p{L}\p{N}])[\'\-]|[\'\-](?=[^\p{L}\p{N}]))%u', '', ' '.$text.' '), 1, -1);
 
 	// Remove punctuation and symbols (actually anything that isn't a letter or number), allow apostrophes and dashes (and % * if we aren't indexing)
-	$text = ucp_preg_replace('/(?![\'\-'.($idx ? '' : '%\*').'])[^\p{L}\p{N}]+/u', ' ', $text);
+	$text = ucp_preg_replace('%(?![\'\-'.($idx ? '' : '\%\*').'])[^\p{L}\p{N}]+%u', ' ', $text);
 
 	// Replace multiple whitespace or dashes
-	$text = preg_replace('/(\s){2,}/u', '\1', $text);
+	$text = preg_replace('%(\s){2,}%u', '\1', $text);
 
 	// Fill an array with all the words
 	$words = array_unique(explode(' ', $text));
@@ -128,7 +128,7 @@ function is_keyword($word)
 //
 function is_cjk($word)
 {
-	return preg_match('/^'.PUN_CJK_HANGUL_REGEX.'+$/u', $word) ? true : false;
+	return preg_match('%^'.PUN_CJK_HANGUL_REGEX.'+$%u', $word) ? true : false;
 }
 
 
@@ -142,9 +142,9 @@ function strip_bbcode($text)
 	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
+			'%\[img=([^\]]*+)\]([^[]*+)\[/img\]%'									=>	'$2 $1',	// Keep the url and description
+			'%\[(url|email)=([^\]]*+)\]([^[]*+(?:(?!\[/\1\])\[[^[]*+)*)\[/\1\]%'	=>	'$2 $3',	// Keep the url and text
+			'%\[(img|url|email)\]([^[]*+(?:(?!\[/\1\])\[[^[]*+)*)\[/\1\]%'			=>	'$2',		// Keep the url
 		);
 	}
 
diff --git a/lang/English/admin_groups.php b/lang/English/admin_groups.php
index dd6ad56..4b1b4ad 100644
--- a/lang/English/admin_groups.php
+++ b/lang/English/admin_groups.php
@@ -26,7 +26,7 @@ $lang_admin_groups = array(
 '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.',
+'Confirm delete warn'			=>	'WARNING! After you deleted a group you cannot 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.',
@@ -77,6 +77,8 @@ $lang_admin_groups = array(
 '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.',
+'Report flood label'			=>	'Report flood interval',
+'Report flood help'				=>	'Number of seconds that users in this group have to wait between reports. 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/lang/English/admin_index.php b/lang/English/admin_index.php
index 9f9cdc7..bd2cd97 100644
--- a/lang/English/admin_index.php
+++ b/lang/English/admin_index.php
@@ -32,14 +32,14 @@ $lang_admin_index = array(
 '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',
+'Turck MMCache'						=>	'Turck 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',
+'Zend Optimizer link'				=>	'www.zend.com/products/guard/zend-optimizer/',
 'eAccelerator'						=>	'eAccelerator',
 'eAccelerator link'					=>	'www.eaccelerator.net/',
 'XCache'							=>	'XCache',
diff --git a/lang/English/admin_plugin_example.php b/lang/English/admin_plugin_example.php
deleted file mode 100644
index b06158d..0000000
--- a/lang/English/admin_plugin_example.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?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/lang/English/admin_prune.php b/lang/English/admin_prune.php
deleted file mode 100644
index 532a74f..0000000
--- a/lang/English/admin_prune.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?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/lang/English/admin_users.php b/lang/English/admin_users.php
index 76d6639..49fad72 100644
--- a/lang/English/admin_users.php
+++ b/lang/English/admin_users.php
@@ -58,6 +58,8 @@ $lang_admin_users = array(
 'Last post after label'		=>	'Last post is after',
 'Date help'					=>	'(yyyy-mm-dd hh:mm:ss)',
 'Last post before label'	=>	'Last post is before',
+'Last visit after label'	=>	'Last visit is after',
+'Last visit before label'	=>	'Last visit is before',
 'Registered after label'	=>	'Registered after',
 'Registered before label'	=>	'Registered before',
 'Order by label'			=>	'Order by',
@@ -65,6 +67,7 @@ $lang_admin_users = array(
 'Order by e-mail'			=>	'Email',
 'Order by posts'			=>	'Number of posts',
 'Order by last post'		=>	'Last post',
+'Order by last visit'		=>	'Last visit',
 'Order by registered'		=>	'Registered',
 'Ascending'					=>	'Ascending',
 'Descending'				=>	'Descending',
diff --git a/lang/English/common.php b/lang/English/common.php
index 7a88e18..6a0c85e 100644
--- a/lang/English/common.php
+++ b/lang/English/common.php
@@ -64,12 +64,11 @@ $lang_common = array(
 '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
+'Mailer'							=>	'%s 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',
-'Forum index'						=>	'Forum index',
 'Spacer'							=>	'…', // Ellipsis for paginate
 
 // Title
@@ -137,24 +136,6 @@ $lang_common = array(
 'Query'								=>	'Query',
 'Total query time'					=>	'Total query time: %s',
 
-// Email related notifications
-'New user notification'				=>	'Alert - New registration',
-'New user message'					=>	'User \'%s\' registered in the forums at %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 description'					=>	'The most recent topics at %s.',
 'RSS description topic'				=>	'The most recent posts in %s.',
@@ -170,4 +151,13 @@ $lang_common = array(
 'New reports'						=>	'There are new reports',
 'Maintenance mode enabled'			=>	'Maintenance mode is enabled!',
 
+// Units for file sizes
+'Size unit B'						=>	'%s B',
+'Size unit KiB'						=>	'%s KiB',
+'Size unit MiB'						=>	'%s MiB',
+'Size unit GiB'						=>	'%s GiB',
+'Size unit TiB'						=>	'%s TiB',
+'Size unit PiB'						=>	'%s PiB',
+'Size unit EiB'						=>	'%s EiB',
+
 );
diff --git a/lang/English/help.php b/lang/English/help.php
index 9289566..7b4e533 100644
--- a/lang/English/help.php
+++ b/lang/English/help.php
@@ -25,10 +25,16 @@ $lang_help = array(
 
 'Links and images'		=>	'Links and images',
 'Links info'			=>	'You can create links to other documents or to email addresses using the following tags:',
+'This help page'		=>	'This help page',
 '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.',
 'FluxBB bbcode test'	=>	'FluxBB bbcode test',
 
+'Test topic'			=>	'Test topic',
+'Test post'				=>	'Test post',
+'Test forum'			=>	'Test forum',
+'Test user'				=>	'Test user',
+
 '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.',
diff --git a/lang/English/mail_templates/activate_email.tpl b/lang/English/mail_templates/activate_email.tpl
index f17066f..49095c0 100644
--- a/lang/English/mail_templates/activate_email.tpl
+++ b/lang/English/mail_templates/activate_email.tpl
@@ -8,5 +8,5 @@ To change your email address, please visit the following page:
 <activation_url>
 
 --
-<board_mailer>
+<board_mailer> Mailer
 (Do not reply to this message)
diff --git a/lang/English/mail_templates/activate_password.tpl b/lang/English/mail_templates/activate_password.tpl
index 33b2b3e..b408927 100644
--- a/lang/English/mail_templates/activate_password.tpl
+++ b/lang/English/mail_templates/activate_password.tpl
@@ -10,5 +10,5 @@ To change your password, please visit the following page:
 <activation_url>
 
 --
-<board_mailer>
+<board_mailer> Mailer
 (Do not reply to this message)
diff --git a/lang/English/mail_templates/banned_email_change.tpl b/lang/English/mail_templates/banned_email_change.tpl
new file mode 100644
index 0000000..276662f
--- /dev/null
+++ b/lang/English/mail_templates/banned_email_change.tpl
@@ -0,0 +1,9 @@
+Subject: Alert - Banned email detected
+
+User '<username>' changed to banned email address: <email>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)
diff --git a/lang/English/mail_templates/banned_email_post.tpl b/lang/English/mail_templates/banned_email_post.tpl
new file mode 100644
index 0000000..f7e0243
--- /dev/null
+++ b/lang/English/mail_templates/banned_email_post.tpl
@@ -0,0 +1,9 @@
+Subject: Alert - Banned email detected
+
+User '<username>' posted with banned email address: <email>
+
+Post URL: <post_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)
diff --git a/lang/English/mail_templates/banned_email_register.tpl b/lang/English/mail_templates/banned_email_register.tpl
new file mode 100644
index 0000000..f0085ec
--- /dev/null
+++ b/lang/English/mail_templates/banned_email_register.tpl
@@ -0,0 +1,9 @@
+Subject: Alert - Banned email detected
+
+User '<username>' registered with banned email address: <email>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)
diff --git a/lang/English/mail_templates/dupe_email_change.tpl b/lang/English/mail_templates/dupe_email_change.tpl
new file mode 100644
index 0000000..583fb24
--- /dev/null
+++ b/lang/English/mail_templates/dupe_email_change.tpl
@@ -0,0 +1,9 @@
+Subject: Alert - Duplicate email detected
+
+User '<username>' changed to an email address that also belongs to: <dupe_list>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)
diff --git a/lang/English/mail_templates/dupe_email_register.tpl b/lang/English/mail_templates/dupe_email_register.tpl
new file mode 100644
index 0000000..b1cb363
--- /dev/null
+++ b/lang/English/mail_templates/dupe_email_register.tpl
@@ -0,0 +1,9 @@
+Subject: Alert - Duplicate email detected
+
+User '<username>' registered with an email address that also belongs to: <dupe_list>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)
diff --git a/lang/English/mail_templates/form_email.tpl b/lang/English/mail_templates/form_email.tpl
index b862422..e3e0d5f 100644
--- a/lang/English/mail_templates/form_email.tpl
+++ b/lang/English/mail_templates/form_email.tpl
@@ -10,4 +10,4 @@ The message reads as follows:
 -----------------------------------------------------------------------
 
 --
-<board_mailer>
+<board_mailer> Mailer
diff --git a/lang/English/mail_templates/new_reply.tpl b/lang/English/mail_templates/new_reply.tpl
index b423bf5..286914e 100644
--- a/lang/English/mail_templates/new_reply.tpl
+++ b/lang/English/mail_templates/new_reply.tpl
@@ -7,5 +7,5 @@ The post is located at <post_url>
 You can unsubscribe by going to <unsubscribe_url>
 
 --
-<board_mailer>
+<board_mailer> Mailer
 (Do not reply to this message)
diff --git a/lang/English/mail_templates/new_reply_full.tpl b/lang/English/mail_templates/new_reply_full.tpl
index 99371c2..73363ea 100644
--- a/lang/English/mail_templates/new_reply_full.tpl
+++ b/lang/English/mail_templates/new_reply_full.tpl
@@ -14,5 +14,5 @@ The post is located at <post_url>
 You can unsubscribe by going to <unsubscribe_url>
 
 --
-<board_mailer>
+<board_mailer> Mailer
 (Do not reply to this message)
diff --git a/lang/English/mail_templates/new_report.tpl b/lang/English/mail_templates/new_report.tpl
new file mode 100644
index 0000000..dedb113
--- /dev/null
+++ b/lang/English/mail_templates/new_report.tpl
@@ -0,0 +1,9 @@
+Subject: Report(<forum_id>) - '<topic_subject>'
+
+User '<username>' has reported the following message: <post_url>
+
+Reason: <reason>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)
diff --git a/lang/English/mail_templates/new_topic.tpl b/lang/English/mail_templates/new_topic.tpl
index ae5e927..2bc048b 100644
--- a/lang/English/mail_templates/new_topic.tpl
+++ b/lang/English/mail_templates/new_topic.tpl
@@ -7,5 +7,5 @@ The topic is located at <topic_url>
 You can unsubscribe by going to <unsubscribe_url>
 
 --
-<board_mailer>
+<board_mailer> Mailer
 (Do not reply to this message)
diff --git a/lang/English/mail_templates/new_topic_full.tpl b/lang/English/mail_templates/new_topic_full.tpl
index 25afd49..2ea6b0f 100644
--- a/lang/English/mail_templates/new_topic_full.tpl
+++ b/lang/English/mail_templates/new_topic_full.tpl
@@ -14,5 +14,5 @@ The topic is located at <topic_url>
 You can unsubscribe by going to <unsubscribe_url>
 
 --
-<board_mailer>
+<board_mailer> Mailer
 (Do not reply to this message)
diff --git a/lang/English/mail_templates/new_user.tpl b/lang/English/mail_templates/new_user.tpl
new file mode 100644
index 0000000..5725b1c
--- /dev/null
+++ b/lang/English/mail_templates/new_user.tpl
@@ -0,0 +1,9 @@
+Subject: Alert - New registration
+
+User '<username>' registered in the forums at <base_url>
+
+User profile: <profile_url>
+
+--
+<board_mailer> Mailer
+(Do not reply to this message)
diff --git a/lang/English/mail_templates/rename.tpl b/lang/English/mail_templates/rename.tpl
index f1ea88c..3cba50d 100644
--- a/lang/English/mail_templates/rename.tpl
+++ b/lang/English/mail_templates/rename.tpl
@@ -8,5 +8,5 @@ New username: <new_username>
 We apologise for any inconvenience caused.
 
 --
-<board_mailer>
+<board_mailer> Mailer
 (Do not reply to this message)
diff --git a/lang/English/mail_templates/welcome.tpl b/lang/English/mail_templates/welcome.tpl
index 0110042..779a574 100644
--- a/lang/English/mail_templates/welcome.tpl
+++ b/lang/English/mail_templates/welcome.tpl
@@ -8,5 +8,5 @@ Password: <password>
 Login at <login_url> to activate the account.
 
 --
-<board_mailer>
+<board_mailer> Mailer
 (Do not reply to this message)
diff --git a/lang/English/profile.php b/lang/English/profile.php
index b1aa3ab..5687e35 100644
--- a/lang/English/profile.php
+++ b/lang/English/profile.php
@@ -81,6 +81,7 @@ $lang_profile = array(
 'Realname'						=>	'Real name',
 'Location'						=>	'Location',
 'Website'						=>	'Website',
+'Invalid website URL'					=>	'The website URL you entered is invalid.',
 'Jabber'						=>	'Jabber',
 'ICQ'							=>	'ICQ',
 'MSN'							=>	'MSN Messenger',
diff --git a/lang/English/search.php b/lang/English/search.php
index 1fe47cf..b0f7fba 100644
--- a/lang/English/search.php
+++ b/lang/English/search.php
@@ -14,6 +14,7 @@ $lang_search = array(
 'Author search'						=>	'Author search',
 'Search in legend'					=>	'Select where to search',
 'Search in info'					=>	'Choose in which forum you would like to search and if you want to search in topic subjects, message text or both.',
+'Search multiple forums info'		=>	'If no forums are selected, all forums will be searched.',
 'Forum search'						=>	'Forum',
 'All forums'						=>	'All forums',
 'Search in'							=>	'Search in',
@@ -35,22 +36,21 @@ $lang_search = array(
 'Show as posts'						=>	'Posts',
 
 // Results
+'Search'							=>	'Search',
 'Search results'					=>	'Search results',
-'Search topics'						=>	'Search topics',
-'Search posts'						=>	'Search posts',
 'Quick search show_new'				=>	'New',
 'Quick search show_recent'			=>	'Active',
 'Quick search show_unanswered'		=>	'Unanswered',
 'Quick search show_replies'			=>	'Posted',
-'Quick search show_user_topics'		=>	'By %s',
-'Quick search show_user_posts'		=>	'By %s',
+'Quick search show_user_topics'		=>	'Topics by %s',
+'Quick search show_user_posts'		=>	'Posts by %s',
 'Quick search show_subscriptions'	=>	'Subscribed by %s',
-'By keywords show as topics'		=>	'With posts with keywords \'%s\'',
-'By keywords show as posts'			=>	'With keywords \'%s\'',
-'By user show as topics'			=>	'With posts by %s',
-'By user show as posts'				=>	'By %s',
-'By both show as topics'			=>	'With keywords \'%s\' in posts by %s',
-'By both show as posts'				=>	'With keywords \'%s\' by %s',
+'By keywords show as topics'		=>	'Topics with posts containing \'%s\'',
+'By keywords show as posts'			=>	'Posts containing \'%s\'',
+'By user show as topics'			=>	'Topics with posts by %s',
+'By user show as posts'				=>	'Posts by %s',
+'By both show as topics'			=>	'Topics with posts containing \'%s\', by %s',
+'By both show as posts'				=>	'Posts containing \'%s\', by %s',
 'No terms'							=>	'You have to enter at least one keyword and/or an author to search for.',
 'No hits'							=>	'Your search returned no hits.',
 'No user posts'						=>	'There are no posts by this user in this forum.',
diff --git a/lang/English/topic.php b/lang/English/topic.php
index f964f0d..ff70bf4 100644
--- a/lang/English/topic.php
+++ b/lang/English/topic.php
@@ -27,13 +27,6 @@ $lang_topic = array(
 'Mod controls'		=>	'Moderator controls',
 'New icon'			=>	'New post',
 'Re'				=>	'Re:',
-'Preview'			=>	'Preview',
+'Preview'			=>	'Preview'
 
-// Solved strings
-'Mark solved'		=> 	'Mark as solved',
-'Mark unsolved'		=>	'Mark as unsolved',
-'Solved'		=>	'[Solved]',
-'Solved closed'		=>	'The topic is closed. Cannot change solve state. Redirecting …',
-'Solved not permitted'	=>	'You are not allowed to change the solve state of this topic. Redirecting …',
-'Solved succesfull'	=>	'Topic solve state changed succesfully. Redirecting …',
 );
diff --git a/lang/English/update.php b/lang/English/update.php
index d4e64b6..437e7fe 100644
--- a/lang/English/update.php
+++ b/lang/English/update.php
@@ -12,6 +12,9 @@ $lang_update = array(
 'Database password info'		=>	'To perform the database update please enter the database password with which FluxBB was installed. If you cannot remember, this is stored in your \'config.php\' file.',
 'Database password note'		=>	'If you are running SQLite (and hence have no database password) please use the database file name instead. This must exactly match the database file name given in your configuration file.',
 'Database password'				=>	'Database password',
+'Maintenance'					=>	'Maintenance',
+'Maintenance message info'		=>	'The message that will be displayed to users during the updating process. This text will not be parsed like regular posts and thus may contain HTML.',
+'Maintenance message'		    =>	'Maintenance message',
 'Next'							=>	'Next',
 
 'You are running error'			=>	'You are running %1$s version %2$s. FluxBB %3$s requires at least %1$s %4$s to run properly. You must upgrade your %1$s installation before you can continue.',
@@ -70,8 +73,4 @@ $lang_update = array(
 'Username BBCode error'			=>	'Usernames may not contain any of the text formatting tags (BBCode) that the forum uses. Please choose another username.',
 'Username duplicate error'		=>	'Someone is already registered with the username %s. 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.',
 
-'JavaScript disabled'			=>	'JavaScript seems to be disabled. %s.',
-'Click here to continue'		=>	'Click here to continue',
-'Required field'				=>	'is a required field in this form.'
-
 );
diff --git a/login.php b/login.php
index 38cb797..97c66b1 100644
--- a/login.php
+++ b/login.php
@@ -161,7 +161,7 @@ else if ($action == 'forget' || $action == 'forget_2')
 
 				// Do the generic replacements first (they apply to all emails sent out here)
 				$mail_message = str_replace('<base_url>', get_base_url().'/', $mail_message);
-				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message);
+				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 				// Loop through users we found
 				while ($cur_hit = $db->fetch_assoc($result))
@@ -269,7 +269,7 @@ if (!empty($_SERVER['HTTP_REFERER']))
 	if (!isset($valid['path']))
 		$valid['path'] = '';
 
-	if ($referrer['host'] == $valid['host'] && preg_match('#^'.preg_quote($valid['path']).'/(.*?)\.php#i', $referrer['path']))
+	if ($referrer['host'] == $valid['host'] && preg_match('%^'.preg_quote($valid['path'], '%').'/(.*?)\.php%i', $referrer['path']))
 		$redirect_url = $_SERVER['HTTP_REFERER'];
 }
 
@@ -301,11 +301,11 @@ require PUN_ROOT.'header.php';
 						</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>
+						<p class="actions"><span><a href="register.php" tabindex="5"><?php echo $lang_login['Not registered'] ?></a></span> <span><a href="login.php?action=forget" tabindex="6"><?php echo $lang_login['Forgotten pass'] ?></a></span></p>
 					</div>
 				</fieldset>
 			</div>
-			<p class="buttons"><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="4" /></p>
 		</form>
 	</div>
 </div>
diff --git a/misc.php b/misc.php
index 8468313..6f7755b 100644
--- a/misc.php
+++ b/misc.php
@@ -125,7 +125,7 @@ else if (isset($_GET['email']))
 		$mail_message = str_replace('<sender>', $pun_user['username'], $mail_message);
 		$mail_message = str_replace('<board_title>', $pun_config['o_board_title'], $mail_message);
 		$mail_message = str_replace('<mail_message>', $message, $mail_message);
-		$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message);
+		$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 		require_once PUN_ROOT.'include/email.php';
 
@@ -150,7 +150,7 @@ else if (isset($_GET['email']))
 		if (strpos($valid['host'], 'www.') === 0)
 			$valid['host'] = substr($valid['host'], 4);
 
-		if ($referrer['host'] == $valid['host'] && preg_match('#^'.preg_quote($valid['path']).'/(.*?)\.php#i', $referrer['path']))
+		if ($referrer['host'] == $valid['host'] && preg_match('%^'.preg_quote($valid['path'], '%').'/(.*?)\.php%i', $referrer['path']))
 			$redirect_url = $_SERVER['HTTP_REFERER'];
 	}
 
@@ -210,8 +210,8 @@ else if (isset($_GET['report']))
 		else if (strlen($reason) > 65535) // TEXT field can only hold 65535 bytes
 			message($lang_misc['Reason too long']);
 
-		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']));
+		if ($pun_user['last_report_sent'] != '' && (time() - $pun_user['last_report_sent']) < $pun_user['g_report_flood'] && (time() - $pun_user['last_report_sent']) >= 0)
+			message(sprintf($lang_misc['Report flood'], $pun_user['g_report_flood']));
 
 		// Get the topic ID
 		$result = $db->query('SELECT topic_id FROM '.$db->prefix.'posts WHERE id='.$post_id) or error('Unable to fetch post info', __FILE__, __LINE__, $db->error());
@@ -237,10 +237,20 @@ else if (isset($_GET['report']))
 			// 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'], get_base_url().'/viewtopic.php?pid='.$post_id.'#p'.$post_id)."\n";
-				$mail_message .= sprintf($lang_common['Report message 2'], $reason)."\n";
-				$mail_message .= "\n".'--'."\n".$lang_common['Email signature'];
+				// Load the "new report" template
+				$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/new_report.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 = str_replace('<forum_id>', $forum_id, $mail_subject);
+				$mail_subject = str_replace('<topic_subject>', $subject, $mail_subject);
+				$mail_message = str_replace('<username>', $pun_user['username'], $mail_message);
+				$mail_message = str_replace('<post_url>', get_base_url().'/viewtopic.php?pid='.$post_id.'#p'.$post_id, $mail_message);
+				$mail_message = str_replace('<reason>', $reason, $mail_message);
+				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 				require PUN_ROOT.'include/email.php';
 
@@ -248,7 +258,7 @@ else if (isset($_GET['report']))
 			}
 		}
 
-		$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());
+		$db->query('UPDATE '.$db->prefix.'users SET last_report_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']);
 	}
diff --git a/moderate.php b/moderate.php
index 77b45e2..7f27d66 100644
--- a/moderate.php
+++ b/moderate.php
@@ -18,7 +18,7 @@ if (isset($_GET['get_host']))
 		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']) || @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}:))$/', $_GET['get_ho
 st']))
+	if (@preg_match('%^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$%', $_GET['get_host']) || @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}:))$%', $_GET['get_ho
 st']))
 		$ip = $_GET['get_host'];
 	else
 	{
@@ -86,7 +86,7 @@ if (isset($_GET['tid']))
 		{
 			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
@@ -153,7 +153,7 @@ if (isset($_GET['tid']))
 		{
 			confirm_referrer('moderate.php');
 
-			if (@preg_match('/[^0-9,]/', $posts))
+			if (@preg_match('%[^0-9,]%', $posts))
 				message($lang_common['Bad request']);
 
 			$move_to_forum = isset($_POST['move_to_forum']) ? intval($_POST['move_to_forum']) : 0;
@@ -420,7 +420,7 @@ if (isset($_REQUEST['move_topics']) || isset($_POST['move_topics_to']))
 	{
 		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']);
@@ -548,21 +548,19 @@ else if (isset($_POST['merge_topics']) || isset($_POST['merge_topics_comply']))
 	{
 		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']);
 		if (count($topics) < 2)
 			message($lang_misc['Not enough topics selected']);
 
-		// Verify that the topic IDs are valid (moved topics can not be merged?)
-		// $result = $db->query('SELECT 1 FROM '.$db->prefix.'topics WHERE id IN('.implode(',', $topics).') AND moved_to IS NULL AND forum_id='.$fid) or error('Unable to check topics', __FILE__, __LINE__, $db->error());
-		$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());
+		// Verify that the topic IDs are valid (redirect links will point to the merged topic after the merge)
+		$result = $db->query('SELECT id FROM '.$db->prefix.'topics WHERE id IN('.implode(',', $topics).') AND forum_id='.$fid.' ORDER BY id ASC') or error('Unable to check topics', __FILE__, __LINE__, $db->error());
 		if ($db->num_rows($result) != count($topics))
 			message($lang_common['Bad request']);
 
-		// Fetch the topic that we're merging into
-		$result = $db->query('SELECT MIN(t.id) FROM '.$db->prefix.'topics AS t WHERE t.id IN('.implode(',', $topics).')') or error('Unable to get topic', __FILE__, __LINE__, $db->error());
+		// The topic that we are merging into is the one with the smallest ID
 		$merge_to_tid = $db->result($result);
 
 		// Make any redirect topics point to our new, merged topic
@@ -644,7 +642,7 @@ else if (isset($_POST['delete_topics']) || isset($_POST['delete_topics_comply'])
 	{
 		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';
diff --git a/post.php b/post.php
index c849b14..9d09f10 100644
--- a/post.php
+++ b/post.php
@@ -59,10 +59,6 @@ $errors = array();
 // Did someone just hit "Submit" or "Preview"?
 if (isset($_POST['form_sent']))
 {
-	// Make sure form_user is correct
-	if (($pun_user['is_guest'] && $_POST['form_user'] != 'Guest') || (!$pun_user['is_guest'] && $_POST['form_user'] != $pun_user['username']))
-		message($lang_common['Bad request']);
-
 	// Flood protection
 	if (!isset($_POST['preview']) && $pun_user['last_post'] != '' && (time() - $pun_user['last_post']) < $pun_user['g_post_flood'])
 		$errors[] = $lang_post['Flood start'].' '.$pun_user['g_post_flood'].' '.$lang_post['flood end'];
@@ -96,8 +92,9 @@ if (isset($_POST['form_sent']))
 	{
 		$username = pun_trim($_POST['req_username']);
 		$email = strtolower(trim(($pun_config['p_force_guest_email'] == '1') ? $_POST['req_email'] : $_POST['email']));
+		$banned_email = false;
 
-		// Load the register.php/profile.php language files
+		// Load the register.php/prof_reg.php language files
 		require PUN_ROOT.'lang/'.$pun_user['language'].'/prof_reg.php';
 		require PUN_ROOT.'lang/'.$pun_user['language'].'/register.php';
 
@@ -119,8 +116,6 @@ if (isset($_POST['form_sent']))
 
 				$banned_email = true; // Used later when we send an alert email
 			}
-			else
-				$banned_email = false;
 		}
 	}
 
@@ -188,7 +183,7 @@ if (isset($_POST['form_sent']))
 			else
 			{
 				// It's a guest. Insert the new post
-				$email_sql = ($pun_config['p_force_guest_email'] == '1' || $email != '') ? '\''.$email.'\'' : 'NULL';
+				$email_sql = ($pun_config['p_force_guest_email'] == '1' || $email != '') ? '\''.$db->escape($email).'\'' : 'NULL';
 				$db->query('INSERT INTO '.$db->prefix.'posts (poster, poster_ip, poster_email, message, hide_smilies, posted, topic_id) VALUES(\''.$db->escape($username).'\', \''.get_remote_address().'\', '.$email_sql.', \''.$db->escape($message).'\', '.$hide_smilies.', '.$now.', '.$tid.')') or error('Unable to create post', __FILE__, __LINE__, $db->error());
 				$new_pid = $db->insert_id();
 			}
@@ -219,6 +214,11 @@ if (isset($_POST['form_sent']))
 
 					$notification_emails = array();
 
+					if ($pun_config['o_censoring'] == '1')
+						$cleaned_message = bbcode2email($censored_message, -1);
+					else
+						$cleaned_message = bbcode2email($message, -1);
+
 					// Loop through subscribed users and send emails
 					while ($cur_subscriber = $db->fetch_assoc($result))
 					{
@@ -247,15 +247,15 @@ if (isset($_POST['form_sent']))
 								$mail_message = str_replace('<replier>', $username, $mail_message);
 								$mail_message = str_replace('<post_url>', get_base_url().'/viewtopic.php?pid='.$new_pid.'#p'.$new_pid, $mail_message);
 								$mail_message = str_replace('<unsubscribe_url>', get_base_url().'/misc.php?action=unsubscribe&tid='.$tid, $mail_message);
-								$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message);
+								$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 								$mail_subject_full = str_replace('<topic_subject>', $cur_posting['subject'], $mail_subject_full);
 								$mail_message_full = str_replace('<topic_subject>', $cur_posting['subject'], $mail_message_full);
 								$mail_message_full = str_replace('<replier>', $username, $mail_message_full);
-								$mail_message_full = str_replace('<message>', $pun_config['o_censoring'] == '1' ? $censored_message : $message, $mail_message_full);
+								$mail_message_full = str_replace('<message>', $cleaned_message, $mail_message_full);
 								$mail_message_full = str_replace('<post_url>', get_base_url().'/viewtopic.php?pid='.$new_pid.'#p'.$new_pid, $mail_message_full);
 								$mail_message_full = str_replace('<unsubscribe_url>', get_base_url().'/misc.php?action=unsubscribe&tid='.$tid, $mail_message_full);
-								$mail_message_full = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message_full);
+								$mail_message_full = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message_full);
 
 								$notification_emails[$cur_subscriber['language']][0] = $mail_subject;
 								$notification_emails[$cur_subscriber['language']][1] = $mail_message;
@@ -275,6 +275,8 @@ if (isset($_POST['form_sent']))
 								pun_mail($cur_subscriber['email'], $notification_emails[$cur_subscriber['language']][2], $notification_emails[$cur_subscriber['language']][3]);
 						}
 					}
+
+					unset($cleaned_message);
 				}
 			}
 		}
@@ -297,7 +299,7 @@ if (isset($_POST['form_sent']))
 			else
 			{
 				// Create the post ("topic post")
-				$email_sql = ($pun_config['p_force_guest_email'] == '1' || $email != '') ? '\''.$email.'\'' : 'NULL';
+				$email_sql = ($pun_config['p_force_guest_email'] == '1' || $email != '') ? '\''.$db->escape($email).'\'' : 'NULL';
 				$db->query('INSERT INTO '.$db->prefix.'posts (poster, poster_ip, poster_email, message, hide_smilies, posted, topic_id) VALUES(\''.$db->escape($username).'\', \''.get_remote_address().'\', '.$email_sql.', \''.$db->escape($message).'\', '.$hide_smilies.', '.$now.', '.$new_tid.')') or error('Unable to create post', __FILE__, __LINE__, $db->error());
 			}
 			$new_pid = $db->insert_id();
@@ -320,6 +322,11 @@ if (isset($_POST['form_sent']))
 
 					$notification_emails = array();
 
+					if ($pun_config['o_censoring'] == '1')
+						$cleaned_message = bbcode2email($censored_message, -1);
+					else
+						$cleaned_message = bbcode2email($message, -1);
+
 					// Loop through subscribed users and send emails
 					while ($cur_subscriber = $db->fetch_assoc($result))
 					{
@@ -349,16 +356,16 @@ if (isset($_POST['form_sent']))
 								$mail_message = str_replace('<poster>', $username, $mail_message);
 								$mail_message = str_replace('<topic_url>', get_base_url().'/viewtopic.php?id='.$new_tid, $mail_message);
 								$mail_message = str_replace('<unsubscribe_url>', get_base_url().'/misc.php?action=unsubscribe&fid='.$cur_posting['id'], $mail_message);
-								$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message);
+								$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 								$mail_subject_full = str_replace('<forum_name>', $cur_posting['forum_name'], $mail_subject_full);
 								$mail_message_full = str_replace('<topic_subject>', $pun_config['o_censoring'] == '1' ? $censored_subject : $subject, $mail_message_full);
 								$mail_message_full = str_replace('<forum_name>', $cur_posting['forum_name'], $mail_message_full);
 								$mail_message_full = str_replace('<poster>', $username, $mail_message_full);
-								$mail_message_full = str_replace('<message>', $pun_config['o_censoring'] == '1' ? $censored_message : $message, $mail_message_full);
+								$mail_message_full = str_replace('<message>', $cleaned_message, $mail_message_full);
 								$mail_message_full = str_replace('<topic_url>', get_base_url().'/viewtopic.php?id='.$new_tid, $mail_message_full);
 								$mail_message_full = str_replace('<unsubscribe_url>', get_base_url().'/misc.php?action=unsubscribe&fid='.$cur_posting['id'], $mail_message_full);
-								$mail_message_full = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message_full);
+								$mail_message_full = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message_full);
 
 								$notification_emails[$cur_subscriber['language']][0] = $mail_subject;
 								$notification_emails[$cur_subscriber['language']][1] = $mail_message;
@@ -378,6 +385,8 @@ if (isset($_POST['form_sent']))
 								pun_mail($cur_subscriber['email'], $notification_emails[$cur_subscriber['language']][2], $notification_emails[$cur_subscriber['language']][3]);
 						}
 					}
+
+					unset($cleaned_message);
 				}
 			}
 		}
@@ -385,10 +394,18 @@ if (isset($_POST['form_sent']))
 		// If we previously found out that the email was banned
 		if ($pun_user['is_guest'] && $banned_email && $pun_config['o_mailing_list'] != '')
 		{
-			$mail_subject = $lang_common['Banned email notification'];
-			$mail_message = sprintf($lang_common['Banned email post message'], $username, $email)."\n";
-			$mail_message .= sprintf($lang_common['Post URL'], get_base_url().'/viewtopic.php?pid='.$new_pid.'#p'.$new_pid)."\n";
-			$mail_message .= "\n".'--'."\n".$lang_common['Email signature'];
+			// Load the "banned email post" template
+			$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/banned_email_post.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_message = str_replace('<username>', $username, $mail_message);
+			$mail_message = str_replace('<email>', $email, $mail_message);
+			$mail_message = str_replace('<post_url>', get_base_url().'/viewtopic.php?pid='.$new_pid.'#p'.$new_pid, $mail_message);
+			$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 			pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
 		}
@@ -596,7 +613,6 @@ $cur_index = 1;
 					<legend><?php echo $lang_common['Write message legend'] ?></legend>
 					<div class="infldset txtarea">
 						<input type="hidden" name="form_sent" value="1" />
-						<input type="hidden" name="form_user" value="<?php echo (!$pun_user['is_guest']) ? pun_htmlspecialchars($pun_user['username']) : 'Guest'; ?>" />
 <?php
 
 if ($pun_user['is_guest'])
diff --git a/profile.php b/profile.php
index 8102a03..b735305 100644
--- a/profile.php
+++ b/profile.php
@@ -210,10 +210,18 @@ else if ($action == 'change_email')
 				message($lang_prof_reg['Banned email']);
 			else if ($pun_config['o_mailing_list'] != '')
 			{
-				$mail_subject = $lang_common['Banned email notification'];
-				$mail_message = sprintf($lang_common['Banned email change message'], $pun_user['username'], $new_email)."\n";
-				$mail_message .= sprintf($lang_common['User profile'], get_base_url().'/profile.php?id='.$id)."\n";
-				$mail_message .= "\n".'--'."\n".$lang_common['Email signature'];
+				// Load the "banned email change" template
+				$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/banned_email_change.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_message = str_replace('<username>', $pun_user['username'], $mail_message);
+				$mail_message = str_replace('<email>', $new_email, $mail_message);
+				$mail_message = str_replace('<profile_url>', get_base_url().'/profile.php?id='.$id, $mail_message);
+				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
 			}
@@ -230,10 +238,18 @@ else if ($action == 'change_email')
 				while ($cur_dupe = $db->fetch_assoc($result))
 					$dupe_list[] = $cur_dupe['username'];
 
-				$mail_subject = $lang_common['Duplicate email notification'];
-				$mail_message = sprintf($lang_common['Duplicate email change message'], $pun_user['username'], implode(', ', $dupe_list))."\n";
-				$mail_message .= sprintf($lang_common['User profile'], get_base_url().'/profile.php?id='.$id)."\n";
-				$mail_message .= "\n".'--'."\n".$lang_common['Email signature'];
+				// Load the "dupe email change" template
+				$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/dupe_email_change.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_message = str_replace('<username>', $pun_user['username'], $mail_message);
+				$mail_message = str_replace('<dupe_list>', implode(', ', $dupe_list), $mail_message);
+				$mail_message = str_replace('<profile_url>', get_base_url().'/profile.php?id='.$id, $mail_message);
+				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
 			}
@@ -255,7 +271,7 @@ else if ($action == 'change_email')
 		$mail_message = str_replace('<username>', $pun_user['username'], $mail_message);
 		$mail_message = str_replace('<base_url>', get_base_url(), $mail_message);
 		$mail_message = str_replace('<activation_url>', get_base_url().'/profile.php?action=change_email&id='.$id.'&key='.$new_email_key, $mail_message);
-		$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message);
+		$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 		pun_mail($new_email, $mail_subject, $mail_message);
 
@@ -523,7 +539,19 @@ else if (isset($_POST['ban']))
 	if ($pun_user['g_id'] != PUN_ADMIN && ($pun_user['g_moderator'] != '1' || $pun_user['g_mod_ban_users'] == '0'))
 		message($lang_common['No permission']);
 
-	redirect('admin_bans.php?add_ban='.$id, $lang_profile['Ban redirect']);
+	// Get the username of the user we are banning
+	$result = $db->query('SELECT username FROM '.$db->prefix.'users WHERE id='.$id) or error('Unable to fetch username', __FILE__, __LINE__, $db->error());
+	$username = $db->result($result);
+
+	// Check whether user is already banned
+	$result = $db->query('SELECT id FROM '.$db->prefix.'bans WHERE username = \''.$db->escape($username).'\' ORDER BY expire IS NULL DESC, expire DESC LIMIT 1') or error('Unable to fetch ban ID', __FILE__, __LINE__, $db->error());
+	if ($db->num_rows($result))
+	{
+		$ban_id = $db->result($result);
+		redirect('admin_bans.php?edit_ban='.$ban_id.'&exists', $lang_profile['Ban redirect']);
+	}
+	else
+		redirect('admin_bans.php?add_ban='.$id, $lang_profile['Ban redirect']);
 }
 
 
@@ -739,8 +767,15 @@ else if (isset($_POST['form_sent']))
 			);
 
 			// Add http:// if the URL doesn't contain it already (while allowing https://, too)
-			if ($form['url'] != '' && !preg_match('#^https?://#i', $form['url']))
-				$form['url'] = 'http://'.$form['url'];
+			if ($form['url'] != '')
+			{
+				$url = url_valid($form['url']);
+
+				if ($url === false)
+					message($lang_profile['Invalid website URL']);
+
+				$form['url'] = $url['url'];
+			}
 
 			if ($pun_user['g_id'] == PUN_ADMIN)
 				$form['title'] = pun_trim($_POST['title']);
@@ -773,7 +808,7 @@ else if (isset($_POST['form_sent']))
 			);
 
 			// If the ICQ UIN contains anything other than digits it's invalid
-			if (preg_match('/[^0-9]/', $form['icq']))
+			if (preg_match('%[^0-9]%', $form['icq']))
 				message($lang_prof_reg['Bad ICQ']);
 
 			break;
@@ -924,6 +959,12 @@ else if (isset($_POST['form_sent']))
 				}
 			}
 		}
+
+		// Regenerate the users info cache
+		if (!defined('FORUM_CACHE_FUNCTIONS_LOADED'))
+			require PUN_ROOT.'include/cache.php';
+
+		generate_users_info_cache();
 	}
 
 	redirect('profile.php?section='.$section.'&id='.$id, $lang_profile['Profile redirect']);
diff --git a/register.php b/register.php
index c99c99b..0ef9832 100644
--- a/register.php
+++ b/register.php
@@ -135,7 +135,7 @@ if (isset($_POST['form_sent']))
 	// Make sure we got a valid language string
 	if (isset($_POST['language']))
 	{
-		$language = preg_replace('#[\.\\\/]#', '', $_POST['language']);
+		$language = preg_replace('%[\.\\\/]%', '', $_POST['language']);
 		if (!file_exists(PUN_ROOT.'lang/'.$language.'/common.php'))
 			message($lang_common['Bad request']);
 	}
@@ -169,10 +169,18 @@ if (isset($_POST['form_sent']))
 			// If we previously found out that the email was banned
 			if ($banned_email)
 			{
-				$mail_subject = $lang_common['Banned email notification'];
-				$mail_message = sprintf($lang_common['Banned email register message'], $username, $email1)."\n";
-				$mail_message .= sprintf($lang_common['User profile'], get_base_url().'/profile.php?id='.$new_uid)."\n";
-				$mail_message .= "\n".'--'."\n".$lang_common['Email signature'];
+				// Load the "banned email register" template
+				$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/banned_email_register.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_message = str_replace('<username>', $username, $mail_message);
+				$mail_message = str_replace('<email>', $email1, $mail_message);
+				$mail_message = str_replace('<profile_url>', get_base_url().'/profile.php?id='.$new_uid, $mail_message);
+				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
 			}
@@ -180,10 +188,18 @@ if (isset($_POST['form_sent']))
 			// If we previously found out that the email was a dupe
 			if (!empty($dupe_list))
 			{
-				$mail_subject = $lang_common['Duplicate email notification'];
-				$mail_message = sprintf($lang_common['Duplicate email register message'], $username, implode(', ', $dupe_list))."\n";
-				$mail_message .= sprintf($lang_common['User profile'], get_base_url().'/profile.php?id='.$new_uid)."\n";
-				$mail_message .= "\n".'--'."\n".$lang_common['Email signature'];
+				// Load the "dupe email register" template
+				$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/dupe_email_register.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_message = str_replace('<username>', $username, $mail_message);
+				$mail_message = str_replace('<dupe_list>', implode(', ', $dupe_list), $mail_message);
+				$mail_message = str_replace('<profile_url>', get_base_url().'/profile.php?id='.$new_uid, $mail_message);
+				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
 			}
@@ -191,10 +207,18 @@ if (isset($_POST['form_sent']))
 			// Should we alert people on the admin mailing list that a new user has registered?
 			if ($pun_config['o_regs_report'] == '1')
 			{
-				$mail_subject = $lang_common['New user notification'];
-				$mail_message = sprintf($lang_common['New user message'], $username, get_base_url().'/')."\n";
-				$mail_message .= sprintf($lang_common['User profile'], get_base_url().'/profile.php?id='.$new_uid)."\n";
-				$mail_message .= "\n".'--'."\n".$lang_common['Email signature'];
+				// Load the "new user" template
+				$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/new_user.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_message = str_replace('<username>', $username, $mail_message);
+				$mail_message = str_replace('<base_url>', get_base_url().'/', $mail_message);
+				$mail_message = str_replace('<profile_url>', get_base_url().'/profile.php?id='.$new_uid, $mail_message);
+				$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
 			}
@@ -216,7 +240,7 @@ if (isset($_POST['form_sent']))
 			$mail_message = str_replace('<username>', $username, $mail_message);
 			$mail_message = str_replace('<password>', $password1, $mail_message);
 			$mail_message = str_replace('<login_url>', get_base_url().'/login.php', $mail_message);
-			$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'].' '.$lang_common['Mailer'], $mail_message);
+			$mail_message = str_replace('<board_mailer>', $pun_config['o_board_title'], $mail_message);
 
 			pun_mail($email1, $mail_subject, $mail_message);
 
@@ -246,9 +270,6 @@ $timezone = isset($timezone) ? $timezone : $pun_config['o_default_timezone'];
 $dst = isset($dst) ? $dst : $pun_config['o_default_dst'];
 $email_setting = isset($email_setting) ? $email_setting : $pun_config['o_default_email_setting'];
 
-?>
-<?php
-
 // If there are errors, we display them
 if (!empty($errors))
 {
@@ -284,8 +305,6 @@ if (!empty($errors))
 					<p><?php echo $lang_register['Desc 1'] ?></p>
 					<p><?php echo $lang_register['Desc 2'] ?></p>
 				</div>
-			</div>
-			<div class="inform">
 				<fieldset>
 					<legend><?php echo $lang_register['Username legend'] ?></legend>
 					<div class="infldset">
diff --git a/search.php b/search.php
index bdbd71b..12e1bbc 100644
--- a/search.php
+++ b/search.php
@@ -28,9 +28,11 @@ require PUN_ROOT.'include/search_idx.php';
 if (isset($_GET['action']) || isset($_GET['search_id']))
 {
 	$action = (isset($_GET['action'])) ? $_GET['action'] : null;
-	$forum = (isset($_GET['forum'])) ? intval($_GET['forum']) : -1;
+	$forums = isset($_GET['forums']) ? (is_array($_GET['forums']) ? $_GET['forums'] : explode(',', $_GET['forums'])) : (isset($_GET['forum']) ? array($_GET['forum']) : array());
 	$sort_dir = (isset($_GET['sort_dir']) && $_GET['sort_dir'] == 'DESC') ? 'DESC' : 'ASC';
 
+	$forums = array_map('intval', $forums);
+
 	// Allow the old action names for backwards compatibility reasons
 	if ($action == 'show_user')
 		$action = 'show_user_posts';
@@ -50,10 +52,10 @@ if (isset($_GET['action']) || isset($_GET['search_id']))
 		$keywords = (isset($_GET['keywords'])) ? utf8_strtolower(pun_trim($_GET['keywords'])) : null;
 		$author = (isset($_GET['author'])) ? utf8_strtolower(pun_trim($_GET['author'])) : null;
 
-		if (preg_match('#^[\*%]+$#', $keywords) || (pun_strlen(str_replace(array('*', '%'), '', $keywords)) < PUN_SEARCH_MIN_WORD && !is_cjk($keywords)))
+		if (preg_match('%^[\*\%]+$%', $keywords) || (pun_strlen(str_replace(array('*', '%'), '', $keywords)) < PUN_SEARCH_MIN_WORD && !is_cjk($keywords)))
 			$keywords = '';
 
-		if (preg_match('#^[\*%]+$#', $author) || pun_strlen(str_replace(array('*', '%'), '', $author)) < 2)
+		if (preg_match('%^[\*\%]+$%', $author) || pun_strlen(str_replace(array('*', '%'), '', $author)) < 2)
 			$author = '';
 
 		if (!$keywords && !$author)
@@ -62,9 +64,9 @@ if (isset($_GET['action']) || isset($_GET['search_id']))
 		if ($author)
 			$author = str_replace('*', '%', $author);
 
-		$show_as = (isset($_GET['show_as'])) ? $_GET['show_as'] : 'posts';
-		$sort_by = (isset($_GET['sort_by'])) ? intval($_GET['sort_by']) : null;
-		$search_in = (!isset($_GET['search_in']) || $_GET['search_in'] == 'all') ? 0 : (($_GET['search_in'] == 'message') ? 1 : -1);
+		$show_as = (isset($_GET['show_as']) && $_GET['show_as'] == 'topics') ? 'topics' : 'posts';
+		$sort_by = (isset($_GET['sort_by'])) ? intval($_GET['sort_by']) : 0;
+		$search_in = (!isset($_GET['search_in']) || $_GET['search_in'] == '0') ? 0 : (($_GET['search_in'] == '1') ? 1 : -1);
 	}
 	// If it's a user search (by ID)
 	else if ($action == 'show_user_posts' || $action == 'show_user_topics' || $action == 'show_subscriptions')
@@ -115,7 +117,7 @@ if (isset($_GET['action']) || isset($_GET['search_id']))
 		$keyword_results = $author_results = array();
 
 		// Search a specific forum?
-		$forum_sql = ($forum != -1 || ($forum == -1 && $pun_config['o_search_all_forums'] == '0' && !$pun_user['is_admmod'])) ? ' AND t.forum_id = '.$forum : '';
+		$forum_sql = (!empty($forums) || (empty($forums) && $pun_config['o_search_all_forums'] == '0' && !$pun_user['is_admmod'])) ? ' AND t.forum_id IN ('.implode(',', $forums).')' : '';
 
 		if (!empty($author) || !empty($keywords))
 		{
@@ -283,17 +285,17 @@ if (isset($_GET['action']) || isset($_GET['search_id']))
 			if ($author && $keywords)
 			{
 				$search_ids = array_intersect_assoc($keyword_results, $author_results);
-				$search_type = array('both', array($keywords, pun_trim($_GET['author'])), $forum, isset($_GET['search_in']) ? $_GET['search_in'] : '');
+				$search_type = array('both', array($keywords, pun_trim($_GET['author'])), implode(',', $forums), $search_in);
 			}
 			else if ($keywords)
 			{
 				$search_ids = $keyword_results;
-				$search_type = array('keywords', $keywords, $forum, isset($_GET['search_in']) ? $_GET['search_in'] : '');
+				$search_type = array('keywords', $keywords, implode(',', $forums), $search_in);
 			}
 			else
 			{
 				$search_ids = $author_results;
-				$search_type = array('author', pun_trim($_GET['author']), $forum, isset($_GET['search_in']) ? $_GET['search_in'] : '');
+				$search_type = array('author', pun_trim($_GET['author']), implode(',', $forums), $search_in);
 			}
 
 			unset($keyword_results, $author_results);
@@ -498,7 +500,7 @@ if (isset($_GET['action']) || isset($_GET['search_id']))
 			$search_set[] = $row;
 
 		$crumbs_text = array();
-		$crumbs_text['show_as'] = $show_as == 'topics' ? $lang_search['Search topics'] : $lang_search['Search posts'];
+		$crumbs_text['show_as'] = $lang_search['Search'];
 
 		if ($search_type[0] == 'action')
 		{
@@ -520,7 +522,7 @@ if (isset($_GET['action']) || isset($_GET['search_id']))
 				$crumbs_text['search_type'] = '<a href="search.php?action=show_subscriptions&user_id='.$subscriber_id.'">'.sprintf($lang_search['Quick search show_subscriptions'], pun_htmlspecialchars($subscriber_name)).'</a>';
 			}
 			else
-				$crumbs_text['search_type'] = '<a href="search.php?action='.pun_htmlspecialchars($search_type[1]).'">'.$lang_search['Quick search '.$search_type[1]].'</a>';
+				$crumbs_text['search_type'] = '<a href="search.php?action='.$search_type[1].'">'.$lang_search['Quick search '.$search_type[1]].'</a>';
 		}
 		else
 		{
@@ -542,7 +544,7 @@ if (isset($_GET['action']) || isset($_GET['search_id']))
 				$crumbs_text['search_type'] = sprintf($lang_search['By user show as '.$show_as], pun_htmlspecialchars($author));
 			}
 
-			$crumbs_text['search_type'] = '<a href="search.php?action=search&keywords='.pun_htmlspecialchars($keywords).'&author='.pun_htmlspecialchars($author).'&forum='.pun_htmlspecialchars($search_type[2]).'&search_in='.pun_htmlspecialchars($search_type[3]).'&sort_by='.pun_htmlspecialchars($sort_by).'&sort_dir='.pun_htmlspecialchars($sort_dir).'&show_as='.pun_htmlspecialchars($show_as).'">'.$crumbs_text['search_type'].'</a>';
+			$crumbs_text['search_type'] = '<a href="search.php?action=search&keywords='.urlencode($keywords).'&author='.urlencode($author).'&forums='.$search_type[2].'&search_in='.$search_type[3].'&sort_by='.$sort_by.'&sort_dir='.$sort_dir.'&show_as='.$show_as.'">'.$crumbs_text['search_type'].'</a>';
 		}
 
 		$page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), $lang_search['Search results']);
@@ -796,42 +798,73 @@ require PUN_ROOT.'header.php';
 				<fieldset>
 					<legend><?php echo $lang_search['Search in legend'] ?></legend>
 					<div class="infldset">
-						<label class="conl"><?php echo $lang_search['Forum search']."\n" ?>
-						<br /><select id="forum" name="forum">
 <?php
 
+$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='.$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());
+
+// We either show a list of forums of which multiple can be selected
 if ($pun_config['o_search_all_forums'] == '1' || $pun_user['is_admmod'])
-	echo "\t\t\t\t\t\t\t".'<option value="-1">'.$lang_search['All forums'].'</option>'."\n";
+{
+	echo "\t\t\t\t\t\t".'<div class="conl multiselect">'.$lang_search['Forum search']."\n";
+	echo "\t\t\t\t\t\t".'<br />'."\n";
+	echo "\t\t\t\t\t\t".'<div class="checklist">'."\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='.$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_category)
+				echo "\t\t\t\t\t\t\t".'</fieldset>'."\n";
+
+			echo "\t\t\t\t\t\t\t".'<fieldset><legend><span>'.pun_htmlspecialchars($cur_forum['cat_name']).'</span></legend>'."\n";
+			$cur_category = $cur_forum['cid'];
+		}
 
-$cur_category = 0;
-while ($cur_forum = $db->fetch_assoc($result))
+		echo "\t\t\t\t\t\t\t\t".'<div class="checklist-item"><span class="fld-input"><input type="checkbox" name="forums[]" id="forum-'.$cur_forum['fid'].'" value="'.$cur_forum['fid'].'" /></span> <label for="forum-'.$cur_forum['fid'].'">'.pun_htmlspecialchars($cur_forum['forum_name']).'</label></div>'."\n";
+	}
+
+	echo "\t\t\t\t\t\t\t".'</fieldset>'."\n";
+	echo "\t\t\t\t\t\t".'</div>'."\n";
+	echo "\t\t\t\t\t\t".'</div>'."\n";
+}
+// ... or a simple select list for one forum only
+else
 {
-	if ($cur_forum['cid'] != $cur_category) // A new category since last iteration?
+	echo "\t\t\t\t\t\t".'<label class="conl">'.$lang_search['Forum search']."\n";
+	echo "\t\t\t\t\t\t".'<br />'."\n";
+	echo "\t\t\t\t\t\t".'<select id="forum" name="forum">'."\n";
+
+	$cur_category = 0;
+	while ($cur_forum = $db->fetch_assoc($result))
 	{
-		if ($cur_category)
-			echo "\t\t\t\t\t\t\t".'</optgroup>'."\n";
+		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";
 
-		echo "\t\t\t\t\t\t\t".'<optgroup label="'.pun_htmlspecialchars($cur_forum['cat_name']).'">'."\n";
-		$cur_category = $cur_forum['cid'];
+			echo "\t\t\t\t\t\t\t".'<optgroup label="'.pun_htmlspecialchars($cur_forum['cat_name']).'">'."\n";
+			$cur_category = $cur_forum['cid'];
+		}
+
+		echo "\t\t\t\t\t\t\t\t".'<option value="'.$cur_forum['fid'].'">'.pun_htmlspecialchars($cur_forum['forum_name']).'</option>'."\n";
 	}
 
-	echo "\t\t\t\t\t\t\t\t".'<option value="'.$cur_forum['fid'].'">'.pun_htmlspecialchars($cur_forum['forum_name']).'</option>'."\n";
+	echo "\t\t\t\t\t\t\t".'</optgroup>'."\n";
+	echo "\t\t\t\t\t\t".'</select>'."\n";
+	echo "\t\t\t\t\t\t".'<br /></label>'."\n";
 }
 
 ?>
-							</optgroup>
-						</select>
-						<br /></label>
 						<label class="conl"><?php echo $lang_search['Search in']."\n" ?>
 						<br /><select id="search_in" name="search_in">
-							<option value="all"><?php echo $lang_search['Message and subject'] ?></option>
-							<option value="message"><?php echo $lang_search['Message only'] ?></option>
-							<option value="topic"><?php echo $lang_search['Topic only'] ?></option>
+							<option value="0"><?php echo $lang_search['Message and subject'] ?></option>
+							<option value="1"><?php echo $lang_search['Message only'] ?></option>
+							<option value="-1"><?php echo $lang_search['Topic only'] ?></option>
 						</select>
 						<br /></label>
-						<p class="clearb"><?php echo $lang_search['Search in info'] ?></p>
+						<p class="clearl"><?php echo $lang_search['Search in info'] ?></p>
+<?php echo ($pun_config['o_search_all_forums'] == '1' || $pun_user['is_admmod'] ? '<p>'.$lang_search['Search multiple forums info'].'</p>' : '') ?>
 					</div>
 				</fieldset>
 			</div>
diff --git a/style/Air.css b/style/Air.css
index 59614e9..cab49c9 100644
--- a/style/Air.css
+++ b/style/Air.css
@@ -151,6 +151,11 @@ html, body, .pun table, .pun div, .pun form, .pun p, .pun h1, .pun h2, .pun h3,
 	clear: none;
 }
 
+.clearl {
+	clear: left;
+}
+
+
 /*****************************************************************
 2. COMMON STYLES
 *****************************************************************/
@@ -767,8 +772,8 @@ MAIN POSTS
 }
 
 .pun .blockpost .postleft, .pun .blockpost .postfootleft {
-	width: 206px;
-	padding: 7px 0 7px 12px;
+	width: 194px;
+	padding: 7px 12px 7px 12px;
 	float: left;
 	margin-left: -218px;
 	position: relative;
@@ -1275,6 +1280,52 @@ MAIN FORMS
 	padding: 7px 12px;
 }
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.25em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+}
+
+.pun .checklist legend {
+	padding: 0;
+}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+}
+
+.pun .checklist .checklist-item {
+	position: relative;
+}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 1.75em;
+}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.55em;
+	width: 1.55em;
+}
+
 /*****************************************************************
 PROFILES (+ ADMIN MENU)
 *****************************************************************/
@@ -1609,6 +1660,15 @@ html, body, .pun {
 	background: #d59b9b;
 }
 
+.pun .multiselect {
+	color: #357082;
+}
+
+.pun .checklist {
+	background: white;
+	border-color: #ccc;
+}
+
 /* Status Indicators
 ----------------------------------------------------------------*/
 
diff --git a/style/Air/base_admin.css b/style/Air/base_admin.css
index 45f192a..2948b81 100644
--- a/style/Air/base_admin.css
+++ b/style/Air/base_admin.css
@@ -123,25 +123,41 @@
 	text-align: center;
 }
 
-#users2 .tcl, #users2 .tc3, #users2 .tc5, #bans1 .tcl, #bans1 .tc3, #bans1 .tc5, #bans1 .tc6 {
-	width: 15%;
+#users2 .tcl, #bans1 .tcl {
+	width: auto;
 	text-align: left;
 }
 
 #users2 .tc2, #bans1 .tc2 {
-	width: 22%;
+	width: 18%;
+	text-align: left;
+}
+
+#users2 .tc3, #users2 .tc5, #bans1 .tc3, #bans1 .tc5, #bans1 .tc6 {
+	width: 12%;
 	text-align: left;
 }
 
 #users2 .tc4, #bans1 .tc4 {
-	width: 8%;
+	width: 10%;
 	text-align: center;
 }
 
-#users2 .tcr, #bans1 .tcr {
+#users2 .tcr {
+	width: 20%;
+	white-space: nowrap;
+}
+
+#bans1 .tcr {
+	width: 15%;
 	white-space: nowrap;
 }
 
+#users2 .tcmod {
+	width: 10%;
+	text-align: center;
+}
+
 .plugin p {
 	padding: 12px 18px 0;
 }
diff --git a/style/Cobalt.css b/style/Cobalt.css
index 0c52912..6698bff 100644
--- a/style/Cobalt.css
+++ b/style/Cobalt.css
@@ -48,6 +48,9 @@
 	min-height: 1px
 	}
 
+.clearl {
+	clear: left;
+	}
 
 /* Hidden Elements
 ----------------------------------------------------------------*/
@@ -72,6 +75,7 @@
 
 .pun {
 	font: 68.75%/1.4545em Verdana, Helvetica, Arial, sans-serif;
+	line-height: normal;
 	}
 
 .pun table, .pun td, .pun th, .pun input, .pun select, .pun optgroup, .pun textarea, .pun samp, .pun legend {
@@ -108,7 +112,7 @@
 .pun h2 {
 	font-size: 1em;
 	font-weight: normal;
-	padding: 4px 7px;
+	padding: 4px 6px;
 	}
 
 .pun h3 {
@@ -209,6 +213,11 @@
 /* Page Layout
 ----------------------------------------------------------------*/
 
+html, body {
+	margin: 0;
+	padding: 0
+	}
+
 .pun {
 	margin: 12px 20px
 	}
@@ -225,6 +234,10 @@
 	margin: 0 0 12px 0;
 	}
 
+#brdtitle p {
+	padding-top: 0px
+	}
+
 #announce, #brdstats {
 	margin: 12px 0 12px 0;
 	}
@@ -281,21 +294,11 @@
 ----------------------------------------------------------------*/
 
 #brdtitle h1 {
-	font-size: 1.454em;
+	font-size: 1.4em;
 	font-weight: bold;
-	line-height: 1em;
 	padding: 3px 0 0 0;
 	}
 
-#brddesc {
-	padding: 3px 0;
-	}
-
-#brddesc * {
-	padding-top: 0;
-	padding-bottom: 0;
-	}
-
 #brdmenu li {
 	display: inline;
 	margin-right: 12px;
@@ -435,12 +438,11 @@
 
 .pun td, .pun th {
 	padding: 4px 6px;
-	line-height: 1.273em;
 	text-align: left;
 	font-weight: normal;
 	}
 
-.pun td {
+.pun td, .pun th {
 	border-style: solid none none solid;
 	border-width: 1px;
 	}
@@ -525,7 +527,8 @@
 	}
 
 .pun .icon {
-	border-width: 7px;
+	margin: 0.1em 0 0 0.2em;
+	border-width: 0.6em;
 	border-style: solid;
 	height: 0;
 	width: 0;
@@ -598,14 +601,6 @@
 	margin-right: 10px
 	}
 
-.pun select {
-	padding-top: 1px;
-	padding-bottom: 1px;
-	}
-
-.pun fieldset .rbox {
-	}
-
 .pun fieldset .rbox br {
 	display: none;
 	}
@@ -665,6 +660,58 @@
 	margin-right: 12px;
 	}
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+	}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.3em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+	}
+
+.pun .checklist fieldset {
+	border: 0;
+	padding: 0;
+	}
+
+.pun .checklist legend {
+	padding: 0;
+	}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+	}
+
+.pun .checklist .checklist-item {
+	position: relative;
+	margin: .2em 0;
+	}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 2.1em;
+	}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+	}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.15em;
+	width: 1.55em;
+	}
+
 /*****************************************************************
 7. PROFILES AND ADMIN
 *****************************************************************/
@@ -674,12 +721,12 @@
 	}
 
 .pun .block2col .blockform, .pun .block2col .block {
-	margin-left: 17em
+	margin-left: 14em
 	}
 
 .pun .blockmenu {
 	float:left;
-	width: 16em
+	width: 13em
 	}
 
 .pun .blockmenu li {
@@ -756,7 +803,7 @@
 	}
 
 .pun .postleft dl {
-	padding: 0.75em 6px;
+	padding: 6px;
 	}
 
 .pun .postleft .usercontacts, .pun .postleft .icon {
@@ -807,12 +854,19 @@
 
 .pun .postfootright ul, .pun .postfootright div, .pun .postfootright p,
 .pun .postfootleft p {
-	padding: 6px 6px 6px 6px;
+	padding: 10px 6px 5px 6px;
 	}
 
 .pun .postfootright li {
 	display: inline;
-	margin-left: 12px;
+	}
+
+.pun .postfootright li:before {
+	content: " | ";
+	}
+
+.pun .postfootright li:first-child:before {
+	content: "";
 	}
 
 .pun .postfootright a:link, .pun .postfootright a:visited {
@@ -926,6 +980,14 @@
 	text-align: center;
 	}
 
+#brdwelcome, #brdfooter dl a, div.blockmenu li, div.rbox input {
+	line-height: 1.4em
+	}
+
+#announce div.inbox div {
+	padding: 3px 0
+	}
+
 /*****************************************************************
 COLOUR SCHEME
 *****************************************************************/
@@ -978,6 +1040,14 @@ body {
 	color: #d4d4d4
 	}
 
+.pun .multiselect, .pun .checklist {
+	color: #D4D4D4;
+	}
+
+.pun .checklist {
+	border-color: #666;
+	}
+
 /* Posts
 ----------------------------------------------------------------*/
 
@@ -1021,10 +1091,14 @@ body {
 	border-color: #565656
 	}
 
-.pun th, .pun fieldset {
+.pun th {
 	border-color: #484848
 	}
 
+.pun fieldset {
+	border-color: #606060
+	}
+
 #adminconsole td, #adminconsole th {
 	border-color: #383838
 	}
diff --git a/style/Earth.css b/style/Earth.css
index 7c20aec..d886bbe 100644
--- a/style/Earth.css
+++ b/style/Earth.css
@@ -151,6 +151,10 @@ html, body, .pun table, .pun div, .pun form, .pun p, .pun h1, .pun h2, .pun h3,
 	clear: none;
 }
 
+.clearl {
+	clear: left;
+}
+
 /*****************************************************************
 2. COMMON STYLES
 *****************************************************************/
@@ -767,8 +771,8 @@ MAIN POSTS
 }
 
 .pun .blockpost .postleft, .pun .blockpost .postfootleft {
-	width: 206px;
-	padding: 7px 0 7px 12px;
+	width: 194px;
+	padding: 7px 12px 7px 12px;
 	float: left;
 	margin-left: -218px;
 	position: relative;
@@ -1275,6 +1279,52 @@ MAIN FORMS
 	padding: 7px 12px;
 }
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.25em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+}
+
+.pun .checklist legend {
+	padding: 0;
+}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+}
+
+.pun .checklist .checklist-item {
+	position: relative;
+}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 1.75em;
+}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.55em;
+	width: 1.55em;
+}
+
 /*****************************************************************
 PROFILES (+ ADMIN MENU)
 *****************************************************************/
@@ -1609,6 +1659,15 @@ html, body, .pun {
 	background: #d59b9b;
 }
 
+.pun .multiselect {
+	color: #83866A;
+}
+
+.pun .checklist {
+	background: white;
+	border-color: #ccc;
+}
+
 /* Status Indicators
 ----------------------------------------------------------------*/
 
diff --git a/style/Earth/base_admin.css b/style/Earth/base_admin.css
index 45f192a..2948b81 100644
--- a/style/Earth/base_admin.css
+++ b/style/Earth/base_admin.css
@@ -123,25 +123,41 @@
 	text-align: center;
 }
 
-#users2 .tcl, #users2 .tc3, #users2 .tc5, #bans1 .tcl, #bans1 .tc3, #bans1 .tc5, #bans1 .tc6 {
-	width: 15%;
+#users2 .tcl, #bans1 .tcl {
+	width: auto;
 	text-align: left;
 }
 
 #users2 .tc2, #bans1 .tc2 {
-	width: 22%;
+	width: 18%;
+	text-align: left;
+}
+
+#users2 .tc3, #users2 .tc5, #bans1 .tc3, #bans1 .tc5, #bans1 .tc6 {
+	width: 12%;
 	text-align: left;
 }
 
 #users2 .tc4, #bans1 .tc4 {
-	width: 8%;
+	width: 10%;
 	text-align: center;
 }
 
-#users2 .tcr, #bans1 .tcr {
+#users2 .tcr {
+	width: 20%;
+	white-space: nowrap;
+}
+
+#bans1 .tcr {
+	width: 15%;
 	white-space: nowrap;
 }
 
+#users2 .tcmod {
+	width: 10%;
+	text-align: center;
+}
+
 .plugin p {
 	padding: 12px 18px 0;
 }
diff --git a/style/Fire.css b/style/Fire.css
index c4951dd..33ee9f7 100644
--- a/style/Fire.css
+++ b/style/Fire.css
@@ -151,6 +151,10 @@ html, body, .pun table, .pun div, .pun form, .pun p, .pun h1, .pun h2, .pun h3,
 	clear: none;
 }
 
+.clearl {
+	clear: left;
+}
+
 /*****************************************************************
 2. COMMON STYLES
 *****************************************************************/
@@ -767,8 +771,8 @@ MAIN POSTS
 }
 
 .pun .blockpost .postleft, .pun .blockpost .postfootleft {
-	width: 206px;
-	padding: 7px 0 7px 12px;
+	width: 194px;
+	padding: 7px 12px 7px 12px;
 	float: left;
 	margin-left: -218px;
 	position: relative;
@@ -1275,6 +1279,52 @@ MAIN FORMS
 	padding: 7px 12px;
 }
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.25em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+}
+
+.pun .checklist legend {
+	padding: 0;
+}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+}
+
+.pun .checklist .checklist-item {
+	position: relative;
+}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 1.75em;
+}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.55em;
+	width: 1.55em;
+}
+
 /*****************************************************************
 PROFILES (+ ADMIN MENU)
 *****************************************************************/
@@ -1609,6 +1659,15 @@ html, body, .pun {
 	background: #d59b9b;
 }
 
+.pun .multiselect {
+	color: #836359;
+}
+
+.pun .checklist {
+	background: white;
+	border-color: #ccc;
+}
+
 /* Status Indicators
 ----------------------------------------------------------------*/
 
diff --git a/style/Fire/base_admin.css b/style/Fire/base_admin.css
index 45f192a..2948b81 100644
--- a/style/Fire/base_admin.css
+++ b/style/Fire/base_admin.css
@@ -123,25 +123,41 @@
 	text-align: center;
 }
 
-#users2 .tcl, #users2 .tc3, #users2 .tc5, #bans1 .tcl, #bans1 .tc3, #bans1 .tc5, #bans1 .tc6 {
-	width: 15%;
+#users2 .tcl, #bans1 .tcl {
+	width: auto;
 	text-align: left;
 }
 
 #users2 .tc2, #bans1 .tc2 {
-	width: 22%;
+	width: 18%;
+	text-align: left;
+}
+
+#users2 .tc3, #users2 .tc5, #bans1 .tc3, #bans1 .tc5, #bans1 .tc6 {
+	width: 12%;
 	text-align: left;
 }
 
 #users2 .tc4, #bans1 .tc4 {
-	width: 8%;
+	width: 10%;
 	text-align: center;
 }
 
-#users2 .tcr, #bans1 .tcr {
+#users2 .tcr {
+	width: 20%;
+	white-space: nowrap;
+}
+
+#bans1 .tcr {
+	width: 15%;
 	white-space: nowrap;
 }
 
+#users2 .tcmod {
+	width: 10%;
+	text-align: center;
+}
+
 .plugin p {
 	padding: 12px 18px 0;
 }
diff --git a/style/Lithium.css b/style/Lithium.css
index f9d50e3..01c6082 100644
--- a/style/Lithium.css
+++ b/style/Lithium.css
@@ -48,6 +48,9 @@
 	min-height: 1px
 	}
 
+.clearl {
+	clear: left;
+	}
 
 /* Hidden Elements
 ----------------------------------------------------------------*/
@@ -72,6 +75,7 @@
 
 .pun {
 	font: 68.75%/1.4545em Verdana, Helvetica, Arial, sans-serif;
+	line-height: normal;
 	}
 
 .pun table, .pun td, .pun th, .pun input, .pun select, .pun optgroup, .pun textarea, .pun samp, .pun legend {
@@ -108,7 +112,7 @@
 .pun h2 {
 	font-size: 1em;
 	font-weight: normal;
-	padding: 4px 7px;
+	padding: 4px 6px;
 	}
 
 .pun h3 {
@@ -209,6 +213,11 @@
 /* Page Layout
 ----------------------------------------------------------------*/
 
+html, body {
+	margin: 0;
+	padding: 0
+	}
+
 .pun {
 	margin: 12px 20px
 	}
@@ -225,6 +234,10 @@
 	margin: 0 0 12px 0;
 	}
 
+#brdtitle p {
+	padding-top: 0px
+	}
+
 #announce, #brdstats {
 	margin: 12px 0 12px 0;
 	}
@@ -281,21 +294,11 @@
 ----------------------------------------------------------------*/
 
 #brdtitle h1 {
-	font-size: 1.454em;
+	font-size: 1.4em;
 	font-weight: bold;
-	line-height: 1em;
 	padding: 3px 0 0 0;
 	}
 
-#brddesc {
-	padding: 3px 0;
-	}
-
-#brddesc * {
-	padding-top: 0;
-	padding-bottom: 0;
-	}
-
 #brdmenu li {
 	display: inline;
 	margin-right: 12px;
@@ -435,12 +438,11 @@
 
 .pun td, .pun th {
 	padding: 4px 6px;
-	line-height: 1.273em;
 	text-align: left;
 	font-weight: normal;
 	}
 
-.pun td {
+.pun td, .pun th {
 	border-style: solid none none solid;
 	border-width: 1px;
 	}
@@ -525,7 +527,8 @@
 	}
 
 .pun .icon {
-	border-width: 7px;
+	margin: 0.1em 0 0 0.2em;
+	border-width: 0.6em;
 	border-style: solid;
 	height: 0;
 	width: 0;
@@ -598,14 +601,6 @@
 	margin-right: 10px
 	}
 
-.pun select {
-	padding-top: 1px;
-	padding-bottom: 1px;
-	}
-
-.pun fieldset .rbox {
-	}
-
 .pun fieldset .rbox br {
 	display: none;
 	}
@@ -665,6 +660,58 @@
 	margin-right: 12px;
 	}
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+	}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.3em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+	}
+
+.pun .checklist fieldset {
+	border: 0;
+	padding: 0;
+	}
+
+.pun .checklist legend {
+	padding: 0;
+	}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+	}
+
+.pun .checklist .checklist-item {
+	position: relative;
+	margin: .2em 0;
+	}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 2.1em;
+	}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+	}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.15em;
+	width: 1.55em;
+	}
+
 /*****************************************************************
 7. PROFILES AND ADMIN
 *****************************************************************/
@@ -674,12 +721,12 @@
 	}
 
 .pun .block2col .blockform, .pun .block2col .block {
-	margin-left: 17em
+	margin-left: 14em
 	}
 
 .pun .blockmenu {
 	float:left;
-	width: 16em
+	width: 13em
 	}
 
 .pun .blockmenu li {
@@ -756,7 +803,7 @@
 	}
 
 .pun .postleft dl {
-	padding: 0.75em 6px;
+	padding: 6px;
 	}
 
 .pun .postleft .usercontacts, .pun .postleft .icon {
@@ -807,12 +854,19 @@
 
 .pun .postfootright ul, .pun .postfootright div, .pun .postfootright p,
 .pun .postfootleft p {
-	padding: 6px 6px 6px 6px;
+	padding: 10px 6px 5px 6px;
 	}
 
 .pun .postfootright li {
 	display: inline;
-	margin-left: 12px;
+	}
+
+.pun .postfootright li:before {
+	content: " | ";
+	}
+
+.pun .postfootright li:first-child:before {
+	content: "";
 	}
 
 .pun .postfootright a:link, .pun .postfootright a:visited {
@@ -926,6 +980,14 @@
 	text-align: center;
 	}
 
+#brdwelcome, #brdfooter dl a, div.blockmenu li, div.rbox input {
+	line-height: 1.4em
+	}
+
+#announce div.inbox div {
+	padding: 3px 0
+	}
+
 /*****************************************************************
 COLOUR SCHEME
 *****************************************************************/
@@ -973,6 +1035,14 @@ body {
 	color: #333
 	}
 
+.pun .multiselect, .pun .checklist {
+	color: #333;
+	}
+
+.pun .checklist {
+	border-color: #ACA899;
+	}
+
 /* posts
 ----------------------------------------------------------------*/
 
@@ -1020,10 +1090,14 @@ body {
 	border-color: #cedeb9
 	}
 
-.pun th, .pun fieldset {
+.pun th {
 	border-color: #d1d1d1
 	}
 
+.pun fieldset {
+	border-color: #aca899
+	}
+
 #adminconsole td, #adminconsole th {
 	border-color: #f1f1f1
 	}
diff --git a/style/Mercury.css b/style/Mercury.css
index 93cea7e..cffebb1 100644
--- a/style/Mercury.css
+++ b/style/Mercury.css
@@ -48,6 +48,9 @@
 	min-height: 1px
 	}
 
+.clearl {
+	clear: left;
+	}
 
 /* Hidden Elements
 ----------------------------------------------------------------*/
@@ -72,6 +75,7 @@
 
 .pun {
 	font: 68.75%/1.4545em Verdana, Helvetica, Arial, sans-serif;
+	line-height: normal;
 	}
 
 .pun table, .pun td, .pun th, .pun input, .pun select, .pun optgroup, .pun textarea, .pun samp, .pun legend {
@@ -108,7 +112,7 @@
 .pun h2 {
 	font-size: 1em;
 	font-weight: normal;
-	padding: 4px 7px;
+	padding: 4px 6px;
 	}
 
 .pun h3 {
@@ -209,6 +213,11 @@
 /* Page Layout
 ----------------------------------------------------------------*/
 
+html, body {
+	margin: 0;
+	padding: 0
+	}
+
 .pun {
 	margin: 12px 20px
 	}
@@ -225,6 +234,10 @@
 	margin: 0 0 12px 0;
 	}
 
+#brdtitle p {
+	padding-top: 0px
+	}
+
 #announce, #brdstats {
 	margin: 12px 0 12px 0;
 	}
@@ -281,21 +294,11 @@
 ----------------------------------------------------------------*/
 
 #brdtitle h1 {
-	font-size: 1.454em;
+	font-size: 1.4em;
 	font-weight: bold;
-	line-height: 1em;
 	padding: 3px 0 0 0;
 	}
 
-#brddesc {
-	padding: 3px 0;
-	}
-
-#brddesc * {
-	padding-top: 0;
-	padding-bottom: 0;
-	}
-
 #brdmenu li {
 	display: inline;
 	margin-right: 12px;
@@ -435,12 +438,11 @@
 
 .pun td, .pun th {
 	padding: 4px 6px;
-	line-height: 1.273em;
 	text-align: left;
 	font-weight: normal;
 	}
 
-.pun td {
+.pun td, .pun th {
 	border-style: solid none none solid;
 	border-width: 1px;
 	}
@@ -525,7 +527,8 @@
 	}
 
 .pun .icon {
-	border-width: 7px;
+	margin: 0.1em 0 0 0.2em;
+	border-width: 0.6em;
 	border-style: solid;
 	height: 0;
 	width: 0;
@@ -598,14 +601,6 @@
 	margin-right: 10px
 	}
 
-.pun select {
-	padding-top: 1px;
-	padding-bottom: 1px;
-	}
-
-.pun fieldset .rbox {
-	}
-
 .pun fieldset .rbox br {
 	display: none;
 	}
@@ -665,6 +660,58 @@
 	margin-right: 12px;
 	}
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+	}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.3em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+	}
+
+.pun .checklist fieldset {
+	border: 0;
+	padding: 0;
+	}
+
+.pun .checklist legend {
+	padding: 0;
+	}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+	}
+
+.pun .checklist .checklist-item {
+	position: relative;
+	margin: .2em 0;
+	}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 2.1em;
+	}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+	}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.15em;
+	width: 1.55em;
+	}
+
 /*****************************************************************
 7. PROFILES AND ADMIN
 *****************************************************************/
@@ -674,12 +721,12 @@
 	}
 
 .pun .block2col .blockform, .pun .block2col .block {
-	margin-left: 17em
+	margin-left: 14em
 	}
 
 .pun .blockmenu {
 	float:left;
-	width: 16em
+	width: 13em
 	}
 
 .pun .blockmenu li {
@@ -756,7 +803,7 @@
 	}
 
 .pun .postleft dl {
-	padding: 0.75em 6px;
+	padding: 6px;
 	}
 
 .pun .postleft .usercontacts, .pun .postleft .icon {
@@ -807,12 +854,19 @@
 
 .pun .postfootright ul, .pun .postfootright div, .pun .postfootright p,
 .pun .postfootleft p {
-	padding: 6px 6px 6px 6px;
+	padding: 10px 6px 5px 6px;
 	}
 
 .pun .postfootright li {
 	display: inline;
-	margin-left: 12px;
+	}
+
+.pun .postfootright li:before {
+	content: " | ";
+	}
+
+.pun .postfootright li:first-child:before {
+	content: "";
 	}
 
 .pun .postfootright a:link, .pun .postfootright a:visited {
@@ -926,6 +980,14 @@
 	text-align: center;
 	}
 
+#brdwelcome, #brdfooter dl a, div.blockmenu li, div.rbox input {
+	line-height: 1.4em
+	}
+
+#announce div.inbox div {
+	padding: 3px 0
+	}
+
 /*****************************************************************
 COLOUR SCHEME
 *****************************************************************/
@@ -978,6 +1040,14 @@ body {
 	color: #d4d4d4
 	}
 
+.pun .multiselect, .pun .checklist {
+	color: #D4D4D4;
+	}
+
+.pun .checklist {
+	border-color: #666;
+	}
+
 /* Posts
 ----------------------------------------------------------------*/
 
@@ -1021,10 +1091,14 @@ body {
 	border-color: #565656
 	}
 
-.pun th, .pun fieldset {
+.pun th {
 	border-color: #484848
 	}
 
+.pun fieldset {
+	border-color: #565656
+	}
+
 #adminconsole td, #adminconsole th {
 	border-color: #383838
 	}
diff --git a/style/Oxygen.css b/style/Oxygen.css
index 1af7310..4705bfb 100644
--- a/style/Oxygen.css
+++ b/style/Oxygen.css
@@ -48,6 +48,9 @@
 	min-height: 1px
 	}
 
+.clearl {
+	clear: left;
+	}
 
 /* Hidden Elements
 ----------------------------------------------------------------*/
@@ -72,6 +75,7 @@
 
 .pun {
 	font: 68.75%/1.4545em Verdana, Helvetica, Arial, sans-serif;
+	line-height: normal;
 	}
 
 .pun table, .pun td, .pun th, .pun input, .pun select, .pun optgroup, .pun textarea, .pun small, .pun samp, .pun legend {
@@ -108,7 +112,7 @@
 .pun h2 {
 	font-size: 1em;
 	font-weight: normal;
-	padding: 4px 7px;
+	padding: 4px 6px;
 	}
 
 .pun h3 {
@@ -210,6 +214,11 @@
 /* Page Layout
 ----------------------------------------------------------------*/
 
+html, body {
+	margin: 0;
+	padding: 0
+	}
+
 .pun {
 	margin: 12px 20px
 	}
@@ -226,6 +235,10 @@
 	margin: 0 0 12px 0;
 	}
 
+#brdtitle p {
+	padding-top: 0px
+	}
+
 #announce, #brdstats {
 	margin: 12px 0 12px 0;
 	}
@@ -282,21 +295,11 @@
 ----------------------------------------------------------------*/
 
 #brdtitle h1 {
-	font-size: 1.454em;
+	font-size: 1.4em;
 	font-weight: bold;
-	line-height: 1em;
 	padding: 3px 0 0 0;
 	}
 
-#brddesc {
-	padding: 3px 0;
-	}
-
-#brddesc * {
-	padding-top: 0;
-	padding-bottom: 0;
-	}
-
 #brdmenu li {
 	display: inline;
 	margin-right: 12px;
@@ -436,12 +439,11 @@
 
 .pun td, .pun th {
 	padding: 4px 6px;
-	line-height: 1.273em;
 	text-align: left;
 	font-weight: normal;
 	}
 
-.pun td {
+.pun td, .pun th {
 	border-style: solid none none solid;
 	border-width: 1px;
 	}
@@ -526,7 +528,8 @@
 	}
 
 .pun .icon {
-	border-width: 7px;
+	margin: 0.1em 0 0 0.2em;
+	border-width: 0.6em;
 	border-style: solid;
 	height: 0;
 	width: 0;
@@ -599,14 +602,6 @@
 	margin-right: 10px
 	}
 
-.pun select {
-	padding-top: 1px;
-	padding-bottom: 1px;
-	}
-
-.pun fieldset .rbox {
-	}
-
 .pun fieldset .rbox br {
 	display: none;
 	}
@@ -666,6 +661,58 @@
 	margin-right: 12px;
 	}
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+	}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.3em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+	}
+
+.pun .checklist fieldset {
+	border: 0;
+	padding: 0;
+	}
+
+.pun .checklist legend {
+	padding: 0;
+	}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+	}
+
+.pun .checklist .checklist-item {
+	position: relative;
+	margin: .2em 0;
+	}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 2.1em;
+	}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+	}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.15em;
+	width: 1.55em;
+	}
+
 /*****************************************************************
 7. PROFILES AND ADMIN
 *****************************************************************/
@@ -675,12 +722,12 @@
 	}
 
 .pun .block2col .blockform, .pun .block2col .block {
-	margin-left: 17em
+	margin-left: 14em
 	}
 
 .pun .blockmenu {
 	float:left;
-	width: 16em
+	width: 13em
 	}
 
 .pun .blockmenu li {
@@ -757,7 +804,7 @@
 	}
 
 .pun .postleft dl {
-	padding: 0.75em 6px;
+	padding: 6px;
 	}
 
 .pun .postleft .usercontacts, .pun .postleft .icon {
@@ -808,12 +855,19 @@
 
 .pun .postfootright ul, .pun .postfootright div, .pun .postfootright p,
 .pun .postfootleft p {
-	padding: 6px 6px 6px 6px;
+	padding: 10px 6px 5px 6px;
 	}
 
 .pun .postfootright li {
 	display: inline;
-	margin-right: 12px;
+	}
+
+.pun .postfootright li:before {
+	content: " | ";
+	}
+
+.pun .postfootright li:first-child:before {
+	content: "";
 	}
 
 .pun .postfootright a:link, .pun .postfootright a:visited {
@@ -927,6 +981,14 @@
 	text-align: center;
 	}
 
+#brdwelcome, #brdfooter dl a, div.blockmenu li, div.rbox input {
+	line-height: 1.4em
+	}
+
+#announce div.inbox div {
+	padding: 3px 0
+	}
+
 /*****************************************************************
 COLOUR SCHEME
 *****************************************************************/
@@ -974,6 +1036,14 @@ body {
 	color: #333
 	}
 
+.pun .multiselect, .pun .checklist {
+	color: #333;
+	}
+
+.pun .checklist {
+	border-color: #ACA899;
+	}
+
 /* Posts
 ----------------------------------------------------------------*/
 
@@ -1021,10 +1091,14 @@ body {
 	border-color: #bbcede
 	}
 
-.pun th, .pun fieldset {
+.pun th {
 	border-color: #d1d1d1
 	}
 
+.pun fieldset {
+	border-color: #aca899
+	}
+
 #adminconsole td, #adminconsole th {
 	border-color: #f1f1f1
 	}
diff --git a/style/Radium.css b/style/Radium.css
index babe283..8b43a10 100644
--- a/style/Radium.css
+++ b/style/Radium.css
@@ -48,6 +48,9 @@
 	min-height: 1px
 	}
 
+.clearl {
+	clear: left;
+	}
 
 /* Hidden Elements
 ----------------------------------------------------------------*/
@@ -72,6 +75,7 @@
 
 .pun {
 	font: 68.75%/1.4545em Verdana, Helvetica, Arial, sans-serif;
+	line-height: normal;
 	}
 
 .pun table, .pun td, .pun th, .pun input, .pun select, .pun optgroup, .pun textarea, .pun samp, .pun legend {
@@ -108,7 +112,7 @@
 .pun h2 {
 	font-size: 1em;
 	font-weight: normal;
-	padding: 4px 7px;
+	padding: 4px 6px;
 	}
 
 .pun h3 {
@@ -209,6 +213,11 @@
 /* Page Layout
 ----------------------------------------------------------------*/
 
+html, body {
+	margin: 0;
+	padding: 0
+	}
+
 .pun {
 	margin: 12px 20px
 	}
@@ -225,6 +234,10 @@
 	margin: 0 0 12px 0;
 	}
 
+#brdtitle p {
+	padding-top: 0px
+	}
+
 #announce, #brdstats {
 	margin: 12px 0 12px 0;
 	}
@@ -281,21 +294,11 @@
 ----------------------------------------------------------------*/
 
 #brdtitle h1 {
-	font-size: 1.454em;
+	font-size: 1.4em;
 	font-weight: bold;
-	line-height: 1em;
 	padding: 3px 0 0 0;
 	}
 
-#brddesc {
-	padding: 3px 0;
-	}
-
-#brddesc * {
-	padding-top: 0;
-	padding-bottom: 0;
-	}
-
 #brdmenu li {
 	display: inline;
 	margin-right: 12px;
@@ -435,12 +438,11 @@
 
 .pun td, .pun th {
 	padding: 4px 6px;
-	line-height: 1.273em;
 	text-align: left;
 	font-weight: normal;
 	}
 
-.pun td {
+.pun td, .pun th {
 	border-style: solid none none solid;
 	border-width: 1px;
 	}
@@ -525,7 +527,8 @@
 	}
 
 .pun .icon {
-	border-width: 7px;
+	margin: 0.1em 0 0 0.2em;
+	border-width: 0.6em;
 	border-style: solid;
 	height: 0;
 	width: 0;
@@ -598,14 +601,6 @@
 	margin-right: 10px
 	}
 
-.pun select {
-	padding-top: 1px;
-	padding-bottom: 1px;
-	}
-
-.pun fieldset .rbox {
-	}
-
 .pun fieldset .rbox br {
 	display: none;
 	}
@@ -665,6 +660,58 @@
 	margin-right: 12px;
 	}
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+	}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.3em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+	}
+
+.pun .checklist fieldset {
+	border: 0;
+	padding: 0;
+	}
+
+.pun .checklist legend {
+	padding: 0;
+	}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+	}
+
+.pun .checklist .checklist-item {
+	position: relative;
+	margin: .2em 0;
+	}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 2.1em;
+	}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+	}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.15em;
+	width: 1.55em;
+	}
+
 /*****************************************************************
 7. PROFILES AND ADMIN
 *****************************************************************/
@@ -674,12 +721,12 @@
 	}
 
 .pun .block2col .blockform, .pun .block2col .block {
-	margin-left: 17em
+	margin-left: 14em
 	}
 
 .pun .blockmenu {
 	float:left;
-	width: 16em
+	width: 13em
 	}
 
 .pun .blockmenu li {
@@ -756,7 +803,7 @@
 	}
 
 .pun .postleft dl {
-	padding: 0.75em 6px;
+	padding: 6px;
 	}
 
 .pun .postleft .usercontacts, .pun .postleft .icon {
@@ -807,12 +854,19 @@
 
 .pun .postfootright ul, .pun .postfootright div, .pun .postfootright p,
 .pun .postfootleft p {
-	padding: 6px 6px 6px 6px;
+	padding: 10px 6px 5px 6px;
 	}
 
 .pun .postfootright li {
 	display: inline;
-	margin-left: 12px;
+	}
+
+.pun .postfootright li:before {
+	content: " | ";
+	}
+
+.pun .postfootright li:first-child:before {
+	content: "";
 	}
 
 .pun .postfootright a:link, .pun .postfootright a:visited {
@@ -926,6 +980,14 @@
 	text-align: center;
 	}
 
+#brdwelcome, #brdfooter dl a, div.blockmenu li, div.rbox input {
+	line-height: 1.4em
+	}
+
+#announce div.inbox div {
+	padding: 3px 0
+	}
+
 /*****************************************************************
 COLOUR SCHEME
 *****************************************************************/
@@ -978,6 +1040,14 @@ body {
 	color: #d4d4d4
 	}
 
+.pun .multiselect, .pun .checklist {
+	color: #D4D4D4;
+	}
+
+.pun .checklist {
+	border-color: #666;
+	}
+
 /* Posts
 ----------------------------------------------------------------*/
 
@@ -1021,10 +1091,14 @@ body {
 	border-color: #565656
 	}
 
-.pun th, .pun fieldset {
+.pun th {
 	border-color: #484848
 	}
 
+.pun fieldset {
+	border-color: #606060
+	}
+
 #adminconsole td, #adminconsole th {
 	border-color: #383838
 	}
diff --git a/style/Sulfur.css b/style/Sulfur.css
index e9d7e5a..b275248 100644
--- a/style/Sulfur.css
+++ b/style/Sulfur.css
@@ -48,6 +48,9 @@
 	min-height: 1px
 	}
 
+.clearl {
+	clear: left;
+	}
 
 /* Hidden Elements
 ----------------------------------------------------------------*/
@@ -72,6 +75,7 @@
 
 .pun {
 	font: 68.75%/1.4545em Verdana, Helvetica, Arial, sans-serif;
+	line-height: normal;
 	}
 
 .pun table, .pun td, .pun th, .pun input, .pun select, .pun optgroup, .pun textarea, .pun samp, .pun legend {
@@ -108,7 +112,7 @@
 .pun h2 {
 	font-size: 1em;
 	font-weight: normal;
-	padding: 4px 7px;
+	padding: 4px 6px;
 	}
 
 .pun h3 {
@@ -209,6 +213,11 @@
 /* Page Layout
 ----------------------------------------------------------------*/
 
+html, body {
+	margin: 0;
+	padding: 0
+	}
+
 .pun {
 	margin: 12px 20px
 	}
@@ -225,6 +234,10 @@
 	margin: 0 0 12px 0;
 	}
 
+#brdtitle p {
+	padding-top: 0px
+	}
+
 #announce, #brdstats {
 	margin: 12px 0 12px 0;
 	}
@@ -281,21 +294,11 @@
 ----------------------------------------------------------------*/
 
 #brdtitle h1 {
-	font-size: 1.454em;
+	font-size: 1.4em;
 	font-weight: bold;
-	line-height: 1em;
 	padding: 3px 0 0 0;
 	}
 
-#brddesc {
-	padding: 3px 0;
-	}
-
-#brddesc * {
-	padding-top: 0;
-	padding-bottom: 0;
-	}
-
 #brdmenu li {
 	display: inline;
 	margin-right: 12px;
@@ -435,12 +438,11 @@
 
 .pun td, .pun th {
 	padding: 4px 6px;
-	line-height: 1.273em;
 	text-align: left;
 	font-weight: normal;
 	}
 
-.pun td {
+.pun td, .pun th {
 	border-style: solid none none solid;
 	border-width: 1px;
 	}
@@ -525,7 +527,8 @@
 	}
 
 .pun .icon {
-	border-width: 7px;
+	margin: 0.1em 0 0 0.2em;
+	border-width: 0.6em;
 	border-style: solid;
 	height: 0;
 	width: 0;
@@ -598,14 +601,6 @@
 	margin-right: 10px
 	}
 
-.pun select {
-	padding-top: 1px;
-	padding-bottom: 1px;
-	}
-
-.pun fieldset .rbox {
-	}
-
 .pun fieldset .rbox br {
 	display: none;
 	}
@@ -665,6 +660,58 @@
 	margin-right: 12px;
 	}
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+	}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.3em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+	}
+
+.pun .checklist fieldset {
+	border: 0;
+	padding: 0;
+	}
+
+.pun .checklist legend {
+	padding: 0;
+	}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+	}
+
+.pun .checklist .checklist-item {
+	position: relative;
+	margin: .2em 0;
+	}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 2.1em;
+	}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+	}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.15em;
+	width: 1.55em;
+	}
+
 /*****************************************************************
 7. PROFILES AND ADMIN
 *****************************************************************/
@@ -674,12 +721,12 @@
 	}
 
 .pun .block2col .blockform, .pun .block2col .block {
-	margin-left: 17em
+	margin-left: 14em
 	}
 
 .pun .blockmenu {
 	float:left;
-	width: 16em
+	width: 13em
 	}
 
 .pun .blockmenu li {
@@ -756,7 +803,7 @@
 	}
 
 .pun .postleft dl {
-	padding: 0.75em 6px;
+	padding: 6px;
 	}
 
 .pun .postleft .usercontacts, .pun .postleft .icon {
@@ -807,12 +854,19 @@
 
 .pun .postfootright ul, .pun .postfootright div, .pun .postfootright p,
 .pun .postfootleft p {
-	padding: 6px 6px 6px 6px;
+	padding: 10px 6px 5px 6px;
 	}
 
 .pun .postfootright li {
 	display: inline;
-	margin-left: 12px;
+	}
+
+.pun .postfootright li:before {
+	content: " | ";
+	}
+
+.pun .postfootright li:first-child:before {
+	content: "";
 	}
 
 .pun .postfootright a:link, .pun .postfootright a:visited {
@@ -926,6 +980,14 @@
 	text-align: center;
 	}
 
+#brdwelcome, #brdfooter dl a, div.blockmenu li, div.rbox input {
+	line-height: 1.4em
+	}
+
+#announce div.inbox div {
+	padding: 3px 0
+	}
+
 /*****************************************************************
 COLOUR SCHEME
 *****************************************************************/
@@ -973,6 +1035,14 @@ body {
 	color: #333
 	}
 
+.pun .multiselect, .pun .checklist {
+	color: #333;
+	}
+
+.pun .checklist {
+	border-color: #ACA899;
+	}
+
 /* Posts
 ----------------------------------------------------------------*/
 
@@ -1020,10 +1090,14 @@ body {
 	border-color: #e1c3c3
 	}
 
-.pun th, .pun fieldset {
+.pun th {
 	border-color: #d1d1d1
 	}
 
+.pun fieldset {
+	border-color: #aca899
+	}
+
 #adminconsole td, #adminconsole th {
 	border-color: #f1f1f1
 	}
diff --git a/style/Technetium.css b/style/Technetium.css
index 765e11b..c4633cb 100644
--- a/style/Technetium.css
+++ b/style/Technetium.css
@@ -63,6 +63,9 @@ body {
 	min-height: 1px
 	}
 
+.clearl {
+	clear: left;
+	}
 
 /* Hidden Elements
 ----------------------------------------------------------------*/
@@ -776,6 +779,51 @@ body {
 	padding: 6px 15px;
 	}
 
+.pun .multiselect {
+	float: left;
+	padding-bottom: 7px;
+	}
+
+.pun .checklist {
+	border-width: 1px;
+	border-style: solid;
+	max-height: 9em;
+	width: 20em;
+	overflow: auto;
+	padding: 0.25em 0.5em;
+	margin: 0.25em 16px 0 0.15em;
+	}
+
+.pun .checklist legend {
+	padding: 0;
+	}
+
+.pun .checklist legend span {
+	width: auto;
+	max-width: 25em;
+	}
+
+.pun .checklist .checklist-item {
+	position: relative;
+	}
+
+.pun .checklist .checklist-item label {
+	padding: 0 0 0 1.75em;
+	}
+
+.pun .checklist .checklist-item .fld-input {
+	position: absolute;
+	left: 0;
+	top: 0;
+	padding: 0;
+	margin: 0;
+	}
+
+.pun .checklist .checklist-item input {
+	margin: 0;
+	height: 1.55em;
+	width: 1.55em;
+	}
 
 /*****************************************************************
 7. PROFILES AND ADMIN
@@ -921,6 +969,14 @@ body {
 	display: inline;
 	}
 
+.pun .postfootright li:before {
+	content: " | ";
+	}
+
+.pun .postfootright li:first-child:before {
+	content: "";
+	}
+
 .pun .postfootright a:link, .pun .postfootright a:visited {
 	text-decoration: none
 	}
@@ -1170,6 +1226,14 @@ body {
 	padding-left: 16px;
 	}
 
+.pun .multiselect {
+	color: #122434;
+	}
+
+.pun .checklist {
+	background: white;
+	border-color: #A2B5CC;
+	}
 
 /* Posts
 ----------------------------------------------------------------*/
diff --git a/style/imports/base_admin.css b/style/imports/base_admin.css
index 3c3c966..26a29c4 100644
--- a/style/imports/base_admin.css
+++ b/style/imports/base_admin.css
@@ -38,10 +38,13 @@ TABLE#forumperms .atcl {TEXT-ALIGN: left; WIDTH: 15em; WHITE-SPACE: nowrap}
 /*** User/Ban Search Result Tables ***/
 #users2 TH, #bans1 TH {TEXT-ALIGN: left}
 #users2 TH.tcmod {TEXT-ALIGN: center}
-#users2 .tcl, #users2 .tc3, #users2 .tc5, #bans1 .tcl, #bans1 .tc3, #bans1 .tc5, #bans1 .tc6 {WIDTH: 15%; TEXT-ALIGN: left; PADDING: 4px 6px}
-#users2 .tc2, #bans1 .tc2 {WIDTH: 22%; TEXT-ALIGN: left; PADDING: 4px 6px}
-#users2 .tc4, #bans1 .tc4 {WIDTH: 8%; TEXT-ALIGN: center}
-#users2 .tcr, #bans1 .tcr {WHITE-SPACE: nowrap}
+#users2 .tcl, #bans1 .tcl {WIDTH: auto; TEXT-ALIGN: left; PADDING: 4px 6px}
+#users2 .tc2, #bans1 .tc2 {WIDTH: 18%; TEXT-ALIGN: left; PADDING: 4px 6px}
+#users2 .tc3, #users2 .tc5, #bans1 .tc3, #bans1 .tc5, #bans1 .tc6 {WIDTH: 12%; TEXT-ALIGN: left; PADDING: 4px 6px}
+#users2 .tc4, #bans1 .tc4 {WIDTH: 10%; TEXT-ALIGN: center}
+#users2 .tcr {WIDTH: 20%; WHITE-SPACE: nowrap}
+#bans1 .tcr {WIDTH: 15%; WHITE-SPACE: nowrap}
+#users2 .tcmod {WIDTH: 10%; TEXT-ALIGN: center}
 #adminconsole #linkst, #adminconsole #linksb A {FONT-WEIGHT: bold}
 
 /*** Plugins ***/
diff --git a/userlist.php b/userlist.php
index c37242a..73d448d 100644
--- a/userlist.php
+++ b/userlist.php
@@ -63,7 +63,7 @@ require PUN_ROOT.'header.php';
 
 ?>
 <div class="blockform">
-	<h2><span><?php echo $lang_common['User list'] ?></span></h2>
+	<h2><span><?php echo $lang_search['User search'] ?></span></h2>
 	<div class="box">
 		<form id="userlist" method="get" action="userlist.php">
 			<div class="inform">
@@ -119,6 +119,7 @@ while ($cur_group = $db->fetch_assoc($result))
 </div>
 
 <div id="users1" class="blocktable">
+	<h2><span><?php echo $lang_common['User list'] ?></span></h2>
 	<div class="box">
 		<div class="inbox">
 			<table cellspacing="0">
diff --git a/viewforum.php b/viewforum.php
index 7a464f0..32c3201 100644
--- a/viewforum.php
+++ b/viewforum.php
@@ -78,29 +78,10 @@ $start_from = $pun_user['disp_topics'] * ($p - 1);
 // Generate paging links
 $paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'viewforum.php?id='.$id);
 
-
-// Add relationship meta tags
-$page_head = array();
-$page_head['up'] = '<link rel="up" href="index.php" title="'.$lang_common['Forum index'].'" />';
-
-if ($num_pages > 1)
-{
-	if ($p > 1)
-	{
-		$page_head['first'] = '<link rel="first" href="viewforum.php?id='.$id.'&p=1" title="'.sprintf($lang_common['Page'], 1).'" />';
-		$page_head['prev'] = '<link rel="prev" href="viewforum.php?id='.$id.'&p='.($p-1).'" title="'.sprintf($lang_common['Page'], $p-1).'" />';
-	}
-	if ($p < $num_pages)
-	{
-		$page_head['next'] = '<link rel="next" href="viewforum.php?id='.$id.'&p='.($p+1).'" title="'.sprintf($lang_common['Page'], $p+1).'" />';
-		$page_head['last'] = '<link rel="last" href="viewforum.php?id='.$id.'&p='.$num_pages.'" title="'.sprintf($lang_common['Page'], $num_pages).'" />';
-	}
-}
-
 if ($pun_config['o_feed_type'] == '1')
-	$page_head['feed'] = '<link rel="alternate" type="application/rss+xml" href="extern.php?action=feed&fid='.$id.'&type=rss" title="'.$lang_common['RSS forum feed'].'" />';
+	$page_head = array('feed' => '<link rel="alternate" type="application/rss+xml" href="extern.php?action=feed&fid='.$id.'&type=rss" title="'.$lang_common['RSS forum feed'].'" />');
 else if ($pun_config['o_feed_type'] == '2')
-	$page_head['feed'] = '<link rel="alternate" type="application/atom+xml" href="extern.php?action=feed&fid='.$id.'&type=atom" title="'.$lang_common['Atom forum feed'].'" />';
+	$page_head = array('feed' => '<link rel="alternate" type="application/atom+xml" href="extern.php?action=feed&fid='.$id.'&type=atom" title="'.$lang_common['Atom forum feed'].'" />');
 
 $forum_actions = array();
 
diff --git a/viewtopic.php b/viewtopic.php
index b77f08c..68ad091 100644
--- a/viewtopic.php
+++ b/viewtopic.php
@@ -200,25 +200,6 @@ $start_from = $pun_user['disp_posts'] * ($p - 1);
 $paging_links = '<span class="pages-label">'.$lang_common['Pages'].' </span>'.paginate($num_pages, $p, 'viewtopic.php?id='.$id);
 
 
-// Add relationship meta tags
-$page_head = array();
-$page_head['up'] = '<link rel="up" href="viewforum.php?id='.$cur_topic['forum_id'].'" title="'.pun_htmlspecialchars($cur_topic['forum_name']).'" />';
-
-if ($num_pages > 1)
-{
-	if ($p > 1)
-	{
-		$page_head['first'] = '<link rel="first" href="viewtopic.php?id='.$id.'&p=1" title="'.sprintf($lang_common['Page'], 1).'" />';
-		$page_head['prev'] = '<link rel="prev" href="viewtopic.php?id='.$id.'&p='.($p-1).'" title="'.sprintf($lang_common['Page'], $p-1).'" />';
-	}
-	if ($p < $num_pages)
-	{
-		$page_head['next'] = '<link rel="next" href="viewtopic.php?id='.$id.'&p='.($p+1).'" title="'.sprintf($lang_common['Page'], $p+1).'" />';
-		$page_head['last'] = '<link rel="last" href="viewtopic.php?id='.$id.'&p='.$num_pages.'" title="'.sprintf($lang_common['Page'], $num_pages).'" />';
-	}
-}
-
-
 if ($pun_config['o_censoring'] == '1')
 	$cur_topic['subject'] = censor_words($cur_topic['subject']);
 
@@ -231,7 +212,13 @@ if ($pun_config['o_quickpost'] == '1' &&
 	// Load the post.php language file
 	require PUN_ROOT.'lang/'.$pun_user['language'].'/post.php';
 
-	$required_fields = array('req_email' => $lang_common['Email'], 'req_message' => $lang_common['Message']);
+	$required_fields = array('req_message' => $lang_common['Message']);
+	if ($pun_user['is_guest'])
+	{
+		$required_fields['req_username'] = $lang_post['Guest name'];
+		if ($pun_config['p_force_guest_email'] == '1')
+			$required_fields['req_email'] = $lang_common['Email'];
+	}
 	$quickpost = true;
 }
 
@@ -247,9 +234,9 @@ else
 	$subscraction = '';
 
 if ($pun_config['o_feed_type'] == '1')
-	$page_head['feed'] = '<link rel="alternate" type="application/rss+xml" href="extern.php?action=feed&tid='.$id.'&type=rss" title="'.$lang_common['RSS topic feed'].'" />';
+	$page_head = array('feed' => '<link rel="alternate" type="application/rss+xml" href="extern.php?action=feed&tid='.$id.'&type=rss" title="'.$lang_common['RSS topic feed'].'" />');
 else if ($pun_config['o_feed_type'] == '2')
-	$page_head['feed'] = '<link rel="alternate" type="application/atom+xml" href="extern.php?action=feed&tid='.$id.'&type=atom" title="'.$lang_common['Atom topic feed'].'" />';
+	$page_head = array('feed' => '<link rel="alternate" type="application/atom+xml" href="extern.php?action=feed&tid='.$id.'&type=atom" title="'.$lang_common['Atom topic feed'].'" />');
 
 $page_title = array(pun_htmlspecialchars($pun_config['o_board_title']), pun_htmlspecialchars($cur_topic['forum_name']), pun_htmlspecialchars($cur_topic['subject']));
 define('PUN_ALLOW_INDEX', 1);
@@ -493,7 +480,6 @@ $cur_index = 1;
 					<legend><?php echo $lang_common['Write message legend'] ?></legend>
 					<div class="infldset txtarea">
 						<input type="hidden" name="form_sent" value="1" />
-						<input type="hidden" name="form_user" value="<?php echo pun_htmlspecialchars($pun_user['username']) ?>" />
 <?php if ($pun_config['o_topic_subscriptions'] == '1' && ($pun_user['auto_notify'] == '1' || $cur_topic['is_subscribed'])): ?>						<input type="hidden" name="subscribe" value="1" />
 <?php endif; ?>
 <?php


More information about the Xfce4-commits mailing list