Finishing re-add, addremove didn't work last time. Integrated with Enano's template engine properly.
authorDan
Sun, 06 Apr 2008 00:28:50 -0400
changeset 7 98bbc533541c
parent 6 5e1f1e916419
child 8 8baccbad4a55
Finishing re-add, addremove didn't work last time. Integrated with Enano's template engine properly.
punbb/COPYING
punbb/admin/index.php
punbb/admin/users.php
punbb/cache/.htaccess
punbb/cache/cache_bans.php
punbb/cache/cache_config.php
punbb/cache/cache_hooks.php
punbb/cache/cache_quickjump_1.php
punbb/cache/cache_quickjump_2.php
punbb/cache/cache_quickjump_3.php
punbb/cache/cache_quickjump_4.php
punbb/cache/cache_ranks.php
punbb/cache/index.html
punbb/delete.php
punbb/edit.php
punbb/extern.php
punbb/footer.php
punbb/header.php
punbb/help.php
punbb/img/avatars/index.html
punbb/img/index.html
punbb/img/smilies/big_smile.png
punbb/img/smilies/cool.png
punbb/img/smilies/hmm.png
punbb/img/smilies/index.html
punbb/img/smilies/lol.png
punbb/img/smilies/mad.png
punbb/img/smilies/neutral.png
punbb/img/smilies/roll.png
punbb/img/smilies/sad.png
punbb/img/smilies/smile.png
punbb/img/smilies/tongue.png
punbb/img/smilies/wink.png
punbb/img/smilies/yikes.png
punbb/include/cache.php
punbb/include/common.php
punbb/include/common_admin.php
punbb/include/dblayer/common_db.php
punbb/include/dblayer/index.html
punbb/include/dblayer/mysql.php
punbb/include/dblayer/mysqli.php
punbb/include/dblayer/pgsql.php
punbb/include/dblayer/sqlite.php
punbb/include/email.php
punbb/include/functions.php
punbb/include/parser.php
punbb/include/search_idx.php
punbb/include/template/admin.tpl
punbb/include/template/help.tpl
punbb/include/template/index.html
punbb/include/template/main.tpl
punbb/include/template/maintenance.tpl
punbb/include/template/redirect.tpl
punbb/index.php
punbb/install.php
punbb/lang/English/admin.php
punbb/lang/English/common.php
punbb/lang/English/delete.php
punbb/lang/English/forum.php
punbb/lang/English/help.php
punbb/lang/English/index.html
punbb/lang/English/index.php
punbb/lang/English/login.php
punbb/lang/English/mail_templates/activate_email.tpl
punbb/lang/English/mail_templates/activate_password.tpl
punbb/lang/English/mail_templates/form_email.tpl
punbb/lang/English/mail_templates/index.html
punbb/lang/English/mail_templates/new_reply.tpl
punbb/lang/English/mail_templates/new_reply_full.tpl
punbb/lang/English/mail_templates/welcome.tpl
punbb/lang/English/misc.php
punbb/lang/English/post.php
punbb/lang/English/profile.php
punbb/lang/English/search.php
punbb/lang/English/stopwords.txt
punbb/lang/English/topic.php
punbb/lang/English/userlist.php
punbb/lang/index.html
punbb/login.php
punbb/misc.php
punbb/moderate.php
punbb/post.php
punbb/profile.php
punbb/register.php
punbb/search.php
punbb/style/index.html
punbb/userlist.php
punbb/viewforum.php
punbb/viewtopic.php
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/COPYING	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- a/punbb/admin/index.php	Sat Apr 05 23:56:45 2008 -0400
+++ b/punbb/admin/index.php	Sun Apr 06 00:28:50 2008 -0400
@@ -46,7 +46,7 @@
 $GLOBALS['lang_admin'] = $lang_admin;
 
 // Show phpinfo() output
-if (isset($_GET['action']) && $_GET['action'] == 'phpinfo' && $pun_user['g_id'] == PUN_ADMIN)
+if (isset($_GET['action']) && $_GET['action'] == 'phpinfo' && $session->user_level >= USER_LEVEL_ADMIN)
 {
 	($hook = get_hook('ain_phpinfo_selected')) ? eval($hook) : null;
 
@@ -213,12 +213,28 @@
 					<li><span><?php echo $punbb_updates ?></span></li>
 				</ul>
 			</div>
+      
+      <div class="idx-item databox db<?php echo ++$pun_page['item_num']?>">
+				<h3 class="legend"><span><?php echo $lang_admin['Enano version'] ?></span></h3>
+				<ul class="data">
+					<li><span><a href="<?php echo makeUrlNS('Special', 'About_Enano', false, true); ?>">Enano CMS</a> v<?php echo enano_version(true); ?></span></li>
+					<li><span>&copy; 2006-2008 Dan Fuhry and the <a href="http://enanocms.org/Enano_CMS:Team">Enano Team</a></span></li>
+				</ul>
+			</div>
+      
+      <div class="idx-item databox db<?php echo ++$pun_page['item_num']?>">
+				<h3 class="legend"><span><?php echo $lang_admin['PunBB port version'] ?></span></h3>
+				<ul class="data">
+					<li><span>Punano Bridge <?php echo PUNANO_VERSION; ?></span></li>
+					<li><span>&copy; 2008 Dan Fuhry</span></li>
+				</ul>
+			</div>
 <?php ($hook = get_hook('ain_pre_server_load')) ? eval($hook) : null; ?>
 			<div class="idx-item databox db<?php echo ++$pun_page['item_num']?>">
 				<h3 class="legend"><span><?php echo $lang_admin['Server load'] ?></span></h3>
 				<p class="data"><?php echo $server_load ?> (<?php echo $num_online.' '.$lang_admin['users online']?>)</p>
 			</div>
-<?php ($hook = get_hook('ain_pre_environment')) ? eval($hook) : null; if ($pun_user['g_id'] == PUN_ADMIN): ?>					<div class="idx-item databox db<?php echo ++$pun_page['item_num']?>">
+<?php ($hook = get_hook('ain_pre_environment')) ? eval($hook) : null; if ($session->user_level >= USER_LEVEL_ADMIN): ?>					<div class="idx-item databox db<?php echo ++$pun_page['item_num']?>">
 				<h3 class="legend"><span><?php echo $lang_admin['Environment'] ?></span></h3>
 				<ul class="data">
 					<li><span><?php echo $lang_admin['Operating system'] ?>: <?php echo PHP_OS ?></span></li>
--- a/punbb/admin/users.php	Sat Apr 05 23:56:45 2008 -0400
+++ b/punbb/admin/users.php	Sun Apr 06 00:28:50 2008 -0400
@@ -205,7 +205,7 @@
 						<th class="tc3" scope="col"><?php echo $lang_admin['Posts'] ?></th>
 <?php ($hook = get_hook('aus_show_users_table_header_after_num_posts')) ? eval($hook) : null; ?>
 						<th class="tcr actions" scope="col"><?php echo $lang_admin['Actions'] ?></th>
-<?php ($hook = get_hook('aus_show_users_table_header_after_actions')) ? eval($hook) : null; if ($pun_user['g_id'] == PUN_ADMIN): ?>						<th class="tcmod" scope="col"><?php echo $lang_misc['Select'] ?></th>
+<?php ($hook = get_hook('aus_show_users_table_header_after_actions')) ? eval($hook) : null; if ($session->user_level >= USER_LEVEL_ADMIN): ?>						<th class="tcmod" scope="col"><?php echo $lang_misc['Select'] ?></th>
 <?php endif; ?>					</tr>
 				</thead>
 				<tbody>
@@ -245,7 +245,7 @@
 						<td class="tc3"><?php echo $user_data['num_posts'] ?></td>
 <?php ($hook = get_hook('aus_show_users_table_contents_after_num_posts')) ? eval($hook) : null; ?>
 						<td class="tcr actions"><?php echo $pun_page['actions'] ?></td>
-<?php ($hook = get_hook('aus_show_users_table_contents_after_actions')) ? eval($hook) : null; if ($pun_user['g_id'] == PUN_ADMIN): ?>						<td class="tcmod"><input type="checkbox" name="users[<?php echo $user_data['id'] ?>]" value="1" /></td>
+<?php ($hook = get_hook('aus_show_users_table_contents_after_actions')) ? eval($hook) : null; if ($session->user_level >= USER_LEVEL_ADMIN): ?>						<td class="tcmod"><input type="checkbox" name="users[<?php echo $user_data['id'] ?>]" value="1" /></td>
 <?php endif; ?>					</tr>
 <?php
 
@@ -260,7 +260,7 @@
 						<td class="tc3">&#160;</td>
 <?php ($hook = get_hook('aus_show_users_table_contents_after_num_posts_guest')) ? eval($hook) : null; ?>
 						<td class="tcr">&#160;</td>
-<?php ($hook = get_hook('aus_show_users_table_contents_after_actions_guest')) ? eval($hook) : null; if ($pun_user['g_id'] == PUN_ADMIN): ?>						<td class="tcmod">&#160;</td>
+<?php ($hook = get_hook('aus_show_users_table_contents_after_actions_guest')) ? eval($hook) : null; if ($session->user_level >= USER_LEVEL_ADMIN): ?>						<td class="tcmod">&#160;</td>
 <?php endif; ?>					</tr>
 <?php
 
@@ -268,7 +268,7 @@
 		}
 	}
 	else
-		echo "\t\t\t\t\t".'<tr><td class="tcl" colspan="'.(($pun_user['g_id'] == PUN_ADMIN) ? '5' : '4').'">'.$lang_admin['Cannot find IP'].'</td></tr>'."\n";
+		echo "\t\t\t\t\t".'<tr><td class="tcl" colspan="'.(($session->user_level >= USER_LEVEL_ADMIN) ? '5' : '4').'">'.$lang_admin['Cannot find IP'].'</td></tr>'."\n";
 
 ?>
 				</tbody>
@@ -825,7 +825,7 @@
 						<th class="tc3" scope="col"><?php echo $lang_admin['Posts'] ?></th>
 <?php ($hook = get_hook('aus_find_user_table_header_after_num_posts')) ? eval($hook) : null; ?>
 						<th class="tcr actions" scope="col"><?php echo $lang_admin['Actions'] ?></th>
-<?php ($hook = get_hook('aus_find_user_table_header_after_actions')) ? eval($hook) : null; if ($pun_user['g_id'] == PUN_ADMIN): ?>					<th class="tcmod" scope="col"><?php echo $lang_misc['Select'] ?></th>
+<?php ($hook = get_hook('aus_find_user_table_header_after_actions')) ? eval($hook) : null; if ($session->user_level >= USER_LEVEL_ADMIN): ?>					<th class="tcmod" scope="col"><?php echo $lang_misc['Select'] ?></th>
 <?php endif; ?>					</tr>
 				</thead>
 				<tbody>
@@ -850,14 +850,14 @@
 						<td class="tc3"><?php echo $user_data['num_posts'] ?></td>
 <?php ($hook = get_hook('aus_find_user_table_contents_after_num_posts')) ? eval($hook) : null; ?>
 						<td class="tcr actions"><?php echo $pun_page['actions'] ?></td>
-<?php ($hook = get_hook('aus_find_user_table_contents_after_actions')) ? eval($hook) : null; if ($pun_user['g_id'] == PUN_ADMIN): ?>					<td class="tcmod"><input type="checkbox" name="users[<?php echo $user_data['id'] ?>]" value="1" /></td>
+<?php ($hook = get_hook('aus_find_user_table_contents_after_actions')) ? eval($hook) : null; if ($session->user_level >= USER_LEVEL_ADMIN): ?>					<td class="tcmod"><input type="checkbox" name="users[<?php echo $user_data['id'] ?>]" value="1" /></td>
 <?php endif; ?>					</tr>
 <?php
 
 		}
 	}
 	else
-		echo "\t\t\t\t\t".'<tr><td class="tcl" colspan="'.(($pun_user['g_id'] == PUN_ADMIN) ? '5' : '4').'">'.$lang_admin['No match'].'</td></tr>'."\n";
+		echo "\t\t\t\t\t".'<tr><td class="tcl" colspan="'.(($session->user_level >= USER_LEVEL_ADMIN) ? '5' : '4').'">'.$lang_admin['No match'].'</td></tr>'."\n";
 
 ?>
 				</tbody>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/cache/.htaccess	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,4 @@
+<Limit GET POST PUT>
+Order Allow,Deny
+Deny from All
+</Limit>
\ No newline at end of file
--- a/punbb/cache/cache_bans.php	Sat Apr 05 23:56:45 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-<?php
-
-define('PUN_BANS_LOADED', 1);
-
-$pun_bans = array (
-);
-
-?>
\ No newline at end of file
--- a/punbb/cache/cache_config.php	Sat Apr 05 23:56:45 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-<?php
-
-define('PUN_CONFIG_LOADED', 1);
-
-$pun_config = array (
-  'o_cur_version' => '1.3-beta',
-  'o_board_title' => 'PunBB 1.3 + Enano',
-  'o_board_desc' => 'PunBB integrated with Enano\'s user and template system. w00t!',
-  'o_default_timezone' => '0',
-  'o_time_format' => 'H:i:s',
-  'o_date_format' => 'Y-m-d',
-  'o_check_for_updates' => '0',
-  'o_timeout_visit' => '1800',
-  'o_timeout_online' => '300',
-  'o_redirect_delay' => '1',
-  'o_show_version' => '0',
-  'o_show_user_info' => '1',
-  'o_show_post_count' => '1',
-  'o_signatures' => '1',
-  'o_smilies' => '1',
-  'o_smilies_sig' => '1',
-  'o_make_links' => '1',
-  'o_default_lang' => 'English',
-  'o_default_style' => 'Oxygen',
-  'o_default_user_group' => '3',
-  'o_topic_review' => '15',
-  'o_disp_topics_default' => '30',
-  'o_disp_posts_default' => '25',
-  'o_indent_num_spaces' => '4',
-  'o_quickpost' => '1',
-  'o_users_online' => '1',
-  'o_censoring' => '0',
-  'o_ranks' => '1',
-  'o_show_dot' => '0',
-  'o_topic_views' => '1',
-  'o_quickjump' => '1',
-  'o_gzip' => '0',
-  'o_additional_navlinks' => '',
-  'o_report_method' => '0',
-  'o_regs_report' => '0',
-  'o_mailing_list' => 'dan@enanocms.org',
-  'o_avatars' => '0',
-  'o_avatars_dir' => 'img/avatars',
-  'o_avatars_width' => '60',
-  'o_avatars_height' => '60',
-  'o_avatars_size' => '10240',
-  'o_search_all_forums' => '1',
-  'o_sef' => 'File_based_(fancy)',
-  'o_admin_email' => 'dan@enanocms.org',
-  'o_webmaster_email' => 'dan@enanocms.org',
-  'o_subscriptions' => '1',
-  'o_smtp_host' => NULL,
-  'o_smtp_user' => NULL,
-  'o_smtp_pass' => NULL,
-  'o_smtp_ssl' => '0',
-  'o_regs_allow' => '1',
-  'o_regs_verify' => '0',
-  'o_announcement' => '0',
-  'o_announcement_heading' => 'Sample announcement',
-  'o_announcement_message' => '<p>Enter your announcement here.</p>',
-  'o_rules' => '0',
-  'o_rules_message' => 'Enter your rules here.',
-  'o_maintenance' => '0',
-  'o_maintenance_message' => 'The forums are temporarily down for maintenance. Please try again in a few minutes.<br />\\n<br />\\n/Administrator',
-  'p_message_bbcode' => '1',
-  'p_message_img_tag' => '1',
-  'p_message_all_caps' => '1',
-  'p_subject_all_caps' => '1',
-  'p_sig_all_caps' => '1',
-  'p_sig_bbcode' => '1',
-  'p_sig_img_tag' => '0',
-  'p_sig_length' => '400',
-  'p_sig_lines' => '4',
-  'p_allow_banned_email' => '1',
-  'p_allow_dupe_email' => '0',
-  'p_force_guest_email' => '1',
-);
-
-?>
\ No newline at end of file
--- a/punbb/cache/cache_hooks.php	Sat Apr 05 23:56:45 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-<?php
-
-define('PUN_HOOKS_LOADED', 1);
-
-$pun_hooks = array (
-);
-
-?>
\ No newline at end of file
--- a/punbb/cache/cache_quickjump_1.php	Sat Apr 05 23:56:45 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-<?php
-
-if (!defined('PUN')) exit;
-define('PUN_QJ_LOADED', 1);
\ No newline at end of file
--- a/punbb/cache/cache_quickjump_2.php	Sat Apr 05 23:56:45 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-<?php
-
-if (!defined('PUN')) exit;
-define('PUN_QJ_LOADED', 1);
\ No newline at end of file
--- a/punbb/cache/cache_quickjump_3.php	Sat Apr 05 23:56:45 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-<?php
-
-if (!defined('PUN')) exit;
-define('PUN_QJ_LOADED', 1);
\ No newline at end of file
--- a/punbb/cache/cache_quickjump_4.php	Sat Apr 05 23:56:45 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-<?php
-
-if (!defined('PUN')) exit;
-define('PUN_QJ_LOADED', 1);
\ No newline at end of file
--- a/punbb/cache/cache_ranks.php	Sat Apr 05 23:56:45 2008 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-<?php
-
-define('PUN_RANKS_LOADED', 1);
-
-$pun_ranks = array (
-  0 => 
-  array (
-    'id' => '1',
-    'rank' => 'New member',
-    'min_posts' => '0',
-  ),
-  1 => 
-  array (
-    'id' => '2',
-    'rank' => 'New member',
-    'min_posts' => '0',
-  ),
-);
-
-?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/cache/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/delete.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,199 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('dl_start')) ? eval($hook) : null;
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+
+// Load the delete.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/delete.php';
+
+
+$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
+if ($id < 1)
+	message($lang_common['Bad request']);
+
+
+// Fetch some info about the post, the topic and the forum
+$query = array(
+	'SELECT'	=> 'f.id AS fid, f.forum_name, f.moderators, f.redirect_url, fp.post_replies, fp.post_topics, t.id AS tid, t.subject, t.posted, t.first_post_id, t.closed, p.poster, p.poster_id, p.message, p.hide_smilies',
+	'FROM'		=> 'posts AS p',
+	'JOINS'		=> array(
+		array(
+			'INNER JOIN'	=> 'topics AS t',
+			'ON'			=> 't.id=p.topic_id'
+		),
+		array(
+			'INNER JOIN'	=> 'forums AS f',
+			'ON'			=> 'f.id=t.forum_id'
+		),
+		array(
+			'LEFT JOIN'		=> 'forum_perms AS fp',
+			'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+		)
+	),
+	'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND p.id='.$id
+);
+
+($hook = get_hook('dl_qr_get_post_info')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+if (!$pun_db->num_rows($result))
+	message($lang_common['Bad request']);
+
+$cur_post = $pun_db->fetch_assoc($result);
+
+// Sort out who the moderators are and if we are currently a moderator (or an admin)
+$mods_array = ($cur_post['moderators'] != '') ? unserialize($cur_post['moderators']) : array();
+$pun_user['is_admmod'] = ($session->user_level >= USER_LEVEL_ADMIN || ($pun_user['g_moderator'] == '1' && array_key_exists($pun_user['username'], $mods_array))) ? true : false;
+
+$cur_post['is_topic'] = ($id == $cur_post['first_post_id']) ? true : false;
+
+// Do we have permission to delete this post?
+if (($pun_user['g_delete_posts'] == '0' ||
+	($pun_user['g_delete_topics'] == '0' && $cur_post['is_topic']) ||
+	$cur_post['poster_id'] != $pun_user['id'] ||
+	$cur_post['closed'] == '1') &&
+	!$pun_user['is_admmod'])
+	message($lang_common['No permission']);
+
+
+// User pressed the cancel button
+if (isset($_POST['cancel']))
+	pun_redirect(pun_link($pun_url['post'], $id), $lang_common['Cancel redirect']);
+
+// User pressed the delete button
+else if (isset($_POST['delete']))
+{
+	($hook = get_hook('dl_form_submitted')) ? eval($hook) : null;
+
+	if (isset($_POST['req_confirm']))
+	{
+		if ($cur_post['is_topic'])
+		{
+			// Delete the topic and all of it's posts
+			delete_topic($cur_post['tid'], $cur_post['fid']);
+
+			pun_redirect(pun_link($pun_url['forum'], $cur_post['fid']), $lang_delete['Topic del redirect']);
+		}
+		else
+		{
+			// Delete just this one post
+			delete_post($id, $cur_post['tid'], $cur_post['fid']);
+
+			pun_redirect(pun_link($pun_url['topic'], $cur_post['tid']), $lang_delete['Post del redirect']);
+		}
+	}
+	else
+		pun_redirect(pun_link($pun_url['post'], $id), $lang_common['No confirm redirect']);
+}
+
+// Run the post through the parser
+require PUN_ROOT.'include/parser.php';
+$cur_post['message'] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
+
+// Setup form
+$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+$pun_page['form_action'] = pun_link($pun_url['delete'], $id);
+
+$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+if ($pun_user['is_admmod'])
+	$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+// Setup form information
+$pun_page['frm_info'] = array(
+	'<li><span><strong>'.$lang_common['Forum'].':</strong> '.htmlspecialchars($cur_post['forum_name']).'</span></li>',
+	'<li><span><strong>'.$lang_common['Topic'].':</strong> '.htmlspecialchars($cur_post['subject']).'</span></li>',
+	'<li><span>'.sprintf((($cur_post['is_topic']) ? $lang_delete['Delete topic info'] : $lang_delete['Delete post info']), $cur_post['poster'], format_time($cur_post['posted'])).'</span></li>'
+);
+
+// Setup main heading
+$pun_page['main_head'] = sprintf(($cur_post['is_topic']) ? $lang_delete['Delete topic head'] : $lang_delete['Delete post head'], $cur_post['poster'], format_time($cur_post['posted']));
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+	array($cur_post['forum_name'], pun_link($pun_url['forum'], $cur_post['fid'])),
+	array($cur_post['subject'], pun_link($pun_url['topic'], $cur_post['tid'])),
+	(($cur_post['is_topic']) ? $lang_delete['Delete topic'] : $lang_delete['Delete post'])
+);
+
+($hook = get_hook('dl_pre_header_load')) ? eval($hook) : null;
+
+define ('PUN_PAGE', 'postdelete');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $pun_page['main_head'] ?></span></h2>
+	</div>
+	<div class="main-content frm">
+		<div class="frm-info">
+			<ul>
+				<?php echo implode("\n\t\t\t\t", $pun_page['frm_info'])."\n" ?>
+			</ul>
+		</div>
+		<div class="post-entry">
+			<div class="entry-content">
+				<?php echo $cur_post['message']."\n" ?>
+			</div>
+		</div>
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_delete['Delete post'] ?></strong></legend>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_common['Please confirm'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_confirm" value="1" checked="checked" /> <?php printf(((($cur_post['is_topic'])) ? $lang_delete['Delete topic head'] : $lang_delete['Delete post head']), $cur_post['poster'], format_time($cur_post['posted'])) ?>.</label>
+				</div>
+			</fieldset>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="delete" value="<?php echo $lang_delete['Delete'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+($hook = get_hook('dl_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/edit.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,361 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('ed_start')) ? eval($hook) : null;
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+
+// Load the post.php/edit.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/post.php';
+
+
+$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
+if ($id < 1)
+	message($lang_common['Bad request']);
+
+
+// Fetch some info about the post, the topic and the forum
+$query = array(
+	'SELECT'	=> 'f.id AS fid, f.forum_name, f.moderators, f.redirect_url, fp.post_replies, fp.post_topics, t.id AS tid, t.subject, t.posted, t.first_post_id, t.closed, p.poster, p.poster_id, p.message, p.hide_smilies',
+	'FROM'		=> 'posts AS p',
+	'JOINS'		=> array(
+		array(
+			'INNER JOIN'	=> 'topics AS t',
+			'ON'			=> 't.id=p.topic_id'
+		),
+		array(
+			'INNER JOIN'	=> 'forums AS f',
+			'ON'			=> 'f.id=t.forum_id'
+		),
+		array(
+			'LEFT JOIN'		=> 'forum_perms AS fp',
+			'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+		)
+	),
+	'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND p.id='.$id
+);
+
+($hook = get_hook('ed_qr_get_post_info')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+if (!$pun_db->num_rows($result))
+	message($lang_common['Bad request']);
+
+$cur_post = $pun_db->fetch_assoc($result);
+
+// Sort out who the moderators are and if we are currently a moderator (or an admin)
+$mods_array = ($cur_post['moderators'] != '') ? unserialize($cur_post['moderators']) : array();
+$pun_user['is_admmod'] = ($session->user_level >= USER_LEVEL_ADMIN || ($pun_user['g_moderator'] == '1' && array_key_exists($pun_user['username'], $mods_array))) ? true : false;
+
+$can_edit_subject = ($id == $cur_post['first_post_id'] && (($pun_user['g_edit_subjects_interval'] == '0' || (time() - $cur_post['posted']) < $pun_user['g_edit_subjects_interval']) || $pun_user['is_admmod'])) ? true : false;
+
+// Do we have permission to edit this post?
+if (($pun_user['g_edit_posts'] == '0' ||
+	$cur_post['poster_id'] != $pun_user['id'] ||
+	$cur_post['closed'] == '1') &&
+	!$pun_user['is_admmod'])
+	message($lang_common['No permission']);
+
+
+// Start with a clean slate
+$errors = array();
+
+if (isset($_POST['form_sent']))
+{
+	($hook = get_hook('ed_form_submitted')) ? eval($hook) : null;
+
+	// If it is a topic it must contain a subject
+	if ($can_edit_subject)
+	{
+		$subject = trim($_POST['req_subject']);
+
+		if ($subject == '')
+			$errors[] = $lang_post['No subject'];
+		else if (pun_strlen($subject) > 70)
+			$errors[] = $lang_post['Too long subject'];
+		else if ($pun_config['p_subject_all_caps'] == '0' && strtoupper($subject) == $subject && !$pun_user['is_admmod'])
+			$subject = ucwords(strtolower($subject));
+	}
+
+	// Clean up message from POST
+	$message = pun_linebreaks(trim($_POST['req_message']));
+
+	if ($message == '')
+		$errors[] = $lang_post['No message'];
+	else if (strlen($message) > 65535)
+		$errors[] = $lang_post['Too long message'];
+	else if ($pun_config['p_message_all_caps'] == '0' && strtoupper($message) == $message && !$pun_user['is_admmod'])
+		$message = ucwords(strtolower($message));
+
+	// Validate BBCode syntax
+	if ($pun_config['p_message_bbcode'] == '1' && strpos($message, '[') !== false && strpos($message, ']') !== false)
+	{
+		require PUN_ROOT.'include/parser.php';
+		$message = preparse_bbcode($message, $errors);
+	}
+
+
+	$hide_smilies = isset($_POST['hide_smilies']) ? intval($_POST['hide_smilies']) : 0;
+	if ($hide_smilies != '1') $hide_smilies = '0';
+
+	// Did everything go according to plan?
+	if (empty($errors) && !isset($_POST['preview']))
+	{
+		($hook = get_hook('ed_pre_post_edited')) ? eval($hook) : null;
+
+		if ($db_type != 'mysql' && $db_type != 'mysqli')
+			require PUN_ROOT.'include/search_idx.php';
+
+		if ($can_edit_subject)
+		{
+			// Update the topic and any redirect topics
+			$query = array(
+				'UPDATE'	=> 'topics',
+				'SET'		=> 'subject=\''.$pun_db->escape($subject).'\'',
+				'WHERE'		=> 'id='.$cur_post['tid'].' OR moved_to='.$cur_post['tid']
+			);
+
+			($hook = get_hook('ed_qr_update_subject')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			// We changed the subject, so we need to take that into account when we update the search words
+			if ($db_type != 'mysql' && $db_type != 'mysqli')
+				update_search_index('edit', $id, $message, $subject);
+		}
+		else if ($db_type != 'mysql' && $db_type != 'mysqli')
+			update_search_index('edit', $id, $message);
+
+		// Update the post
+		$query = array(
+			'UPDATE'	=> 'posts',
+			'SET'		=> 'message=\''.$pun_db->escape($message).'\', hide_smilies=\''.$hide_smilies.'\'',
+			'WHERE'		=> 'id='.$id
+		);
+
+		if (!isset($_POST['silent']) || !$pun_user['is_admmod'])
+			$query['SET'] .= ', edited='.time().', edited_by=\''.$pun_db->escape($pun_user['username']).'\'';
+
+		($hook = get_hook('ed_qr_update_post')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		pun_redirect(pun_link($pun_url['post'], $id), $lang_post['Edit redirect']);
+	}
+}
+
+// Setup error messages
+if (!empty($errors))
+{
+	$pun_page['errors'] = array();
+
+	while (list(, $cur_error) = each($errors))
+		$pun_page['errors'][] = '<li><span>'.$cur_error.'</span></li>';
+}
+
+// Setup form
+$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+$pun_page['form_action'] = pun_link($pun_url['edit'], $id);
+
+$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+if ($pun_user['is_admmod'])
+	$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+// Setup help
+$pun_page['main_head_options'] = array();
+if ($pun_config['p_message_bbcode'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'bbcode').'" title="'.sprintf($lang_common['Help page'], $lang_common['BBCode']).'">'.$lang_common['BBCode'].'</a>';
+if ($pun_config['p_message_img_tag'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'img').'" title="'.sprintf($lang_common['Help page'], $lang_common['Images']).'">'.$lang_common['Images'].'</a>';
+if ($pun_config['o_smilies'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'smilies').'" title="'.sprintf($lang_common['Help page'], $lang_common['Smilies']).'">'.$lang_common['Smilies'].'</a>';
+
+// Setup main heading
+$pun_page['main_head'] = sprintf($lang_post['Edit this'], (($id == $cur_post['first_post_id']) ? $lang_post['Topic'] : $lang_post['Reply']), $cur_post['poster']);
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+	array($cur_post['forum_name'], pun_link($pun_url['forum'], $cur_post['fid'])),
+	array($cur_post['subject'], pun_link($pun_url['topic'], $cur_post['tid'])),
+	$lang_post['Edit post']
+);
+
+($hook = get_hook('ed_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_PAGE', 'postedit');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+<?php
+
+// If preview selected and there are no errors
+if (isset($_POST['preview']) && empty($pun_page['errors']))
+{
+	require_once PUN_ROOT.'include/parser.php';
+	$pun_page['preview_message'] = parse_message(trim($_POST['req_message']), $hide_smilies);
+
+?>
+	<div class="main-head">
+		<h2><span><?php echo $lang_post['Preview reply'] ?></span></h2>
+	</div>
+
+	<div id="post-preview" class="main-content topic">
+		<div class="post firstpost">
+			<div class="postmain">
+				<div class="posthead">
+					<h3><?php echo $lang_post['Preview info'] ?></h3>
+				</div>
+				<div class="postbody">
+					<div class="user">
+						<h4 class="user-ident"><strong class="username"><?php echo $cur_post['poster'] ?></strong></h4>
+					</div>
+					<div class="post-entry">
+						<div class="entry-content">
+						<?php echo $pun_page['preview_message']."\n" ?>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+<?php
+
+}
+
+?>
+	<div class="main-head">
+		<h2><span><?php echo $pun_page['main_head'] ?></span></h2>
+<?php if (!empty($pun_page['main_head_options'])): ?>		<p class="main-options"><?php printf($lang_common['You may use'], implode(' ', $pun_page['main_head_options'])) ?></p>
+<?php endif; ?>	</div>
+
+	<div class="main-content frm">
+<?php
+
+// If there were any errors, show them
+if (isset($pun_page['errors']))
+{
+
+?>
+		<div class="frm-error">
+			<h3 class="warn"><?php echo $lang_post['Post errors'] ?></h3>
+			<ul>
+				<?php echo implode("\n\t\t\t\t\t", $pun_page['errors'])."\n" ?>
+			</ul>
+		</div>
+<?php
+
+}
+
+?>
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('ed_pre_main_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_post['Edit post legend'] ?></strong></legend>
+<?php if ($can_edit_subject): ?>				<div class="frm-fld text longtext required">
+					<label for="fld<?php echo ++ $pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_post['Topic subject'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="req_subject" size="80" maxlength="70" value="<?php echo htmlspecialchars(isset($_POST['req_subject']) ? $_POST['req_subject'] : $cur_post['subject']) ?>" /></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+<?php endif; ($hook = get_hook('ed_pre_message_box')) ? eval($hook) : null; ?>				<div class="frm-fld text textarea required">
+					<label for="fld<?php echo ++ $pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_post['Write message'] ?></span><br />
+						<span class="fld-input"><textarea id="fld<?php echo $pun_page['fld_count'] ?>" name="req_message" rows="14" cols="95"><?php echo htmlspecialchars(isset($_POST['req_message']) ? $message : $cur_post['message']) ?></textarea></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+			</fieldset>
+<?php
+
+$pun_page['checkboxes'] = array();
+if ($pun_config['o_smilies'] == '1')
+{
+	if (isset($_POST['hide_smilies']) || $cur_post['hide_smilies'] == '1')
+		$pun_page['checkboxes'][] = '<div class="radbox"><label for="fld'.(++$pun_page['fld_count']).'"><input type="checkbox" id="fld'.$pun_page['fld_count'].'" name="hide_smilies" value="1" checked="checked" /> '.$lang_post['Hide smilies'].'</label></div>';
+	else
+		$pun_page['checkboxes'][] = '<div class="radbox"><label for="fld'.(++$pun_page['fld_count']).'"><input type="checkbox" id="fld'.$pun_page['fld_count'].'" name="hide_smilies" value="1" /> '.$lang_post['Hide smilies'].'</label></div>';
+}
+
+if ($pun_user['is_admmod'])
+{
+	if ((isset($_POST['form_sent']) && isset($_POST['silent'])) || !isset($_POST['form_sent']))
+		$pun_page['checkboxes'][] = '<div class="radbox"><label for="fld'.(++$pun_page['fld_count']).'"><input type="checkbox" id="fld'.$pun_page['fld_count'].'" name="silent" value="1" checked="checked" /> '.$lang_post['Silent edit'].'</label></div>';
+	else
+		$pun_page['checkboxes'][] = '<div class="radbox"><label for="fld'.(++$pun_page['fld_count']).'"><input type="checkbox" id="fld'.$pun_page['fld_count'].'" name="silent" value="1" /> '.$lang_post['Silent edit'].'</label></div>';
+}
+
+($hook = get_hook('ed_pre_checkbox_display')) ? eval($hook) : null;
+
+if (!empty($pun_page['checkboxes']))
+{
+
+?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_post['Optional legend'] ?></strong></legend>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_post['Post settings'] ?></span></legend>
+					<?php echo implode("\n\t\t\t\t\t\t", $pun_page['checkboxes'])."\n"; ?>
+				</fieldset>
+			</fieldset>
+
+<?php
+
+}
+
+($hook = get_hook('ed_post_checkbox_display')) ? eval($hook) : null;
+
+?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" accesskey="s" title="<?php echo $lang_common['Submit title'] ?>" /></span>
+				<span class="submit"><input type="submit" name="preview" value="<?php echo $lang_common['Preview'] ?>" accesskey="p" title="<?php echo $lang_common['Preview title'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+($hook = get_hook('ed_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/extern.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,519 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************
+
+  INSTRUCTIONS
+
+  This script is used to include information about your board from
+  pages outside the forums and to syndicate news about recent
+  discussions via RSS/Atom/XML. The script can display a list of
+  recent discussions, a list of active users or a collection of
+  general board statistics. The script can be called directly via
+  an URL, from a PHP include command or through the use of Server
+  Side Includes (SSI).
+
+  The scripts behaviour is controlled via variables supplied in the
+  URL to the script. The different variables are: action (what to
+  do), show (how many items to display), fid (the ID or ID's of
+  the forum(s) to poll for topics), nfid (the ID or ID's of forums
+  that should be excluded), tid (the ID of the topic from which to
+  display posts) and type (output as HTML or RSS). The only
+  mandatory variable is action. Possible/default values are:
+
+    action: feed - show most recent topics/posts (HTML or RSS)
+            online - show users online (HTML)
+            online_full - as above, but includes a full list (HTML)
+            stats - show board statistics (HTML)
+
+    type:   rss - output as RSS 2.0
+            atom - output as Atom 1.0
+            xml - output as XML
+            html - output as HTML (<li>'s)
+
+    fid:    One or more forum ID's (comma-separated). If ignored,
+            topics from all guest-readable forums will be pulled.
+
+    nfid:   One or more forum ID's (comma-separated) that are to be
+            excluded. E.g. the ID of a a test forum.
+
+    tid:    A topic ID from which to show posts. If a tid is supplied,
+            fid and nfid are ignored.
+
+    show:   Any integer value between 1 and 50. This variables is
+            ignored for RSS/Atom output. The default is 15.
+
+
+/***********************************************************************/
+
+// The length at which topic subjects will be truncated (for HTML output)
+define('MAX_SUBJECT_LENGTH', 30);
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('ex_start')) ? eval($hook) : null;
+
+if ($pun_user['g_read_board'] == '0')
+	exit($lang_common['No view']);
+
+
+//
+// Converts the CDATA end sequence ]]> into ]]&gt;
+//
+function escape_cdata($str)
+{
+	return str_replace(']]>', ']]&gt;', $str);
+}
+
+
+//
+// Output $feed as RSS 2.0
+//
+function output_rss($feed)
+{
+	global $lang_common, $pun_config;
+
+	// Send XML/no cache headers
+	header('Content-Type: text/xml; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
+
+	echo '<?xml version="1.0" encoding="utf-8"?>'."\r\n";
+	echo '<rss version="2.0">'."\r\n";
+	echo "\t".'<channel>'."\r\n";
+	echo "\t\t".'<title>'.htmlspecialchars($feed['title']).'</title>'."\r\n";
+	echo "\t\t".'<link>'.$feed['link'].'</link>'."\r\n";
+	echo "\t\t".'<description>'.htmlspecialchars($feed['description']).'</description>'."\r\n";
+	echo "\t\t".'<lastBuildDate>'.gmdate('r', count($feed['items']) ? $feed['items'][0]['pubdate'] : time()).'</lastBuildDate>'."\r\n";
+
+	if ($pun_config['o_show_version'] == '1')
+		echo "\t\t".'<generator>PunBB '.$pun_config['o_cur_version'].'</generator>'."\r\n";
+	else
+		echo "\t\t".'<generator>PunBB</generator>'."\r\n";
+
+	$num_items = count($feed['items']);
+	for ($i = 0; $i < $num_items; ++$i)
+	{
+		echo "\t\t".'<item>'."\r\n";
+		echo "\t\t\t".'<title>'.htmlspecialchars($feed['items'][$i]['title']).'</title>'."\r\n";
+		echo "\t\t\t".'<link>'.$feed['items'][$i]['link'].'</link>'."\r\n";
+		echo "\t\t\t".'<description>'.htmlspecialchars($feed['items'][$i]['description']).'</description>'."\r\n";
+		echo "\t\t\t".'<author>dummy@email.com ('.htmlspecialchars($feed['items'][$i]['author']).')</author>'."\r\n";
+		echo "\t\t\t".'<pubDate>'.gmdate('r', $feed['items'][$i]['pubdate']).'</pubDate>'."\r\n";
+		echo "\t\t\t".'<guid>'.$feed['items'][$i]['link'].'</guid>'."\r\n";
+		echo "\t\t".'</item>'."\r\n";
+	}
+
+	echo "\t".'</channel>'."\r\n";
+	echo '</rss>'."\r\n";
+}
+
+
+//
+// Output $feed as Atom 1.0
+//
+function output_atom($feed)
+{
+	global $lang_common, $pun_config;
+
+	// Send XML/no cache headers
+	header('Content-Type: text/xml; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
+
+	echo '<?xml version="1.0" encoding="utf-8"?>'."\r\n";
+	echo '<feed xmlns="http://www.w3.org/2005/Atom">'."\r\n";
+
+	echo "\t".'<title type="html">'.htmlspecialchars($feed['title']).'</title>'."\r\n";
+	echo "\t".'<link rel="self" href="'.htmlspecialchars($_SERVER['SCRIPT_NAME'].($_SERVER['QUERY_STRING'] != '' ? '?'.$_SERVER['QUERY_STRING'] :'')).'"/>'."\r\n";
+	echo "\t".'<updated>'.gmdate('Y-m-d\TH:i:s\Z', $feed['items'][0]['pubdate']).'</updated>'."\r\n";
+
+	if ($pun_config['o_show_version'] == '1')
+		echo "\t".'<generator version="'.$pun_config['o_cur_version'].'">PunBB</generator>'."\r\n";
+	else
+		echo "\t".'<generator>PunBB</generator>'."\r\n";
+
+	echo "\t".'<id>'.$feed['link'].'</id>'."\r\n";
+
+	$content_tag = ($feed['type'] == 'posts') ? 'content' : 'summary';
+
+	$num_items = count($feed['items']);
+	for ($i = 0; $i < $num_items; ++$i)
+	{
+		echo "\t\t".'<entry>'."\r\n";
+		echo "\t\t\t".'<title type="html">'.htmlspecialchars($feed['items'][$i]['title']).'</title>'."\r\n";
+		echo "\t\t\t".'<link rel="alternate" href="'.$feed['items'][$i]['link'].'"/>'."\r\n";
+		echo "\t\t\t".'<'.$content_tag.' type="html">'.htmlspecialchars($feed['items'][$i]['description']).'</'.$content_tag.'>'."\r\n";
+		echo "\t\t\t".'<author>'."\r\n";
+		echo "\t\t\t\t".'<name>'.htmlspecialchars($feed['items'][$i]['author']).'</name>'."\r\n";
+		echo "\t\t\t".'</author>'."\r\n";
+		echo "\t\t\t".'<updated>'.gmdate('Y-m-d\TH:i:s\Z', $feed['items'][$i]['pubdate']).'</updated>'."\r\n";
+		echo "\t\t\t".'<id>'.$feed['items'][$i]['link'].'</id>'."\r\n";
+		echo "\t\t".'</entry>'."\r\n";
+	}
+
+	echo '</feed>'."\r\n";
+}
+
+
+//
+// Output $feed as XML
+//
+function output_xml($feed)
+{
+	global $lang_common, $pun_config;
+
+	// Send XML/no cache headers
+	header('Content-Type: text/xml; charset=utf-8');
+	header('Expires: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+	header('Pragma: public');
+
+	echo '<?xml version="1.0" encoding="utf-8"?>'."\r\n";
+	echo '<source>'."\r\n";
+	echo "\t".'<url>'.$feed['link'].'</url>'."\r\n";
+
+	$pun_tag = ($feed['type'] == 'posts') ? 'post' : 'topic';
+
+	$num_items = count($feed['items']);
+	for ($i = 0; $i < $num_items; ++$i)
+	{
+		echo "\t".'<'.$pun_tag.' id="'.$feed['items'][$i]['id'].'">'."\r\n";
+
+		echo "\t\t".'<title>'.htmlspecialchars($feed['items'][$i]['title']).'</title>'."\r\n";
+		echo "\t\t".'<link>'.$feed['items'][$i]['link'].'</link>'."\r\n";
+		echo "\t\t".'<content>'.htmlspecialchars($feed['items'][$i]['description']).'</content>'."\r\n";
+		echo "\t\t".'<author>'.htmlspecialchars($feed['items'][$i]['author']).'</author>'."\r\n";
+		echo "\t\t".'<posted>'.gmdate('r', $feed['items'][$i]['pubdate']).'</posted>'."\r\n";
+
+		echo "\t".'</'.$pun_tag.'>'."\r\n";
+	}
+
+	echo '</source>'."\r\n";
+}
+
+
+//
+// Output $feed as HTML (using <li> tags)
+//
+function output_html($feed)
+{
+	global $pun_config;
+
+	$num_items = count($feed['items']);
+	for ($i = 0; $i < $num_items; ++$i)
+	{
+		if ($pun_config['o_censoring'] == '1')
+			$feed['items'][$i]['title'] = censor_words($feed['items'][$i]['title']);
+
+		if (pun_strlen($feed['items'][$i]['title']) > MAX_SUBJECT_LENGTH)
+			$subject_truncated = htmlspecialchars(trim(substr($feed['items'][$i]['title'], 0, (MAX_SUBJECT_LENGTH-5)))).' …';
+		else
+			$subject_truncated = htmlspecialchars($feed['items'][$i]['title']);
+
+		echo '<li><a href="'.$feed['items'][$i]['link'].'" title="'.htmlspecialchars($feed['items'][$i]['title']).'">'.$subject_truncated.'</a></li>'."\n";
+	}
+}
+
+
+//
+// Show recent discussions
+//
+if ($_GET['action'] == 'feed')
+{
+	// Determine what type of feed to output
+	$type = 'html';
+	if (isset($_GET['type']) && is_scalar($_GET['type']))
+	{
+		if (strtolower($_GET['type']) == 'rss')
+			$type = 'rss';
+		else if (strtolower($_GET['type']) == 'atom')
+			$type = 'atom';
+		else if (strtolower($_GET['type']) == 'xml')
+			$type = 'xml';
+	}
+
+	$forum_sql = '';
+
+	// Was a topic ID supplied?
+	if (isset($_GET['tid']))
+	{
+		$tid = intval($_GET['tid']);
+
+		// Fetch topic subject
+		$query = array(
+			'SELECT'	=> 't.subject, t.num_replies',
+			'FROM'		=> 'topics AS t',
+			'JOINS'		=> array(
+				array(
+					'LEFT JOIN'		=> 'forum_perms AS fp',
+					'ON'			=> '(fp.forum_id=t.forum_id AND fp.group_id=2)'
+				)
+			),
+			'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND t.moved_to IS NULL and t.id='.$tid
+		);
+
+		($hook = get_hook('ex_qr_get_topic_data')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if (!$pun_db->num_rows($result))
+			exit('Bad request. The link you followed is incorrect or outdated.');
+
+		$cur_topic = $pun_db->fetch_assoc($result);
+
+		if ($pun_config['o_censoring'] == '1')
+			$cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+		// Setup the feed
+		$feed = array(
+			'title' 		=>	$pun_config['o_board_title'].' - '.$cur_topic['subject'],
+			'link'			=>	pun_link($pun_url['topic'], $tid),
+			'description'	=>	sprintf($lang_common['RSS description topic'], $cur_topic['subject']),
+			'items'			=>	array(),
+			'type'			=>	'posts'
+		);
+
+		// Fetch 15 posts
+		$query = array(
+			'SELECT'	=> 'p.id, p.poster, p.message, p.posted',
+			'FROM'		=> 'posts AS p',
+			'WHERE'		=> 'p.topic_id='.$tid,
+			'ORDER BY'	=> 'p.posted DESC',
+			'LIMIT'		=> '15'
+		);
+
+		($hook = get_hook('ex_qr_get_posts')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+		while ($cur_post = $pun_db->fetch_assoc($result))
+		{
+			$feed['items'][] = array(
+				'id'			=>	$cur_post['id'],
+				'title'			=>	$lang_common['RSS reply'].$cur_topic['subject'],
+				'link'			=>	pun_link($pun_url['post'], $cur_post['id']),
+				'description'	=>	$cur_post['message'],
+				'author'		=>	$cur_post['poster'],
+				'pubdate'		=>	$cur_post['posted']
+			);
+		}
+
+		if (intval($cur_topic['num_replies']) <= 14)
+			$feed['items'][count($feed['items'])-1]['title'] = $cur_topic['subject'];
+
+		($hook = get_hook('ex_pre_topic_output')) ? eval($hook) : null;
+
+		$output_func = 'output_'.$type;
+		$output_func($feed);
+	}
+	else
+	{
+		// Was any specific forum ID's supplied?
+		if (isset($_GET['fid']) && is_scalar($_GET['fid']) && $_GET['fid'] != '')
+		{
+			$fids = explode(',', trim($_GET['fid']));
+			$fids = array_map('intval', $fids);
+
+			if (!empty($fids))
+				$forum_sql = ' AND f.id IN('.implode(',', $fids).')';
+		}
+
+		// Any forum ID's to exclude?
+		if (isset($_GET['nfid']) && is_scalar($_GET['nfid']) && $_GET['nfid'] != '')
+		{
+			$nfids = explode(',', trim($_GET['nfid']));
+			$nfids = array_map('intval', $nfids);
+
+			if (!empty($nfids))
+				$forum_sql = ' AND f.id NOT IN('.implode(',', $nfids).')';
+		}
+
+		// Setup the feed
+		$feed = array(
+			'title' 		=>	$pun_config['o_board_title'],
+			'link'			=>	pun_link($pun_url['index']),
+			'description'	=>	sprintf($lang_common['RSS description'], $pun_config['o_board_title']),
+			'items'			=>	array(),
+			'type'			=>	'topics'
+		);
+
+
+		if (isset($_GET['type']) && is_scalar($_GET['type']) && strtoupper($_GET['type']) == 'RSS')
+			$show = 15;
+		else
+		{
+			$show = isset($_GET['show']) ? intval($_GET['show']) : 15;
+			if ($show < 1 || $show > 50)
+				$show = 15;
+		}
+
+		// Fetch $show topics
+		$query = array(
+			'SELECT'	=> 't.id, t.poster, t.subject, t.last_post, t.last_poster, f.id AS fid, f.forum_name',
+			'FROM'		=> 'topics AS t',
+			'JOINS'		=> array(
+				array(
+					'INNER JOIN'	=> 'forums AS f',
+					'ON'			=> 'f.id=t.forum_id'
+				),
+				array(
+					'LEFT JOIN'		=> 'forum_perms AS fp',
+					'ON'			=> '(fp.forum_id=f.id AND fp.group_id=2)'
+				)
+			),
+			'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND t.moved_to IS NULL',
+			'ORDER BY'	=> 't.last_post DESC',
+			'LIMIT'		=> $show
+		);
+
+		if (isset($forum_sql))
+			$query['WHERE'] .= $forum_sql;
+
+		($hook = get_hook('ex_qr_get_topics')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+		while ($cur_topic = $pun_db->fetch_assoc($result))
+		{
+			if ($pun_config['o_censoring'] == '1')
+				$cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+			$feed['items'][] = array(
+				'id'			=>	$cur_topic['id'],
+				'title'			=>	$cur_topic['subject'],
+				'link'			=>	pun_link($pun_url['topic_new_posts'], $cur_topic['id']),
+				'description'	=>	$lang_common['Forum'].': <a href="'.pun_link($pun_url['forum'], $cur_topic['fid']).'">'.$cur_topic['forum_name'].'</a>',
+				'author'		=>	$cur_topic['last_poster'],
+				'pubdate'		=>	$cur_topic['last_post']
+			);
+		}
+
+		($hook = get_hook('ex_pre_forum_output')) ? eval($hook) : null;
+
+		$output_func = 'output_'.$type;
+		$output_func($feed);
+	}
+
+	return;
+}
+
+
+//
+// Show users online
+//
+else if ($_GET['action'] == 'online' || $_GET['action'] == 'online_full')
+{
+	// Load the index.php language file
+	require PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/index.php';
+
+	// Fetch users online info and generate strings for output
+	$num_guests = $num_users = 0;
+	$users = array();
+
+	$query = array(
+		'SELECT'	=> 'o.user_id, o.ident',
+		'FROM'		=> 'online AS o',
+		'WHERE'		=> 'o.idle=0',
+		'ORDER BY'	=> 'o.ident'
+	);
+
+	($hook = get_hook('ex_qr_get_users_online')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+	while ($pun_user_online = $pun_db->fetch_assoc($result))
+	{
+		if ($pun_user_online['user_id'] > 1)
+		{
+			$users[] = '<a href="'.pun_link($pun_url['user'], $pun_user_online['user_id']).'">'.htmlspecialchars($pun_user_online['ident']).'</a>';
+			++$num_users;
+		}
+		else
+			++$num_guests;
+	}
+
+	echo $lang_index['Guests online'].': '.$num_guests.'<br />';
+
+	if ($_GET['action'] == 'online_full')
+		echo $lang_index['Users online'].': '.implode(', ', $users).'<br />';
+	else
+		echo $lang_index['Users online'].': '.$num_users.'<br />';
+
+	return;
+}
+
+
+//
+// Show board statistics
+//
+else if ($_GET['action'] == 'stats')
+{
+	// Load the index.php language file
+	require PUN_ROOT.'lang/'.$pun_config['o_default_lang'].'/index.php';
+
+	// Collect some statistics from the database
+	$query = array(
+		'SELECT'	=> 'COUNT(u.id)-1',
+		'FROM'		=> 'users AS u'
+	);
+
+	($hook = get_hook('ex_qr_get_user_count')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$stats['total_users'] = $pun_db->result($result);
+
+	$query = array(
+		'SELECT'	=> 'u.id, u.username',
+		'FROM'		=> 'users AS u',
+		'ORDER BY'	=> 'u.registered DESC',
+		'LIMIT'		=> '1'
+	);
+
+	($hook = get_hook('ex_qr_get_newest_user')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$stats['last_user'] = $pun_db->fetch_assoc($result);
+
+	$query = array(
+		'SELECT'	=> 'SUM(f.num_topics), SUM(f.num_posts)',
+		'FROM'		=> 'forums AS f'
+	);
+
+	($hook = get_hook('ex_qr_get_post_stats')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	list($stats['total_topics'], $stats['total_posts']) = $pun_db->fetch_row($result);
+
+	echo $lang_index['No of users'].': '.$stats['total_users'].'<br />';
+	echo $lang_index['Newest user'].': <a href="'.pun_link($pun_url['user'], $stats['last_user']['id']).'">'.htmlspecialchars($stats['last_user']['username']).'</a><br />';
+	echo $lang_index['No of topics'].': '.intval($stats['total_topics']).'<br />';
+	echo $lang_index['No of posts'].': '.intval($stats['total_posts']);
+
+	return;
+}
+
+
+($hook = get_hook('ex_new_action')) ? eval($hook) : null;
+
+// If we end up here, the script was called with some wacky parameters
+exit($lang_common['Bad request']);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/footer.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,221 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
+
+($hook = get_hook('ft_pun_main_end')) ? eval($hook) : null;
+
+$tpl_temp = trim(ob_get_contents());
+$tpl_main = str_replace('<!-- pun_main -->', $tpl_temp, $tpl_main);
+ob_end_clean();
+// END SUBST - <!-- pun_main -->
+
+
+// START SUBST - <!-- pun_stats -->
+if (PUN_PAGE == 'index')
+{
+	ob_start();
+
+	// Collect some statistics from the database
+	$query = array(
+		'SELECT'	=> 'COUNT(u.id)-1',
+		'FROM'		=> 'users AS u'
+	);
+
+	($hook = get_hook('ft_qr_get_user_count')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$stats['total_users'] = $pun_db->result($result);
+
+	$query = array(
+		'SELECT'	=> 'u.id, u.username',
+		'FROM'		=> 'users AS u',
+		'ORDER BY'	=> 'u.registered DESC',
+		'LIMIT'		=> '1'
+	);
+
+	($hook = get_hook('ft_qr_get_newest_user')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$stats['last_user'] = $pun_db->fetch_assoc($result);
+
+	$query = array(
+		'SELECT'	=> 'SUM(f.num_topics), SUM(f.num_posts)',
+		'FROM'		=> 'forums AS f'
+	);
+
+	($hook = get_hook('ft_qr_get_post_stats')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	list($stats['total_topics'], $stats['total_posts']) = $pun_db->fetch_row($result);
+
+	$stats_list[] = '<li class="st-users"><span>'.$lang_index['No of users'].':</span> <strong>'. $stats['total_users'].'</strong></li>';
+	$stats_list[] = '<li class="st-users"><span>'.$lang_index['Newest user'].':</span> <strong><a href="'.pun_link($pun_url['user'], $stats['last_user']['id']).'">'.htmlspecialchars($stats['last_user']['username']).'</a></strong></li>';
+	$stats_list[] = '<li class="st-activity"><span>'.$lang_index['No of topics'].':</span> <strong>'.intval($stats['total_topics']).'</strong></li>';
+	$stats_list[] = '<li class="st-activity"><span>'.$lang_index['No of posts'].':</span> <strong>'.intval($stats['total_posts']).'</strong></li>';
+
+?>
+<div id="pun-info" class="main">
+	<div class="main-head">
+		<h2><span><?php echo $lang_index['Forum information'] ?></span></h2>
+	</div>
+	<div class="main-content">
+		<div id="stats">
+			<h3><?php echo $lang_index['Statistics'] ?></h3>
+			<ul>
+				<?php echo implode("\n\t\t\t\t", $stats_list)."\n" ?>
+			</ul>
+		</div>
+<?php
+
+	if ($pun_config['o_users_online'] == '1')
+	{
+		// Fetch users online info and generate strings for output
+		$query = array(
+			'SELECT'	=> 'o.user_id, o.ident',
+			'FROM'		=> 'online AS o',
+			'WHERE'		=> 'o.idle=0',
+			'ORDER BY'	=> 'o.ident'
+		);
+
+		$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+		$num_guests = 0;
+		$users = array();
+
+		while ($pun_user_online = $pun_db->fetch_assoc($result))
+		{
+			if ($pun_user_online['user_id'] > 1)
+				$users[] = '<a href="'.pun_link($pun_url['user'], $pun_user_online['user_id']).'">'.htmlspecialchars($pun_user_online['ident']).'</a>';
+			else
+				++$num_guests;
+		}
+
+?>
+		<div id="onlinelist">
+			<h3><?php printf($lang_index['Online'], $num_guests, count($users)) ?></h3>
+<?php
+
+		// If there are registered users logged in, list them
+		if (count($users) > 0)
+			echo "\t\t\t".'<p>'.implode(', ', $users).'</p>'."\n";
+
+?>
+		</div>
+<?php
+
+	}
+
+?>
+	</div>
+</div>
+<?php
+
+	$tpl_temp = trim(ob_get_contents());
+	$tpl_main = str_replace('<!-- pun_stats -->', $tpl_temp, $tpl_main);
+	ob_end_clean();
+}
+// END SUBST - <!-- pun_stats -->
+
+
+// START SUBST - <!-- pun_about -->
+ob_start();
+
+?>
+<div id="pun-about">
+<?php
+
+// Display the "Jump to" drop list
+if ($pun_config['o_quickjump'] == '1')
+{
+	// Load cached quickjump
+	if (file_exists(PUN_CACHE_DIR.'cache_quickjump_'.$pun_user['g_id'].'.php'))
+		include PUN_CACHE_DIR.'cache_quickjump_'.$pun_user['g_id'].'.php';
+
+	if (!defined('PUN_QJ_LOADED'))
+	{
+		require_once PUN_ROOT.'include/cache.php';
+		generate_quickjump_cache($pun_user['g_id']);
+		require PUN_CACHE_DIR.'cache_quickjump_'.$pun_user['g_id'].'.php';
+	}
+}
+
+
+// End the transaction
+$pun_db->end_transaction();
+
+?>
+	<p id="copyright">Powered by <strong><a href="http://punbb.org/">PunBB</a><?php if ($pun_config['o_show_version'] == '1') echo ' '.$pun_config['o_cur_version']; ?></strong></p>
+<?php
+
+($hook = get_hook('ft_about_info_extra')) ? eval($hook) : null;
+
+// Display debug info (if enabled/defined)
+if (defined('PUN_DEBUG'))
+{
+	// Calculate script generation time
+	list($usec, $sec) = explode(' ', microtime());
+	$time_diff = sprintf('%.3f', ((float)$usec + (float)$sec) - $pun_start);
+	echo "\t".'<p id="querytime">[ Generated in '.$time_diff.' seconds, '.$pun_db->get_num_queries().' queries executed ]</p>'."\n";
+}
+echo '</div>'."\n";
+
+$tpl_temp = trim(ob_get_contents());
+$tpl_main = str_replace('<!-- pun_about -->', $tpl_temp, $tpl_main);
+ob_end_clean();
+// END SUBST - <!-- pun_about -->
+
+
+// START SUBST - <!-- pun_debug -->
+if (defined('PUN_SHOW_QUERIES'))
+	$tpl_main = str_replace('<!-- pun_debug -->', get_saved_queries(), $tpl_main);
+// END SUBST - <!-- pun_debug -->
+
+
+// START SUBST - <!-- pun_include "*" -->
+while (preg_match('#<!-- ?pun_include "([^/\\\\]*?)" ?-->#', $tpl_main, $cur_include))
+{
+	if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1]))
+		error('Unable to process user include &lt;!-- pun_include "'.htmlspecialchars($cur_include[1]).'" --&gt; from template main.tpl. There is no such file in folder /include/user/', __FILE__, __LINE__);
+
+	ob_start();
+	include PUN_ROOT.'include/user/'.$cur_include[1];
+	$tpl_temp = ob_get_contents();
+	$tpl_main = str_replace($cur_include[0], $tpl_temp, $tpl_main);
+	ob_end_clean();
+}
+// END SUBST - <!-- pun_include "*" -->
+
+
+// Last call!
+($hook = get_hook('ft_end')) ? eval($hook) : null;
+
+
+// Close the db connection (and free up any result data)
+$pun_db->close();
+
+// Spit out the page
+global $template;
+$template->header();
+echo($tpl_main);
+$template->footer();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/header.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,276 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
+
+// Send no-cache headers
+header('Expires: Thu, 21 Jul 1977 07:30:00 GMT');	// When yours truly first set eyes on this world! :)
+header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
+header('Cache-Control: post-check=0, pre-check=0', false);
+header('Pragma: no-cache');		// For HTTP/1.0 compability
+
+// Send the Content-type header in case the web server is setup to send something else
+header('Content-type: text/html; charset=utf-8');
+
+// Load the main template
+if (substr(PUN_PAGE, 0, 5) == 'admin')
+{
+	if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/admin.tpl'))
+		$tpl_main = file_get_contents(PUN_ROOT.'style/'.$pun_user['style'].'/admin.tpl');
+	else
+		$tpl_main = file_get_contents(PUN_ROOT.'include/template/admin.tpl');
+}
+else if (PUN_PAGE == 'help')
+	$tpl_main = file_get_contents(PUN_ROOT.'include/template/help.tpl');
+else
+{
+	if (file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/main.tpl'))
+		$tpl_main = file_get_contents(PUN_ROOT.'style/'.$pun_user['style'].'/main.tpl');
+	else
+		$tpl_main = file_get_contents(PUN_ROOT.'include/template/main.tpl');
+}
+
+($hook = get_hook('hd_template_loaded')) ? eval($hook) : null;
+
+
+// START SUBST - <!-- pun_local -->
+$tpl_main = str_replace('<!-- pun_local -->', 'xml:lang="'.$lang_common['lang_identifier'].'" lang="'.$lang_common['lang_identifier'].'" dir="'.$lang_common['lang_direction'].'"', $tpl_main);
+// END SUBST - <!-- pun_local -->
+
+
+// START SUBST - <!-- pun_head -->
+ob_start();
+
+// Is this a page that we want search index spiders to index?
+if (!defined('PUN_ALLOW_INDEX'))
+	echo '<meta name="ROBOTS" content="NOINDEX, FOLLOW" />'."\n";
+else
+	echo '<meta name="description" content="'.generate_crumbs(true).'" />'."\n";
+
+// Should we output a MicroID? http://microid.org/
+if (strpos(PUN_PAGE, 'profile') === 0)
+	echo '<meta name="microid" content="mailto+http:sha1:'.sha1(sha1('mailto:'.$user['email']).sha1(pun_link($pun_url['user'], $id))).'" />'."\n";
+
+?>
+<title><?php echo generate_crumbs(true) ?></title>
+<?php
+
+// Should we output feed links?
+if (PUN_PAGE == 'viewtopic')
+{
+	echo '<link rel="alternate" type="application/rss+xml" href="'.pun_link($pun_url['topic_rss'], $id).'" title="'.$lang_common['RSS Feed'].'" />'."\n";
+	echo '<link rel="alternate" type="application/atom+xml" href="'.pun_link($pun_url['topic_atom'], $id).'" title="'.$lang_common['ATOM Feed'].'" />'."\n";
+}
+else if (PUN_PAGE == 'viewforum')
+{
+	echo '<link rel="alternate" type="application/rss+xml" href="'.pun_link($pun_url['forum_rss'], $id).'" title="RSS" />'."\n";
+	echo '<link rel="alternate" type="application/atom+xml" href="'.pun_link($pun_url['forum_atom'], $id).'" title="ATOM" />'."\n";
+}
+
+?>
+<link rel="top" href="<?php echo $base_url ?>" title="<?php echo $lang_common['Forum index'] ?>" />
+<?php
+
+// If there are more than two breadcrumbs, add the "up" link (second last)
+if (count($pun_page['crumbs']) > 2)
+	echo '<link rel="up" href="'.$pun_page['crumbs'][count($pun_page['crumbs']) - 2][1].'" title="'.htmlspecialchars($pun_page['crumbs'][count($pun_page['crumbs']) - 2][0]).'" />'."\n";
+
+// If there are other page navigation links (first, next, prev and last)
+if (!empty($pun_page['nav']))
+	echo implode("\n", $pun_page['nav'])."\n";
+
+?>
+<link rel="search" href="<?php echo pun_link($pun_url['search']) ?>" title="<?php echo $lang_common['Search'] ?>" />
+<link rel="author" href="<?php echo pun_link($pun_url['users']) ?>" title="<?php echo $lang_common['User list'] ?>" />
+<?php
+
+// Include stylesheets
+	require PUN_ROOT.'style/'.$pun_user['style'].'/'.$pun_user['style'].'.php';
+
+?>
+<script type="text/javascript" src="<?php echo $base_url ?>/include/js/common.js"></script>
+
+<!-- ugly style override for oxygen -->
+<style type="text/css">
+div.pun-page ul li {
+  list-style-image: none !important;
+  list-style-type: none !important;
+}
+div.pun-page h2 {
+  border-bottom-width: 0 !important;
+}
+</style>
+
+<?php
+
+($hook = get_hook('hd_'.PUN_PAGE.'_head')) ? eval($hook) : null;
+
+($hook = get_hook('hd_head')) ? eval($hook) : null;
+
+$tpl_temp = trim(ob_get_contents());
+$template->add_header($tpl_temp);
+ob_end_clean();
+// END SUBST - <!-- pun_head -->
+
+
+// START SUBST - <!-- pun_page -->
+$tpl_main = str_replace('<!-- pun_page -->', 'id="pun-'.PUN_PAGE.'"', $tpl_main);
+// END SUBST - <!-- pun_page -->
+
+
+// START SUBST - <!-- pun_skip -->
+$tpl_main = str_replace('<!-- pun_skip -->', '<div id="pun-access"><a href="#pun-main">'.$lang_common['Skip to content'].'</a></div>'."\n", $tpl_main);
+// END SUBST - <!-- pun_skip -->
+
+// START SUBST - <!-- pun_title -->
+$tpl_main = str_replace('<!-- pun_title -->', '<div id="pun-title">'."\n\t".'<div><strong>'.htmlspecialchars($pun_config['o_board_title']).'</strong></div>'."\n".'</div>'."\n", $tpl_main);
+// END SUBST - <!-- pun_title -->
+
+
+// START SUBST - <!-- pun_desc -->
+if ($pun_config['o_board_desc'] != '')
+	$tpl_main = str_replace('<!-- pun_desc -->', '<div id="pun-desc">'."\n\t".'<div>'.htmlspecialchars($pun_config['o_board_desc']).'</div>'."\n".'</div>'."\n", $tpl_main);
+// END SUBST - <!-- pun_desc -->
+
+
+// START SUBST - <!-- pun_navlinks -->
+$tpl_main = str_replace('<!-- pun_navlinks -->', '<div id="pun-navlinks">'."\n\t".'<ul>'."\n\t\t".generate_navlinks()."\n\t".'</ul>'."\n".'</div>'."\n", $tpl_main);
+// END SUBST - <!-- pun_navlinks -->
+
+
+// START SUBST - <!-- pun_crumbs -->
+$tpl_main = str_replace('<!-- pun_crumbs -->', '<div id="pun-crumbs-head">'."\n\t".'<p class="crumbs">'.generate_crumbs(false).'</p>'."\n".'</div>'."\n", $tpl_main);
+// END SUBST - <!-- pun_crumbs -->
+
+
+// START SUBST - <!-- pun_visit -->
+ob_start();
+
+if ($pun_user['is_guest'])
+{
+	$visit_msg = array(
+		'<span id="vs-logged">'.$lang_common['Not logged in'].'</span>',
+		'<span id="vs-message">'.$lang_common['Login nag'].'</span>'
+	);
+}
+else
+{
+	$visit_msg = array(
+		'<span id="vs-logged">'.sprintf($lang_common['Logged in as'], '<strong>'.htmlspecialchars($pun_user['username']).'</strong>').'</span>',
+		'<span id="vs-message">'.sprintf($lang_common['Last visit'], '<strong>'.format_time($pun_user['last_visit']).'</strong>').'</span>'
+	);
+
+	$visit_links = array(
+		'<li id="vs-searchnew"><a href="'.pun_link($pun_url['search_new']).'" title="'.$lang_common['New posts info'].'">'.$lang_common['New posts'].'</a></li>',
+		'<li id="vs-markread"><a href="'.pun_link($pun_url['mark_read']).'">'.$lang_common['Mark all as read'].'</a></li>'
+	);
+
+	if ($pun_user['is_admmod'])
+	{
+		$query = array(
+			'SELECT'	=> 'COUNT(r.id)',
+			'FROM'		=> 'reports AS r',
+			'WHERE'		=> 'r.zapped IS NULL',
+		);
+
+		($hook = get_hook('hd_qr_get_unread_reports_count')) ? eval($hook) : null;
+		$result_header = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		if ($pun_db->result($result_header))
+			$visit_links[] = '<li id="vs-reports"><a href="'.pun_link($pun_url['admin_reports']).'"><strong>'.$lang_common['New reports'].'</strong></a></li>';
+	}
+}
+
+($hook = get_hook('hd_visit')) ? eval($hook) : null;
+
+?>
+<div id="pun-visit">
+<?php if (!$pun_user['is_guest']): ?>	<ul>
+		<?php echo implode("\n\t\t", $visit_links)."\n" ?>
+	</ul>
+<?php endif; ?>	<p>
+		<?php echo implode("\n\t\t", $visit_msg)."\n" ?>
+	</p>
+</div>
+<?php
+
+$tpl_temp = ob_get_contents();
+$tpl_main = str_replace('<!-- pun_visit -->', $tpl_temp, $tpl_main);
+ob_end_clean();
+// END SUBST - <!-- pun_visit -->
+
+
+// START SUBST - <!-- pun_alert -->
+$alert_items = array();
+
+if ($pun_config['o_maintenance'] == '1' && $session->user_level >= USER_LEVEL_ADMIN)
+	$alert_items[] = '<p id="maint-alert"'.(empty($alert_items) ? ' class="first-alert"' : '').'><strong>'.$lang_common['Maintenance mode'].'</strong> <span>'.$lang_common['Maintenance alert'].'</span></p>';
+
+if ($session->user_level >= USER_LEVEL_ADMIN && $pun_config['o_check_for_updates'] == '1')
+{
+	if ($pun_updates['fail'])
+		$alert_items[] = '<p id="updates-alert"'.(empty($alert_items) ? ' class="first-alert"' : '').'><strong>'.$lang_common['Updates'].'</strong> <span>'.$lang_common['Updates failed'].'</span></p>';
+	else if (isset($pun_updates['version']) && isset($pun_updates['hotfix']))
+		$alert_items[] = '<p id="updates-alert"'.(empty($alert_items) ? ' class="first-alert"' : '').'><strong>'.$lang_common['Updates'].'</strong> <span>'.sprintf($lang_common['Updates version n hf'], $pun_updates['version']).'</span></p>';
+	else if (isset($pun_updates['version']))
+		$alert_items[] = '<p id="updates-alert"'.(empty($alert_items) ? ' class="first-alert"' : '').'><strong>'.$lang_common['Updates'].'</strong> <span>'.sprintf($lang_common['Updates version'], $pun_updates['version']).'</span></p>';
+	else if (isset($pun_updates['hotfix']))
+		$alert_items[] = '<p id="updates-alert"'.(empty($alert_items) ? ' class="first-alert"' : '').'><strong>'.$lang_common['Updates'].'</strong> <span>'.$lang_common['Updates hf'].'</span></p>';
+}
+
+($hook = get_hook('hd_alert')) ? eval($hook) : null;
+
+if (!empty($alert_items))
+{
+	ob_start();
+
+?>
+<div id="pun-alert">
+	<h1 class="warn"><strong><?php echo $lang_common['Attention'] ?></strong></h1>
+	<div>
+		<?php echo implode("\n\t\t", $alert_items)."\n" ?>
+	</div>
+</div>
+<?php
+
+	$tpl_temp = ob_get_contents();
+	$tpl_main = str_replace('<!-- pun_alert -->', $tpl_temp, $tpl_main);
+	ob_end_clean();
+}
+// END SUBST - <!-- pun_alert -->
+
+
+// START SUBST - <!-- pun_announcement -->
+if ($pun_config['o_announcement'] == '1')
+	$tpl_main = str_replace('<!-- pun_announcement -->', '<div id="pun-announcement">'."\n\t".'<div class="userbox">'.($pun_config['o_announcement_heading'] != '' ? "\n\t\t".'<h2 class="msg-head">'.$pun_config['o_announcement_heading'].'</h2>' : '')."\n\t\t".$pun_config['o_announcement_message']."\n\t".'</div>'."\n".'</div>'."\n", $tpl_main);
+// END SUBST - <!-- pun_announcement -->
+
+
+// START SUBST - <!-- pun_main -->
+ob_start();
+
+define('PUN_HEADER', 1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/help.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,247 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('he_start')) ? eval($hook) : null;
+
+$section = isset($_GET['section']) ? $_GET['section'] : null;
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+
+// Load the help.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/help.php';
+
+
+$page_title = htmlspecialchars($pun_config['o_board_title']).' - '.$lang_help['Help'];
+define('PUN_PAGE', 'help');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo $lang_help['Help'] ?></span></h1>
+
+<?php
+
+if (!$section || $section == 'bbcode')
+{
+
+?>
+	<div class="main-head">
+		<h2><span><?php printf($lang_help['Help with'], $lang_common['BBCode']) ?></span></h2>
+	</div>
+	<div class="main-content frm">
+		<div class="frm-info">
+			<p><?php echo $lang_help['BBCode info 1'] ?></p>
+			<p><?php echo $lang_help['BBCode info 2'] ?></p>
+		</div>
+		<div class="frm-form">
+			<div class="frm-set set1">
+				<h3><?php echo $lang_help['Text style'] ?></h3>
+				<ul class="example">
+					<li>
+						<code>[b]<?php echo $lang_help['Bold text'] ?>[/b]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><strong><?php echo $lang_help['Bold text'] ?></strong></samp>
+					</li>
+					<li>
+						<code>[u]<?php echo $lang_help['Underlined text'] ?>[/u]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><em class="bbuline"><?php echo $lang_help['Underlined text'] ?></em></samp>
+					</li>
+					<li>
+						<code>[i]<?php echo $lang_help['Italic text'] ?>[/i]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><i><?php echo $lang_help['Italic text'] ?></i></samp>
+					</li>
+					<li>
+						<code>[color=#FF0000]<?php echo $lang_help['Red text'] ?>[/color]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><span style="color: #ff0000"><?php echo $lang_help['Red text'] ?></span></samp>
+					</li>
+					<li>
+						<code>[color=blue]<?php echo $lang_help['Blue text'] ?>[/color]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><span style="color: blue"><?php echo $lang_help['Blue text'] ?></span></samp>
+					</li>
+					<li>
+						<code>[b][u]<?php echo $lang_help['Bold, underlined text'] ?>[/u][/b]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><em class="bbuline"><b><?php echo $lang_help['Bold, underlined text'] ?></b></em></samp>
+					</li>
+				</ul>
+			</div>
+			<div class="frm-set">
+				<h3><?php echo $lang_help['Links info'] ?></h3>
+				<ul class="example">
+					<li>
+						<code>[url=<?php echo $base_url.'/' ?>]<?php echo htmlspecialchars($pun_config['o_board_title']) ?>[/url]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><a href="<?php echo $base_url.'/' ?>"><?php echo htmlspecialchars($pun_config['o_board_title']) ?></a></samp>
+					</li>
+					<li>
+						<code>[url]<?php echo $base_url.'/' ?>[/url]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><a href="<?php echo $base_url ?>"><?php echo $base_url.'/' ?></a></samp>
+					</li>
+					<li>
+						<code>[email]myname@mydomain.com[/email]</code> <span><?php echo $lang_help['produces'] ?></span>
+						<samp><a href="mailto:myname@mydomain.com">myname@mydomain.com</a></samp>
+					</li>
+					<li>
+						<code>[email=myname@mydomain.com]<?php echo $lang_help['My e-mail address'] ?>[/email]</code><span><?php echo $lang_help['produces'] ?></span>
+						<samp><a href="mailto:myname@mydomain.com"><?php echo $lang_help['My e-mail address'] ?></a></samp>
+					</li>
+				</ul>
+			</div>
+			<div class="frm-set">
+				<h3><span><?php echo $lang_help['Quotes info'] ?></span></h3>
+				<ul class="example">
+					<li><code>[quote=James]<?php echo $lang_help['Quote text'] ?>[/quote]</code> <span><?php echo $lang_help['produces named'] ?></span>
+						<div class="entry-content samp">
+							<div class="quotebox"><cite>James <?php echo $lang_common['wrote'] ?>:</cite><blockquote><p><?php echo $lang_help['Quote text'] ?></p></blockquote></div>
+						</div>
+					</li>
+					<li><code>[quote]<?php echo $lang_help['Quote text'] ?>[/quote]</code> <span><?php echo $lang_help['produces unnamed'] ?></span>
+						<div class="entry-content samp">
+							<div class="quotebox"><blockquote><p><?php echo $lang_help['Quote text'] ?></p></blockquote></div>
+						</div>
+					</li>
+				</ul>
+			</div>
+			<div class="frm-set">
+				<h3><span><?php echo $lang_help['Code info'] ?></span></h3>
+				<ul class="example">
+					<li><code>[code]<?php echo $lang_help['Code text'] ?>[/code]</code> <span><?php echo $lang_help['produces code box'] ?></span>
+						<div class="entry-content samp">
+							<div class="codebox"><strong class="legend"><?php echo $lang_common['Code'] ?>:</strong><pre><code><?php echo $lang_help['Code text'] ?></code></pre></div>
+						</div>
+					</li>
+					<li><code>[code]<?php echo $lang_help['Code text long'] ?>[/code]</code> <span><?php echo $lang_help['produces scroll box'] ?></span>
+						<div class="entry-content samp">
+							<div class="codebox"><strong class="legend"><?php echo $lang_common['Code'] ?>:</strong><pre><code><?php echo $lang_help['Code text long'] ?></code></pre></div>
+						</div>
+					</li>
+				</ul>
+			</div>
+		</div>
+	</div>
+<?php
+
+}
+else if ($section == 'img')
+{
+
+?>
+	<div class="main-head">
+		<h2><span><?php printf($lang_help['Help with'], $lang_common['Images']) ?></span></h2>
+	</div>
+	<div class="main-content frm">
+		<div class="frm-info">
+			<p><?php echo $lang_help['Image info 1'] ?></p>
+			<p><?php echo $lang_help['Image info 2'] ?></p>
+		</div>
+		<div class="frm-form">
+			<ul class="example">
+				<li>
+					<code>[img=PunBB logo]<?php echo $base_url ?>/img/logo.png[/img]</code>
+					<samp><img src="<?php echo $base_url ?>/img/logo.png" alt="PunBB logo" /></samp>
+				</li>
+			</ul>
+		</div>
+	</div>
+<?php
+
+}
+else if ($section == 'smilies')
+{
+
+?>
+	<div id="smilies" class="main-head">
+		<h2><span><?php printf($lang_help['Help with'], $lang_common['Smilies']) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="frm-info">
+			<p><?php echo $lang_help['Smilies info'] ?></p>
+		</div>
+		<div class="frm-form">
+			<ul class="example">
+<?php
+
+	// Display the smiley set
+	require PUN_ROOT.'include/parser.php';
+
+	$num_smilies = count($smiley_text);
+	for ($i = 0; $i < $num_smilies; ++$i)
+	{
+		// Is there a smiley at the current index?
+		if (!isset($smiley_text[$i]))
+			continue;
+
+		echo "\t\t\t\t".'<li><code>'.$smiley_text[$i];
+
+		// Save the current text and image
+		$cur_img = $smiley_img[$i];
+		$cur_text = $smiley_text[$i];
+
+		// Loop through the rest of the array and see if there are any duplicate images
+		// (more than one text representation for one image)
+		for ($next = $i + 1; $next < $num_smilies; ++$next)
+		{
+			// Did we find a dupe?
+			if (isset($smiley_img[$next]) && $smiley_img[$i] == $smiley_img[$next])
+			{
+				echo ' '.$lang_common['and'].' '.$smiley_text[$next];
+
+				// Remove the dupe so we won't display it twice
+				unset($smiley_text[$next]);
+				unset($smiley_img[$next]);
+			}
+		}
+
+		echo ' <span>'.$lang_help['produces'].'</span> <img src="'.$base_url.'/img/smilies/'.$cur_img.'" width="15" height="15" alt="'.$cur_text.'" /></code></li>'."\n";
+	}
+
+?>
+			</ul>
+		</div>
+	</div>
+<?php
+
+}
+
+($hook = get_hook('he_new_section')) ? eval($hook) : null;
+
+?>
+
+</div>
+<?php
+
+($hook = get_hook('he_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/img/avatars/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/img/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
Binary file punbb/img/smilies/big_smile.png has changed
Binary file punbb/img/smilies/cool.png has changed
Binary file punbb/img/smilies/hmm.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/img/smilies/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
Binary file punbb/img/smilies/lol.png has changed
Binary file punbb/img/smilies/mad.png has changed
Binary file punbb/img/smilies/neutral.png has changed
Binary file punbb/img/smilies/roll.png has changed
Binary file punbb/img/smilies/sad.png has changed
Binary file punbb/img/smilies/smile.png has changed
Binary file punbb/img/smilies/tongue.png has changed
Binary file punbb/img/smilies/wink.png has changed
Binary file punbb/img/smilies/yikes.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/cache.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,346 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
+
+
+//
+// Generate the config cache PHP script
+//
+function generate_config_cache()
+{
+	global $pun_db;
+
+	// Get the forum config from the DB
+	$query = array(
+		'SELECT'	=> 'c.*',
+		'FROM'		=> 'config AS c'
+	);
+
+	($hook = get_hook('ch_qr_get_config')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+	$output = array();
+	while ($cur_config_item = $pun_db->fetch_row($result))
+		$output[$cur_config_item[0]] = $cur_config_item[1];
+
+	// Output config as PHP code
+	$fh = @fopen(PUN_CACHE_DIR.'cache_config.php', 'wb');
+	if (!$fh)
+		error('Unable to write configuration cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__);
+
+	fwrite($fh, '<?php'."\n\n".'define(\'PUN_CONFIG_LOADED\', 1);'."\n\n".'$pun_config = '.var_export($output, true).';'."\n\n".'?>');
+
+	fclose($fh);
+}
+
+
+//
+// Generate the bans cache PHP script
+//
+function generate_bans_cache()
+{
+	global $pun_db;
+
+	// Get the ban list from the DB
+	$query = array(
+		'SELECT'	=> 'b.*, u.username AS ban_creator_username',
+		'FROM'		=> 'bans AS b',
+		'JOINS'		=> array(
+			array(
+				'LEFT JOIN'		=> 'users AS u',
+				'ON'			=> 'u.id=b.ban_creator'
+			)
+		),
+		'ORDER BY'	=> 'b.id'
+	);
+
+	($hook = get_hook('ch_qr_get_bans')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+	$output = array();
+	while ($cur_ban = $pun_db->fetch_assoc($result))
+		$output[] = $cur_ban;
+
+	// Output ban list as PHP code
+	$fh = @fopen(PUN_CACHE_DIR.'cache_bans.php', 'wb');
+	if (!$fh)
+		error('Unable to write bans cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__);
+
+	fwrite($fh, '<?php'."\n\n".'define(\'PUN_BANS_LOADED\', 1);'."\n\n".'$pun_bans = '.var_export($output, true).';'."\n\n".'?>');
+
+	fclose($fh);
+}
+
+
+//
+// Generate the ranks cache PHP script
+//
+function generate_ranks_cache()
+{
+	global $pun_db;
+
+	// Get the rank list from the DB
+	$query = array(
+		'SELECT'	=> 'r.*',
+		'FROM'		=> 'ranks AS r',
+		'ORDER BY'	=> 'r.min_posts'
+	);
+
+	($hook = get_hook('ch_qr_get_ranks')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+	$output = array();
+	while ($cur_rank = $pun_db->fetch_assoc($result))
+		$output[] = $cur_rank;
+
+	// Output ranks list as PHP code
+	$fh = @fopen(PUN_CACHE_DIR.'cache_ranks.php', 'wb');
+	if (!$fh)
+		error('Unable to write ranks cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__);
+
+	fwrite($fh, '<?php'."\n\n".'define(\'PUN_RANKS_LOADED\', 1);'."\n\n".'$pun_ranks = '.var_export($output, true).';'."\n\n".'?>');
+
+	fclose($fh);
+}
+
+
+//
+// Generate the censor cache PHP script
+//
+function generate_censors_cache()
+{
+	global $pun_db;
+
+	// Get the censor list from the DB
+	$query = array(
+		'SELECT'	=> 'c.*',
+		'FROM'		=> 'censoring AS c',
+		'ORDER BY'	=> 'c.id'
+	);
+
+	($hook = get_hook('ch_qr_get_censored_words')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+	$output = array();
+	while ($cur_censor = $pun_db->fetch_assoc($result))
+		$output[] = $cur_censor;
+
+	// Output censors list as PHP code
+	$fh = @fopen(PUN_CACHE_DIR.'cache_censors.php', 'wb');
+	if (!$fh)
+		error('Unable to write censor cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__);
+
+	fwrite($fh, '<?php'."\n\n".'define(\'PUN_CENSORS_LOADED\', 1);'."\n\n".'$pun_censors = '.var_export($output, true).';'."\n\n".'?>');
+
+	fclose($fh);
+}
+
+
+//
+// Generate quickjump cache PHP scripts
+//
+function generate_quickjump_cache($group_id = false)
+{
+	global $pun_db, $lang_common, $pun_url, $pun_config, $pun_user, $base_url;
+
+	// If a group_id was supplied, we generate the quickjump cache for that group only
+	if ($group_id !== false)
+		$groups[0] = $group_id;
+	else
+	{
+		// A group_id was not supplied, so we generate the quickjump cache for all groups
+		$query = array(
+			'SELECT'	=> 'g.g_id',
+			'FROM'		=> 'groups AS g'
+		);
+
+		($hook = get_hook('ch_qr_get_groups')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		$num_groups = $pun_db->num_rows($result);
+
+		for ($i = 0; $i < $num_groups; ++$i)
+			$groups[] = $pun_db->result($result, $i);
+	}
+
+	// Loop through the groups in $groups and output the cache for each of them
+	while (list(, $group_id) = @each($groups))
+	{
+		// Output quickjump as PHP code
+		$fh = @fopen(PUN_CACHE_DIR.'cache_quickjump_'.$group_id.'.php', 'wb');
+		if (!$fh)
+			error('Unable to write quickjump cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__);
+
+		$output = '<?php'."\n\n".'if (!defined(\'PUN\')) exit;'."\n".'define(\'PUN_QJ_LOADED\', 1);'."\n".'$forum_id = isset($forum_id) ? $forum_id : 0;'."\n\n".'?>';
+		$output .= "\t".'<form id="qjump" method="get" accept-charset="utf-8" action="'.$base_url.'/viewforum.php">'."\n\t\t".'<fieldset>'."\n\t\t\t".'<legend>'.$lang_common['Quick jump legend'].'</legend>'."\n\t\t\t".'<label for="qjump-select"><?php echo $lang_common[\'Jump to\'] ?>'.'</label><br />'."\n\t\t\t".'<span><select id="qjump-select" name="id">'."\n";
+
+		// Get the list of categories and forums from the DB
+		$query = array(
+			'SELECT'	=> 'c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url',
+			'FROM'		=> 'categories AS c',
+			'JOINS'		=> array(
+				array(
+					'INNER JOIN'	=> 'forums AS f',
+					'ON'			=> 'c.id=f.cat_id'
+				),
+				array(
+					'LEFT JOIN'		=> 'forum_perms AS fp',
+					'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$group_id.')'
+				)
+			),
+			'WHERE'		=> 'fp.read_forum IS NULL OR fp.read_forum=1',
+			'ORDER BY'	=> 'c.disp_position, c.id, f.disp_position'
+		);
+
+		($hook = get_hook('ch_qr_get_cats_and_forums')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+		$cur_category = 0;
+		$forum_count = 0;
+		while ($cur_forum = $pun_db->fetch_assoc($result))
+		{
+			if ($cur_forum['cid'] != $cur_category)	// A new category since last iteration?
+			{
+				if ($cur_category)
+					$output .= "\t\t\t".'</optgroup>'."\n";
+
+				$output .= "\t\t\t".'<optgroup label="'.htmlspecialchars($cur_forum['cat_name']).'">'."\n";
+				$cur_category = $cur_forum['cid'];
+			}
+
+			$redirect_tag = ($cur_forum['redirect_url'] != '') ? ' &gt;&gt;&gt;' : '';
+			$output .= "\t\t\t\t".'<option value="'.$cur_forum['fid'].'"<?php echo ($forum_id == '.$cur_forum['fid'].') ? \' selected="selected"\' : \'\' ?>>'.htmlspecialchars($cur_forum['forum_name']).$redirect_tag.'</option>'."\n";
+			$forum_count++;
+		}
+
+		$output .= "\t\t\t".'</optgroup>'."\n\t\t\t".'</select>'."\n\t\t\t".'<input type="submit" value="<?php echo $lang_common[\'Go\'] ?>" /></span>'."\n\t\t".'</fieldset>'."\n\t".'</form>'."\n";
+
+		if ($forum_count < 2)
+			$output = '<?php'."\n\n".'if (!defined(\'PUN\')) exit;'."\n".'define(\'PUN_QJ_LOADED\', 1);';
+
+		fwrite($fh, $output);
+
+		fclose($fh);
+	}
+}
+
+
+//
+// Generate the hooks cache PHP script
+//
+function generate_hooks_cache()
+{
+	global $pun_db, $pun_config, $base_url;
+
+	// Get the hooks from the DB
+	$query = array(
+		'SELECT'	=> 'eh.id, eh.code, eh.extension_id',
+		'FROM'		=> 'extension_hooks AS eh',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'extensions AS e',
+				'ON'			=> 'e.id=eh.extension_id'
+			)
+		),
+		'WHERE'		=> 'e.disabled=0',
+		'ORDER BY'	=> 'eh.installed'
+	);
+
+	($hook = get_hook('ch_qr_get_hooks')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+	$output = array();
+	while ($cur_hook = $pun_db->fetch_assoc($result))
+	{
+		$ext_info = '$ext_info = array('."\n".
+			'\'id\'		=> \''.$cur_hook['extension_id'].'\','."\n".
+			'\'path\'	=> PUN_ROOT.\'extensions/'.$cur_hook['extension_id'].'\','."\n".
+			'\'url\'	=> $base_url.\'/extensions/'.$cur_hook['extension_id'].'\');';
+		$output[$cur_hook['id']][] = $ext_info."\n\n".$cur_hook['code']."\n";
+	}
+
+	// Output hooks as PHP code
+	$fh = @fopen(PUN_CACHE_DIR.'cache_hooks.php', 'wb');
+	if (!$fh)
+		error('Unable to write hooks cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__);
+
+	fwrite($fh, '<?php'."\n\n".'define(\'PUN_HOOKS_LOADED\', 1);'."\n\n".'$pun_hooks = '.var_export($output, true).';'."\n\n".'?>');
+
+	fclose($fh);
+}
+
+
+//
+// Generate the updates cache PHP script
+//
+function generate_updates_cache()
+{
+	global $pun_db, $pun_config;
+
+	// Get a list of installed hotfix extensions
+	$query = array(
+		'SELECT'	=> 'e.id',
+		'FROM'		=> 'extensions AS e',
+		'WHERE'		=> 'e.id LIKE \'hotfix_%\''
+	);
+
+	($hook = get_hook('ch_qr_get_hotfixes')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$num_hotfixes = $pun_db->num_rows($result);
+
+	$hotfixes = array();
+	for ($i = 0; $i < $num_hotfixes; ++$i)
+		$hotfixes[] = urlencode($pun_db->result($result, $i));
+
+	// Contact the punbb.org updates service
+	$result = get_remote_file('http://punbb.org/update/?type=xml&version='.urlencode($pun_config['o_cur_version']).'&hotfixes='.implode(',', $hotfixes), 8);
+
+	// Make sure we got everything we need
+	if ($result != null && strpos($result['content'], '</updates>') !== false)
+	{
+		require PUN_ROOT.'/include/xml.php';
+
+		$output = xml_to_array($result['content']);
+		$output = current($output);
+		$output['cached'] = time();
+		$output['fail'] = false;
+	}
+	else	// If the update check failed, set the fail flag
+		$output = array('cached' => time(), 'fail' => true);
+
+	// This hook could potentially (and responsibly) be used by an extension to do its own little update check
+	($hook = get_hook('ch_generate_updates_cache_write')) ? eval($hook) : null;
+
+	// Output update status as PHP code
+	$fh = @fopen(PUN_CACHE_DIR.'cache_updates.php', 'wb');
+	if (!$fh)
+		error('Unable to write updates cache file to cache directory. Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__);
+
+	fwrite($fh, '<?php'."\n\n".'if (!defined(\'PUN_UPDATES_LOADED\')) define(\'PUN_UPDATES_LOADED\', 1);'."\n\n".'$pun_updates = '.var_export($output, true).';'."\n\n".'?>');
+
+	fclose($fh);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/common.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,146 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+if (!defined('PUN_ROOT'))
+	exit('The constant PUN_ROOT must be defined and point to a valid PunBB installation root directory.');
+
+if (!defined('PUN_ESSENTIALS_LOADED'))
+	require PUN_ROOT.'include/essentials.php';
+
+// Turn off magic_quotes_runtime
+set_magic_quotes_runtime(0);
+
+// Strip slashes from GET/POST/COOKIE (if magic_quotes_gpc is enabled)
+if (get_magic_quotes_gpc())
+{
+	function stripslashes_array($array)
+	{
+		return is_array($array) ? array_map('stripslashes_array', $array) : stripslashes($array);
+	}
+
+	$_GET = stripslashes_array($_GET);
+	$_POST = stripslashes_array($_POST);
+	$_COOKIE = stripslashes_array($_COOKIE);
+}
+
+// If a cookie name is not specified in config.php, we use the default (punbb_cookie)
+if (empty($cookie_name))
+	$cookie_name = 'punbb_cookie';
+
+// Define a few commonly used constants
+define('PUN_UNVERIFIED', 0);
+define('PUN_ADMIN', 1);
+define('PUN_GUEST', 2);
+define('PUN_MEMBER', 3);
+
+// Enable output buffering
+if (!defined('PUN_DISABLE_BUFFERING'))
+{
+	// For some very odd reason, "Norton Internet Security" unsets this
+	$_SERVER['HTTP_ACCEPT_ENCODING'] = isset($_SERVER['HTTP_ACCEPT_ENCODING']) ? $_SERVER['HTTP_ACCEPT_ENCODING'] : '';
+
+	// Should we use gzip output compression?
+	if ($pun_config['o_gzip'] && extension_loaded('zlib') && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false || strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') !== false))
+		ob_start('ob_gzhandler');
+	else
+		ob_start();
+}
+
+// Setup base URL (added for Enano)
+global $paths;
+$base_url = contentPath . $paths->nslist['Special'] . 'Forum';
+
+// Define standard date/time formats
+$pun_time_formats = array($pun_config['o_time_format'], 'H:i:s', 'H:i', 'g:i:s a', 'g:i a');
+$pun_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');
+
+// Create pun_page array
+$pun_page = array();
+
+// Login and fetch user info
+$pun_user = array();
+cookie_login($pun_user);
+
+// Attempt to load the common language file
+if (file_exists(PUN_ROOT.'lang/'.$pun_user['language'].'/common.php'))
+	include PUN_ROOT.'lang/'.$pun_user['language'].'/common.php';
+else
+	error('There is no valid language pack \''.htmlspecialchars($pun_user['language']).'\' installed. Please reinstall a language of that name.');
+
+// Check if we are to display a maintenance message
+if ($pun_config['o_maintenance'] && $pun_user['g_id'] > PUN_ADMIN && !defined('PUN_TURN_OFF_MAINT'))
+	maintenance_message();
+
+// Setup the URL rewriting scheme
+if (file_exists(PUN_ROOT.'include/url/'.$pun_config['o_sef'].'.php'))
+	require PUN_ROOT.'include/url/'.$pun_config['o_sef'].'.php';
+else
+	require PUN_ROOT.'include/url/Default.php';
+
+
+// Load cached updates info
+if ($session->user_level >= USER_LEVEL_ADMIN)
+{
+	if (file_exists(PUN_CACHE_DIR.'cache_updates.php'))
+		include PUN_CACHE_DIR.'cache_updates.php';
+
+	// Regenerate cache only if automatic updates are enabled and if the cache is more than 12 hours old
+	if ($pun_config['o_check_for_updates'] == '1' && (!defined('PUN_UPDATES_LOADED') || $pun_updates['cached'] < (time() - 43200)))
+	{
+		require_once PUN_ROOT.'include/cache.php';
+		generate_updates_cache();
+		require PUN_CACHE_DIR.'cache_updates.php';
+	}
+}
+
+
+// Load cached bans
+if (file_exists(PUN_CACHE_DIR.'cache_bans.php'))
+	include PUN_CACHE_DIR.'cache_bans.php';
+
+if (!defined('PUN_BANS_LOADED'))
+{
+	require_once PUN_ROOT.'include/cache.php';
+	generate_bans_cache();
+	require PUN_CACHE_DIR.'cache_bans.php';
+}
+
+// Check if current user is banned
+check_bans();
+
+
+// Update online list
+update_users_online();
+
+// Check to see if we logged in without a cookie being set
+if ($pun_user['is_guest'] && isset($_GET['login']))
+	message($lang_common['No cookie']);
+
+// If we're an administrator or moderator, make sure the CSRF token in $_POST is valid (token in post.php is dealt with in post.php)
+if (!empty($_POST) && $pun_user['is_admmod'] && (isset($_POST['confirm_cancel']) || (!isset($_POST['csrf_token']) || $_POST['csrf_token'] !== generate_form_token(get_current_url()))) && basename($_SERVER['PHP_SELF']) != 'post.php')
+	csrf_confirm_form();
+
+// A good place to add common functions for your extension
+($hook = get_hook('co_common')) ? eval($hook) : null;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/common_admin.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,203 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
+
+// Check for Enano authentication
+global $db, $session, $paths, $template, $plugins; // Common objects
+if ( $session->auth_level < USER_LEVEL_ADMIN )
+{
+  redirect(makeUrlComplete('Special', 'Login/' . $paths->fullpage, 'level=' . $session->user_level, false), 'Permission denied', 'Re-auth needed.', 0);
+}
+
+//
+// Display the admin navigation menu
+//
+function generate_admin_menu()
+{
+	global $pun_config, $pun_url, $pun_user, $lang_admin, $db_type;
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  
+	$adnav_sublinks = array();
+
+	if ($session->user_level < USER_LEVEL_ADMIN)
+	{
+		$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-information') ? ' class="li-first isactive">' : ' class="li-first">').'<a href="'.pun_link($pun_url['admin_index']).'">'.$lang_admin['Information'].'</span></a></li>';
+		$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-users') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_users']).'">'.$lang_admin['User search'].'</a></li>';
+		$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-censoring') ? ' class="isactive">' : '>').'<a href="'.pun_link($pun_url['admin_censoring']).'">'.$lang_admin['Censoring'].'</a></li>';
+		$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-reports') ? ' class="isactive">' : '>').'<a href="'.pun_link($pun_url['admin_reports']).'">'.$lang_admin['Reports'].'</a></li>';
+
+		if ($pun_user['g_mod_ban_users'] == '1')
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-bans') ? ' class="isactive">' : '>').'<a href="'.pun_link($pun_url['admin_bans']).'">'.$lang_admin['Bans'].'</a></li>';
+	}
+	else
+	{
+		if (PUN_PAGE_SECTION == 'start')
+		{
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-information') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_index']).'">'.$lang_admin['Information'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-categories') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_categories']).'">'.$lang_admin['Categories'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-forums') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_forums']).'">'.$lang_admin['Forums'].'</a></li>';
+		}
+		else if (PUN_PAGE_SECTION == 'users')
+		{
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-users') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_users']).'">'.$lang_admin['Searches'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-groups') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_groups']).'">'.$lang_admin['Groups'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-ranks') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_ranks']).'">'.$lang_admin['Ranks'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-bans') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_bans']).'">'.$lang_admin['Bans'].'</a></li>';
+		}
+		else if (PUN_PAGE_SECTION == 'options')
+		{
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-options-setup') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_options_setup']).'">'.$lang_admin['Setup'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-options-features') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_options_features']).'">'.$lang_admin['Features'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-options-email') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_options_email']).'">'.$lang_admin['E-mail'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-options-registration') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_options_registration']).'">'.$lang_admin['Registration'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-censoring') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_censoring']).'">'.$lang_admin['Censoring'].'</a></li>';
+		}
+		else if (PUN_PAGE_SECTION == 'management')
+		{
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-reports') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_reports']).'">'.$lang_admin['Reports'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-prune') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_prune']).'">'.$lang_admin['Prune topics'].'</a></li>';
+
+			if ($db_type != 'mysql' && $db_type != 'mysqli')
+				$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-reindex') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_reindex']).'">'.$lang_admin['Rebuild index'].'</a></li>';
+
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-options-maintenance') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_options_maintenance']).'">'.$lang_admin['Maintenance mode'].'</a></li>';
+		}
+		else if (PUN_PAGE_SECTION == 'extensions')
+		{
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-extensions-manage') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_extensions_manage']).'">'.$lang_admin['Manage extensions'].'</a></li>';
+			$adnav_sublinks[] = '<li'.((PUN_PAGE == 'admin-extensions-install') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_extensions_install']).'">'.$lang_admin['Install extensions'].'</a></li>';
+		}
+	}
+
+	($hook = get_hook('ca_admin_menu_new_sublink')) ? eval($hook) : null;
+
+	if (count($adnav_sublinks) > 1)
+		$adnav_submenu = "\n\t\t\t\t".'<div><ul>'."\n\t\t\t\t\t".implode("\n\t\t\t\t\t", $adnav_sublinks)."\n\t\t\t\t".'</ul></div>';
+	else
+		$adnav_submenu = '';
+
+	if ($session->user_level < USER_LEVEL_ADMIN)
+		$adnav_links[] = '<li class="topactive"><a href="'.pun_link($pun_url['admin_index']).'"><span>'.$lang_admin['Moderate'].'</span></a>'.$adnav_submenu."\n\t\t\t".'</li>';
+	else
+	{
+		$adnav_links[] = '<li'.((PUN_PAGE_SECTION == 'start') ? ' class="topactive"' : '').'><a href="'.pun_link($pun_url['admin_index']).'"><span>'.$lang_admin['Start'].'</span></a>'.(((PUN_PAGE_SECTION == 'start') && ($adnav_submenu != '')) ? $adnav_submenu."\n\t\t\t" : '').'</li>';
+		$adnav_links[] = '<li'.((PUN_PAGE_SECTION == 'options') ? ' class="topactive"' : '').'><a href="'.pun_link($pun_url['admin_options_setup']).'"><span>'.$lang_admin['Settings'].'</span></a>'.(((PUN_PAGE_SECTION == 'options') && ($adnav_submenu != '')) ? $adnav_submenu."\n\t\t\t" : '').'</li>';
+		$adnav_links[] = '<li'.((PUN_PAGE_SECTION == 'users') ? ' class="topactive"' : '').'><a href="'.pun_link($pun_url['admin_users']).'"><span>'.$lang_admin['Users'].'</span></a>'.(((PUN_PAGE_SECTION == 'users') && ($adnav_submenu != '')) ? $adnav_submenu."\n\t\t\t" : '').'</li>';
+		$adnav_links[] = '<li'.((PUN_PAGE_SECTION == 'management') ? ' class="topactive"' : '').'><a href="'.pun_link($pun_url['admin_reports']).'"><span>'.$lang_admin['Management'].'</span></a>'.(((PUN_PAGE_SECTION == 'management') && ($adnav_submenu != '')) ? $adnav_submenu."\n\t\t\t" : '').'</li>';
+		$adnav_links[] = '<li'.((PUN_PAGE_SECTION == 'extensions') ? ' class="topactive"' : '').'><a href="'.pun_link($pun_url['admin_extensions_manage']).'"><span>'.$lang_admin['Extensions'].'</span></a>'.(((PUN_PAGE_SECTION == 'extensions') && ($adnav_submenu != '')) ? $adnav_submenu."\n\t\t\t" : '').'</li>';
+	}
+
+?>
+	<div class="main-nav<?php if ($adnav_submenu != '') echo ' submenu' ?>">
+		<ul>
+			<?php echo implode("\n\t\t\t", $adnav_links)."\n" ?>
+		</ul>
+	</div>
+<?php
+
+}
+
+
+//
+// Delete topics from $forum_id that are "older than" $prune_date (if $prune_sticky is 1, sticky topics will also be deleted)
+//
+function prune($forum_id, $prune_sticky, $prune_date)
+{
+	global $pun_db, $db_type;
+
+	// Fetch topics to prune
+	$query = array(
+		'SELECT'	=> 't.id',
+		'FROM'		=> 'topics AS t',
+		'WHERE'		=> 't.forum_id='.$forum_id
+	);
+
+	if ($prune_date != -1)
+		$query['WHERE'] .= ' AND last_post<'.$prune_date;
+	if (!$prune_sticky)
+		$query['WHERE'] .= ' AND sticky=\'0\'';
+
+	($hook = get_hook('ca_qr_get_topics_to_prune')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+	$topic_ids = '';
+	while ($row = $pun_db->fetch_row($result))
+		$topic_ids .= (($topic_ids != '') ? ',' : '').$row[0];
+
+	if ($topic_ids != '')
+	{
+		// Fetch posts to prune (used lated for updating the search index)
+		$query = array(
+			'SELECT'	=> 'p.id',
+			'FROM'		=> 'posts AS p',
+			'WHERE'		=> 'p.topic_id IN('.$topic_ids.')'
+		);
+
+		($hook = get_hook('ca_qr_get_posts_to_prune')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+		$post_ids = '';
+		while ($row = $pun_db->fetch_row($result))
+			$post_ids .= (($post_ids != '') ? ',' : '').$row[0];
+
+		// Delete topics
+		$query = array(
+			'DELETE'	=> 'topics',
+			'WHERE'		=> 'id IN('.$topic_ids.')'
+		);
+
+		($hook = get_hook('ca_qr_prune_topics')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		// Delete posts
+		$query = array(
+			'DELETE'	=> 'posts',
+			'WHERE'		=> 'topic_id IN('.$topic_ids.')'
+		);
+
+		($hook = get_hook('ca_qr_prune_posts')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		// Delete subscriptions
+		$query = array(
+			'DELETE'	=> 'subscriptions',
+			'WHERE'		=> 'topic_id IN('.$topic_ids.')'
+		);
+
+		($hook = get_hook('ca_qr_prune_subscriptions')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		// We removed a bunch of posts, so now we have to update the search index
+		if ($db_type != 'mysql' && $db_type != 'mysqli')
+		{
+			require_once PUN_ROOT.'include/search_idx.php';
+			strip_search_index($post_ids);
+		}
+	}
+}
+
+($hook = get_hook('ca_new_function')) ? eval($hook) : null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/dblayer/common_db.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,64 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
+
+// import Enano data
+global $dbdriver;
+$db_type =& $dbdriver;
+
+//
+// Return current timestamp (with microseconds) as a float (used in dblayer)
+//
+if (defined('PUN_SHOW_QUERIES'))
+{
+	function get_microtime()
+	{
+		list($usec, $sec) = explode(' ', microtime());
+		return ((float)$usec + (float)$sec);
+	}
+}
+
+
+// Load the appropriate DB layer class
+switch ($db_type)
+{
+	case 'mysql':
+		require PUN_ROOT.'include/dblayer/enano_mysql.php';
+		break;
+
+	case 'pgsql':
+		require PUN_ROOT.'include/dblayer/enano_pgsql.php';
+		break;
+
+	default:
+		error('\''.$db_type.'\' is not a valid database type. Please check settings in config.php.', __FILE__, __LINE__);
+		break;
+}
+
+// Create the database adapter object (and open/connect to/select db)
+$pun_db = new DBLayer();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/dblayer/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/dblayer/mysql.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,317 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure we have built in support for MySQL
+if (!function_exists('mysql_connect'))
+	exit('This PHP environment doesn\'t have MySQL support built in. MySQL support is required if you want to use a MySQL database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+	var $prefix;
+	var $link_id;
+	var $query_result;
+
+	var $saved_queries = array();
+	var $num_queries = 0;
+
+
+	function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+	{
+		$this->prefix = $db_prefix;
+
+		if ($p_connect)
+			$this->link_id = @mysql_pconnect($db_host, $db_username, $db_password);
+		else
+			$this->link_id = @mysql_connect($db_host, $db_username, $db_password);
+
+		if ($this->link_id)
+		{
+			if (@mysql_select_db($db_name, $this->link_id))
+				return $this->link_id;
+			else
+				error('Unable to select database. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
+		}
+		else
+			error('Unable to connect to MySQL server. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
+
+		// Setup the client-server character set (UTF-8)
+		if (!defined('PUN_NO_SET_NAMES'))
+			mysql_query('SET NAMES \'utf8\'', $this->link_id) or error(__FILE__, __LINE__);
+	}
+
+
+	function start_transaction()
+	{
+		return;
+	}
+
+
+	function end_transaction()
+	{
+		return;
+	}
+
+
+	function query($sql, $unbuffered = false)
+	{
+		if (strlen($sql) > 140000)
+			exit('Insane query. Aborting.');
+
+		if (defined('PUN_SHOW_QUERIES'))
+			$q_start = get_microtime();
+
+		if ($unbuffered)
+			$this->query_result = @mysql_unbuffered_query($sql, $this->link_id);
+		else
+			$this->query_result = @mysql_query($sql, $this->link_id);
+
+		if ($this->query_result)
+		{
+			if (defined('PUN_SHOW_QUERIES'))
+				$this->saved_queries[] = array($sql, sprintf('%.5f', get_microtime() - $q_start));
+
+			++$this->num_queries;
+
+			return $this->query_result;
+		}
+		else
+		{
+			if (defined('PUN_SHOW_QUERIES'))
+				$this->saved_queries[] = array($sql, 0);
+
+			return false;
+		}
+	}
+
+
+	function query_build($query, $unbuffered = false)
+	{
+		$sql = '';
+
+		if (isset($query['SELECT']))
+		{
+			$sql = 'SELECT '.$query['SELECT'].' FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['FROM'];
+
+			if (isset($query['JOINS']))
+			{
+				foreach ($query['JOINS'] as $cur_join)
+					$sql .= ' '.key($cur_join).' '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).current($cur_join).' ON '.$cur_join['ON'];
+			}
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+			if (!empty($query['GROUP BY']))
+				$sql .= ' GROUP BY '.$query['GROUP BY'];
+			if (!empty($query['HAVING']))
+				$sql .= ' HAVING '.$query['HAVING'];
+			if (!empty($query['ORDER BY']))
+				$sql .= ' ORDER BY '.$query['ORDER BY'];
+			if (!empty($query['LIMIT']))
+				$sql .= ' LIMIT '.$query['LIMIT'];
+		}
+		else if (isset($query['INSERT']))
+		{
+			$sql = 'INSERT INTO '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['INTO'];
+
+			if (!empty($query['INSERT']))
+				$sql .= ' ('.$query['INSERT'].')';
+
+			$sql .= ' VALUES('.$query['VALUES'].')';
+		}
+		else if (isset($query['UPDATE']))
+		{
+			$query['UPDATE'] = (isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['UPDATE'];
+
+			if (isset($query['PARAMS']['LOW_PRIORITY']))
+				$query['UPDATE'] = 'LOW_PRIORITY '.$query['UPDATE'];
+
+			$sql = 'UPDATE '.$query['UPDATE'].' SET '.$query['SET'];
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+		}
+		else if (isset($query['DELETE']))
+		{
+			$sql = 'DELETE FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['DELETE'];
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+		}
+		else if (isset($query['REPLACE']))
+		{
+			$sql = 'REPLACE INTO '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['INTO'];
+
+			if (!empty($query['REPLACE']))
+				$sql .= ' ('.$query['REPLACE'].')';
+
+			$sql .= ' VALUES('.$query['VALUES'].')';
+		}
+
+		return $this->query($sql, $unbuffered);
+	}
+
+
+	function result($query_id = 0, $row = 0)
+	{
+		return ($query_id) ? @mysql_result($query_id, $row) : false;
+	}
+
+
+	function fetch_assoc($query_id = 0)
+	{
+		return ($query_id) ? @mysql_fetch_assoc($query_id) : false;
+	}
+
+
+	function fetch_row($query_id = 0)
+	{
+		return ($query_id) ? @mysql_fetch_row($query_id) : false;
+	}
+
+
+	function num_rows($query_id = 0)
+	{
+		return ($query_id) ? @mysql_num_rows($query_id) : false;
+	}
+
+
+	function affected_rows()
+	{
+		return ($this->link_id) ? @mysql_affected_rows($this->link_id) : false;
+	}
+
+
+	function insert_id()
+	{
+		return ($this->link_id) ? @mysql_insert_id($this->link_id) : false;
+	}
+
+
+	function get_num_queries()
+	{
+		return $this->num_queries;
+	}
+
+
+	function get_saved_queries()
+	{
+		return $this->saved_queries;
+	}
+
+
+	function free_result($query_id = false)
+	{
+		return ($query_id) ? @mysql_free_result($query_id) : false;
+	}
+
+
+	function escape($str)
+	{
+		if (is_array($str))
+			return '';
+		else if (function_exists('mysql_real_escape_string'))
+			return mysql_real_escape_string($str, $this->link_id);
+		else
+			return mysql_escape_string($str);
+	}
+
+
+	function error()
+	{
+		$result['error_sql'] = @current(@end($this->saved_queries));
+		$result['error_no'] = @mysql_errno($this->link_id);
+		$result['error_msg'] = @mysql_error($this->link_id);
+
+		return $result;
+	}
+
+
+	function close()
+	{
+		if ($this->link_id)
+		{
+			if ($this->query_result)
+				@mysql_free_result($this->query_result);
+
+			return @mysql_close($this->link_id);
+		}
+		else
+			return false;
+	}
+
+
+	function table_exists($table_name)
+	{
+		$result = $this->query('SHOW TABLES LIKE \''.$this->escape($table_name).'\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function field_exists($table_name, $field_name)
+	{
+		$result = $this->query('SHOW COLUMNS FROM '.$table_name.' LIKE \''.$this->escape($field_name).'\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function index_exists($table_name, $index_name)
+	{
+		$exists = false;
+
+		$result = $this->query('SHOW INDEX FROM '.$table_name);
+		while ($cur_index = $this->fetch_assoc($result))
+		{
+			if ($cur_index['Key_name'] == $index_name)
+			{
+				$exists = true;
+				break;
+			}
+		}
+
+		return $exists;
+	}
+
+
+	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null)
+	{
+		if ($this->field_exists($table_name, $field_name))
+			return;
+
+		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
+			$default_value = '\''.$this->escape($default_value).'\'';
+
+		$this->query('ALTER TABLE '.$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
+	}
+
+
+	function drop_field($table_name, $field_name)
+	{
+		if (!$this->field_exists($table_name, $field_name))
+			return;
+
+		$this->query('ALTER TABLE '.$table_name.' DROP '.$field_name) or error(__FILE__, __LINE__);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/dblayer/mysqli.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,315 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure we have built in support for MySQL
+if (!function_exists('mysqli_connect'))
+	exit('This PHP environment doesn\'t have Improved MySQL (mysqli) support built in. Improved MySQL support is required if you want to use a MySQL 4.1 (or later) database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+	var $prefix;
+	var $link_id;
+	var $query_result;
+
+	var $saved_queries = array();
+	var $num_queries = 0;
+
+
+	function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $foo)
+	{
+		$this->prefix = $db_prefix;
+
+		// Was a custom port supplied with $db_host?
+		if (strpos($db_host, ':') !== false)
+			list($db_host, $db_port) = explode(':', $db_host);
+
+		if (isset($db_port))
+			$this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name, $db_port);
+		else
+			$this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name);
+
+		if (!$this->link_id)
+			error('Unable to connect to MySQL and select database. MySQL reported: '.mysqli_connect_error(), __FILE__, __LINE__);
+
+		// Setup the client-server character set (UTF-8)
+		if (!defined('PUN_NO_SET_NAMES'))
+			mysqli_query($this->link_id, 'SET NAMES \'utf8\'') or error(__FILE__, __LINE__);
+	}
+
+
+	function start_transaction()
+	{
+		return;
+	}
+
+
+	function end_transaction()
+	{
+		return;
+	}
+
+
+	function query($sql, $unbuffered = false)
+	{
+		if (strlen($sql) > 140000)
+			exit('Insane query. Aborting.');
+
+		if (defined('PUN_SHOW_QUERIES'))
+			$q_start = get_microtime();
+
+		$this->query_result = @mysqli_query($this->link_id, $sql);
+
+		if ($this->query_result)
+		{
+			if (defined('PUN_SHOW_QUERIES'))
+				$this->saved_queries[] = array($sql, sprintf('%.5f', get_microtime() - $q_start));
+
+			++$this->num_queries;
+
+			return $this->query_result;
+		}
+		else
+		{
+			if (defined('PUN_SHOW_QUERIES'))
+				$this->saved_queries[] = array($sql, 0);
+
+			return false;
+		}
+	}
+
+
+	function query_build($query, $unbuffered = false)
+	{
+		$sql = '';
+
+		if (isset($query['SELECT']))
+		{
+			$sql = 'SELECT '.$query['SELECT'].' FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['FROM'];
+
+			if (isset($query['JOINS']))
+			{
+				foreach ($query['JOINS'] as $cur_join)
+					$sql .= ' '.key($cur_join).' '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).current($cur_join).' ON '.$cur_join['ON'];
+			}
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+			if (!empty($query['GROUP BY']))
+				$sql .= ' GROUP BY '.$query['GROUP BY'];
+			if (!empty($query['HAVING']))
+				$sql .= ' HAVING '.$query['HAVING'];
+			if (!empty($query['ORDER BY']))
+				$sql .= ' ORDER BY '.$query['ORDER BY'];
+			if (!empty($query['LIMIT']))
+				$sql .= ' LIMIT '.$query['LIMIT'];
+		}
+		else if (isset($query['INSERT']))
+		{
+			$sql = 'INSERT INTO '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['INTO'];
+
+			if (!empty($query['INSERT']))
+				$sql .= ' ('.$query['INSERT'].')';
+
+			$sql .= ' VALUES('.$query['VALUES'].')';
+		}
+		else if (isset($query['UPDATE']))
+		{
+			$query['UPDATE'] = (isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['UPDATE'];
+
+			if (isset($query['PARAMS']['LOW_PRIORITY']))
+				$query['UPDATE'] = 'LOW_PRIORITY '.$query['UPDATE'];
+
+			$sql = 'UPDATE '.$query['UPDATE'].' SET '.$query['SET'];
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+		}
+		else if (isset($query['DELETE']))
+		{
+			$sql = 'DELETE FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['DELETE'];
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+		}
+		else if (isset($query['REPLACE']))
+		{
+			$sql = 'REPLACE INTO '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['INTO'];
+
+			if (!empty($query['REPLACE']))
+				$sql .= ' ('.$query['REPLACE'].')';
+
+			$sql .= ' VALUES('.$query['VALUES'].')';
+		}
+
+		return $this->query($sql, $unbuffered);
+	}
+
+
+	function result($query_id = 0, $row = 0)
+	{
+		if ($query_id)
+		{
+			if ($row)
+				@mysqli_data_seek($query_id, $row);
+
+			$cur_row = @mysqli_fetch_row($query_id);
+			return $cur_row[0];
+		}
+		else
+			return false;
+	}
+
+
+	function fetch_assoc($query_id = 0)
+	{
+		return ($query_id) ? @mysqli_fetch_assoc($query_id) : false;
+	}
+
+
+	function fetch_row($query_id = 0)
+	{
+		return ($query_id) ? @mysqli_fetch_row($query_id) : false;
+	}
+
+
+	function num_rows($query_id = 0)
+	{
+		return ($query_id) ? @mysqli_num_rows($query_id) : false;
+	}
+
+
+	function affected_rows()
+	{
+		return ($this->link_id) ? @mysqli_affected_rows($this->link_id) : false;
+	}
+
+
+	function insert_id()
+	{
+		return ($this->link_id) ? @mysqli_insert_id($this->link_id) : false;
+	}
+
+
+	function get_num_queries()
+	{
+		return $this->num_queries;
+	}
+
+
+	function get_saved_queries()
+	{
+		return $this->saved_queries;
+	}
+
+
+	function free_result($query_id = false)
+	{
+		return ($query_id) ? @mysqli_free_result($query_id) : false;
+	}
+
+
+	function escape($str)
+	{
+		return is_array($str) ? '' : mysqli_real_escape_string($this->link_id, $str);
+	}
+
+
+	function error()
+	{
+		$result['error_sql'] = @current(@end($this->saved_queries));
+		$result['error_no'] = @mysqli_errno($this->link_id);
+		$result['error_msg'] = @mysqli_error($this->link_id);
+
+		return $result;
+	}
+
+
+	function close()
+	{
+		if ($this->link_id)
+		{
+			if ($this->query_result)
+				@mysqli_free_result($this->query_result);
+
+			return @mysqli_close($this->link_id);
+		}
+		else
+			return false;
+	}
+
+
+	function table_exists($table_name)
+	{
+		$result = $this->query('SHOW TABLES LIKE \''.$this->escape($table_name).'\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function field_exists($table_name, $field_name)
+	{
+		$result = $this->query('SHOW COLUMNS FROM '.$table_name.' LIKE \''.$this->escape($field_name).'\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function index_exists($table_name, $index_name)
+	{
+		$exists = false;
+
+		$result = $this->query('SHOW INDEX FROM '.$table_name);
+		while ($cur_index = $this->fetch_assoc($result))
+		{
+			if ($cur_index['Key_name'] == $index_name)
+			{
+				$exists = true;
+				break;
+			}
+		}
+
+		return $exists;
+	}
+
+
+	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null)
+	{
+		if ($this->field_exists($table_name, $field_name))
+			return;
+
+		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
+			$default_value = '\''.$this->escape($default_value).'\'';
+
+		$this->query('ALTER TABLE '.$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
+	}
+
+
+	function drop_field($table_name, $field_name)
+	{
+		if (!$this->field_exists($table_name, $field_name))
+			return;
+
+		$this->query('ALTER TABLE '.$table_name.' DROP '.$field_name) or error(__FILE__, __LINE__);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/dblayer/pgsql.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,376 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure we have built in support for PostgreSQL
+if (!function_exists('pg_connect'))
+	exit('This PHP environment doesn\'t have PostgreSQL support built in. PostgreSQL support is required if you want to use a PostgreSQL database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+	var $prefix;
+	var $link_id;
+	var $query_result;
+	var $last_query_text = array();
+	var $in_transaction = 0;
+
+	var $saved_queries = array();
+	var $num_queries = 0;
+
+	var $error_no = false;
+	var $error_msg = 'Unknown';
+
+
+	function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+	{
+		$this->prefix = $db_prefix;
+
+		if ($db_host != '')
+		{
+			if (strpos($db_host, ':') !== false)
+			{
+				list($db_host, $dbport) = explode(':', $db_host);
+				$connect_str[] = 'host='.$db_host.' port='.$dbport;
+			}
+			else
+			{
+				if ($db_host != 'localhost')
+					$connect_str[] = 'host='.$db_host;
+			}
+		}
+
+		if ($db_name)
+			$connect_str[] = 'dbname='.$db_name;
+
+		if ($db_username != '')
+			$connect_str[] = 'user='.$db_username;
+
+		if ($db_password != '')
+			$connect_str[] = 'password='.$db_password;
+
+		if ($p_connect)
+			$this->link_id = @pg_pconnect(implode(' ', $connect_str));
+		else
+			$this->link_id = @pg_connect(implode(' ', $connect_str));
+
+		if (!$this->link_id)
+			error('Unable to connect to PostgreSQL server.', __FILE__, __LINE__);
+		else
+			return $this->link_id;
+	}
+
+
+	function start_transaction()
+	{
+		++$this->in_transaction;
+
+		return (@pg_query($this->link_id, 'BEGIN')) ? true : false;
+	}
+
+
+	function end_transaction()
+	{
+		--$this->in_transaction;
+
+		if (@pg_query($this->link_id, 'COMMIT'))
+			return true;
+		else
+		{
+			@pg_query($this->link_id, 'ROLLBACK');
+			return false;
+		}
+	}
+
+
+	function query($sql, $unbuffered = false)	// $unbuffered is ignored since there is no pgsql_unbuffered_query()
+	{
+		if (strlen($sql) > 140000)
+			exit('Insane query. Aborting.');
+
+		if (strrpos($sql, 'LIMIT') !== false)
+			$sql = preg_replace('#LIMIT ([0-9]+),([ 0-9]+)#', 'LIMIT \\2 OFFSET \\1', $sql);
+
+		if (defined('PUN_SHOW_QUERIES'))
+			$q_start = get_microtime();
+
+		@pg_send_query($this->link_id, $sql);
+		$this->query_result = @pg_get_result($this->link_id);
+
+		if (pg_result_status($this->query_result) != PGSQL_FATAL_ERROR)
+		{
+			if (defined('PUN_SHOW_QUERIES'))
+				$this->saved_queries[] = array($sql, sprintf('%.5f', get_microtime() - $q_start));
+
+			++$this->num_queries;
+
+			$this->last_query_text[$this->query_result] = $sql;
+
+			return $this->query_result;
+		}
+		else
+		{
+			if (defined('PUN_SHOW_QUERIES'))
+				$this->saved_queries[] = array($sql, 0);
+
+			$this->error_msg = @pg_result_error($this->query_result);
+
+			if ($this->in_transaction)
+				@pg_query($this->link_id, 'ROLLBACK');
+
+			--$this->in_transaction;
+
+			return false;
+		}
+	}
+
+
+	function query_build($query, $unbuffered = false)
+	{
+		$sql = '';
+
+		if (isset($query['SELECT']))
+		{
+			$sql = 'SELECT '.$query['SELECT'].' FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['FROM'];
+
+			if (isset($query['JOINS']))
+			{
+				foreach ($query['JOINS'] as $cur_join)
+					$sql .= ' '.key($cur_join).' '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).current($cur_join).' ON '.$cur_join['ON'];
+			}
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+			if (!empty($query['GROUP BY']))
+				$sql .= ' GROUP BY '.$query['GROUP BY'];
+			if (!empty($query['HAVING']))
+				$sql .= ' HAVING '.$query['HAVING'];
+			if (!empty($query['ORDER BY']))
+				$sql .= ' ORDER BY '.$query['ORDER BY'];
+			if (!empty($query['LIMIT']))
+				$sql .= ' LIMIT '.$query['LIMIT'];
+		}
+		else if (isset($query['INSERT']))
+		{
+			$sql = 'INSERT INTO '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['INTO'];
+
+			if (!empty($query['INSERT']))
+				$sql .= ' ('.$query['INSERT'].')';
+
+			$sql .= ' VALUES('.$query['VALUES'].')';
+		}
+		else if (isset($query['UPDATE']))
+		{
+			$query['UPDATE'] = (isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['UPDATE'];
+
+			$sql = 'UPDATE '.$query['UPDATE'].' SET '.$query['SET'];
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+		}
+		else if (isset($query['DELETE']))
+		{
+			$sql = 'DELETE FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['DELETE'];
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+		}
+
+		return $this->query($sql, $unbuffered);
+	}
+
+
+	function result($query_id = 0, $row = 0)
+	{
+		return ($query_id) ? @pg_fetch_result($query_id, $row, 0) : false;
+	}
+
+
+	function fetch_assoc($query_id = 0)
+	{
+		return ($query_id) ? @pg_fetch_assoc($query_id) : false;
+	}
+
+
+	function fetch_row($query_id = 0)
+	{
+		return ($query_id) ? @pg_fetch_row($query_id) : false;
+	}
+
+
+	function num_rows($query_id = 0)
+	{
+		return ($query_id) ? @pg_num_rows($query_id) : false;
+	}
+
+
+	function affected_rows()
+	{
+		return ($this->query_result) ? @pg_affected_rows($this->query_result) : false;
+	}
+
+
+	function insert_id()
+	{
+		$query_id = $this->query_result;
+
+		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))
+			{
+				// Hack (don't ask)
+				if (substr($table_name[1], -6) == 'groups')
+					$table_name[1] .= '_g';
+
+				$temp_q_id = @pg_query($this->link_id, 'SELECT currval(\''.$table_name[1].'_id_seq\')');
+				return ($temp_q_id) ? intval(@pg_fetch_result($temp_q_id, 0)) : false;
+			}
+		}
+
+		return false;
+	}
+
+
+	function get_num_queries()
+	{
+		return $this->num_queries;
+	}
+
+
+	function get_saved_queries()
+	{
+		return $this->saved_queries;
+	}
+
+
+	function free_result($query_id = false)
+	{
+		if (!$query_id)
+			$query_id = $this->query_result;
+
+		return ($query_id) ? @pg_free_result($query_id) : false;
+	}
+
+
+	function escape($str)
+	{
+		return is_array($str) ? '' : pg_escape_string($str);
+	}
+
+
+	function error()
+	{
+		$result['error_sql'] = @current(@end($this->saved_queries));
+		$result['error_no'] = false;
+/*
+		if (!empty($this->query_result))
+		{
+			$result['error_msg'] = trim(@pg_result_error($this->query_result));
+			if ($result['error_msg'] != '')
+				return $result;
+		}
+
+		$result['error_msg'] = (!empty($this->link_id)) ? trim(@pg_last_error($this->link_id)) : trim(@pg_last_error());
+*/
+		$result['error_msg'] = $this->error_msg;
+
+		return $result;
+	}
+
+
+	function close()
+	{
+		if ($this->link_id)
+		{
+			if ($this->in_transaction)
+			{
+				if (defined('PUN_SHOW_QUERIES'))
+					$this->saved_queries[] = array('COMMIT', 0);
+
+				@pg_query($this->link_id, 'COMMIT');
+			}
+
+			if ($this->query_result)
+				@pg_free_result($this->query_result);
+
+			return @pg_close($this->link_id);
+		}
+		else
+			return false;
+	}
+
+
+	function table_exists($table_name)
+	{
+		$result = $this->query('SELECT 1 FROM pg_class WHERE relname = \''.$this->escape($table_name).'\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function field_exists($table_name, $field_name)
+	{
+		$result = $this->query('SELECT 1 FROM pg_class c INNER JOIN pg_attribute a ON a.attrelid = c.oid WHERE c.relname = \''.$this->escape($table_name).'\' AND a.attname = \''.$this->escape($field_name).'\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function index_exists($table_name, $index_name)
+	{
+		$result = $this->query('SELECT 1 FROM pg_index i INNER JOIN pg_class c1 ON c1.oid = i.indrelid INNER JOIN pg_class c2 ON c2.oid = i.indexrelid WHERE c1.relname = \''.$this->escape($table_name).'\' AND c2.relname = \''.$this->escape($index_name).'\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null)
+	{
+		if ($this->field_exists($table_name, $field_name))
+			return;
+
+		$field_type = str_replace(array('TINY', 'FLOAT'), array('SMALL', 'REAL'), strtoupper($field_type));
+		$field_type = preg_replace('/(.*?INT)(\([0-9]+)\)/', '$1', $field_type);
+
+		$this->query('ALTER TABLE '.$table_name.' ADD '.$field_name.' '.$field_type) or error(__FILE__, __LINE__);
+
+		if ($default_value !== null)
+		{
+			if (!is_int($default_value) && !is_float($default_value))
+				$default_value = '\''.$this->escape($default_value).'\'';
+
+			$this->query('ALTER TABLE '.$table_name.' ALTER '.$field_name.' SET DEFAULT '.$default_value) or error(__FILE__, __LINE__);
+			$this->query('UPDATE '.$table_name.' SET '.$field_name.'='.$default_value) or error(__FILE__, __LINE__);
+		}
+
+		if (!$allow_null)
+			$this->query('ALTER TABLE '.$table_name.' ALTER '.$field_name.' SET NOT NULL') or error(__FILE__, __LINE__);
+	}
+
+
+	function drop_field($table_name, $field_name)
+	{
+		if (!$this->field_exists($table_name, $field_name))
+			return;
+
+		$this->query('ALTER TABLE '.$table_name.' DROP '.$field_name) or error(__FILE__, __LINE__);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/dblayer/sqlite.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,354 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure we have built in support for SQLite
+if (!function_exists('sqlite_open'))
+	exit('This PHP environment doesn\'t have SQLite support built in. SQLite support is required if you want to use a SQLite database to run this forum. Consult the PHP documentation for further assistance.');
+
+
+class DBLayer
+{
+	var $prefix;
+	var $link_id;
+	var $query_result;
+	var $in_transaction = 0;
+
+	var $saved_queries = array();
+	var $num_queries = 0;
+
+	var $error_no = false;
+	var $error_msg = 'Unknown';
+
+
+	function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
+	{
+		// Prepend $db_name with the path to the forum root directory
+		$db_name = PUN_ROOT.$db_name;
+
+		$this->prefix = $db_prefix;
+
+		if (!file_exists($db_name))
+		{
+			@touch($db_name);
+			@chmod($db_name, 0666);
+			if (!file_exists($db_name))
+				error('Unable to create new database \''.$db_name.'\'. Permission denied.', __FILE__, __LINE__);
+		}
+
+		if (!is_readable($db_name))
+			error('Unable to open database \''.$db_name.'\' for reading. Permission denied.', __FILE__, __LINE__);
+
+		if (!is_writable($db_name))
+			error('Unable to open database \''.$db_name.'\' for writing. Permission denied.', __FILE__, __LINE__);
+
+		if ($p_connect)
+			$this->link_id = @sqlite_popen($db_name, 0666, $sqlite_error);
+		else
+			$this->link_id = @sqlite_open($db_name, 0666, $sqlite_error);
+
+		if (!$this->link_id)
+			error('Unable to open database \''.$db_name.'\'. SQLite reported: '.$sqlite_error, __FILE__, __LINE__);
+		else
+			return $this->link_id;
+	}
+
+
+	function start_transaction()
+	{
+		++$this->in_transaction;
+
+		return (@sqlite_query($this->link_id, 'BEGIN')) ? true : false;
+	}
+
+
+	function end_transaction()
+	{
+		--$this->in_transaction;
+
+		if (@sqlite_query($this->link_id, 'COMMIT'))
+			return true;
+		else
+		{
+			@sqlite_query($this->link_id, 'ROLLBACK');
+			return false;
+		}
+	}
+
+
+	function query($sql, $unbuffered = false)
+	{
+		if (strlen($sql) > 140000)
+			exit('Insane query. Aborting.');
+
+		if (defined('PUN_SHOW_QUERIES'))
+			$q_start = get_microtime();
+
+		if ($unbuffered)
+			$this->query_result = @sqlite_unbuffered_query($this->link_id, $sql);
+		else
+			$this->query_result = @sqlite_query($this->link_id, $sql);
+
+		if ($this->query_result)
+		{
+			if (defined('PUN_SHOW_QUERIES'))
+				$this->saved_queries[] = array($sql, sprintf('%.5f', get_microtime() - $q_start));
+
+			++$this->num_queries;
+
+			return $this->query_result;
+		}
+		else
+		{
+			if (defined('PUN_SHOW_QUERIES'))
+				$this->saved_queries[] = array($sql, 0);
+
+			$this->error_no = @sqlite_last_error($this->link_id);
+			$this->error_msg = @sqlite_error_string($this->error_no);
+
+			if ($this->in_transaction)
+				@sqlite_query($this->link_id, 'ROLLBACK');
+
+			--$this->in_transaction;
+
+			return false;
+		}
+	}
+
+
+	function query_build($query, $unbuffered = false)
+	{
+		$sql = '';
+
+		if (isset($query['SELECT']))
+		{
+			$sql = 'SELECT '.$query['SELECT'].' FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['FROM'];
+
+			if (isset($query['JOINS']))
+			{
+				foreach ($query['JOINS'] as $cur_join)
+					$sql .= ' '.key($cur_join).' '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).current($cur_join).' ON '.$cur_join['ON'];
+			}
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+			if (!empty($query['GROUP BY']))
+				$sql .= ' GROUP BY '.$query['GROUP BY'];
+			if (!empty($query['HAVING']))
+				$sql .= ' HAVING '.$query['HAVING'];
+			if (!empty($query['ORDER BY']))
+				$sql .= ' ORDER BY '.$query['ORDER BY'];
+			if (!empty($query['LIMIT']))
+				$sql .= ' LIMIT '.$query['LIMIT'];
+		}
+		else if (isset($query['INSERT']))
+		{
+			$sql = 'INSERT INTO '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['INTO'];
+
+			if (!empty($query['INSERT']))
+				$sql .= ' ('.$query['INSERT'].')';
+
+			$sql .= ' VALUES('.$query['VALUES'].')';
+		}
+		else if (isset($query['UPDATE']))
+		{
+			$query['UPDATE'] = (isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['UPDATE'];
+
+			$sql = 'UPDATE '.$query['UPDATE'].' SET '.$query['SET'];
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+		}
+		else if (isset($query['DELETE']))
+		{
+			$sql = 'DELETE FROM '.(isset($query['PARAMS']['NO_PREFIX']) ? '' : $this->prefix).$query['DELETE'];
+
+			if (!empty($query['WHERE']))
+				$sql .= ' WHERE '.$query['WHERE'];
+		}
+
+		return $this->query($sql, $unbuffered);
+	}
+
+
+	function result($query_id = 0, $row = 0)
+	{
+		if ($query_id)
+		{
+			if ($row != 0)
+				@sqlite_seek($query_id, $row);
+
+			return @current(@sqlite_current($query_id));
+		}
+		else
+			return false;
+	}
+
+
+	function fetch_assoc($query_id = 0)
+	{
+		if ($query_id)
+		{
+			$cur_row = @sqlite_fetch_array($query_id, SQLITE_ASSOC);
+			if ($cur_row)
+			{
+				// Horrible hack to get rid of table names and table aliases from the array keys
+				while (list($key, $value) = @each($cur_row))
+				{
+					$dot_spot = strpos($key, '.');
+					if ($dot_spot !== false)
+					{
+						unset($cur_row[$key]);
+						$key = substr($key, $dot_spot+1);
+						$cur_row[$key] = $value;
+					}
+				}
+			}
+
+			return $cur_row;
+		}
+		else
+			return false;
+	}
+
+
+	function fetch_row($query_id = 0)
+	{
+		return ($query_id) ? @sqlite_fetch_array($query_id, SQLITE_NUM) : false;
+	}
+
+
+	function num_rows($query_id = 0)
+	{
+		return ($query_id) ? @sqlite_num_rows($query_id) : false;
+	}
+
+
+	function affected_rows()
+	{
+		return ($this->query_result) ? @sqlite_changes($this->query_result) : false;
+	}
+
+
+	function insert_id()
+	{
+		return ($this->link_id) ? @sqlite_last_insert_rowid($this->link_id) : false;
+	}
+
+
+	function get_num_queries()
+	{
+		return $this->num_queries;
+	}
+
+
+	function get_saved_queries()
+	{
+		return $this->saved_queries;
+	}
+
+
+	function free_result($query_id = false)
+	{
+		return true;
+	}
+
+
+	function escape($str)
+	{
+		return is_array($str) ? '' : sqlite_escape_string($str);
+	}
+
+
+	function error()
+	{
+		$result['error_sql'] = @current(@end($this->saved_queries));
+		$result['error_no'] = $this->error_no;
+		$result['error_msg'] = $this->error_msg;
+
+		return $result;
+	}
+
+
+	function close()
+	{
+		if ($this->link_id)
+		{
+			if ($this->in_transaction)
+			{
+				if (defined('PUN_SHOW_QUERIES'))
+					$this->saved_queries[] = array('COMMIT', 0);
+
+				@sqlite_query($this->link_id, 'COMMIT');
+			}
+
+			return @sqlite_close($this->link_id);
+		}
+		else
+			return false;
+	}
+
+
+	function table_exists($table_name)
+	{
+		$result = $this->query('SELECT 1 FROM sqlite_master WHERE name = \''.$this->escape($table_name).'\' AND type=\'table\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function field_exists($table_name, $field_name)
+	{
+		$result = $this->query('SELECT sql FROM sqlite_master WHERE name = \''.$this->escape($table_name).'\' AND type=\'table\'');
+		if (!$this->num_rows($result))
+			return false;
+
+		return preg_match('/[\r\n]'.preg_quote($field_name).' /', $this->result($result));
+	}
+
+
+	function index_exists($table_name, $index_name)
+	{
+		$result = $this->query('SELECT 1 FROM sqlite_master WHERE tbl_name = \''.$this->escape($table_name).'\' AND name = \''.$this->escape($index_name).'\' AND type=\'index\'');
+		return $this->num_rows($result) > 0;
+	}
+
+
+	function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null)
+	{
+		if ($this->field_exists($table_name, $field_name))
+			return;
+
+		if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
+			$default_value = '\''.$this->escape($default_value).'\'';
+
+		$this->query('ALTER TABLE '.$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ')) or error(__FILE__, __LINE__);
+	}
+
+
+	function drop_field($table_name, $field_name)
+	{
+		// No DROP column in SQLite
+		return;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/email.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,189 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
+
+
+//
+// Validate an e-mail address
+//
+function is_valid_email($email)
+{
+	if (strlen($email) > 80)
+		return false;
+
+	return preg_match('/^(([^<>()[\]\\.,;:\s@"\']+(\.[^<>()[\]\\.,;:\s@"\']+)*)|("[^"\']+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\d\-]+\.)+[a-zA-Z]{2,}))$/', $email);
+}
+
+
+//
+// Check if $email is banned
+//
+function is_banned_email($email)
+{
+	global $pun_db, $pun_bans;
+
+	foreach ($pun_bans as $cur_ban)
+	{
+		if ($cur_ban['email'] != '' &&
+			($email == $cur_ban['email'] ||
+			(strpos($cur_ban['email'], '@') === false && stristr($email, '@'.$cur_ban['email']))))
+			return true;
+	}
+
+	return false;
+}
+
+
+//
+// Wrapper for PHP's mail()
+//
+function pun_mail($to, $subject, $message, $from = '')
+{
+	global $pun_config, $lang_common;
+
+	// Default sender/return address
+	if (!$from)
+		$from = '"'.sprintf($lang_common['Forum mailer'], str_replace('"', '', $pun_config['o_board_title'])).'" <'.$pun_config['o_webmaster_email'].'>';
+
+	// Do a little spring cleaning
+	$to = trim(preg_replace('#[\n\r]+#s', '', $to));
+	$subject = trim(preg_replace('#[\n\r]+#s', '', $subject));
+	$from = trim(preg_replace('#[\n\r:]+#s', '', $from));
+
+	$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: PunBB Mailer';
+
+	// Make sure all linebreaks are CRLF in message (and strip out any NULL bytes)
+	$message = str_replace(array("\n", "\0"), array("\r\n", ''), pun_linebreaks($message));
+
+	if ($pun_config['o_smtp_host'] != '')
+		smtp_mail($to, $subject, $message, $headers);
+	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);
+
+		mail($to, $subject, $message, $headers);
+	}
+}
+
+
+//
+// This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com).
+// They deserve all the credit for writing it. I made small modifications for it to suit PunBB and it's coding standards.
+//
+function server_parse($socket, $expected_response)
+{
+	$server_response = '';
+	while (substr($server_response, 3, 1) != ' ')
+	{
+		if (!($server_response = fgets($socket, 256)))
+			error('Couldn\'t get mail server response codes. Please contact the forum administrator.', __FILE__, __LINE__);
+	}
+
+	if (!(substr($server_response, 0, 3) == $expected_response))
+		error('Unable to send e-mail. Please contact the forum administrator with the following error message reported by the SMTP server: "'.$server_response.'"', __FILE__, __LINE__);
+}
+
+
+//
+// This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com).
+// They deserve all the credit for writing it. I made small modifications for it to suit PunBB and it's coding standards.
+//
+function smtp_mail($to, $subject, $message, $headers = '')
+{
+	global $pun_config;
+
+	$recipients = explode(',', $to);
+
+	// Are we using port 25 or a custom port?
+	if (strpos($pun_config['o_smtp_host'], ':') !== false)
+		list($smtp_host, $smtp_port) = explode(':', $pun_config['o_smtp_host']);
+	else
+	{
+		$smtp_host = $pun_config['o_smtp_host'];
+		$smtp_port = 25;
+	}
+
+	if ($pun_config['o_smtp_ssl'] == '1')
+		$smtp_host = 'ssl://'.$smtp_host;
+
+	if (!($socket = fsockopen($smtp_host, $smtp_port, $errno, $errstr, 15)))
+		error('Could not connect to smtp host "'.$pun_config['o_smtp_host'].'" ('.$errno.') ('.$errstr.').', __FILE__, __LINE__);
+
+	server_parse($socket, '220');
+
+	if ($pun_config['o_smtp_user'] != '' && $pun_config['o_smtp_pass'] != '')
+	{
+		fwrite($socket, 'EHLO '.$smtp_host."\r\n");
+		server_parse($socket, '250');
+
+		fwrite($socket, 'AUTH LOGIN'."\r\n");
+		server_parse($socket, '334');
+
+		fwrite($socket, base64_encode($pun_config['o_smtp_user'])."\r\n");
+		server_parse($socket, '334');
+
+		fwrite($socket, base64_encode($pun_config['o_smtp_pass'])."\r\n");
+		server_parse($socket, '235');
+	}
+	else
+	{
+		fwrite($socket, 'HELO '.$smtp_host."\r\n");
+		server_parse($socket, '250');
+	}
+
+	fwrite($socket, 'MAIL FROM: <'.$pun_config['o_webmaster_email'].'>'."\r\n");
+	server_parse($socket, '250');
+
+	$to_header = 'To: ';
+
+	@reset($recipients);
+	while (list(, $email) = @each($recipients))
+	{
+		fwrite($socket, 'RCPT TO: <'.$email.'>'."\r\n");
+		server_parse($socket, '250');
+
+		$to_header .= '<'.$email.'>, ';
+	}
+
+	fwrite($socket, 'DATA'."\r\n");
+	server_parse($socket, '354');
+
+	fwrite($socket, 'Subject: '.$subject."\r\n".$to_header."\r\n".$headers."\r\n\r\n".$message."\r\n");
+
+	fwrite($socket, '.'."\r\n");
+	server_parse($socket, '250');
+
+	fwrite($socket, 'QUIT'."\r\n");
+	fclose($socket);
+
+	return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/functions.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,2634 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+//
+// Return all code blocks that hook into $hook_id
+//
+function get_hook($hook_id)
+{
+	global $pun_hooks;
+
+	return !defined('PUN_DISABLE_HOOKS') && isset($pun_hooks[$hook_id]) ? implode("\n", $pun_hooks[$hook_id]) : false;
+}
+
+
+//
+// Authenticates the provided username and password against the user database
+// $user can be either a user ID (integer) or a username (string)
+// $password can be either a plaintext password or a password hash including salt ($password_is_hash must be set accordingly)
+//
+function authenticate_user($user, $password, $password_is_hash = false)
+{
+	global $pun_db, $pun_user;
+
+	($hook = get_hook('fn_authenticate_user_start')) ? eval($hook) : null;
+
+	// Check if there's a user matching $user and $password
+	$query = array(
+		'SELECT'	=> 'eu.username AS username, u.*, g.*, o.logged, o.idle, o.csrf_token, o.prev_url',
+		'FROM'		=> 'users AS u',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'groups AS g',
+				'ON'			=> 'g.g_id=u.group_id'
+			),
+			array(
+				'LEFT JOIN'		=> 'online AS o',
+				'ON'			=> 'o.user_id=u.id'
+			)
+		)
+	);
+  
+	// Are we looking for a user ID or a username?
+	$query['WHERE'] = is_int($user) ? 'u.id='.intval($user) : 'u.username=\''.$pun_db->escape($user).'\'';
+
+	($hook = get_hook('fn_qr_get_user')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$pun_user = $pun_db->fetch_assoc($result);
+
+	if (!isset($pun_user['id']) ||
+		($password_is_hash && $password != $pun_user['password']) ||
+		(!$password_is_hash && sha1($pun_user['salt'].sha1($password)) != $pun_user['password']))
+		set_default_user();
+    
+	($hook = get_hook('fn_authenticate_user_end')) ? eval($hook) : null;
+}
+
+//
+// Replacement for authenticate_user() for Enano.
+//
+
+function authenticate_user_enano()
+{
+	global $pun_db, $pun_user;
+	// import Enano globals
+	global $db, $session, $paths, $template, $plugins; // Common objects
+
+	($hook = get_hook('fn_authenticate_user_start')) ? eval($hook) : null;
+
+	// Check if there's a user matching $user and $password
+	$query = array(
+		'SELECT'	=> 'eu.username AS username_authoritative, u.*, u.username AS bla, g.*, o.logged, o.idle, o.csrf_token, o.prev_url',
+    'FROM'		=> $pun_db->prefix . 'users AS u',
+		'JOINS'		=> array(
+      array(
+        'LEFT JOIN' => table_prefix . 'users AS eu',
+        'ON'        => 'eu.user_id = u.id'
+      ),
+			array(
+				'INNER JOIN'	=> $pun_db->prefix . 'groups AS g',
+				'ON'			=> 'g.g_id=u.group_id'
+			),
+			array(
+				'LEFT JOIN'		=> $pun_db->prefix . 'online AS o',
+				'ON'			=> 'o.user_id=u.id'
+			)
+		),
+    'PARAMS' => array(
+      'NO_PREFIX' => ''
+    )
+	);
+
+	// Are we looking for a user ID or a username?
+	$query['WHERE'] = 'u.id=' . $session->user_id;
+
+	($hook = get_hook('fn_qr_get_user')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$pun_user = $pun_db->fetch_assoc($result);
+  $pun_user['username'] =& $pun_user['username_authoritative'];
+
+	if (!$session->user_logged_in)
+		set_default_user();
+  
+	($hook = get_hook('fn_authenticate_user_end')) ? eval($hook) : null;
+}
+
+//
+// Attempt to login with the user ID and password hash from the cookie
+//
+function cookie_login(&$pun_user)
+{
+	global $pun_db, $db_type, $pun_config, $cookie_name, $cookie_path, $cookie_domain, $cookie_secure, $pun_time_formats, $pun_date_formats;
+  // import Enano globals
+	global $db, $session, $paths, $template, $plugins; // Common objects
+
+	($hook = get_hook('fn_cookie_login_start')) ? eval($hook) : null;
+	
+	$now = time();
+	
+	($hook = get_hook('fn_cookie_login_fetch_cookie')) ? eval($hook) : null;
+	
+	if ( $session->user_logged_in )
+	{
+		authenticate_user_enano();
+
+		// If we got back the default user, the login failed
+		if ($pun_user['id'] == '1')
+		{
+			// pun_setcookie($cookie_name, base64_encode('1|'.random_key(8, true)), $expire);
+			return;
+		}
+		
+		// Set a default language if the user selected language no longer exists
+		if (!@file_exists(PUN_ROOT.'lang/'.$pun_user['language']))
+			$pun_user['language'] = $pun_config['o_default_lang'];
+
+		// Set a default style if the user selected style no longer exists
+		if (!@file_exists(PUN_ROOT.'style/'.$pun_user['style'].'/'.$pun_user['style'].'.css'))
+			$pun_user['style'] = $pun_config['o_default_style'];
+
+		if (!$pun_user['disp_topics'])
+			$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
+		if (!$pun_user['disp_posts'])
+			$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
+
+		if ($pun_user['save_pass'] == '0')
+			$expire = 0;
+
+		// Check user has a valid date and time format
+		if (!isset($pun_time_formats[$pun_user['time_format']]))
+			$pun_user['time_format'] = 0;
+		if (!isset($pun_date_formats[$pun_user['date_format']]))
+			$pun_user['date_format'] = 0;
+
+		// Define this if you want this visit to affect the online list and the users last visit data
+		if (!defined('PUN_QUIET_VISIT'))
+		{
+			// Update the online list
+			if (!$pun_user['logged'])
+			{
+				$pun_user['logged'] = $now;
+				$pun_user['csrf_token'] = random_key(40, false, true);
+				$pun_user['prev_url'] = get_current_url();
+
+				// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
+				switch ($db_type)
+				{
+					case 'pgsql':
+						$query = 'INSERT INTO '.$pun_db->prefix.'online (user_id, ident, logged, csrf_token, prev_url) SELECT '.$pun_user['id'].', \''.$pun_db->escape($pun_user['username']).'\', '.$pun_user['logged'].', \''.$pun_user['csrf_token'].'\', \''.$pun_db->escape($pun_user['prev_url']).'\' FROM '.$pun_db->prefix.'users WHERE id = '.$pun_user['id'].' AND NOT EXISTS (SELECT 1 FROM '.$pun_db->prefix.'online WHERE user_id='.$pun_user['id'].')';
+						($hook = get_hook('fn_qr_add_online_user')) ? eval($hook) : null;
+						$pun_db->query($query) or error(__FILE__, __LINE__);
+						break;
+
+					default:
+						$query = array(
+							'REPLACE'	=> 'user_id, ident, logged, csrf_token, prev_url',
+							'INTO'		=> 'online',
+							'VALUES'	=> $pun_user['id'].', \''.$pun_db->escape($pun_user['username']).'\', '.$pun_user['logged'].', \''.$pun_user['csrf_token'].'\', \''.$pun_db->escape($pun_user['prev_url']).'\''
+						);
+						($hook = get_hook('fn_qr_add_online_user')) ? eval($hook) : null;
+						$pun_db->query_build($query) or error(__FILE__, __LINE__);
+						break;
+				}
+
+				// Reset tracked topics
+				set_tracked_topics(null);
+			}
+			else
+			{
+				// Special case: We've timed out, but no other user has browsed the forums since we timed out
+				if ($pun_user['logged'] < ($now-$pun_config['o_timeout_visit']))
+				{
+					$query = array(
+						'UPDATE'	=> 'users',
+						'SET'		=> 'last_visit='.$pun_user['logged'],
+						'WHERE'		=> 'id='.$pun_user['id']
+					);
+
+					($hook = get_hook('fn_qr_update_user_visit')) ? eval($hook) : null;
+					$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+					$pun_user['last_visit'] = $pun_user['logged'];
+				}
+
+				// Now update the logged time and save the current URL in the online list
+				$query = array(
+					'UPDATE'	=> 'online',
+					'SET'		=> 'logged='.$now.', prev_url=\''.$pun_db->escape(get_current_url()).'\'',
+					'WHERE'		=> 'user_id='.$pun_user['id']
+				);
+
+				if ($pun_user['idle'] == '1')
+					$query['SET'] .= ', idle=0';
+
+				($hook = get_hook('fn_qr_update_online_user')) ? eval($hook) : null;
+				$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+				// Update tracked topics with the current expire time
+				if (isset($_COOKIE[$cookie_name.'_track']))
+					pun_setcookie($cookie_name.'_track', $_COOKIE[$cookie_name.'_track'], time() + $pun_config['o_timeout_visit']);
+			}
+		}
+
+		$pun_user['is_guest'] = false;
+		$pun_user['is_admmod'] = $session->user_level >= USER_LEVEL_MOD || $pun_user['g_moderator'] == '1';
+	}
+	else
+		set_default_user();
+
+	($hook = get_hook('fn_cookie_login_end')) ? eval($hook) : null;
+}
+
+
+//
+// Fill $pun_user with default values (for guests)
+//
+function set_default_user()
+{
+	global $pun_db, $db_type, $pun_user, $pun_config;
+
+	($hook = get_hook('fn_set_default_user_start')) ? eval($hook) : null;
+
+	$remote_addr = get_remote_address();
+
+	// Fetch guest user
+	$query = array(
+		'SELECT'	=> 'u.*, g.*, o.logged, o.csrf_token, o.prev_url',
+		'FROM'		=> 'users AS u',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'groups AS g',
+				'ON'			=> 'g.g_id=u.group_id'
+			),
+			array(
+				'LEFT JOIN'		=> 'online AS o',
+				'ON'			=> 'o.ident=\''.$remote_addr.'\''
+			)
+		),
+		'WHERE'		=> 'u.id=1'
+	);
+
+	($hook = get_hook('fn_qr_get_default_user')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if (!$pun_db->num_rows($result))
+		exit('Unable to fetch guest information. The table \''.$pun_db->prefix.'users\' must contain an entry with id = 1 that represents anonymous users.');
+
+	$pun_user = $pun_db->fetch_assoc($result);
+
+	// Update online list
+	if (!$pun_user['logged'])
+	{
+		$pun_user['logged'] = time();
+		$pun_user['csrf_token'] = random_key(40, false, true);
+		$pun_user['prev_url'] = get_current_url();
+
+		// With MySQL/MySQLi/SQLite, REPLACE INTO avoids a user having two rows in the online table
+		switch ($db_type)
+		{
+			case 'pgsql':
+				$query = 'INSERT INTO '.$pun_db->prefix.'online (user_id, ident, logged, csrf_token, prev_url) SELECT 1, \''.$pun_db->escape($remote_addr).'\', '.$pun_user['logged'].', \''.$pun_user['csrf_token'].'\', \''.$pun_db->escape($pun_user['prev_url']).'\' FROM '.$pun_db->prefix.'users WHERE id=1 AND NOT EXISTS (SELECT 1 FROM '.$pun_db->prefix.'online WHERE user_id=1 AND ident=\''.$pun_db->escape($remote_addr).'\')';
+				($hook = get_hook('fn_qr_add_online_guest_user')) ? eval($hook) : null;
+				$pun_db->query($query) or error(__FILE__, __LINE__);
+				break;
+
+			default:
+				$query = array(
+					'REPLACE'	=> 'user_id, ident, logged, csrf_token, prev_url',
+					'INTO'		=> 'online',
+					'VALUES'	=> '1, \''.$pun_db->escape($remote_addr).'\', '.$pun_user['logged'].', \''.$pun_user['csrf_token'].'\', \''.$pun_db->escape($pun_user['prev_url']).'\''
+				);
+				($hook = get_hook('fn_qr_add_online_guest_user')) ? eval($hook) : null;
+				$pun_db->query_build($query) or error(__FILE__, __LINE__);
+				break;
+		}
+	}
+	else
+	{
+		$query = array(
+			'UPDATE'	=> 'online',
+			'SET'		=> 'logged='.time().', prev_url=\''.$pun_db->escape(get_current_url()).'\'',
+			'WHERE'		=> 'ident=\''.$pun_db->escape($remote_addr).'\''
+		);
+
+		($hook = get_hook('fn_qr_update_online_guest_user')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	}
+
+	$pun_user['disp_topics'] = $pun_config['o_disp_topics_default'];
+	$pun_user['disp_posts'] = $pun_config['o_disp_posts_default'];
+	$pun_user['timezone'] = $pun_config['o_default_timezone'];
+	$pun_user['language'] = $pun_config['o_default_lang'];
+	$pun_user['style'] = $pun_config['o_default_style'];
+	$pun_user['is_guest'] = true;
+	$pun_user['is_admmod'] = false;
+}
+
+
+//
+// Set a cookie, PunBB style!
+//
+function pun_setcookie($name, $value, $expire)
+{
+	global $cookie_path, $cookie_domain, $cookie_secure;
+
+	($hook = get_hook('fn_pun_setcookie_start')) ? eval($hook) : null;
+
+	// Enable sending of a P3P header by removing // from the following line (try this if login is failing in IE6)
+//	@header('P3P: CP="CUR ADM"');
+
+	if (version_compare(PHP_VERSION, '5.2.0', '>='))
+		setcookie($name, $value, $expire, $cookie_path, $cookie_domain, $cookie_secure, true);
+	else
+		setcookie($name, $value, $expire, $cookie_path.'; HttpOnly', $cookie_domain, $cookie_secure);
+}
+
+
+//
+// Check whether the connecting user is banned (and delete any expired bans while we're at it)
+//
+function check_bans()
+{
+	global $pun_db, $pun_config, $lang_common, $pun_user, $pun_bans;
+  // import Enano globals
+	global $db, $session, $paths, $template, $plugins; // Common objects
+
+	($hook = get_hook('fn_check_bans_start')) ? eval($hook) : null;
+
+	// Admins aren't affected
+	if (defined('PUN_ADMIN') && $session->user_level >= USER_LEVEL_ADMIN || !$pun_bans)
+		return;
+
+	// Add a dot at the end of the IP address to prevent banned address 192.168.0.5 from matching e.g. 192.168.0.50
+	$user_ip = get_remote_address().'.';
+	$bans_altered = false;
+
+	foreach ($pun_bans as $cur_ban)
+	{
+		// Has this ban expired?
+		if ($cur_ban['expire'] != '' && $cur_ban['expire'] <= time())
+		{
+			$query = array(
+				'DELETE'	=> 'bans',
+				'WHERE'		=> 'id='.$cur_ban['id']
+			);
+
+			($hook = get_hook('fn_qr_delete_expired_ban')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			$bans_altered = true;
+			continue;
+		}
+
+		if ($cur_ban['username'] != '' && strtolower($pun_user['username']) == strtolower($cur_ban['username']))
+		{
+			$query = array(
+				'DELETE'	=> 'online',
+				'WHERE'		=> 'ident=\''.$pun_db->escape($pun_user['username']).'\''
+			);
+
+			($hook = get_hook('fn_qr_delete_online_user')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			message($lang_common['Ban message'].' '.(($cur_ban['expire'] != '') ? sprintf($lang_common['Ban message 2'], strtolower(format_time($cur_ban['expire'], true))) : '').(($cur_ban['message'] != '') ? ' '.$lang_common['Ban message 3'].'<br /><br /><strong>'.htmlspecialchars($cur_ban['message']).'</strong><br /><br />' : '<br /><br />').sprintf($lang_common['Ban message 4'], '<a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>'), true);
+		}
+
+		if ($cur_ban['ip'] != '')
+		{
+			$cur_ban_ips = explode(' ', $cur_ban['ip']);
+
+			$num_ips = count($cur_ban_ips);
+			for ($i = 0; $i < $num_ips; ++$i)
+			{
+				$cur_ban_ips[$i] = $cur_ban_ips[$i].'.';
+
+				if (substr($user_ip, 0, strlen($cur_ban_ips[$i])) == $cur_ban_ips[$i])
+				{
+					$query = array(
+						'DELETE'	=> 'online',
+						'WHERE'		=> 'ident=\''.$pun_db->escape($pun_user['username']).'\''
+					);
+
+					($hook = get_hook('fn_qr_delete_online_user2')) ? eval($hook) : null;
+					$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+					message($lang_common['Ban message'].' '.(($cur_ban['expire'] != '') ? sprintf($lang_common['Ban message 2'], strtolower(format_time($cur_ban['expire'], true))) : '').(($cur_ban['message'] != '') ? ' '.$lang_common['Ban message 3'].'<br /><br /><strong>'.htmlspecialchars($cur_ban['message']).'</strong><br /><br />' : '<br /><br />').sprintf($lang_common['Ban message 4'], '<a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>'), true);
+				}
+			}
+		}
+	}
+
+	// If we removed any expired bans during our run-through, we need to regenerate the bans cache
+	if ($bans_altered)
+	{
+		require_once PUN_ROOT.'include/cache.php';
+		generate_bans_cache();
+	}
+}
+
+
+//
+// Update "Users online"
+//
+function update_users_online()
+{
+	global $pun_db, $pun_config, $pun_user;
+
+	$now = time();
+
+	($hook = get_hook('fn_update_users_online_start')) ? eval($hook) : null;
+
+	// Fetch all online list entries that are older than "o_timeout_online"
+	$query = array(
+		'SELECT'	=> 'o.*',
+		'FROM'		=> 'online AS o',
+		'WHERE'		=> 'o.logged<'.($now-$pun_config['o_timeout_online'])
+	);
+
+	($hook = get_hook('fn_qr_get_old_online_users')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	while ($cur_user = $pun_db->fetch_assoc($result))
+	{
+		// If the entry is a guest, delete it
+		if ($cur_user['user_id'] == '1')
+		{
+			$query = array(
+				'DELETE'	=> 'online',
+				'WHERE'		=> 'ident=\''.$pun_db->escape($cur_user['ident']).'\''
+			);
+
+			($hook = get_hook('fn_qr_delete_online_guest_user')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+		}
+		else
+		{
+			// If the entry is older than "o_timeout_visit", update last_visit for the user in question, then delete him/her from the online list
+			if ($cur_user['logged'] < ($now-$pun_config['o_timeout_visit']))
+			{
+				$query = array(
+					'UPDATE'	=> 'users',
+					'SET'		=> 'last_visit='.$cur_user['logged'],
+					'WHERE'		=> 'id='.$cur_user['user_id']
+				);
+
+				($hook = get_hook('fn_qr_update_user_visit2')) ? eval($hook) : null;
+				$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+				$query = array(
+					'DELETE'	=> 'online',
+					'WHERE'		=> 'user_id='.$cur_user['user_id']
+				);
+
+				($hook = get_hook('fn_qr_delete_online_user3')) ? eval($hook) : null;
+				$pun_db->query_build($query) or error(__FILE__, __LINE__);
+			}
+			else if ($cur_user['idle'] == '0')
+			{
+				$query = array(
+					'UPDATE'	=> 'online',
+					'SET'		=> 'idle=1',
+					'WHERE'		=> 'user_id='.$cur_user['user_id']
+				);
+
+				($hook = get_hook('fn_qr_update_online_user2')) ? eval($hook) : null;
+				$pun_db->query_build($query) or error(__FILE__, __LINE__);
+			}
+		}
+	}
+
+	($hook = get_hook('fn_update_users_online_end')) ? eval($hook) : null;
+}
+
+
+//
+// Generate the "navigator" that appears at the top of every page
+//
+function generate_navlinks()
+{
+	global $pun_config, $lang_common, $pun_url, $pun_user;
+
+	// Index should always be displayed
+	$links[] = '<li id="navindex"'.((PUN_PAGE == 'index') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['index']).'"><span>'.$lang_common['Index'].'</span></a></li>';
+
+	if ($pun_user['g_view_users'] == '1')
+		$links[] = '<li id="navuserlist"'.((PUN_PAGE == 'userlist') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['users']).'"><span>'.$lang_common['User list'].'</span></a></li>';
+
+	if ($pun_config['o_rules'] == '1')
+		$links[] = '<li id="navrules"'.((PUN_PAGE == 'rules') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['rules']).'"><span>'.$lang_common['Rules'].'</span></a></li>';
+
+	if ($pun_user['is_guest'])
+	{
+		if ($pun_user['g_search'] == '1')
+			$links[] = '<li id="navsearch"'.((PUN_PAGE == 'search') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['search']).'"><span>'.$lang_common['Search'].'</span></a></li>';
+
+		$links[] = '<li id="navregister"'.((PUN_PAGE == 'register') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['register']).'"><span>'.$lang_common['Register'].'</span></a></li>';
+		$links[] = '<li id="navlogin"'.((PUN_PAGE == 'login') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['login']).'"><span>'.$lang_common['Login'].'</span></a></li>';
+	}
+	else
+	{
+		if (!$pun_user['is_admmod'])
+		{
+			if ($pun_user['g_search'] == '1')
+				$links[] = '<li id="navsearch"'.((PUN_PAGE == 'search') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['search']).'"><span>'.$lang_common['Search'].'</span></a></li>';
+
+			$links[] = '<li id="navprofile"'.((PUN_PAGE == 'editprofile' || PUN_PAGE == 'viewprofile') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['user'], $pun_user['id']).'"><span>'.$lang_common['Profile'].'</span></a></li>';
+		}
+		else
+		{
+			$links[] = '<li id="navsearch"'.((PUN_PAGE == 'search') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['search']).'"><span>'.$lang_common['Search'].'</span></a></li>';
+			$links[] = '<li id="navprofile"'.((PUN_PAGE == 'editprofile' || PUN_PAGE == 'viewprofile') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['user'], $pun_user['id']).'"><span>'.$lang_common['Profile'].'</span></a></li>';
+			$links[] = '<li id="navadmin"'.((substr(PUN_PAGE, 0, 5) == 'admin') ? ' class="isactive"' : '').'><a href="'.pun_link($pun_url['admin_index']).'"><span>'.$lang_common['Admin'].'</span></a></li>';
+		}
+
+		$links[] = '<li id="navlogout"><a href="'.pun_link($pun_url['logout'], array($pun_user['id'], generate_form_token('logout'.$pun_user['id']))).'"><span>'.$lang_common['Logout'].'</span></a></li>';
+	}
+
+	// Are there any additional navlinks we should insert into the array before imploding it?
+	if ($pun_config['o_additional_navlinks'] != '')
+	{
+		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]);
+			for ($i = 0; $i < $num_links; ++$i)
+				array_insert($links, $extra_links[1][$i], '<li id="navextra'.($i + 1).'">'.$extra_links[2][$i].'</li>');
+		}
+	}
+
+	($hook = get_hook('fn_generate_navlinks_end')) ? eval($hook) : null;
+
+	return implode("\n\t\t", $links);
+}
+
+
+//
+// Display the profile navigation menu
+//
+function generate_profile_menu()
+{
+	global $lang_profile, $pun_url, $pun_config, $pun_user, $id;
+
+	// Setup links for profile menu
+	$profilenav_links = array(
+		'<li'.((PUN_PAGE == 'profile-about')  ? ' class="topactive">' : '>').'<a href="'.pun_link($pun_url['profile_about'], $id).'"><span>'.$lang_profile['Section about'].'</span></a></li>',
+		'<li'.((PUN_PAGE == 'profile-identity')  ? ' class="topactive">' : '>').'<a href="'.pun_link($pun_url['profile_identity'], $id).'"><span>'.$lang_profile['Section identity'].'</span></a></li>',
+		'<li'.((PUN_PAGE == 'profile-settings') ? ' class="topactive">' : '>').'<a href="'.pun_link($pun_url['profile_settings'], $id).'"><span>'.$lang_profile['Section settings'].'</span></a></li>',
+	);
+
+	if ($pun_config['o_signatures'] == '1')
+		$profilenav_links[] = '<li'.((PUN_PAGE == 'profile-signature') ? ' class="topactive">' : '>').'<a href="'.pun_link($pun_url['profile_signature'], $id).'"><span>'.$lang_profile['Section signature'].'</span></a></li>';
+
+	if ($pun_config['o_avatars'] == '1')
+		$profilenav_links[] = '<li'.((PUN_PAGE == 'profile-avatar') ? ' class="topactive">' : '>').'<a href="'.pun_link($pun_url['profile_avatar'], $id).'"><span>'.$lang_profile['Section avatar'].'</span></a></li>';
+
+	if ($session->user_level >= USER_LEVEL_ADMIN || ($pun_user['g_moderator'] == '1' && $pun_user['g_mod_ban_users'] == '1'))
+		$profilenav_links[] = '<li'.((PUN_PAGE == 'profile-admin') ? ' class="topactive">' : '>').'<a href="'.pun_link($pun_url['profile_admin'], $id).'"><span>'.$lang_profile['Section admin'].'</span></a></li>';
+
+	($hook = get_hook('fn_generate_profile_menu_end')) ? eval($hook) : null;
+
+?>
+	<div id="profilenav" class="main-nav">
+		<ul>
+			<?php echo implode("\n\t\t\t", $profilenav_links)."\n"; ?>
+		</ul>
+	</div>
+<?php
+
+}
+
+
+//
+// Generate breadcrumb navigation
+//
+function generate_crumbs($reverse)
+{
+	global $lang_common, $pun_url, $pun_config, $pun_page;
+
+	if (empty($pun_page['crumbs']))
+		$pun_page['crumbs'][0] = $pun_config['o_board_title'];
+
+	$crumbs = '';
+	$num_crumbs = count($pun_page['crumbs']);
+
+	if ($reverse)
+	{
+		for ($i = ($num_crumbs - 1); $i >= 0; --$i)
+			$crumbs .= (is_array($pun_page['crumbs'][$i]) ? htmlspecialchars($pun_page['crumbs'][$i][0]) : htmlspecialchars($pun_page['crumbs'][$i])).((isset($pun_page['page']) && $i == ($num_crumbs - 1)) ? ' ('.$lang_common['Page'].' '.$pun_page['page'].')' : '').($i > 0 ? $lang_common['Title separator'] : '');
+	}
+	else
+	{
+		for ($i = 0; $i < $num_crumbs; ++$i)
+		{
+			if ($i < ($num_crumbs - 1))
+				$crumbs .= '<span class="crumb'.(($i == 0) ? ' crumbfirst' : '').'"><span>'.(($i >= 1) ? $lang_common['Crumb separator'] : '').$lang_common['Back to'].' </span>'.(is_array($pun_page['crumbs'][$i]) ? '<a href="'.$pun_page['crumbs'][$i][1].'">'.htmlspecialchars($pun_page['crumbs'][$i][0]).'</a>' : htmlspecialchars($pun_page['crumbs'][$i])).'</span>';
+			else
+				$crumbs .= '<strong class="crumb crumblast'.(($i == 0) ? ' crumbfirst' : '').'"><span>'.(($i >= 1) ? $lang_common['Crumb separator'] : '').$lang_common['You are here'].' </span>'.(is_array($pun_page['crumbs'][$i]) ? '<a href="'.$pun_page['crumbs'][$i][1].'">'.htmlspecialchars($pun_page['crumbs'][$i][0]).'</a>' : htmlspecialchars($pun_page['crumbs'][$i])).'</strong>';
+		}
+	}
+
+	($hook = get_hook('fn_generate_crumbs_end')) ? eval($hook) : null;
+
+	return $crumbs;
+}
+
+
+//
+// Save array of tracked topics in cookie
+//
+function set_tracked_topics($tracked_topics)
+{
+	global $cookie_name, $cookie_path, $cookie_domain, $cookie_secure, $pun_config;
+
+	($hook = get_hook('fn_set_tracked_topics_start')) ? eval($hook) : null;
+
+	$cookie_data = '';
+	if (!empty($tracked_topics))
+	{
+		// Sort the arrays (latest read first)
+		arsort($tracked_topics['topics'], SORT_NUMERIC);
+		arsort($tracked_topics['forums'], SORT_NUMERIC);
+
+		// Homebrew serialization (to avoid having to run unserialize() on cookie data)
+		foreach ($tracked_topics['topics'] as $id => $timestamp)
+			$cookie_data .= 't'.$id.'='.$timestamp.';';
+		foreach ($tracked_topics['forums'] as $id => $timestamp)
+			$cookie_data .= 'f'.$id.'='.$timestamp.';';
+
+		// Enforce a 4048 byte size limit (4096 minus some space for the cookie name)
+		if (strlen($cookie_data) > 4048)
+		{
+			$cookie_data = substr($cookie_data, 0, 4048);
+			$cookie_data = substr($cookie_data, 0, strrpos($cookie_data, ';')).';';
+		}
+	}
+
+	pun_setcookie($cookie_name.'_track', $cookie_data, time() + $pun_config['o_timeout_visit']);
+	$_COOKIE[$cookie_name.'_track'] = $cookie_data;	// Set it directly in $_COOKIE as well
+}
+
+
+//
+// Extract array of tracked topics from cookie
+//
+function get_tracked_topics()
+{
+	global $cookie_name;
+
+	$cookie_data = isset($_COOKIE[$cookie_name.'_track']) ? $_COOKIE[$cookie_name.'_track'] : false;
+	if (!$cookie_data)
+		return array('topics' => array(), 'forums' => array());
+
+	if (strlen($cookie_data) > 4048)
+		return array('topics' => array(), 'forums' => array());
+
+	// Unserialize data from cookie
+	$tracked_topics = array('topics' => array(), 'forums' => array());
+	$temp = explode(';', $cookie_data);
+	foreach ($temp as $t)
+	{
+		$type = substr($t, 0, 1) == 'f' ? 'forums' : 'topics';
+		$id = intval(substr($t, 1));
+		$timestamp = intval(@substr($t, strpos($t, '=') + 1));
+		if ($id > 0 && $timestamp > 0)
+			$tracked_topics[$type][$id] = $timestamp;
+	}
+
+	($hook = get_hook('fn_get_tracked_topics_end')) ? eval($hook) : null;
+
+	return $tracked_topics;
+}
+
+
+//
+// Update posts, topics, last_post, last_post_id and last_poster for a forum
+//
+function sync_forum($forum_id)
+{
+	global $pun_db;
+
+	($hook = get_hook('fn_sync_forum_start')) ? eval($hook) : null;
+
+	// Get topic and post count for forum
+	$query = array(
+		'SELECT'	=> 'COUNT(t.id), SUM(t.num_replies)',
+		'FROM'		=> 'topics AS t',
+		'WHERE'		=> 't.forum_id='.$forum_id
+	);
+
+	($hook = get_hook('fn_qr_get_forum_stats')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	list($num_topics, $num_posts) = $pun_db->fetch_row($result);
+
+	$num_posts = $num_posts + $num_topics;		// $num_posts is only the sum of all replies (we have to add the topic posts)
+
+	// Get last_post, last_post_id and last_poster for forum (if any)
+	$query = array(
+		'SELECT'	=> 't.last_post, t.last_post_id, t.last_poster',
+		'FROM'		=> 'topics AS t',
+		'WHERE'		=> 't.forum_id='.$forum_id.' AND t.moved_to is NULL',
+		'ORDER BY'	=> 't.last_post DESC',
+		'LIMIT'		=> '1'
+	);
+
+	($hook = get_hook('fn_qr_get_forum_last_post_data')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if ($pun_db->num_rows($result))
+	{
+		list($last_post, $last_post_id, $last_poster) = $pun_db->fetch_row($result);
+		$last_poster = '\''.$pun_db->escape($last_poster).'\'';
+	}
+	else
+		$last_post = $last_post_id = $last_poster = 'NULL';
+
+	// Now update the forum
+	$query = array(
+		'UPDATE'	=> 'forums',
+		'SET'		=> 'num_topics='.$num_topics.', num_posts='.$num_posts.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster='.$last_poster,
+		'WHERE'		=> 'id='.$forum_id
+	);
+
+	($hook = get_hook('fn_qr_update_forum')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+}
+
+
+//
+// Update replies, last_post, last_post_id and last_poster for a topic
+//
+function sync_topic($topic_id)
+{
+	global $pun_db;
+
+	($hook = get_hook('fn_sync_topic_start')) ? eval($hook) : null;
+
+	// Count number of replies in the topic
+	$query = array(
+		'SELECT'	=> 'COUNT(p.id)',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$topic_id
+	);
+
+	($hook = get_hook('fn_qr_get_topic_reply_count')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$num_replies = $pun_db->result($result, 0) - 1;
+
+	// Get last_post, last_post_id and last_poster
+	$query = array(
+		'SELECT'	=> 'p.posted, p.id, p.poster',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$topic_id,
+		'ORDER BY'	=> 'p.id DESC',
+		'LIMIT'		=> '1'
+	);
+
+	($hook = get_hook('fn_qr_get_topic_last_post_data')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	list($last_post, $last_post_id, $last_poster) = $pun_db->fetch_row($result);
+
+	// Now update the topic
+	$query = array(
+		'UPDATE'	=> 'topics',
+		'SET'		=> 'num_replies='.$num_replies.', last_post='.$last_post.', last_post_id='.$last_post_id.', last_poster=\''.$pun_db->escape($last_poster).'\'',
+		'WHERE'		=> 'id='.$topic_id
+	);
+
+	($hook = get_hook('fn_qr_update_topic')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+}
+
+
+//
+// Verifies that the provided username is OK for insertion into the database
+//
+function validate_username($username, $exclude_id = null)
+{
+	global $lang_common, $lang_register, $lang_profile, $pun_config;
+
+	$errors = array();
+
+	($hook = get_hook('fn_validate_username_start')) ? eval($hook) : null;
+
+	// Convert multiple whitespace characters into one (to prevent people from registering with indistinguishable usernames)
+	$username = preg_replace('#\s+#s', ' ', $username);
+
+	// Validate username
+	if (pun_strlen($username) < 2)
+		$errors[] = $lang_profile['Username too short'];
+	else if (pun_strlen($username) > 25)
+		$errors[] = $lang_profile['Username too long'];
+	else if (strtolower($username) == 'guest' || strtolower($username) == strtolower($lang_common['Guest']))
+		$errors[] = $lang_profile['Username guest'];
+	else if (preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $username))
+		$errors[] = $lang_profile['Username IP'];
+	else if ((strpos($username, '[') !== false || strpos($username, ']') !== false) && strpos($username, '\'') !== false && strpos($username, '"') !== false)
+		$errors[] = $lang_profile['Username reserved chars'];
+	else if (preg_match('#\[b\]|\[/b\]|\[u\]|\[/u\]|\[i\]|\[/i\]|\[color|\[/color\]|\[quote\]|\[quote=|\[/quote\]|\[code\]|\[/code\]|\[img\]|\[/img\]|\[url|\[/url\]|\[email|\[/email\]#i', $username))
+		$errors[] = $lang_profile['Username BBCode'];
+
+	// Check username for any censored words
+	if ($pun_config['o_censoring'] == '1' && censor_words($username) != $username)
+		$errors[] = $lang_register['Username censor'];
+
+	// Check for username dupe
+	$dupe = check_username_dupe($username, $exclude_id);
+	if ($dupe !== false)
+		$errors[] = sprintf($lang_profile['Username dupe'], htmlspecialchars($dupe));
+
+	return $errors;
+}
+
+
+//
+// Adds a new user. The username must be passed through validate_username() first.
+//
+function add_user($user_info, &$new_uid)
+{
+	global $pun_db, $base_url, $lang_common, $pun_config, $pun_user, $pun_url;
+
+	($hook = get_hook('fn_add_user_start')) ? eval($hook) : null;
+
+	// Add the user
+	$query = array(
+		'INSERT'	=> 'username, group_id, password, email, email_setting, save_pass, timezone, language, style, registered, registration_ip, last_visit, salt, activate_key',
+		'INTO'		=> 'users',
+		'VALUES'	=> '\''.$pun_db->escape($user_info['username']).'\', '.$user_info['group_id'].', \''.$pun_db->escape($user_info['password_hash']).'\', \''.$pun_db->escape($user_info['email']).'\', '.$user_info['email_setting'].', '.$user_info['save_pass'].', '.floatval($user_info['timezone']).', \''.$pun_db->escape($user_info['language']).'\', \''.$pun_db->escape($user_info['style']).'\', '.$user_info['registered'].', \''.$pun_db->escape($user_info['registration_ip']).'\', '.$user_info['registered'].', \''.$pun_db->escape($user_info['salt']).'\', '.$user_info['activate_key'].''
+	);
+
+	($hook = get_hook('fn_qr_add_user')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$new_uid = $pun_db->insert_id();
+
+	// Must the user verify the registration?
+	if ($user_info['require_verification'])
+	{
+		// Load the "welcome" template
+		$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/welcome.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('<board_title>', $pun_config['o_board_title'], $mail_subject);
+		$mail_message = str_replace('<base_url>', $base_url.'/', $mail_message);
+		$mail_message = str_replace('<username>', $user_info['username'], $mail_message);
+		$mail_message = str_replace('<activation_url>', str_replace('&amp;', '&', pun_link($pun_url['change_password_key'], array($new_uid, substr($user_info['activate_key'], 1, -1)))), $mail_message);
+		$mail_message = str_replace('<board_mailer>', sprintf($lang_common['Forum mailer'], $pun_config['o_board_title']), $mail_message);
+
+		($hook = get_hook('fn_add_user_send_verification')) ? eval($hook) : null;
+
+		pun_mail($user_info['email'], $mail_subject, $mail_message);
+	}
+
+	// Should we alert people on the admin mailing list that a new user has registered?
+	if ($user_info['notify_admins'] && $pun_config['o_mailing_list'] != '')
+	{
+		$mail_subject = 'Alert - New registration';
+		$mail_message = 'User \''.$user_info['username'].'\' registered in the forums at '.$base_url.'/'."\n\n".'User profile: '.pun_link($pun_url['user'], $new_uid)."\n\n".'-- '."\n".'Forum Mailer'."\n".'(Do not reply to this message)';
+
+		pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
+	}
+
+	($hook = get_hook('fn_add_user_end')) ? eval($hook) : null;
+
+	return $new_uid;
+}
+
+
+//
+// Delete a user and all information associated with it
+//
+function delete_user($user_id)
+{
+	global $pun_db, $db_type, $pun_config;
+
+	($hook = get_hook('fn_delete_user_start')) ? eval($hook) : null;
+
+	// First we need to get some data on the user
+	$query = array(
+		'SELECT'	=> 'u.username, u.group_id, g.g_moderator',
+		'FROM'		=> 'users AS u',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'groups AS g',
+				'ON'			=> 'g.g_id=u.group_id'
+			)
+		),
+		'WHERE'		=> 'u.id='.$user_id
+	);
+
+	($hook = get_hook('fn_qr_get_user_data')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$user = $pun_db->fetch_assoc($result);
+
+	// If the user is a moderator or an administrator, we remove him/her from the moderator list in all forums
+	// and regenerate the bans cache
+	if ($user['group_id'] == PUN_ADMIN || $user['g_moderator'] == '1')
+	{
+		clean_forum_moderators();
+
+		// Regenerate the bans cache
+		require_once PUN_ROOT.'include/cache.php';
+		generate_bans_cache();
+	}
+
+	// Delete any subscriptions
+	$query = array(
+		'DELETE'	=> 'subscriptions',
+		'WHERE'		=> 'user_id='.$user_id
+	);
+
+	($hook = get_hook('fn_qr_delete_subscriptions')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	// Remove him/her from the online list (if they happen to be logged in)
+	$query = array(
+		'DELETE'	=> 'online',
+		'WHERE'		=> 'user_id='.$user_id
+	);
+
+	($hook = get_hook('fn_qr_delete_online_user3')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	// Should we delete all posts made by this user?
+	if (isset($_POST['delete_posts']))
+	{
+		@set_time_limit(0);
+
+		// Find all posts made by this user
+		$query = array(
+			'SELECT'	=> 'p.id, p.topic_id, t.forum_id, t.first_post_id',
+			'FROM'		=> 'posts AS p',
+			'JOINS'		=> array(
+				array(
+					'INNER JOIN'	=> 'topics AS t',
+					'ON'			=> 't.id=p.topic_id'
+				)
+			),
+			'WHERE'		=> 'p.poster_id='.$user_id
+		);
+
+		($hook = get_hook('fn_qr_get_user_posts')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		while ($cur_post = $pun_db->fetch_assoc($result))
+		{
+			if ($cur_post['first_post_id'] == $cur_post['id'])
+				delete_topic($cur_post['topic_id'], $cur_post['forum_id']);
+			else
+				delete_post($cur_post['id'], $cur_post['topic_id'], $cur_post['forum_id']);
+		}
+	}
+	else
+	{
+		// Set all his/her posts to guest
+		$query = array(
+			'UPDATE'	=> 'posts',
+			'SET'		=> 'poster_id=1',
+			'WHERE'		=> 'poster_id='.$user_id
+		);
+
+		($hook = get_hook('fn_qr_reset_user_posts')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	}
+
+	// Delete the user
+	$query = array(
+		'DELETE'	=> 'users',
+		'WHERE'		=> 'id='.$user_id
+	);
+
+	($hook = get_hook('fn_qr_delete_user')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	// Delete user avatar
+	if (file_exists($pun_config['o_avatars_dir'].'/'.$user_id.'.gif'))
+		@unlink($pun_config['o_avatars_dir'].'/'.$user_id.'.gif');
+	if (file_exists($pun_config['o_avatars_dir'].'/'.$user_id.'.jpg'))
+		@unlink($pun_config['o_avatars_dir'].'/'.$user_id.'.jpg');
+	if (file_exists($pun_config['o_avatars_dir'].'/'.$user_id.'.png'))
+		@unlink($pun_config['o_avatars_dir'].'/'.$user_id.'.png');
+
+	($hook = get_hook('fn_delete_user_end')) ? eval($hook) : null;
+}
+
+
+//
+// Iterates through all forum moderator lists and removes any erroneous entries
+//
+function clean_forum_moderators()
+{
+	global $pun_db;
+
+	($hook = get_hook('fn_clean_forum_moderators_start')) ? eval($hook) : null;
+
+	// Get a list of forums and their respective lists of moderators
+	$query = array(
+		'SELECT'	=> 'f.id, f.moderators',
+		'FROM'		=> 'forums AS f',
+		'WHERE'		=> 'f.moderators IS NOT NULL'
+	);
+
+	($hook = get_hook('fn_qr_get_forum_moderators')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	while ($cur_forum = $pun_db->fetch_assoc($result))
+	{
+		$cur_moderators = unserialize($cur_forum['moderators']);
+		$new_moderators = $cur_moderators;
+
+		// Iterate through each user in the list and check if he/she is in a moderator or admin group
+		foreach ($cur_moderators as $username => $user_id)
+		{
+			$query = array(
+				'SELECT'	=> '1',
+				'FROM'		=> 'users AS u',
+				'JOINS'		=> array(
+					array(
+						'INNER JOIN'	=> 'groups AS g',
+						'ON'			=> 'g.g_id=u.group_id'
+					)
+				),
+				'WHERE'		=> '(g.g_moderator=1 OR u.group_id=1) AND u.id='.$user_id
+			);
+
+			($hook = get_hook('fn_qr_check_user_in_moderator_group')) ? eval($hook) : null;
+			$result2 = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			if (!$pun_db->num_rows($result2))	// If the user isn't in a moderator or admin group, remove him/her from the list
+				unset($new_moderators[$username]);
+		}
+
+		// If we changed anything, update the forum
+		if ($cur_moderators != $new_moderators)
+		{
+			$new_moderators = (!empty($new_moderators)) ? '\''.$pun_db->escape(serialize($new_moderators)).'\'' : 'NULL';
+
+			$query = array(
+				'UPDATE'	=> 'forums',
+				'SET'		=> 'moderators='.$new_moderators,
+				'WHERE'		=> 'id='.$cur_forum['id']
+			);
+
+			($hook = get_hook('fn_qr_set_forum_moderators')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+		}
+	}
+
+	($hook = get_hook('fn_clean_forum_moderators_end')) ? eval($hook) : null;
+}
+
+
+//
+// Locate and delete any orphaned redirect topics
+//
+function delete_orphans()
+{
+	global $pun_db;
+
+	($hook = get_hook('fn_delete_orphans_start')) ? eval($hook) : null;
+
+	// Locate any orphaned redirect topics
+	$query = array(
+		'SELECT'	=> 't1.id',
+		'FROM'		=> 'topics AS t1',
+		'JOINS'		=> array(
+			array(
+				'LEFT JOIN'		=> 'topics AS t2',
+				'ON'			=> 't1.moved_to=t2.id'
+			)
+		),
+		'WHERE'		=> 't2.id IS NULL AND t1.moved_to IS NOT NULL'
+	);
+
+	($hook = get_hook('fn_qr_get_orphans')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$num_orphans = $pun_db->num_rows($result);
+
+	if ($num_orphans)
+	{
+		for ($i = 0; $i < $num_orphans; ++$i)
+			$orphans[] = $pun_db->result($result, $i);
+
+		// Delete the orphan
+		$query = array(
+			'DELETE'	=> 'topics',
+			'WHERE'		=> 'id IN('.implode(',', $orphans).')'
+		);
+
+		($hook = get_hook('fn_qr_delete_orphan')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	}
+}
+
+
+//
+// Delete a topic and all of it's posts
+//
+function delete_topic($topic_id, $forum_id)
+{
+	global $pun_db, $db_type;
+
+	($hook = get_hook('fn_delete_topic_start')) ? eval($hook) : null;
+
+	// Delete the topic and any redirect topics
+	$query = array(
+		'DELETE'	=> 'topics',
+		'WHERE'		=> 'id='.$topic_id.' OR moved_to='.$topic_id
+	);
+
+	($hook = get_hook('fn_qr_delete_topic')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	// Create a list of the post ID's in this topic
+	$post_ids = '';
+	$query = array(
+		'SELECT'	=> 'p.id',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$topic_id
+	);
+
+	($hook = get_hook('fn_qr_get_posts_to_delete')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	while ($row = $pun_db->fetch_row($result))
+		$post_ids .= ($post_ids != '') ? ','.$row[0] : $row[0];
+
+	// Make sure we have a list of post ID's
+	if ($post_ids != '')
+	{
+		// Delete posts in topic
+		$query = array(
+			'DELETE'	=> 'posts',
+			'WHERE'		=> 'topic_id='.$topic_id
+		);
+
+		($hook = get_hook('fn_qr_delete_topic_posts')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		if ($db_type != 'mysql' && $db_type != 'mysqli')
+		{
+			require PUN_ROOT.'include/search_idx.php';
+			strip_search_index($post_ids);
+		}
+	}
+
+	// Delete any subscriptions for this topic
+	$query = array(
+		'DELETE'	=> 'subscriptions',
+		'WHERE'		=> 'topic_id='.$topic_id
+	);
+
+	($hook = get_hook('fn_qr_delete_topic_subscriptions')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	sync_forum($forum_id);
+
+	($hook = get_hook('fn_delete_topic_end')) ? eval($hook) : null;
+}
+
+
+//
+// Delete a single post
+//
+function delete_post($post_id, $topic_id, $forum_id)
+{
+	global $pun_db, $db_type;
+
+	($hook = get_hook('fn_delete_post_start')) ? eval($hook) : null;
+
+	$query = array(
+		'SELECT'	=> 'p.id, p.poster, p.posted',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$topic_id,
+		'ORDER BY'	=> 'p.id DESC',
+		'LIMIT'		=> '2'
+	);
+
+	($hook = get_hook('fn_qr_get_topic_lastposts_info')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	list($last_id, ,) = $pun_db->fetch_row($result);
+	list($second_last_id, $second_poster, $second_posted) = $pun_db->fetch_row($result);
+
+	// Delete the post
+	$query = array(
+		'DELETE'	=> 'posts',
+		'WHERE'		=> 'id='.$post_id
+	);
+
+	($hook = get_hook('fn_qr_delete_post')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	if ($db_type != 'mysql' && $db_type != 'mysqli')
+	{
+		require PUN_ROOT.'include/search_idx.php';
+		strip_search_index($post_id);
+	}
+
+	// Count number of replies in the topic
+	$query = array(
+		'SELECT'	=> 'COUNT(p.id)',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$topic_id
+	);
+
+	($hook = get_hook('fn_qr_get_topic_reply_count2')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$num_replies = $pun_db->result($result, 0) - 1;
+
+	// Update the topic now that a post has been deleted
+	$query = array(
+		'UPDATE'	=> 'topics',
+		'SET'		=> 'num_replies='.$num_replies,
+		'WHERE'		=> 'id='.$topic_id
+	);
+
+	// If we deleted the most recent post, we need to sync up last post data as wel
+	if ($last_id == $post_id)
+		$query['SET'] .= ', last_post='.$second_posted.', last_post_id='.$second_last_id.', last_poster=\''.$pun_db->escape($second_poster).'\'';
+
+	($hook = get_hook('fn_qr_update_topic2')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	sync_forum($forum_id);
+
+	($hook = get_hook('fn_delete_post_end')) ? eval($hook) : null;
+}
+
+
+//
+// Creates a new topic with its first post
+//
+function add_topic($post_info, &$new_tid, &$new_pid)
+{
+	global $pun_db, $db_type, $pun_config, $lang_common;
+
+	($hook = get_hook('fn_add_topic_start')) ? eval($hook) : null;
+
+	// Add the topic
+	$query = array(
+		'INSERT'	=> 'poster, subject, posted, last_post, last_poster, forum_id',
+		'INTO'		=> 'topics',
+		'VALUES'	=> '\''.$pun_db->escape($post_info['poster']).'\', \''.$pun_db->escape($post_info['subject']).'\', '.$post_info['posted'].', '.$post_info['posted'].', \''.$pun_db->escape($post_info['poster']).'\', '.$post_info['forum_id']
+	);
+
+	($hook = get_hook('fn_qr_add_topic')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$new_tid = $pun_db->insert_id();
+
+	// To subscribe or not to subscribe, that ...
+	if (!$post_info['is_guest'] && $post_info['subscribe'])
+	{
+		$query = array(
+			'INSERT'	=> 'user_id, topic_id',
+			'INTO'		=> 'subscriptions',
+			'VALUES'	=> $post_info['poster_id'].' ,'.$new_tid
+		);
+
+		($hook = get_hook('fn_qr_add_subscription')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	}
+
+	// Create the post ("topic post")
+	$query = array(
+		'INSERT'	=> 'poster, poster_id, poster_ip, message, hide_smilies, posted, topic_id',
+		'INTO'		=> 'posts',
+		'VALUES'	=> '\''.$pun_db->escape($post_info['poster']).'\', '.$post_info['poster_id'].', \''.get_remote_address().'\', \''.$pun_db->escape($post_info['message']).'\', '.$post_info['hide_smilies'].', '.$post_info['posted'].', '.$new_tid
+	);
+
+	// If it's a guest post, there might be an e-mail address we need to include
+	if ($post_info['is_guest'] && $post_info['poster_email'] != null)
+	{
+		$query['INSERT'] .= ', poster_email';
+		$query['VALUES'] .= ', \''.$post_info['poster_email'].'\'';
+	}
+
+	($hook = get_hook('fn_qr_add_topic_post')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$new_pid = $pun_db->insert_id();
+
+	// Update the topic with last_post_id and first_post_id
+	$query = array(
+		'UPDATE'	=> 'topics',
+		'SET'		=> 'last_post_id='.$new_pid.', first_post_id='.$new_pid,
+		'WHERE'		=> 'id='.$new_tid
+	);
+
+	($hook = get_hook('fn_qr_update_topic3')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	if ($db_type != 'mysql' && $db_type != 'mysqli')
+	{
+		require PUN_ROOT.'include/search_idx.php';
+		update_search_index('post', $new_pid, $post_info['message'], $post_info['subject']);
+	}
+
+	sync_forum($post_info['forum_id']);
+
+	($hook = get_hook('fn_add_topic_end')) ? eval($hook) : null;
+}
+
+
+//
+// Creates a new post
+//
+function add_post($post_info, &$new_pid)
+{
+	global $pun_db, $db_type, $pun_config, $lang_common;
+
+	($hook = get_hook('fn_add_post_start')) ? eval($hook) : null;
+
+	// Add the post
+	$query = array(
+		'INSERT'	=> 'poster, poster_id, poster_ip, message, hide_smilies, posted, topic_id',
+		'INTO'		=> 'posts',
+		'VALUES'	=> '\''.$pun_db->escape($post_info['poster']).'\', '.$post_info['poster_id'].', \''.get_remote_address().'\', \''.$pun_db->escape($post_info['message']).'\', '.$post_info['hide_smilies'].', '.$post_info['posted'].', '.$post_info['topic_id']
+	);
+
+	// If it's a guest post, there might be an e-mail address we need to include
+	if ($post_info['is_guest'] && $post_info['poster_email'] != null)
+	{
+		$query['INSERT'] .= ', poster_email';
+		$query['VALUES'] .= ', \''.$post_info['poster_email'].'\'';
+	}
+
+	($hook = get_hook('fn_qr_add_post')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$new_pid = $pun_db->insert_id();
+
+	if (!$post_info['is_guest'])
+	{
+		// Subscribe or unsubscribe?
+		if ($post_info['subscr_action'] == 1)
+		{
+			$query = array(
+				'INSERT'	=> 'user_id, topic_id',
+				'INTO'		=> 'subscriptions',
+				'VALUES'	=> $post_info['poster_id'].' ,'.$post_info['topic_id']
+			);
+
+			($hook = get_hook('fn_qr_add_subscription2')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+		}
+		else if ($post_info['subscr_action'] == 2)
+		{
+			$query = array(
+				'DELETE'	=> 'subscriptions',
+				'WHERE'		=> 'topic_id='.$post_info['topic_id'].' AND user_id='.$post_info['poster_id']
+			);
+
+			($hook = get_hook('fn_qr_delete_subscription')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+		}
+	}
+
+	// Count number of replies in the topic
+	$query = array(
+		'SELECT'	=> 'COUNT(p.id)',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$post_info['topic_id']
+	);
+
+	($hook = get_hook('fn_qr_get_topic_reply_count3')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$num_replies = $pun_db->result($result, 0) - 1;
+
+	// Update topic
+	$query = array(
+		'UPDATE'	=> 'topics',
+		'SET'		=> 'num_replies='.$num_replies.', last_post='.$post_info['posted'].', last_post_id='.$new_pid.', last_poster=\''.$pun_db->escape($post_info['poster']).'\'',
+		'WHERE'		=> 'id='.$post_info['topic_id']
+	);
+
+	($hook = get_hook('fn_qr_update_topic4')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	sync_forum($post_info['forum_id']);
+
+	if ($db_type != 'mysql' && $db_type != 'mysqli')
+	{
+		require PUN_ROOT.'include/search_idx.php';
+		update_search_index('post', $new_pid, $post_info['message']);
+	}
+
+	send_subscriptions($post_info, $new_pid);
+
+	($hook = get_hook('fn_add_post_end')) ? eval($hook) : null;
+}
+
+
+//
+// Send out subscription emails
+//
+function send_subscriptions($post_info, $new_pid)
+{
+	global $pun_config, $pun_db, $pun_url, $lang_common;
+
+	($hook = get_hook('fn_send_subscriptions_start')) ? eval($hook) : null;
+
+	if ($pun_config['o_subscriptions'] != '1')
+		return;
+
+	// Get the post time for the previous post in this topic
+	$query = array(
+		'SELECT'	=> 'p.posted',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$post_info['topic_id'],
+		'ORDER BY'	=> 'p.id DESC',
+		'LIMIT'		=> '1, 1'
+	);
+
+	($hook = get_hook('fn_qr_get_previous_post_time')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$previous_post_time = $pun_db->result($result);
+
+	// Get any subscribed users that should be notified (banned users are excluded)
+	$query = array(
+		'SELECT'	=> 'u.id, u.email, u.notify_with_post, u.language',
+		'FROM'		=> 'users AS u',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'subscriptions AS s',
+				'ON'			=> 'u.id=s.user_id'
+			),
+			array(
+				'LEFT JOIN'		=> 'forum_perms AS fp',
+				'ON'			=> '(fp.forum_id='.$post_info['forum_id'].' AND fp.group_id=u.group_id)'
+			),
+			array(
+				'INNER JOIN'	=> 'online AS o',
+				'ON'			=> 'u.id=o.user_id'
+			),
+			array(
+				'INNER JOIN'	=> 'bans AS b',
+				'ON'			=> 'u.username=b.username'
+			),
+		),
+		'WHERE'		=> 'b.username IS NULL AND COALESCE(o.logged, u.last_visit)>'.$previous_post_time.' AND (fp.read_forum IS NULL OR fp.read_forum=1) AND s.topic_id='.$post_info['topic_id'].' AND u.id!='.$post_info['poster_id']
+	);
+
+	($hook = get_hook('fn_qr_get_users_to_notify')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	if ($pun_db->num_rows($result))
+	{
+		require_once PUN_ROOT.'include/email.php';
+
+		$notification_emails = array();
+
+		// Loop through subscribed users and send e-mails
+		while ($cur_subscriber = $pun_db->fetch_assoc($result))
+		{
+			// Is the subscription e-mail for $cur_subscriber['language'] cached or not?
+			if (!isset($notification_emails[$cur_subscriber['language']]))
+			{
+				if (file_exists(PUN_ROOT.'lang/'.$cur_subscriber['language'].'/mail_templates/new_reply.tpl'))
+				{
+					// Load the "new reply" template
+					$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$cur_subscriber['language'].'/mail_templates/new_reply.tpl'));
+
+					// Load the "new reply full" template (with post included)
+					$mail_tpl_full = trim(file_get_contents(PUN_ROOT.'lang/'.$cur_subscriber['language'].'/mail_templates/new_reply_full.tpl'));
+
+					// The first row contains the subject (it also starts with "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));
+
+					$first_crlf = strpos($mail_tpl_full, "\n");
+					$mail_subject_full = trim(substr($mail_tpl_full, 8, $first_crlf-8));
+					$mail_message_full = trim(substr($mail_tpl_full, $first_crlf));
+
+					$mail_subject = str_replace('<topic_subject>', '\''.$post_info['subject'].'\'', $mail_subject);
+					$mail_message = str_replace('<topic_subject>', '\''.$post_info['subject'].'\'', $mail_message);
+					$mail_message = str_replace('<replier>', $post_info['poster'], $mail_message);
+					$mail_message = str_replace('<post_url>', pun_link($pun_url['post'], $new_pid), $mail_message);
+					$mail_message = str_replace('<unsubscribe_url>', pun_link($pun_url['unsubscribe'], $post_info['topic_id']), $mail_message);
+					$mail_message = str_replace('<board_mailer>', sprintf($lang_common['Forum mailer'], $pun_config['o_board_title']), $mail_message);
+
+					$mail_subject_full = str_replace('<topic_subject>', '\''.$post_info['subject'].'\'', $mail_subject_full);
+					$mail_message_full = str_replace('<topic_subject>', '\''.$post_info['subject'].'\'', $mail_message_full);
+					$mail_message_full = str_replace('<replier>', $post_info['poster'], $mail_message_full);
+					$mail_message_full = str_replace('<message>', $post_info['message'], $mail_message_full);
+					$mail_message_full = str_replace('<post_url>', pun_link($pun_url['post'], $new_pid), $mail_message_full);
+					$mail_message_full = str_replace('<unsubscribe_url>', pun_link($pun_url['unsubscribe'], $post_info['topic_id']), $mail_message_full);
+					$mail_message_full = str_replace('<board_mailer>', sprintf($lang_common['Forum 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;
+					$notification_emails[$cur_subscriber['language']][2] = $mail_subject_full;
+					$notification_emails[$cur_subscriber['language']][3] = $mail_message_full;
+
+					$mail_subject = $mail_message = $mail_subject_full = $mail_message_full = null;
+				}
+			}
+
+			// We have to double check here because the templates could be missing
+			if (isset($notification_emails[$cur_subscriber['language']]))
+			{
+				// Make sure the e-mail address format is valid before sending
+				if (is_valid_email($cur_subscriber['email']))
+				{
+					if ($cur_subscriber['notify_with_post'] == '0')
+						pun_mail($cur_subscriber['email'], $notification_emails[$cur_subscriber['language']][0], $notification_emails[$cur_subscriber['language']][1]);
+					else
+						pun_mail($cur_subscriber['email'], $notification_emails[$cur_subscriber['language']][2], $notification_emails[$cur_subscriber['language']][3]);
+				}
+			}
+		}
+	}
+
+	($hook = get_hook('fn_send_subscriptions_end')) ? eval($hook) : null;
+}
+
+
+//
+// Make a string safe to use in a URL
+//
+function sef_friendly($string)
+{
+	($hook = get_hook('fn_sef_friendly_start')) ? eval($hook) : null;
+
+	$reserved_words = array('atom', 'last');
+	$words = explode(' ', $string);
+	$string = '';
+
+	foreach ($words as $word)
+	{
+		if (strlen($word) > 3 && !in_array(strtolower($word), $reserved_words))
+			$string .= '-'.$word;
+	}
+
+	$string = urlencode(strtr(str_replace('?', '', utf8_decode($string)), utf8_decode('ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ/'), 'AAAAAAaaaaaaOOOOOOooooooEEEEeeeeCcIIIIiiiiUUUUuuuuyNn-'));
+
+	return $string;
+}
+
+
+//
+// Replace censored words in $text
+//
+function censor_words($text)
+{
+	global $pun_db;
+	static $search_for, $replace_with;
+
+	($hook = get_hook('fn_censor_words_start')) ? eval($hook) : null;
+
+	// If not already loaded in a previous call, load the cached censors
+	if (!defined('PUN_CENSORS_LOADED'))
+	{
+		if (file_exists(PUN_CACHE_DIR.'cache_censors.php'))
+			include PUN_CACHE_DIR.'cache_censors.php';
+
+		if (!defined('PUN_CENSORS_LOADED'))
+		{
+			require_once PUN_ROOT.'include/cache.php';
+			generate_censors_cache();
+			require PUN_CACHE_DIR.'cache_censors.php';
+		}
+
+		$search_for = array();
+		$replace_with = array();
+
+		foreach ($pun_censors as $censor_key => $cur_word)
+		{
+			$search_for[$censor_key] = '/\b('.str_replace('\*', '\w*?', preg_quote($cur_word['search_for'], '/')).')\b/iu';
+			$replace_with[$censor_key] = $cur_word['replace_with'];
+
+			($hook = get_hook('fn_censor_words_setup_regex')) ? eval($hook) : null;
+		}
+	}
+
+	if (!empty($search_for))
+		$text = substr(preg_replace($search_for, $replace_with, ' '.$text.' '), 1, -1);
+
+	return $text;
+}
+
+
+//
+// Check if a username is occupied
+//
+function check_username_dupe($username, $exclude_id = null)
+{
+	global $pun_db;
+
+	($hook = get_hook('fn_check_username_dupe_start')) ? eval($hook) : null;
+
+	$query = array(
+		'SELECT'	=> 'u.username',
+		'FROM'		=> 'users AS u',
+		'WHERE'		=> '(UPPER(username)=UPPER(\''.$pun_db->escape($username).'\') OR UPPER(username)=UPPER(\''.$pun_db->escape(preg_replace('/[^\w]/u', '', $username)).'\')) AND id>1'
+	);
+
+	if ($exclude_id)
+		$query['WHERE'] .= ' AND id!='.$exclude_id;
+
+	($hook = get_hook('fn_qr_check_username_dupe')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	return $pun_db->num_rows($result) ? $pun_db->result($result) : false;
+}
+
+
+//
+// Determines the correct title for $user
+// $user must contain the elements 'username', 'title', 'posts', 'g_id' and 'g_user_title'
+//
+function get_title($user)
+{
+	global $pun_db, $pun_config, $pun_bans, $lang_common;
+	static $ban_list, $pun_ranks;
+
+	($hook = get_hook('fn_get_title_start')) ? eval($hook) : null;
+
+	// If not already built in a previous call, build an array of lowercase banned usernames
+	if (empty($ban_list))
+	{
+		$ban_list = array();
+
+		foreach ($pun_bans as $cur_ban)
+			$ban_list[] = strtolower($cur_ban['username']);
+	}
+
+	// If not already loaded in a previous call, load the cached ranks
+	if ($pun_config['o_ranks'] == '1' && !defined('PUN_RANKS_LOADED'))
+	{
+		if (file_exists(PUN_CACHE_DIR.'cache_ranks.php'))
+			include PUN_CACHE_DIR.'cache_ranks.php';
+
+		if (!defined('PUN_RANKS_LOADED'))
+		{
+			require_once PUN_ROOT.'include/cache.php';
+			generate_ranks_cache();
+			require PUN_CACHE_DIR.'cache_ranks.php';
+		}
+	}
+
+	// If the user has a custom title
+	if ($user['title'] != '')
+		$user_title = htmlspecialchars($pun_config['o_censoring'] == '1' ? censor_words($user['title']) : $user['title']);
+	// If the user is banned
+	else if (in_array(strtolower($user['username']), $ban_list))
+		$user_title = $lang_common['Banned'];
+	// If the user group has a default user title
+	else if ($user['g_user_title'] != '')
+		$user_title = htmlspecialchars($user['g_user_title']);
+	// If the user is a guest
+	else if ($user['g_id'] == PUN_GUEST)
+		$user_title = $lang_common['Guest'];
+	else
+	{
+		// Are there any ranks?
+		if ($pun_config['o_ranks'] == '1' && !empty($pun_ranks))
+		{
+			@reset($pun_ranks);
+			while (list(, $cur_rank) = @each($pun_ranks))
+			{
+				if (intval($user['num_posts']) >= $cur_rank['min_posts'])
+					$user_title = htmlspecialchars($cur_rank['rank']);
+			}
+		}
+
+		// If the user didn't "reach" any rank (or if ranks are disabled), we assign the default
+		if (!isset($user_title))
+			$user_title = $lang_common['Member'];
+	}
+
+	($hook = get_hook('fn_get_title_end')) ? eval($hook) : null;
+
+	return $user_title;
+}
+
+
+//
+// Generate a string with numbered links (for multipage scripts)
+//
+function pun_paginate($num_pages, $cur_page, $link, $args = null)
+{
+	global $pun_url, $lang_common;
+
+	$pages = array();
+	$link_to_all = false;
+
+	($hook = get_hook('fn_paginate_start')) ? eval($hook) : null;
+
+	// If $cur_page == -1, we link to all pages (used in viewforum.php)
+	if ($cur_page == -1)
+	{
+		$cur_page = 1;
+		$link_to_all = true;
+	}
+
+	if ($num_pages <= 1)
+		$pages = array('<strong>1</strong>');
+	else
+	{
+		// Add a previous page link
+		if ($num_pages > 1 && $cur_page > 1)
+			$pages[] = '<a class="prev" href="'.pun_sublink($link, $pun_url['page'], ($cur_page - 1), $args).'">'.$lang_common['Previous'].'</a>&#160;';
+
+		if ($cur_page > 3)
+		{
+			$pages[] = '<a href="'.pun_sublink($link, $pun_url['page'], 1, $args).'">1</a>';
+
+			if ($cur_page > 5)
+				$pages[] = '…';
+		}
+
+		// Don't ask me how the following works. It just does, OK? :-)
+		for ($current = ($cur_page == 5) ? $cur_page - 3 : $cur_page - 2, $stop = ($cur_page + 4 == $num_pages) ? $cur_page + 4 : $cur_page + 3; $current < $stop; ++$current)
+		{
+			if ($current < 1 || $current > $num_pages)
+				continue;
+			else if ($current != $cur_page || $link_to_all)
+				$pages[] = '<a href="'.pun_sublink($link, $pun_url['page'], $current, $args).'">'.$current.'</a>';
+			else
+				$pages[] = '<strong>'.$current.'</strong>';
+		}
+
+		if ($cur_page <= ($num_pages-3))
+		{
+			if ($cur_page != ($num_pages-3) && $cur_page != ($num_pages-4))
+				$pages[] = '…';
+
+			$pages[] = '<a href="'.pun_sublink($link, $pun_url['page'], $num_pages, $args).'">'.$num_pages.'</a>';
+		}
+
+		// Add a next page link
+		if ($num_pages > 1 && !$link_to_all && $cur_page < $num_pages)
+			$pages[] = '&#160;<a class="next" href="'.pun_sublink($link, $pun_url['page'], ($cur_page + 1), $args).'">'.$lang_common['Next'].'</a>';
+	}
+
+	($hook = get_hook('fn_paginate_end')) ? eval($hook) : null;
+
+	return implode($lang_common['Page separator'], $pages);
+}
+
+
+//
+// Clean version string from trailing '.0's
+//
+function clean_version($version)
+{
+	return preg_replace('/(\.0)+(?!\.)|(\.0+$)/', '$2', $version);
+}
+
+
+//
+// Display a message
+//
+function message($message, $link = '')
+{
+	global $pun_db, $pun_url, $lang_common, $pun_config, $base_url, $pun_start, $tpl_main, $pun_user, $pun_page, $pun_updates;
+
+	($hook = get_hook('fn_message_start')) ? eval($hook) : null;
+
+	if (!defined('PUN_HEADER'))
+	{
+		// Setup breadcrumbs
+		$pun_page['crumbs'] = array(
+			array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+			$lang_common['Info']
+		);
+
+		define('PUN_PAGE', 'message');
+		require PUN_ROOT.'header.php';
+	}
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_common['Forum message'] ?></span></h2>
+	</div>
+	<div class="main-content message">
+		<p><?php echo $message ?> <?php if ($link != '') echo '<span>'.$link.'</span>' ?></p>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+//
+// Display a form that the user can use to confirm that they want to undertake an action.
+// Used when the CSRF token from the request does not match the token stored in the database.
+//
+function csrf_confirm_form()
+{
+	global $pun_db, $pun_url, $lang_common, $pun_config, $base_url, $pun_start, $tpl_main, $pun_user, $pun_page, $pun_updates;
+
+	// User pressed the cancel button
+	if (isset($_POST['confirm_cancel']))
+		pun_redirect(htmlspecialchars($_POST['prev_url']), $lang_common['Cancel redirect']);
+
+	//
+	// A helper function for csrf_confirm_form. It takes a multi-dimensional array and returns it as a 
+	// single-dimensional array suitable for use in hidden fields.
+	//
+	function _csrf_confirm_form($key, $values)
+	{
+		$fields = array();
+
+		if (is_array($values))
+		{
+			foreach ($values as $cur_key => $cur_values)
+				$fields = array_merge($fields, _csrf_confirm_form($key.'['.$cur_key.']', $cur_values));
+
+			return $fields;
+		}
+		else
+			$fields[$key] = $values;
+
+		return $fields;
+	}
+
+	($hook = get_hook('fn_csrf_confirm_form_start')) ? eval($hook) : null;
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		$lang_common['Confirm action']
+	);
+
+	$pun_page['form_action'] = get_current_url();
+
+	$pun_page['hidden_fields'] = array(
+		'<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />',
+		'<input type="hidden" name="prev_url" value="'.htmlspecialchars($pun_user['prev_url']).'" />'
+	);
+
+	foreach ($_POST as $submitted_key => $submitted_val)
+	{
+		if ($submitted_key != 'csrf_token' && $submitted_key != 'prev_url')
+		{
+			$hidden_fields = _csrf_confirm_form($submitted_key, $submitted_val);
+			foreach ($hidden_fields as $field_key => $field_val)
+				$pun_page['hidden_fields'][] = '<input type="hidden" name="'.htmlspecialchars($field_key).'" value="'.htmlspecialchars($field_val).'" />';
+		}
+	}
+
+	define('PUN_PAGE', 'dialogue');
+	require PUN_ROOT.'header.php';
+
+	($hook = get_hook('fn_csrf_confirm_form_pre_header_load')) ? eval($hook) : null;
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_common['Confirm action head'] ?></span></h2>
+	</div>
+	<div class="main-content frm">
+		<div class="frm-info">
+			<p><?php echo $lang_common['CSRF token mismatch'] ?></p>
+		</div>
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" value="<?php echo $lang_common['Confirm'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="confirm_cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+//
+// Generate a hyperlink with parameters and anchor
+//
+function pun_link($link, $args = null)
+{
+	global $pun_config, $base_url;
+
+	$gen_link = $link;
+	if ($args == null)
+		$gen_link = $link;
+	else if (!is_array($args))
+		$gen_link = str_replace('$1', $args, $link);
+	else
+	{
+		for ($i = 0; isset($args[$i]); ++$i)
+			$gen_link = str_replace('$'.($i + 1), $args[$i], $gen_link);
+	}
+  
+  $gen_link = makeUrlNS('Special', "Forum/$gen_link");
+
+	($hook = get_hook('fn_pun_link_end')) ? eval($hook) : null;
+
+	return $gen_link;
+}
+
+
+//
+// Generate a hyperlink with parameters and anchor and a subsection such as a subpage
+//
+function pun_sublink($link, $sublink, $subarg, $args = null)
+{
+	global $pun_config, $pun_url, $base_url;
+
+	$gen_link = $link;
+	if (!is_array($args) && $args != null)
+		$gen_link = str_replace('$1', $args, $link);
+	else
+	{
+		for ($i = 0; isset($args[$i]); ++$i)
+			$gen_link = str_replace('$'.($i + 1), $args[$i], $gen_link);
+	}
+
+	if (isset($pun_url['insertion_find']))
+		$gen_link = $base_url.'/'.str_replace($pun_url['insertion_find'], str_replace('$1', str_replace('$1', $subarg, $sublink), $pun_url['insertion_replace']), $gen_link);
+	else
+		$gen_link = $base_url.'/'.$gen_link.str_replace('$1', $subarg, $sublink);
+
+	($hook = get_hook('fn_pun_sublink_end')) ? eval($hook) : null;
+
+	return $gen_link;
+}
+
+
+//
+// Format a time string according to $time_format and timezones
+//
+function format_time($timestamp, $date_only = false)
+{
+	global $pun_config, $lang_common, $pun_user, $pun_time_formats, $pun_date_formats;
+
+	($hook = get_hook('fn_format_time_start')) ? eval($hook) : null;
+
+	if ($timestamp == '')
+		return $lang_common['Never'];
+
+	$diff = ($pun_user['timezone'] + $pun_user['dst']) * 3600;
+	$timestamp += $diff;
+	$now = time();
+
+	$date = gmdate($pun_date_formats[$pun_user['date_format']], $timestamp);
+	$base = gmdate('Y-m-d', $timestamp);
+	$today = gmdate('Y-m-d', $now+$diff);
+	$yesterday = gmdate('Y-m-d', $now+$diff-86400);
+
+	if ($base == $today)
+		$date = $lang_common['Today'];
+	else if ($base == $yesterday)
+		$date = $lang_common['Yesterday'];
+
+	if (!$date_only)
+		$date .= ' '.gmdate($pun_time_formats[$pun_user['time_format']], $timestamp);
+
+	return $date;
+}
+
+
+//
+// Generate a random key of length $len
+//
+function random_key($len, $readable = false, $hash = false)
+{
+	$key = '';
+
+	if ($hash)
+		$key = substr(sha1(uniqid(rand(), true)), 0, $len);
+	else if ($readable)
+	{
+		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+		for ($i = 0; $i < $len; ++$i)
+			$key .= substr($chars, (mt_rand() % strlen($chars)), 1);
+	}
+	else
+	{
+		for ($i = 0; $i < $len; ++$i)
+			$key .= chr(mt_rand(33, 126));
+	}
+
+	($hook = get_hook('fn_random_key_end')) ? eval($hook) : null;
+
+	return $key;
+}
+
+
+//
+// Generates a valid CSRF token for use when submitting a form to $target_url
+// $target_url should be an absolute URL and it should be exactly the URL that the user is going to
+// Alternately, if the form token is going to be used in GET (which would mean the token is going to be
+// a part of the URL itself), $target_url may be a plain string containing information related to the URL. 
+//
+function generate_form_token ($target_url)
+{
+	global $pun_user;
+
+	($hook = get_hook('fn_generate_form_token_start')) ? eval($hook) : null;
+
+	return sha1(str_replace('&amp;', '&', $target_url).$pun_user['csrf_token']);
+}
+
+//
+// Try to determine the correct remote IP-address
+//
+function get_remote_address()
+{
+	($hook = get_hook('fn_get_remote_address_start')) ? eval($hook) : null;
+
+	return $_SERVER['REMOTE_ADDR'];
+}
+
+
+//
+// Try to determine the current URL
+//
+function get_current_url()
+{
+	global $base_url;
+
+	($hook = get_hook('fn_get_current_url')) ? eval($hook) : null;
+
+	$protocol = (!isset($_SERVER['HTTPS']) || strtolower($_SERVER['HTTPS']) == 'off') ? 'http://' : 'https://';
+	$port = (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] != '80' && strpos($_SERVER['HTTP_HOST'], ':') === false) ? ':'.$_SERVER['SERVER_PORT'] : '';
+
+	return /* $protocol.$_SERVER['HTTP_HOST'].$port. */ $_SERVER['REQUEST_URI'];
+}
+
+
+//
+// An UTF-8 aware version of strlen()
+//
+function pun_strlen($str)
+{
+	return strlen(utf8_decode($str));
+}
+
+
+//
+// Convert \r\n and \r to \n
+//
+function pun_linebreaks($str)
+{
+	return str_replace(array("\r\n", "\r"), "\n", $str);
+}
+
+
+//
+// Inserts $element into $input at $offset
+//
+function array_insert(&$input, $offset, $element)
+{
+	// Out of bounds checks
+	if ($offset > count($input))
+		$offset = count($input);
+	else if ($offset < 0)
+		$offset = 0;
+
+	array_splice($input, $offset, 0, 0);
+	$input[$offset] = $element;
+}
+
+
+//
+// Attempts to fetch the provided URL using any available means
+//
+function get_remote_file($url, $timeout, $head_only = false)
+{
+	$result = null;
+	$parsed_url = parse_url($url);
+	$allow_url_fopen = strtolower(@ini_get('allow_url_fopen'));
+
+	// Quite unlikely that this will be allowed on a shared host, but it can't hurt
+	if (function_exists('ini_set'))
+		@ini_set('default_socket_timeout', $timeout);
+
+	// If we have cURL, we might as well use it
+	if (function_exists('curl_init'))
+	{
+		// Setup the transfer
+		$ch = curl_init();
+		curl_setopt($ch, CURLOPT_URL, $url);
+		curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+		curl_setopt($ch, CURLOPT_HEADER, true);
+		curl_setopt($ch, CURLOPT_NOBODY, $head_only);
+		curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
+		curl_setopt($ch, CURLOPT_USERAGENT, 'PunBB');
+
+		// Grab the page
+		$content = @curl_exec($ch);
+
+		// Ignore everything except a 200 response code
+		if ($content !== false && curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200')
+		{
+			if ($head_only)
+				$result['headers'] = explode("\r\n", trim($content));
+			else
+			{
+				$content_start = strpos($content, "\r\n\r\n");
+				if ($content_start !== false)
+				{
+					$result['headers'] = explode("\r\n", substr($content, 0, $content_start));
+					$result['content'] = trim(substr($content, $content_start));
+				}
+			}
+		}
+
+		curl_close($ch);
+	}
+	// fsockopen() is the second best thing
+	else if (function_exists('fsockopen'))
+	{
+		$remote = @fsockopen($parsed_url['host'], !empty($parsed_url['port']) ? intval($parsed_url['port']) : 80, $errno, $errstr, $timeout);
+		if ($remote)
+		{
+			// Send a standard HTTP 1.0 request for the page
+			$method = $head_only ? 'HEAD' : 'GET';
+			fwrite($remote, ($head_only ? 'HEAD' : 'GET').' '.(!empty($parsed_url['path']) ? $parsed_url['path'] : '/').(!empty($parsed_url['query']) ? '?'.$parsed_url['query'] : '').' HTTP/1.0'."\r\n");
+			fwrite($remote, 'Host: '.$parsed_url['host']."\r\n");
+			fwrite($remote, 'User-Agent: PunBB'."\r\n");
+			fwrite($remote, 'Connection: Close'."\r\n\r\n");
+
+			stream_set_timeout($remote, $timeout);
+			$stream_meta = stream_get_meta_data($remote);
+
+			// Fetch the response 1024 bytes at a time and watch out for a timeout
+			$content = false;
+			while (!feof($remote) && !$stream_meta['timed_out'])
+			{
+				$content .= fgets($remote, 1024);
+				$stream_meta = stream_get_meta_data($remote);
+			}
+
+			fclose($remote);
+
+			// Ignore everything except a 200 response code (we don't support redirects)
+			if ($content !== false && preg_match('#^HTTP/1.[01] 200 OK#', $content))
+			{
+				if ($head_only)
+					$result['headers'] = explode("\r\n", trim($content));
+				else
+				{
+					$content_start = strpos($content, "\r\n\r\n");
+					if ($content_start !== false)
+					{
+						$result['headers'] = explode("\r\n", substr($content, 0, $content_start));
+						$result['content'] = trim(substr($content, $content_start));
+					}
+				}
+			}
+		}
+	}
+	// Last case scenario, we use file_get_contents provided allow_url_fopen is enabled (any non 200 response results in a failure)
+	else if (in_array($allow_url_fopen, array('on', 'true', '1')))
+	{
+		// PHP5's version of file_get_contents() supports stream options
+		if (version_compare(PHP_VERSION, '5.0.0', '>='))
+		{
+			// Setup a stream context
+			$stream_context = stream_context_create(
+				array(
+					'http' => array(
+						'method'		=> $head_only ? 'HEAD' : 'GET',
+						'user_agent'	=> 'PunBB',
+						'max_redirects'	=> 3,		// PHP >=5.1.0 only
+						'timeout'		=> $timeout	// PHP >=5.2.1 only
+					)
+				)
+			);
+
+			$content = @file_get_contents($url, false, $stream_context);
+		}
+		else
+			$content = @file_get_contents($url);
+
+		// Did we get anything?
+		if ($content !== false)
+		{
+			// Gotta love the fact that $http_response_header just appears in the global scope (*cough* hack! *cough*)
+			$result['headers'] = $http_response_header;
+			if (!$head_only)
+				$result['content'] = trim($content);
+		}
+	}
+
+	return $result;
+}
+
+
+//
+// Display a message when board is in maintenance mode
+//
+function maintenance_message()
+{
+	global $pun_db, $pun_config, $lang_common, $pun_user, $base_url;
+
+	($hook = get_hook('fn_maintenance_message_start')) ? eval($hook) : null;
+
+	// Deal with newlines, tabs and multiple spaces
+	$pattern = array("\t\t", '  ', '  ');
+	$replace = array('&#160; &#160; ', '&#160; ', ' &#160;');
+	$message = str_replace($pattern, $replace, $pun_config['o_maintenance_message']);
+
+	// Send the Content-type header in case the web server is setup to send something else
+	header('Content-type: text/html; charset=utf-8');
+
+	// Send a 503 HTTP response code to prevent search bots from indexing the maintenace message
+	header('HTTP/1.1 503 Service Temporarily Unavailable');
+
+	// Load the maintenance template
+	$tpl_maint = trim(file_get_contents(PUN_ROOT.'include/template/maintenance.tpl'));
+
+	// START SUBST - <!-- pun_local -->
+	$tpl_maint = str_replace('<!-- pun_local -->', 'xml:lang="'.$lang_common['lang_identifier'].'" lang="'.$lang_common['lang_identifier'].'" dir="'.$lang_common['lang_direction'].'"', $tpl_maint);
+	// END SUBST - <!-- pun_local -->
+
+
+	// START SUBST - <!-- pun_head -->
+	ob_start();
+
+?>
+<title><?php echo $lang_common['Maintenance'].' - '.htmlspecialchars($pun_config['o_board_title']) ?></title>
+<link rel="stylesheet" type="text/css" media="screen" href="<?php echo $base_url ?>/style/<?php echo $pun_user['style'] ?>/<?php echo $pun_user['style'].'.css' ?>" />
+<!--[if lte IE 6]><link rel="stylesheet" type="text/css" href="<?php echo $base_url ?>/style/<?php echo $pun_user['style'] ?>/<?php echo $pun_user['style'].'_fix.css' ?>" /><![endif]-->
+<!--[if IE 7]><link rel="stylesheet" type="text/css" href="<?php echo $base_url ?>/style/<?php echo $pun_user['style'] ?>/<?php echo $pun_user['style'].'_fix7.css' ?>" /><![endif]-->
+<?php
+
+	$tpl_temp = trim(ob_get_contents());
+	$tpl_maint = str_replace('<!-- pun_head -->', $tpl_temp, $tpl_maint);
+	ob_end_clean();
+	// END SUBST - <!-- pun_head -->
+
+
+	// START SUBST - <!-- pun_maint_main -->
+	ob_start();
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo $lang_common['Maintenance'] ?></span></h1>
+
+	<div class="main-content message">
+		<div class="userbox">
+			<?php echo $message."\n" ?>
+		</div>
+	</div>
+
+</div>
+<?php
+
+	$tpl_temp = "\t".trim(ob_get_contents());
+	$tpl_maint = str_replace('<!-- pun_maint_main -->', $tpl_temp, $tpl_maint);
+	ob_end_clean();
+	// END SUBST - <!-- pun_maint_main -->
+
+
+	// End the transaction
+	$pun_db->end_transaction();
+
+
+	// START SUBST - <!-- pun_include "*" -->
+	while (preg_match('#<!-- ?pun_include "([^/\\\\]*?)" ?-->#', $tpl_maint, $cur_include))
+	{
+		if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1]))
+			error('Unable to process user include &lt;!-- pun_include "'.htmlspecialchars($cur_include[1]).'" --&gt; from template maintenance.tpl. There is no such file in folder /include/user/.');
+
+		ob_start();
+		include PUN_ROOT.'include/user/'.$cur_include[1];
+		$tpl_temp = ob_get_contents();
+		$tpl_maint = str_replace($cur_include[0], $tpl_temp, $tpl_maint);
+		ob_end_clean();
+	}
+	// END SUBST - <!-- pun_include "*" -->
+
+
+	// Close the db connection (and free up any result data)
+	$pun_db->close();
+
+	exit($tpl_maint);
+}
+
+
+//
+// Display $message and redirect user to $destination_url
+//
+function pun_redirect($destination_url, $message)
+{
+	global $pun_db, $pun_config, $lang_common, $pun_user, $base_url;
+
+	($hook = get_hook('fn_redirect_start')) ? eval($hook) : null;
+
+	// Prefix with base_url (unless it's there already)
+	// if (strpos($destination_url, 'http') !== 0)
+	// 	$destination_url = $base_url.'/'.$destination_url;
+  
+	// Do a little spring cleaning
+	$destination_url = preg_replace('/([\r\n])|(%0[ad])|(;[\s]*data[\s]*:)/i', '', $destination_url);
+  
+	// If the delay is 0 seconds, we might as well skip the redirect all together
+	if ($pun_config['o_redirect_delay'] == '0')
+		header('Location: '.str_replace('&amp;', '&', $destination_url));
+
+	// Send no-cache headers
+	header('Expires: Thu, 21 Jul 1977 07:30:00 GMT');	// When yours truly first set eyes on this world! :)
+	header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
+	header('Cache-Control: post-check=0, pre-check=0', false);
+	header('Pragma: no-cache');		// For HTTP/1.0 compability
+
+	// Send the Content-type header in case the web server is setup to send something else
+	header('Content-type: text/html; charset=utf-8');
+
+	// Load the redirect template
+	$tpl_redir = trim(file_get_contents(PUN_ROOT.'include/template/redirect.tpl'));
+
+
+	// START SUBST - <!-- pun_local -->
+	$tpl_redir = str_replace('<!-- pun_local -->', 'xml:lang="'.$lang_common['lang_identifier'].'" lang="'.$lang_common['lang_identifier'].'" dir="'.$lang_common['lang_direction'].'"', $tpl_redir);
+	// END SUBST - <!-- pun_local -->
+
+
+	// START SUBST - <!-- pun_head -->
+	ob_start();
+
+?>
+<meta http-equiv="refresh" content="<?php echo $pun_config['o_redirect_delay'] ?>;URL=<?php echo str_replace(array('<', '>', '"'), array('&lt;', '&gt;', '&quot;'), $destination_url) ?>" />
+<title><?php echo $lang_common['Redirecting'].' - '.htmlspecialchars($pun_config['o_board_title']) ?></title>
+<?php
+
+	// Include the stylesheets
+	require PUN_ROOT.'style/'.$pun_user['style'].'/'.$pun_user['style'].'.php';
+
+	$tpl_temp = "\t".trim(ob_get_contents());
+	$tpl_redir = str_replace('<!-- pun_head -->', $tpl_temp, $tpl_redir);
+	ob_end_clean();
+	// END SUBST - <!-- pun_head -->
+
+
+	// START SUBST - <!-- pun_redir_main -->
+	ob_start();
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo $lang_common['Redirecting'] ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $message ?></span></h2>
+	</div>
+	<div class="main-content message">
+		<p><?php printf($lang_common['Forwarding info'], $pun_config['o_redirect_delay']) ?><span> <a href="<?php echo $destination_url ?>"><?php echo $lang_common['Click redirect'] ?></a></span></p>
+	</div>
+
+</div>
+<?php
+
+	$tpl_temp = "\t".trim(ob_get_contents());
+	$tpl_redir = str_replace('<!-- pun_redir_main -->', $tpl_temp, $tpl_redir);
+	ob_end_clean();
+	// END SUBST - <!-- pun_redir_main -->
+
+
+	// START SUBST - <!-- pun_debug -->
+	if (defined('PUN_SHOW_QUERIES'))
+		$tpl_redir = str_replace('<!-- pun_debug -->', get_saved_queries(), $tpl_redir);
+
+	// End the transaction
+	$pun_db->end_transaction();
+	// END SUBST - <!-- pun_debug -->
+
+
+	// START SUBST - <!-- pun_include "*" -->
+	while (preg_match('#<!-- ?pun_include "([^/\\\\]*?)" ?-->#', $tpl_redir, $cur_include))
+	{
+		if (!file_exists(PUN_ROOT.'include/user/'.$cur_include[1]))
+			error('Unable to process user include &lt;!-- pun_include "'.htmlspecialchars($cur_include[1]).'" --&gt; from template redirect.tpl. There is no such file in folder /include/user/.');
+
+		ob_start();
+		include PUN_ROOT.'include/user/'.$cur_include[1];
+		$tpl_temp = ob_get_contents();
+		$tpl_redir = str_replace($cur_include[0], $tpl_temp, $tpl_redir);
+		ob_end_clean();
+	}
+	// END SUBST - <!-- pun_include "*" -->
+
+
+	// Close the db connection (and free up any result data)
+	$pun_db->close();
+
+	exit($tpl_redir);
+}
+
+
+//
+// Display a simple error message
+//
+function error()
+{
+	global $pun_config;
+
+	/*
+		Parse input parameters. Possible function signatures:
+		error('Error message.');
+		error(__FILE__, __LINE__);
+		error('Error message.', __FILE__, __LINE__);
+	*/
+	$num_args = func_num_args();
+	if ($num_args == 3)
+	{
+		$message = func_get_arg(0);
+		$file = func_get_arg(1);
+		$line = func_get_arg(2);
+	}
+	else if ($num_args == 2)
+	{
+		$file = func_get_arg(0);
+		$line = func_get_arg(1);
+	}
+	else if ($num_args == 1)
+		$message = func_get_arg(0);
+
+	// Set a default title if the script failed before $pun_config could be populated
+	if (empty($pun_config))
+		$pun_config['o_board_title'] = 'PunBB';
+
+	// Empty all output buffers and stop buffering
+	while (@ob_end_clean());
+
+	// "Restart" output buffering if we are using ob_gzhandler (since the gzip header is already sent)
+	if (!empty($pun_config['o_gzip']) && extension_loaded('zlib') && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false || strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') !== false))
+		ob_start('ob_gzhandler');
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
+<head>
+<title>Error - <?php echo htmlspecialchars($pun_config['o_board_title']) ?></title>
+</head>
+<body style="margin: 40px; font: 85%/130% verdana, arial, sans-serif; color: #333;">
+
+<h1>An error was encountered</h1>
+<hr />
+<?php
+
+	if (isset($message))
+		echo '<p>'.$message.'</p>'."\n";
+
+	if ($num_args > 1)
+	{
+		if (defined('PUN_DEBUG'))
+		{
+			if (isset($file) && isset($line))
+				echo '<p><em>The error occurred on line '.$line.' in '.$file.'</em></p>'."\n";
+
+			$db_error = isset($GLOBALS['pun_db']) ? $GLOBALS['pun_db']->error() : array();
+			if (!empty($db_error['error_msg']))
+			{
+				echo '<p><strong>Database reported:</strong> '.htmlspecialchars($db_error['error_msg']).(($db_error['error_no']) ? ' (Errno: '.$db_error['error_no'].')' : '').'.</p>'."\n";
+
+				if ($db_error['error_sql'] != '')
+					echo '<p><strong>Failed query:</strong> <code>'.htmlspecialchars($db_error['error_sql']).'</code></p>'."\n";
+			}
+		}
+		else
+			echo '<p><strong>Note:</strong> For detailed error information (necessary for troubleshooting), enable "DEBUG mode". To enable "DEBUG mode", open up the file include/common.php in a text editor and locate the line "//define(\'PUN_DEBUG\', 1);". It it located at the very top of the file below the software license preamble. Then remove the two slashes in the beginning of the line and save/upload the script. Once you\'ve solved the problem, it is recommended that "DEBUG mode" be turned off again (just add the two slashes back again).</p>'."\n";
+	}
+
+?>
+
+</body>
+</html>
+<?php
+
+	// If a database connection was established (before this error) we close it
+	if (isset($GLOBALS['db']))
+		$GLOBALS['db']->close();
+
+	exit;
+}
+
+
+//
+// Unset any variables instantiated as a result of register_globals being enabled
+//
+function pun_unregister_globals()
+{
+	$register_globals = @ini_get('register_globals');
+	if ($register_globals === "" || $register_globals === "0" || strtolower($register_globals) === "off")
+		return;
+
+	// Prevent script.php?GLOBALS[foo]=bar
+	if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS']))
+		exit('I\'ll have a steak sandwich and... a steak sandwich.');
+
+	// Variables that shouldn't be unset
+	$no_unset = array('GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES');
+
+	// Remove elements in $GLOBALS that are present in any of the superglobals
+	$input = array_merge($_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES, isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());
+	foreach ($input as $k => $v)
+	{
+		if (!in_array($k, $no_unset) && isset($GLOBALS[$k]))
+		{
+			unset($GLOBALS[$k]);
+			unset($GLOBALS[$k]);	// Double unset to circumvent the zend_hash_del_key_or_index hole in PHP <4.4.3 and <5.1.4
+		}
+	}
+}
+
+
+// DEBUG FUNCTIONS BELOW
+
+//
+// Display executed queries (if enabled)
+//
+function get_saved_queries()
+{
+	global $pun_db, $lang_common;
+
+	// Get the queries so that we can print them out
+	$saved_queries = $pun_db->get_saved_queries();
+
+	$output = '
+<div id="pun-debug" class="main">
+
+	<div class="main-head">
+		<h2><span>'.$lang_common['Debug table'].'</span></h2>
+	</div>
+
+	<div class="main-content debug">
+		<table cellspacing="0" summary="Database query performance information">
+			<thead>
+				<tr>
+					<th class="tcl" scope="col">Time (s)</th>
+					<th class="tcr" scope="col">Query</th>
+				</tr>
+			</thead>
+			<tbody>
+';
+
+	$query_time_total = 0.0;
+	while (list(, $cur_query) = @each($saved_queries))
+	{
+		$query_time_total += $cur_query[1];
+
+		$output .= '
+				<tr>
+					<td class="tcl">'.(($cur_query[1] != 0) ? $cur_query[1] : '&#160;').'</td>
+					<td class="tcr">'.htmlspecialchars($cur_query[0]).'</td>
+				</tr>
+';
+
+	}
+
+	$output .= '
+				<tr class="totals">
+					<td class="tcl"><em>'.$query_time_total.' s</em></td>
+					<td class="tcr"><em>Total query time</em></td>
+				</tr>
+			</tbody>
+		</table>
+	</div>
+</div>
+';
+
+	return $output;
+}
+
+
+//
+// Dump contents of variable(s)
+//
+function dump()
+{
+	echo '<pre>';
+
+	$num_args = func_num_args();
+
+	for ($i = 0; $i < $num_args; ++$i)
+	{
+		print_r(func_get_arg($i));
+		echo "\n\n";
+	}
+
+	echo '</pre>';
+	exit;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/parser.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,476 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
+
+
+// Here you can add additional smilies if you like (please note that you must escape singlequote and backslash)
+$smiley_text = array(':)', '=)', ':|', '=|', ':(', '=(', ':D', '=D', ':o', ':O', ';)', ':/', ':P', ':lol:', ':mad:', ':rolleyes:', ':cool:');
+$smiley_img = array('smile.png', 'smile.png', 'neutral.png', 'neutral.png', 'sad.png', 'sad.png', 'big_smile.png', 'big_smile.png', 'yikes.png', 'yikes.png', 'wink.png', 'hmm.png', 'tongue.png', 'lol.png', 'mad.png', 'roll.png', 'cool.png');
+
+// Uncomment the next row if you add smilies that contain any of the characters &"'<>
+//$smiley_text = array_map('pun_htmlspecialchars', $smiley_text);
+
+
+//
+// Make sure all BBCodes are lower case and do a little cleanup
+//
+function preparse_bbcode($text, &$errors, $is_signature = false)
+{
+	// Change all simple BBCodes to lower case
+	$a = array('[B]', '[I]', '[U]', '[/B]', '[/I]', '[/U]');
+	$b = array('[b]', '[i]', '[u]', '[/b]', '[/i]', '[/u]');
+	$text = str_replace($a, $b, $text);
+
+	// Do the more complex BBCodes (also strip excessive whitespace and useless quotes)
+	$a = array( '#\[url=("|\'|)(.*?)\\1\]\s*#i',
+				'#\[url\]\s*#i',
+				'#\s*\[/url\]#i',
+				'#\[email=("|\'|)(.*?)\\1\]\s*#i',
+				'#\[email\]\s*#i',
+				'#\s*\[/email\]#i',
+				'#\[img\]\s*(.*?)\s*\[/img\]#is',
+				'#\[colou?r=("|\'|)(.*?)\\1\](.*?)\[/colou?r\]#is');
+
+	$b = array(	'[url=$2]',
+				'[url]',
+				'[/url]',
+				'[email=$2]',
+				'[email]',
+				'[/email]',
+				'[img]$1[/img]',
+				'[color=$2]$3[/color]');
+
+	if (!$is_signature)
+	{
+		// For non-signatures, we have to do the quote and code tags as well
+		$a[] = '#\[quote=(&quot;|"|\'|)(.*?)\\1\]\s*#i';
+		$a[] = '#\[quote\]\s*#i';
+		$a[] = '#\s*\[/quote\]\s*#i';
+		$a[] = '#\[code\][\r\n]*(.*?)\s*\[/code\]\s*#is';
+
+		$b[] = '[quote=$1$2$1]';
+		$b[] = '[quote]';
+		$b[] = '[/quote]'."\n";
+		$b[] = '[code]$1[/code]'."\n";
+	}
+
+	// Run this baby!
+	$text = preg_replace($a, $b, $text);
+
+	if (!$is_signature)
+	{
+		$overflow = check_tag_order($text, $error);
+
+		if ($error)
+			// A BBCode error was spotted in check_tag_order()
+			$errors[] = $error;
+		else if ($overflow)
+			// The quote depth level was too high, so we strip out the inner most quote(s)
+			$text = substr($text, 0, $overflow[0]).substr($text, $overflow[1], (strlen($text) - $overflow[0]));
+	}
+	else
+	{
+		global $lang_profile;
+
+		if (preg_match('#\[quote=(&quot;|"|\'|)(.*)\\1\]|\[quote\]|\[/quote\]|\[code\]|\[/code\]#i', $text))
+			message($lang_profile['Signature quote/code']);
+	}
+
+	return trim($text);
+}
+
+
+//
+// Parse text and make sure that [code] and [quote] syntax is correct
+//
+function check_tag_order($text, &$error)
+{
+	global $lang_common;
+
+	// The maximum allowed quote depth
+	$max_depth = 3;
+
+	$cur_index = 0;
+	$q_depth = 0;
+
+	while (true)
+	{
+		// Look for regular code and quote tags
+		$c_start = strpos($text, '[code]');
+		$c_end = strpos($text, '[/code]');
+		$q_start = strpos($text, '[quote]');
+		$q_end = strpos($text, '[/quote]');
+
+		// Look for [quote=username] style quote tags
+		if (preg_match('#\[quote=(&quot;|"|\'|)(.*)\\1\]#sU', $text, $matches))
+			$q2_start = strpos($text, $matches[0]);
+		else
+			$q2_start = 65536;
+
+		// Deal with strpos() returning false when the string is not found
+		// (65536 is one byte longer than the maximum post length)
+		if ($c_start === false) $c_start = 65536;
+		if ($c_end === false) $c_end = 65536;
+		if ($q_start === false) $q_start = 65536;
+		if ($q_end === false) $q_end = 65536;
+
+		// If none of the strings were found
+		if (min($c_start, $c_end, $q_start, $q_end, $q2_start) == 65536)
+			break;
+
+		// We are interested in the first quote (regardless of the type of quote)
+		$q3_start = ($q_start < $q2_start) ? $q_start : $q2_start;
+
+		// We found a [quote] or a [quote=username]
+		if ($q3_start < min($q_end, $c_start, $c_end))
+		{
+			$step = ($q_start < $q2_start) ? 7 : strlen($matches[0]);
+
+			$cur_index += $q3_start + $step;
+
+			// Did we reach $max_depth?
+			if ($q_depth == $max_depth)
+				$overflow_begin = $cur_index - $step;
+
+			++$q_depth;
+			$text = substr($text, $q3_start + $step);
+		}
+
+		// We found a [/quote]
+		else if ($q_end < min($q_start, $c_start, $c_end))
+		{
+			if ($q_depth == 0)
+			{
+				$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 1'];
+				return;
+			}
+
+			$q_depth--;
+			$cur_index += $q_end+8;
+
+			// Did we reach $max_depth?
+			if ($q_depth == $max_depth)
+				$overflow_end = $cur_index;
+
+			$text = substr($text, $q_end+8);
+		}
+
+		// We found a [code]
+		else if ($c_start < min($c_end, $q_start, $q_end))
+		{
+			// Make sure there's a [/code] and that any new [code] doesn't occur before the end tag
+			$tmp = strpos($text, '[/code]');
+			$tmp2 = strpos(substr($text, $c_start+6), '[code]');
+			if ($tmp2 !== false)
+				$tmp2 += $c_start+6;
+
+			if ($tmp === false || ($tmp2 !== false && $tmp2 < $tmp))
+			{
+				$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 2'];
+				return;
+			}
+			else
+				$text = substr($text, $tmp+7);
+
+			$cur_index += $tmp+7;
+		}
+
+		// We found a [/code] (this shouldn't happen since we handle both start and end tag in the if clause above)
+		else if ($c_end < min($c_start, $q_start, $q_end))
+		{
+			$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 3'];
+			return;
+		}
+	}
+
+	// If $q_depth <> 0 something is wrong with the quote syntax
+	if ($q_depth)
+	{
+		$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 4'];
+		return;
+	}
+	else if ($q_depth < 0)
+	{
+		$error = $lang_common['BBCode error'].' '.$lang_common['BBCode error 5'];
+		return;
+	}
+
+	// If the quote depth level was higher than $max_depth we return the index for the
+	// beginning and end of the part we should strip out
+	if (isset($overflow_begin))
+		return array($overflow_begin, $overflow_end);
+	else
+		return null;
+}
+
+
+//
+// Split text into chunks ($inside contains all text inside $start and $end, and $outside contains all text outside)
+//
+function split_text($text, $start, $end)
+{
+	global $pun_config;
+
+	$tokens = explode($start, $text);
+
+	$outside[] = $tokens[0];
+
+	$num_tokens = count($tokens);
+	for ($i = 1; $i < $num_tokens; ++$i)
+	{
+		$temp = explode($end, $tokens[$i]);
+		$inside[] = $temp[0];
+		$outside[] = $temp[1];
+	}
+
+	if ($pun_config['o_indent_num_spaces'] != 8 && $start == '[code]')
+	{
+		$spaces = str_repeat(' ', $pun_config['o_indent_num_spaces']);
+		$inside = str_replace("\t", $spaces, $inside);
+	}
+
+	return array($inside, $outside);
+}
+
+
+//
+// Truncate URL if longer than 55 characters (add http:// or ftp:// if missing)
+//
+function handle_url_tag($url, $link = '')
+{
+	global $pun_user;
+
+	$full_url = str_replace(array(' ', '\'', '`', '"'), array('%20', '', '', ''), $url);
+	if (strpos($url, 'www.') === 0)			// If it starts with www, we add http://
+		$full_url = 'http://'.$full_url;
+	else if (strpos($url, 'ftp.') === 0)	// Else if it starts with ftp, we add ftp://
+		$full_url = 'ftp://'.$full_url;
+	else if (!preg_match('#^([a-z0-9]{3,6})://#', $url, $bah)) 	// Else if it doesn't start with abcdef://, we add http://
+		$full_url = 'http://'.$full_url;
+
+	// Ok, not very pretty :-)
+	$link = ($link == '' || $link == $url) ? ((strlen($url) > 55) ? substr($url, 0 , 39).' &#133; '.substr($url, -10) : $url) : stripslashes($link);
+
+	return '<a href="'.$full_url.'">'.$link.'</a>';
+}
+
+
+//
+// Turns an URL from the [img] tag into an <img> tag or a <a href...> tag
+//
+function handle_img_tag($url, $is_signature = false)
+{
+	global $lang_common, $pun_config, $pun_user;
+
+	$img_tag = '<a href="'.$url.'">&lt;'.$lang_common['Image link'].'&gt;</a>';
+
+	if ($is_signature && $pun_user['show_img_sig'] != '0')
+		$img_tag = '<img class="sigimage" src="'.$url.'" alt="'.htmlspecialchars($url).'" />';
+	else if (!$is_signature && $pun_user['show_img'] != '0')
+		$img_tag = '<span class="postimg"><img src="'.$url.'" alt="'.htmlspecialchars($url).'" /></span>';
+
+	return $img_tag;
+}
+
+
+//
+// Convert BBCodes to their HTML equivalent
+//
+function do_bbcode($text)
+{
+	global $lang_common, $pun_user;
+
+	if (strpos($text, 'quote') !== false)
+	{
+		$text = str_replace('[quote]', '</p><div class="quotebox"><blockquote><p>', $text);
+		$text = preg_replace('#\[quote=(&quot;|"|\'|)(.*)\\1\]#seU', '"</p><div class=\"quotebox\"><cite>".str_replace(array(\'[\', \'\\"\'), array(\'&#91;\', \'"\'), \'$2\')." ".$lang_common[\'wrote\'].":</cite><blockquote><p>"', $text);
+		$text = preg_replace('#\[\/quote\]\s*#', '</p></blockquote></div><p>', $text);
+	}
+
+	$pattern = array('#\[b\](.*?)\[/b\]#s',
+					 '#\[i\](.*?)\[/i\]#s',
+					 '#\[u\](.*?)\[/u\]#s',
+					 '#\[url\]([^\[]*?)\[/url\]#e',
+					 '#\[url=([^\[]*?)\](.*?)\[/url\]#e',
+					 '#\[email\]([^\[]*?)\[/email\]#',
+					 '#\[email=([^\[]*?)\](.*?)\[/email\]#',
+					 '#\[color=([a-zA-Z]*|\#?[0-9a-fA-F]{6})](.*?)\[/color\]#s');
+
+	$replace = array('<strong>$1</strong>',
+					 '<em>$1</em>',
+					 '<em class="bbuline">$1</em>',
+					 'handle_url_tag(\'$1\')',
+					 'handle_url_tag(\'$1\', \'$2\')',
+					 '<a href="mailto:$1">$1</a>',
+					 '<a href="mailto:$1">$2</a>',
+					 '<span style="color: $1">$2</span>');
+
+	// This thing takes a while! :)
+	$text = preg_replace($pattern, $replace, $text);
+
+	return $text;
+}
+
+
+//
+// Make hyperlinks clickable
+//
+function do_clickable($text)
+{
+	global $pun_user;
+
+	$text = ' '.$text;
+
+	$text = preg_replace('#([\s\(\)])(https?|ftp|news){1}://([\w\-]+\.([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^"\s\(\)<\[]*)?)#ie', '\'$1\'.handle_url_tag(\'$2://$3\')', $text);
+	$text = preg_replace('#([\s\(\)])(www|ftp)\.(([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^"\s\(\)<\[]*)?)#ie', '\'$1\'.handle_url_tag(\'$2.$3\', \'$2.$3\')', $text);
+
+	return substr($text, 1);
+}
+
+
+//
+// Convert a series of smilies to images
+//
+function do_smilies($text)
+{
+	global $pun_config, $base_url, $smiley_text, $smiley_img;
+
+	$text = ' '.$text.' ';
+
+	$num_smilies = count($smiley_text);
+	for ($i = 0; $i < $num_smilies; ++$i)
+		$text = preg_replace("#(?<=.\W|\W.|^\W)".preg_quote($smiley_text[$i], '#')."(?=.\W|\W.|\W$)#m", '$1<img src="'.$base_url.'/img/smilies/'.$smiley_img[$i].'" width="15" height="15" alt="'.substr($smiley_img[$i], 0, strrpos($smiley_img[$i], '.')).'" />$2', $text);
+
+	return substr($text, 1, -1);
+}
+
+
+//
+// Parse message text
+//
+function parse_message($text, $hide_smilies)
+{
+	global $pun_config, $lang_common, $pun_user;
+
+	if ($pun_config['o_censoring'] == '1')
+		$text = censor_words($text);
+
+	// Convert applicable characters to HTML entities
+	$text = htmlspecialchars($text);
+
+	// If the message contains a code tag we have to split it up (text within [code][/code] shouldn't be touched)
+	if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
+	{
+		list($inside, $outside) = split_text($text, '[code]', '[/code]');
+		$outside = array_map('ltrim', $outside);
+		$text = implode('<">', $outside);
+	}
+
+	if ($pun_config['o_make_links'] == '1')
+		$text = do_clickable($text);
+
+
+	if ($pun_config['o_smilies'] == '1' && $pun_user['show_smilies'] == '1' && $hide_smilies == '0')
+		$text = do_smilies($text);
+
+	if ($pun_config['p_message_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
+	{
+		$text = do_bbcode($text);
+
+		if ($pun_config['p_message_img_tag'] == '1')
+		{
+//			$text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\.(jpg|jpeg|png|gif)\[/img\]#e', 'handle_img_tag(\'$1$3.$4\')', $text);
+			$text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e', 'handle_img_tag(\'$1$3\')', $text);
+		}
+	}
+
+	// Deal with newlines, tabs and multiple spaces
+	$pattern = array("\n", "\t", '  ', '  ');
+	$replace = array('<br />', '&nbsp; &nbsp; ', '&nbsp; ', ' &nbsp;');
+	$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('<">', $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"><strong>'.$lang_common['Code'].':</strong><pre><code>'.$inside[$i].'</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><p>", $text);
+	$text = str_replace('<p></p>', '', '<p>'.$text.'</p>');
+
+	return $text;
+}
+
+
+//
+// Parse signature text
+//
+function parse_signature($text)
+{
+	global $pun_config, $lang_common, $pun_user;
+
+	if ($pun_config['o_censoring'] == '1')
+		$text = censor_words($text);
+
+	$text = htmlspecialchars($text);
+
+	if ($pun_config['o_make_links'] == '1')
+		$text = do_clickable($text);
+
+	if ($pun_config['o_smilies_sig'] == '1' && $pun_user['show_smilies'] != '0')
+		$text = do_smilies($text);
+
+	if ($pun_config['p_sig_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false)
+	{
+		$text = do_bbcode($text);
+
+		if ($pun_config['p_sig_img_tag'] == '1')
+		{
+//			$text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\.(jpg|jpeg|png|gif)\[/img\]#e', 'handle_img_tag(\'$1$3.$4\', true)', $text);
+			$text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e', 'handle_img_tag(\'$1$3\', true)', $text);
+		}
+	}
+
+	// Deal with newlines, tabs and multiple spaces
+	$pattern = array("\n", "\t", '  ', '  ');
+	$replace = array('<br />', '&nbsp; &nbsp; ', '&nbsp; ', ' &nbsp;');
+	$text = str_replace($pattern, $replace, $text);
+
+	return $text;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/search_idx.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,231 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// The contents of this file are very much inspired by the file functions_search.php
+// from the phpBB Group forum software phpBB2 (http://www.phpbb.com). 
+
+
+// Make sure no one attempts to run this script "directly"
+if (!defined('PUN'))
+	exit;
+
+
+//
+// "Cleans up" a text string and returns an array of unique words
+// This function depends on the current locale setting
+//
+function split_words($text)
+{
+	global $pun_user;
+	static $noise_match, $noise_replace, $stopwords;
+
+	if (empty($noise_match))
+	{
+		$noise_match = 		array('[quote', '[code', '[url', '[img', '[email', '[color', '[colour', 'quote]', 'code]', 'url]', 'img]', 'email]', 'color]', 'colour]', '^', '$', '&', '(', ')', '<', '>', '`', '\'', '"', '|', ',', '@', '_', '?', '%', '~', '+', '[', ']', '{', '}', ':', '\\', '/', '=', '#', ';', '!', '*');
+		$noise_replace =	array('',       '',      '',     '',     '',       '',       '',        '',       '',      '',     '',     '',       '',       '',        ' ', ' ', ' ', ' ', ' ', ' ', ' ', '',  '',   ' ', ' ', ' ', ' ', '',  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '' ,  ' ', ' ', ' ', ' ', ' ', ' ');
+
+		$stopwords = (array)@file(PUN_ROOT.'lang/'.$pun_user['language'].'/stopwords.txt');
+		$stopwords = array_map('trim', $stopwords);
+	}
+
+	// Clean up
+	$patterns[] = '#&[\#a-z0-9]+?;#i';
+	$patterns[] = '#\b[\w]+:\/\/[a-z0-9\.\-]+(\/[a-z0-9\?\.%_\-\+=&\/~]+)?#';
+	$patterns[] = '#\[\/?[a-z\*=\+\-]+(\:?[0-9a-z]+)?:[a-z0-9]{10,}(\:[a-z0-9]+)?=?.*?\]#';
+	$text = preg_replace($patterns, ' ', ' '.strtolower($text).' ');
+
+	// Filter out junk
+	$text = str_replace($noise_match, $noise_replace, $text);
+
+	// Strip out extra whitespace between words
+	$text = trim(preg_replace('#\s+#', ' ', $text));
+
+	// Fill an array with all the words
+	$words = explode(' ', $text);
+
+	if (!empty($words))
+	{
+		while (list($i, $word) = @each($words))
+		{
+			$words[$i] = trim($word, '.');
+			$num_chars = pun_strlen($word);
+
+			if ($num_chars < 3 || $num_chars > 20 || in_array($words[$i], $stopwords))
+				unset($words[$i]);
+		}
+	}
+
+	return array_unique($words);
+}
+
+
+//
+// Updates the search index with the contents of $post_id (and $subject)
+//
+function update_search_index($mode, $post_id, $message, $subject = null)
+{
+	global $db_type, $pun_db;
+
+	// Split old and new post/subject to obtain array of 'words'
+	$words_message = split_words($message);
+	$words_subject = ($subject) ? split_words($subject) : array();
+
+	if ($mode == 'edit')
+	{
+		$result = $pun_db->query('SELECT w.id, w.word, m.subject_match FROM '.$pun_db->prefix.'search_words AS w INNER JOIN '.$pun_db->prefix.'search_matches AS m ON w.id=m.word_id WHERE m.post_id='.$post_id, true) or error(__FILE__, __LINE__);
+
+		// Declare here to stop array_keys() and array_diff() from complaining if not set
+		$cur_words['post'] = array();
+		$cur_words['subject'] = array();
+
+		while ($row = $pun_db->fetch_row($result))
+		{
+			$match_in = ($row[2]) ? 'subject' : 'post';
+			$cur_words[$match_in][$row[1]] = $row[0];
+		}
+
+		$pun_db->free_result($result);
+
+		$words['add']['post'] = array_diff($words_message, array_keys($cur_words['post']));
+		$words['add']['subject'] = array_diff($words_subject, array_keys($cur_words['subject']));
+		$words['del']['post'] = array_diff(array_keys($cur_words['post']), $words_message);
+		$words['del']['subject'] = array_diff(array_keys($cur_words['subject']), $words_subject);
+	}
+	else
+	{
+		$words['add']['post'] = $words_message;
+		$words['add']['subject'] = $words_subject;
+		$words['del']['post'] = array();
+		$words['del']['subject'] = array();
+	}
+
+	unset($words_message);
+	unset($words_subject);
+
+	// Get unique words from the above arrays
+	$unique_words = array_unique(array_merge($words['add']['post'], $words['add']['subject']));
+
+	if (!empty($unique_words))
+	{
+		$result = $pun_db->query('SELECT id, word FROM '.$pun_db->prefix.'search_words WHERE word IN('.implode(',', preg_replace('#^(.*)$#', '\'\1\'', $unique_words)).')', true) or error(__FILE__, __LINE__);
+
+		$word_ids = array();
+		while ($row = $pun_db->fetch_row($result))
+			$word_ids[$row[1]] = $row[0];
+
+		$pun_db->free_result($result);
+
+		$new_words = array_diff($unique_words, array_keys($word_ids));
+		unset($unique_words);
+
+		if (!empty($new_words))
+		{
+			switch ($db_type)
+			{
+				case 'mysql':
+				case 'mysqli':
+					$pun_db->query('INSERT INTO '.$pun_db->prefix.'search_words (word) VALUES'.implode(',', preg_replace('#^(.*)$#', '(\'\1\')', $new_words))) or error(__FILE__, __LINE__);
+					break;
+
+				default:
+					while (list(, $word) = @each($new_words))
+						$pun_db->query('INSERT INTO '.$pun_db->prefix.'search_words (word) VALUES(\''.$word.'\')') or error(__FILE__, __LINE__);
+					break;
+			}
+		}
+
+		unset($new_words);
+	}
+
+	// Delete matches (only if editing a post)
+	while (list($match_in, $wordlist) = @each($words['del']))
+	{
+		$subject_match = ($match_in == 'subject') ? 1 : 0;
+
+		if (!empty($wordlist))
+		{
+			$sql = '';
+			while (list(, $word) = @each($wordlist))
+				$sql .= (($sql != '') ? ',' : '').$cur_words[$match_in][$word];
+
+			$pun_db->query('DELETE FROM '.$pun_db->prefix.'search_matches WHERE word_id IN('.$sql.') AND post_id='.$post_id.' AND subject_match='.$subject_match) or error(__FILE__, __LINE__);
+		}
+	}
+
+	// Add new matches
+	while (list($match_in, $wordlist) = @each($words['add']))
+	{
+		$subject_match = ($match_in == 'subject') ? 1 : 0;
+
+		if (!empty($wordlist))
+			$pun_db->query('INSERT INTO '.$pun_db->prefix.'search_matches (post_id, word_id, subject_match) SELECT '.$post_id.', id, '.$subject_match.' FROM '.$pun_db->prefix.'search_words WHERE word IN('.implode(',', preg_replace('#^(.*)$#', '\'\1\'', $wordlist)).')') or error(__FILE__, __LINE__);
+	}
+
+	unset($words);
+}
+
+
+//
+// Strip search index of indexed words in $post_ids
+//
+function strip_search_index($post_ids)
+{
+	global $db_type, $pun_db;
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+		{
+			$result = $pun_db->query('SELECT word_id FROM '.$pun_db->prefix.'search_matches WHERE post_id IN('.$post_ids.') GROUP BY word_id') or error(__FILE__, __LINE__);
+
+			if ($pun_db->num_rows($result))
+			{
+				$word_ids = '';
+				while ($row = $pun_db->fetch_row($result))
+					$word_ids .= ($word_ids != '') ? ','.$row[0] : $row[0];
+
+				$result = $pun_db->query('SELECT word_id FROM '.$pun_db->prefix.'search_matches WHERE word_id IN('.$word_ids.') GROUP BY word_id HAVING COUNT(word_id)=1') or error(__FILE__, __LINE__);
+
+				if ($pun_db->num_rows($result))
+				{
+					$word_ids = '';
+					while ($row = $pun_db->fetch_row($result))
+						$word_ids .= ($word_ids != '') ? ','.$row[0] : $row[0];
+
+					$pun_db->query('DELETE FROM '.$pun_db->prefix.'search_words WHERE id IN('.$word_ids.')') or error(__FILE__, __LINE__);
+				}
+			}
+
+			break;
+		}
+
+		default:
+			$pun_db->query('DELETE FROM '.$pun_db->prefix.'search_words WHERE id IN(SELECT word_id FROM '.$pun_db->prefix.'search_matches WHERE word_id IN(SELECT word_id FROM '.$pun_db->prefix.'search_matches WHERE post_id IN('.$post_ids.') GROUP BY word_id) GROUP BY word_id HAVING COUNT(word_id)=1)') or error(__FILE__, __LINE__);
+			break;
+	}
+
+	$pun_db->query('DELETE FROM '.$pun_db->prefix.'search_matches WHERE post_id IN('.$post_ids.')') or error(__FILE__, __LINE__);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/template/admin.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" <!-- pun_local -->>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<!-- pun_head -->
+</head>
+<body>
+
+<div <!-- pun_page --> class="pun-page">
+<div class="pun">
+<!-- pun_skip -->
+<!-- pun_title -->
+<!-- pun_desc -->
+<!-- pun_navlinks -->
+<!-- pun_visit -->
+
+<!-- pun_alert -->
+
+<!-- pun_announcement -->
+
+<!-- pun_crumbs -->
+
+<div class="divider"><hr /></div>
+
+<!-- pun_main -->
+
+<div class="divider"><hr /></div>
+
+<!-- pun_stats -->
+
+<!-- pun_about -->
+
+<!-- pun_debug -->
+
+</div>
+</div>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/template/help.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" <!-- pun_local -->>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<!-- pun_head -->
+</head>
+<body>
+
+<div <!-- pun_page --> class="pun-page">
+<div class="pun">
+
+<!-- pun_main -->
+
+</div>
+</div>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/template/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/template/main.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,33 @@
+
+<div <!-- pun_page --> class="pun-page">
+<div class="pun">
+
+<!-- pun_skip -->
+<!-- div id="pun-home">Powered by <a href="http://punbb.org/">PunBB</a></div -->
+
+<!-- pun_title -->
+<!-- pun_desc -->
+<!-- pun_navlinks -->
+<!-- pun_visit -->
+
+<!-- pun_alert -->
+
+<!-- pun_announcement -->
+
+<!-- pun_crumbs -->
+
+<div class="divider"><hr /></div>
+
+<!-- pun_main -->
+
+<div class="divider"><hr /></div>
+
+<!-- pun_stats -->
+
+<!-- pun_about -->
+
+<!-- pun_debug -->
+
+</div>
+</div>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/template/maintenance.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" <!-- pun_local -->>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<!-- pun_head -->
+</head>
+<body>
+
+<div id="pun-maint">
+<div class="pun">
+
+<!-- pun_maint_main -->
+
+</div>
+</div>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/include/template/redirect.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,21 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" <!-- pun_local -->>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<!-- pun_head -->
+</head>
+<body>
+
+<div id="pun-redirect">
+<div class="pun">
+
+<!-- pun_redir_main -->
+
+<!-- pun_debug -->
+
+</div>
+</div>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/index.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,270 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('in_start')) ? eval($hook) : null;
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+
+// Load the index.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/index.php';
+
+// Get list of forums and topics with new posts since last visit
+if (!$pun_user['is_guest'])
+{
+	$query = array(
+		'SELECT'	=> 't.forum_id, t.id, t.last_post',
+		'FROM'		=> 'topics AS t',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'forums AS f',
+				'ON'			=> 'f.id=t.forum_id'
+			),
+			array(
+				'LEFT JOIN'		=> 'forum_perms AS fp',
+				'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+			)
+		),
+		'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND t.last_post>'.$pun_user['last_visit'].' AND t.moved_to IS NULL'
+	);
+
+	($hook = get_hook('in_qr_get_new_topics')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+	$new_topics = array();
+	while ($cur_topic = $pun_db->fetch_assoc($result))
+		$new_topics[$cur_topic['forum_id']][$cur_topic['id']] = $cur_topic['last_post'];
+
+	$tracked_topics = get_tracked_topics();
+}
+
+($hook = get_hook('in_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_ALLOW_INDEX', 1);
+define('PUN_PAGE', 'index');
+
+require PUN_ROOT.'header.php';
+
+// Print the categories and forums
+$query = array(
+	'SELECT'	=> 'c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.forum_desc, f.redirect_url, f.moderators, f.num_topics, f.num_posts, f.last_post, f.last_post_id, f.last_poster',
+	'FROM'		=> 'categories AS c',
+	'JOINS'		=> array(
+		array(
+			'INNER JOIN'	=> 'forums AS f',
+			'ON'			=> 'c.id=f.cat_id'
+		),
+		array(
+			'LEFT JOIN'		=> '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',
+	'ORDER BY'	=> 'c.disp_position, c.id, f.disp_position'
+);
+
+($hook = get_hook('in_qr_get_cats_and_forums')) ? eval($hook) : null;
+$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo htmlspecialchars($pun_config['o_board_title']) ?></span></h1>
+<?php
+
+$pun_page['cur_category'] = $pun_page['cat_count'] = $pun_page['item_count'] = 0;
+
+while ($cur_forum = $pun_db->fetch_assoc($result))
+{
+	($hook = get_hook('in_forum_loop_start')) ? eval($hook) : null;
+
+	$pun_page['item_mods'] = '';
+	++$pun_page['item_count'];
+
+	if ($cur_forum['cid'] != $pun_page['cur_category'])	// A new category since last iteration?
+	{
+		if ($pun_page['cur_category'] != 0)
+		{
+
+?>
+			</tbody>
+		</table>
+	</div>
+<?php
+
+		}
+
+		++$pun_page['cat_count'];
+		$pun_page['item_count'] = 1;
+
+?>
+	<div class="main-head">
+		<h2><span><?php echo htmlspecialchars($cur_forum['cat_name']) ?></span></h2>
+	</div>
+
+	<div id="category<?php echo $pun_page['cat_count'] ?>" class="main-content category">
+		<table cellspacing="0" summary="<?php printf($lang_index['Table summary'], htmlspecialchars($cur_forum['cat_name'])) ?>">
+			<thead>
+				<tr>
+					<th class="tcl" scope="col"><?php echo $lang_common['Forum'] ?></th>
+					<th class="tc2" scope="col"><?php echo $lang_common['Topics'] ?></th>
+					<th class="tc3" scope="col"><?php echo $lang_common['Posts'] ?></th>
+<?php ($hook = get_hook('in_table_header_after_num_posts')) ? eval($hook) : null; ?>
+					<th class="tcr" scope="col"><?php echo $lang_common['Last post'] ?></th>
+<?php ($hook = get_hook('in_table_header_after_last_post')) ? eval($hook) : null; ?>
+				</tr>
+			</thead>
+			<tbody class="statused">
+<?php
+
+		$pun_page['cur_category'] = $cur_forum['cid'];
+	}
+
+	$pun_page['item_status'] = $pun_page['item_subject'] = $pun_page['item_last_post'] = array();
+	$pun_page['item_alt_message'] = $lang_common['Forum'];
+	$pun_page['item_indicator'] = '';
+
+	// Is this a redirect forum?
+	if ($cur_forum['redirect_url'] != '')
+	{
+		$pun_page['item_title'] = '<h3><a class="external" href="'.htmlspecialchars($cur_forum['redirect_url']).'" title="'.sprintf($lang_index['Link to'], htmlspecialchars($cur_forum['redirect_url'])).'"><span>'.htmlspecialchars($cur_forum['forum_name']).'</span></a></h3>';
+		$cur_forum['num_topics'] = $cur_forum['num_posts'] = ' - ';
+		$pun_page['item_status'][] = 'redirect';
+		$pun_page['item_alt_message'] = $lang_index['External forum'];
+		$pun_page['item_last_post'][] = $lang_common['Unknown'];
+
+		if ($cur_forum['forum_desc'] != '')
+			$pun_page['item_subject'][] = $cur_forum['forum_desc'];
+	}
+	else
+	{
+		$pun_page['item_title'] = '<h3><a href="'.pun_link($pun_url['forum'], array($cur_forum['fid'], sef_friendly($cur_forum['forum_name']))).'"><span>'.htmlspecialchars($cur_forum['forum_name']).'</span></a></h3>';
+
+		// Are there new posts since our last visit?
+		if (!$pun_user['is_guest'] && $cur_forum['last_post'] > $pun_user['last_visit'] && (empty($tracked_topics['forums'][$cur_forum['fid']]) || $cur_forum['last_post'] > $tracked_topics['forums'][$cur_forum['fid']]))
+		{
+			// There are new posts in this forum, but have we read all of them already?
+			while (list($check_topic_id, $check_last_post) = @each($new_topics[$cur_forum['fid']]))
+			{
+				if (empty($tracked_topics['topics'][$check_topic_id]) || $tracked_topics['topics'][$check_topic_id] < $check_last_post)
+				{
+					$pun_page['item_status'][] = 'new';
+					$pun_page['item_alt_message'] = $lang_index['Forum has new'];
+					break;
+				}
+			}
+		}
+
+		if ($cur_forum['forum_desc'] != '')
+			$pun_page['item_subject'][] = $cur_forum['forum_desc'];
+
+		if ($cur_forum['moderators'] != '')
+		{
+			$pun_page['mods_array'] = unserialize($cur_forum['moderators']);
+			$pun_page['item_mods'] = array();
+
+			while (list($mod_username, $mod_id) = @each($pun_page['mods_array']))
+				$pun_page['item_mods'][] = '<a href="'.pun_link($pun_url['user'], $mod_id).'">'.htmlspecialchars($mod_username).'</a>';
+
+			$pun_page['item_subject'][] = '<span class="modlist">('.sprintf($lang_index['Moderated by'], implode(', ', $pun_page['item_mods'])).')</span>';
+		}
+
+		// If there is a last_post/last_poster.
+		if ($cur_forum['last_post'] != '')
+		{
+			$pun_page['item_last_post'][] = '<a href="'.pun_link($pun_url['post'], $cur_forum['last_post_id']).'"><span>'.format_time($cur_forum['last_post']).'</span></a>';
+			$pun_page['item_last_post'][] =	'<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($cur_forum['last_poster'])).'</span>';
+		}
+		else
+			$pun_page['item_last_post'][] = $lang_common['Never'];
+
+		if (empty($pun_page['item_status']))
+			$pun_page['item_status'][] = 'normal';
+	}
+
+	$pun_page['item_style'] = (($pun_page['item_count'] % 2 != 0) ? 'odd' : 'even').' '.implode(' ', $pun_page['item_status']);
+	$pun_page['item_indicator'] = '<span class="status '.implode(' ', $pun_page['item_status']).'" title="'.$pun_page['item_alt_message'].'"><img src="'.$base_url.'/style/'.$pun_user['style'].'/status.png" alt="'.$pun_page['item_alt_message'].'" /></span>';
+
+	($hook = get_hook('in_row_pre_display')) ? eval($hook) : null;
+
+?>
+				<tr id="forum<?php echo $cur_forum['fid'] ?>" class="<?php echo $pun_page['item_style'] ?>">
+					<td class="tcl"><?php echo $pun_page['item_indicator'].' '.$pun_page['item_title'].implode('<br />', $pun_page['item_subject']) ?></td>
+					<td class="tc2"><?php echo $cur_forum['num_topics'] ?></td>
+					<td class="tc3"><?php echo $cur_forum['num_posts'] ?></td>
+<?php ($hook = get_hook('in_table_contents_after_num_posts')) ? eval($hook) : null; ?>
+					<td class="tcr"><?php if (!empty($pun_page['item_last_post'])) echo implode(' ', $pun_page['item_last_post']) ?></td>
+<?php ($hook = get_hook('in_table_contents_after_last_post')) ? eval($hook) : null; ?>
+				</tr>
+<?php
+
+}
+
+// Did we output any categories and forums?
+if ($pun_page['cur_category'] > 0)
+{
+
+?>
+			</tbody>
+		</table>
+	</div>
+
+</div>
+<?php
+
+}
+else
+{
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo htmlspecialchars($pun_config['o_board_title']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_common['Forum message'] ?></span></h2>
+	</div>
+	<div class="main-content message">
+		<p><?php echo $lang_index['Empty board'] ?></p>
+	</div>
+
+</div>
+<?php
+
+}
+
+($hook = get_hook('in_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/install.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,1673 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+define('PUN_VERSION', '1.3 Beta');
+define('MIN_PHP_VERSION', '4.3.0');
+define('MIN_MYSQL_VERSION', '4.1.2');
+
+define('PUN_ROOT', './');
+define('PUN', 1);
+define('PUN_DEBUG', 1);
+
+if (file_exists(PUN_ROOT.'config.php'))
+	exit('The file \'config.php\' already exists which would mean that PunBB is already installed. You should go <a href="index.php">here</a> instead.');
+
+
+// Make sure we are running at least MIN_PHP_VERSION
+if (!function_exists('version_compare') || version_compare(PHP_VERSION, MIN_PHP_VERSION, '<'))
+	exit('You are running PHP version '.PHP_VERSION.'. PunBB requires at least PHP '.MIN_PHP_VERSION.' to run properly. You must upgrade your PHP installation before you can continue.');
+
+// Disable error reporting for uninitialized variables
+error_reporting(E_ALL);
+
+// Turn off PHP time limit
+@set_time_limit(0);
+
+// We need some stuff from functions.php
+require PUN_ROOT.'include/functions.php';
+
+// Load the language file
+require PUN_ROOT.'lang/English/install.php';
+
+
+if (isset($_POST['generate_config']))
+{
+	header('Content-Type: text/x-delimtext; name="config.php"');
+	header('Content-disposition: attachment; filename=config.php');
+
+	$db_type = $_POST['db_type'];
+	$db_host = $_POST['db_host'];
+	$db_name = $_POST['db_name'];
+	$db_username = $_POST['db_username'];
+	$db_password = $_POST['db_password'];
+	$db_prefix = $_POST['db_prefix'];
+	$base_url = $_POST['base_url'];
+	$cookie_name = $_POST['cookie_name'];
+
+	echo get_config_file();
+	exit;
+}
+
+
+if (!isset($_POST['form_sent']))
+{
+	// Determine available database extensions
+	$dual_mysql = false;
+	$db_extensions = array();
+	if (function_exists('mysqli_connect'))
+		$db_extensions[] = array('mysqli', 'MySQL Improved');
+	if (function_exists('mysql_connect'))
+	{
+		$db_extensions[] = array('mysql', 'MySQL Standard');
+
+		if (count($db_extensions) > 1)
+			$dual_mysql = true;
+	}
+	if (function_exists('sqlite_open'))
+		$db_extensions[] = array('sqlite', 'SQLite');
+	if (function_exists('pg_connect'))
+		$db_extensions[] = array('pgsql', 'PostgreSQL');
+
+	if (empty($db_extensions))
+		error('This PHP environment does not have support for any of the databases that PunBB supports. PHP needs to have support for either MySQL, PostgreSQL or SQLite in order for PunBB to be installed.');
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>PunBB Installation</title>
+<link rel="stylesheet" type="text/css" href="style/Oxygen/Oxygen.css" />
+<link rel="stylesheet" type="text/css" href="style/Oxygen/Oxygen_cs.css" />
+<!--[if lte IE 6]><link rel="stylesheet" type="text/css" href="style/Oxygen/Oxygen_ie6.css" /><![endif]-->
+<!--[if IE 7]><link rel="stylesheet" type="text/css" href="style/Oxygen/Oxygen_ie7.css" /><![endif]-->
+</head>
+<body>
+
+<div id="pun-install" class="pun-page">
+<div class="pun">
+
+<div id="pun-title">
+	<div><strong><?php printf($lang_install['Install PunBB'], PUN_VERSION) ?></strong></div>
+</div>
+
+<div id="pun-desc">
+	<div><?php printf ($lang_install['Install welcome'], PUN_VERSION) ?></div>
+</div>
+
+<div id="pun-head">
+	<div id="pun-visit">
+		<p><?php echo $lang_install['Install intro'] ?></p>
+	</div>
+</div>
+
+
+<div id="pun-main" class="main">
+
+	<div class="main-head">
+		<h1><span><?php printf($lang_install['Install PunBB'], PUN_VERSION) ?></span></h1>
+	</div>
+
+	<div class="main-content frm parted">
+		<div class="frm-head">
+			<h2><span><?php echo $lang_install['Install head'] ?></span></h2>
+		</div>
+		<form class="frm-form" method="post" accept-charset="utf-8" action="install.php">
+			<div class="hidden">
+				<input type="hidden" name="form_sent" value="1" />
+			</div>
+			<div class="frm-part part1">
+				<h3><span><?php echo $lang_install['Part1'] ?></span></h3>
+				<div class="frm-info">
+					<p><?php echo $lang_install['Part1 intro'] ?></p>
+					<ul class="pair">
+						<li><strong><?php echo $lang_install['Database type'] ?></strong> <span><?php echo $lang_install['Database type info'] ?><?php if ($dual_mysql) echo ' '.$lang_install['Mysql type info'] ?></span></li>
+						<li><strong><?php echo $lang_install['Database server'] ?></strong> <span><?php echo $lang_install['Database server info'] ?></span></li>
+						<li><strong><?php echo $lang_install['Database name'] ?></strong> <span><?php echo $lang_install['Database name info'] ?></span></li>
+						<li><strong><?php echo $lang_install['Database user pass'] ?></strong> <span><?php echo $lang_install['Database username info'] ?></span></li>
+						<li><strong><?php echo $lang_install['Table prefix'] ?></strong> <span><?php echo $lang_install['Table prefix info'] ?></span></li>
+					</ul>
+				</div>
+				<fieldset class="frm-set set1">
+					<legend class="frm-legend"><strong><?php echo $lang_install['Part1 legend'] ?></strong></legend>
+					<div class="frm-fld select required">
+						<label for="fld1">
+							<span class="fld-label"><?php echo $lang_install['Database type'] ?></span><br />
+							<span class="fld-input"><select id="fld1" name="req_db_type">
+<?php
+
+	foreach ($db_extensions as $db_type)
+		echo "\t\t\t\t\t\t\t".'<option value="'.$db_type[0].'">'.$db_type[1].'</option>'."\n";
+
+?>
+							</select></span><br />
+							<em class="req-text"><?php echo $lang_install['Required'] ?></em>
+							<span class="fld-help"><?php echo $lang_install['Database type help'] ?></span>
+						</label>
+					</div>
+					<div class="frm-fld text required">
+						<label for="fld2">
+							<span class="fld-label"><?php echo $lang_install['Database server'] ?></span><br />
+							<span class="fld-input"><input id="fld2" type="text" name="req_db_host" value="localhost" size="50" maxlength="100" /></span><br />
+							<em class="req-text"><?php echo $lang_install['Required'] ?></em>
+							<span class="fld-help"><?php echo $lang_install['Database server help'] ?></span>
+						</label>
+					</div>
+					<div class="frm-fld text required">
+						<label for="req_db_name">
+							<span class="fld-label"><?php echo $lang_install['Database name'] ?></span><br />
+							<span class="fld-input"><input id="req_db_name" type="text" name="req_db_name" size="35" maxlength="50" /></span><br />
+							<em class="req-text"><?php echo $lang_install['Required'] ?></em>
+							<span class="fld-help"><?php echo $lang_install['Database name help'] ?></span>
+						</label>
+					</div>
+					<div class="frm-fld text">
+						<label for="fld3">
+							<span class="fld-label"><?php echo $lang_install['Database username'] ?></span><br />
+							<span class="fld-input"><input id="fld3" type="text" name="db_username" size="35" maxlength="50" /></span><br />
+							<span class="fld-help"><?php echo $lang_install['Database username help'] ?></span>
+						</label>
+					</div>
+					<div class="frm-fld text">
+						<label for="fld4">
+							<span class="fld-label"><?php echo $lang_install['Database password'] ?></span><br />
+							<span class="fld-input"><input id="fld4" type="text" name="db_password" size="35" maxlength="50" /></span><br />
+							<span class="fld-help"><?php echo $lang_install['Database password help'] ?></span>
+						</label>
+					</div>
+					<div class="frm-fld text">
+						<label for="fld5">
+							<span class="fld-label"><?php echo $lang_install['Table prefix'] ?></span><br />
+							<span class="fld-input"><input id="fld5" type="text" name="db_prefix" size="20" maxlength="30" /></span><br />
+							<span class="fld-help"><?php echo $lang_install['Table prefix help'] ?></span>
+						</label>
+					</div>
+				</fieldset>
+			</div>
+			<div class="frm-part part2">
+				<h3><span><?php echo $lang_install['Part2'] ?></span></h3>
+				<div class="frm-info">
+					<p><?php echo $lang_install['Part2 intro'] ?></p>
+					<ul class="pair">
+						<li><strong><?php echo $lang_install['Admin username'] ?></strong> <span><?php echo $lang_install['Admin username info'] ?></span></li>
+						<li><strong><?php echo $lang_install['Admin password'] ?></strong> <span><?php echo $lang_install['Admin password info'] ?></span></li>
+						<li><strong><?php echo $lang_install['Admin e-mail'] ?></strong> <span><?php echo $lang_install['Admin e-mail info'] ?></span></li>
+					</ul>
+				</div>
+				<fieldset class="frm-set set1">
+					<legend class="frm-legend"><strong><?php echo $lang_install['Part2 legend'] ?></strong></legend>
+					<div class="frm-fld text required">
+						<label for="fld6">
+							<span class="fld-label"><?php echo $lang_install['Username'] ?></span><br />
+							<span class="fld-input"><input type="text" name="req_username" size="35" maxlength="25" /></span><br />
+							<em class="req-text"><?php echo $lang_install['Required'] ?></em>
+							<span class="fld-help"><?php echo $lang_install['Username help'] ?></span>
+						</label>
+					</div>
+					<div class="frm-fld text required">
+						<label for="fld7">
+							<span class="fld-label"><?php echo $lang_install['Password'] ?></span><br />
+							<span class="fld-input"><input id="fld7" type="text" name="req_password1" size="35" /></span><br />
+							<em class="req-text"><?php echo $lang_install['Required'] ?></em>
+							<span class="fld-help"><?php echo $lang_install['Password help'] ?></span>
+						</label>
+					</div>
+					<div class="frm-fld text required">
+						<label for="fld8">
+							<span class="fld-label"><?php echo $lang_install['Admin confirm password'] ?></span><br />
+							<span class="fld-input"><input id="fld8" type="text" name="req_password2" size="35" /></span><br />
+							<em class="req-text"><?php echo $lang_install['Required'] ?></em>
+							<span class="fld-help"><?php echo $lang_install['Confirm password help'] ?></span>
+						</label>
+					</div>
+					<div class="frm-fld text required">
+						<label for="fld9">
+							<span class="fld-label"><?php echo $lang_install['E-mail address'] ?></span><br />
+							<span class="fld-input"><input id="fld9" type="text" name="req_email" size="50" maxlength="80" /></span><br />
+							<em class="req-text"><?php echo $lang_install['Required'] ?></em>
+							<span class="fld-help"><?php echo $lang_install['E-mail address help'] ?></span>
+						</label>
+					</div>
+				</fieldset>
+			</div>
+
+			<div class="frm-part part3">
+				<h3><span><?php echo $lang_install['Part3'] ?></span></h3>
+				<div class="frm-info">
+					<p><?php echo $lang_install['Part3 intro'] ?></p>
+					<ul class="pair">
+						<li><strong><?php echo $lang_install['Board title and desc'] ?></strong> <span><?php echo $lang_install['Board title info'] ?></span></li>
+						<li><strong><?php echo $lang_install['Base URL'] ?></strong> <span><?php echo $lang_install['Base URL info'] ?></span></li>
+					</ul>
+				</div>
+				<fieldset class="frm-set set1">
+					<legend class="frm-legend"><strong><?php echo $lang_install['Part3 legend'] ?></strong></legend>
+					<div class="frm-fld text">
+						<label for="fld10">
+							<span class="fld-label"><?php echo $lang_install['Board title'] ?></span><br />
+							<span class="fld-input"><input id="fld10" type="text" name="board_title" size="50" maxlength="255" /></span>
+						</label>
+					</div>
+					<div class="frm-fld text">
+						<label for="fld11">
+							<span class="fld-label"><?php echo $lang_install['Board description'] ?></span><br />
+							<span class="fld-input"><input id="fld11" type="text" name="board_descrip" size="50" maxlength="255" /></span>
+						</label>
+					</div>
+					<div class="frm-fld text required">
+						<label for="fld12">
+							<span class="fld-label"><?php echo $lang_install['Base URL'] ?></span><br />
+							<span class="fld-input"><input id="fld12" type="text" name="req_base_url" value="<?php echo ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://').preg_replace('/:80$/', '', $_SERVER['HTTP_HOST']).str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'])) ?>" size="60" maxlength="100" /></span><br />
+							<em class="req-text"><?php echo $lang_install['Required'] ?></em>
+							<span class="fld-help"><?php echo $lang_install['Base URL help'] ?></span>
+						</label>
+					</div>
+				</fieldset>
+			</div>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="start" value="Start install" /></span>
+			</div>
+		</form>
+	</div>
+</div>
+
+</div>
+</div>
+</body>
+</html>
+<?php
+
+}
+else
+{
+	//
+	// Strip slashes only if magic_quotes_gpc is on.
+	//
+	function unescape($str)
+	{
+		return (get_magic_quotes_gpc() == 1) ? stripslashes($str) : $str;
+	}
+
+
+	$db_type = $_POST['req_db_type'];
+	$db_host = trim($_POST['req_db_host']);
+	$db_name = trim($_POST['req_db_name']);
+	$db_username = unescape(trim($_POST['db_username']));
+	$db_password = unescape(trim($_POST['db_password']));
+	$db_prefix = trim($_POST['db_prefix']);
+	$username = unescape(trim($_POST['req_username']));
+	$email = unescape(strtolower(trim($_POST['req_email'])));
+	$password1 = unescape(trim($_POST['req_password1']));
+	$password2 = unescape(trim($_POST['req_password2']));
+	$board_title = unescape(trim($_POST['board_title']));
+	$board_descrip = unescape(trim($_POST['board_descrip']));
+
+
+	// Make sure base_url doesn't end with a slash
+	if (substr($_POST['req_base_url'], -1) == '/')
+		$base_url = substr($_POST['req_base_url'], 0, -1);
+	else
+		$base_url = $_POST['req_base_url'];
+
+	// Validate form
+	if (pun_strlen($db_name) == 0)
+		error('You must enter a database name. Please go back and correct.');
+	if (pun_strlen($username) < 2)
+		error('Usernames must be at least 2 characters long. Please go back and correct.');
+	if (pun_strlen($password1) < 4)
+		error('Passwords must be at least 4 characters long. Please go back and correct.');
+	if ($password1 != $password2)
+		error('Passwords do not match. Please go back and correct.');
+	if (strtolower($username) == 'guest')
+		error('The username guest is reserved. Please go back and correct.');
+	if (preg_match('/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/', $username))
+		error('Usernames may not be in the form of an IP address. Please go back and correct.');
+	if (preg_match('#\[b\]|\[/b\]|\[u\]|\[/u\]|\[i\]|\[/i\]|\[color|\[/color\]|\[quote\]|\[/quote\]|\[code\]|\[/code\]|\[img\]|\[/img\]|\[url|\[/url\]|\[email|\[/email\]#i', $username))
+		error('Usernames may not contain any of the text formatting tags (BBCode) that the forum uses. Please go back and correct.');
+
+	// Validate email
+	if (strlen($email) > 80 || !preg_match('/^(([^<>()[\]\\.,;:\s@"\']+(\.[^<>()[\]\\.,;:\s@"\']+)*)|("[^"\']+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\d\-]+\.)+[a-zA-Z]{2,}))$/', $email))
+		error('The administrator e-mail address you entered is invalid. Please go back and correct.');
+
+	// Make sure board title and description aren't left blank
+	if ($board_title == '')
+		$board_title = 'My PunBB forum';
+	if ($board_descrip == '')
+		$board_descrip = 'Unfortunately no one can be told what PunBB is - you have to see it for yourself.';
+
+	if (pun_strlen($base_url) == 0)
+		error('You must enter a base URL. Please go back and correct.');
+
+
+	// Load the appropriate DB layer class
+	switch ($db_type)
+	{
+		case 'mysql':
+			require PUN_ROOT.'include/dblayer/mysql.php';
+			break;
+
+		case 'mysqli':
+			require PUN_ROOT.'include/dblayer/mysqli.php';
+			break;
+
+		case 'pgsql':
+			require PUN_ROOT.'include/dblayer/pgsql.php';
+			break;
+
+		case 'sqlite':
+			require PUN_ROOT.'include/dblayer/sqlite.php';
+			break;
+
+		default:
+			error('\''.$db_type.'\' is not a valid database type.');
+	}
+
+	// Create the database object (and connect/select db)
+	$pun_db = new DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, false);
+
+
+	// If MySQL, make sure it's at least 4.1.2
+	if ($db_type == 'mysql' || $db_type == 'mysqli')
+	{
+		$result = $pun_db->query('SELECT VERSION()') or error(__FILE__, __LINE__);
+		$mysql_version = $pun_db->result($result);
+		if (version_compare($mysql_version, MIN_MYSQL_VERSION, '<'))
+			error('You are running MySQL version '.$mysql_version.'. PunBB requires at least MySQL '.MIN_MYSQL_VERSION.' to run properly. You must upgrade your MySQL installation before you can continue.');
+	}
+
+	// Validate prefix
+	if (strlen($db_prefix) > 0 && (!preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $db_prefix) || strlen($db_prefix) > 40))
+		error('The table prefix \''.$db_prefix.'\' contains illegal characters or is too long. The prefix may contain the letters a to z, any numbers and the underscore character. They must however not start with a number. The maximum length is 40 characters. Please choose a different prefix.');
+
+	// Check SQLite prefix collision
+	if ($db_type == 'sqlite' && strtolower($db_prefix) == 'sqlite_')
+		error('The table prefix \'sqlite_\' is reserved for use by the SQLite engine. Please choose a different prefix.');
+
+
+	// Make sure PunBB isn't already installed
+	$result = $pun_db->query('SELECT 1 FROM '.$db_prefix.'users WHERE id=1');
+	if ($pun_db->num_rows($result))
+		error('A table called "'.$db_prefix.'users" is already present in the database "'.$db_name.'". This could mean that PunBB is already installed or that another piece of software is installed and is occupying one or more of the table names PunBB requires. If you want to install multiple copies of PunBB in the same database, you must choose a different table prefix.');
+
+
+	// Create all tables
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."bans (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					username VARCHAR(200),
+					ip VARCHAR(255),
+					email VARCHAR(80),
+					message VARCHAR(255),
+					expire INT(10) UNSIGNED,
+					ban_creator INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$pun_db->start_transaction();
+
+			$sql = 'CREATE TABLE '.$db_prefix."bans (
+					id SERIAL,
+					username VARCHAR(200),
+					ip VARCHAR(255),
+					email VARCHAR(80),
+					message VARCHAR(255),
+					expire INT,
+					ban_creator INT NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$pun_db->start_transaction();
+
+			$sql = 'CREATE TABLE '.$db_prefix."bans (
+					id INTEGER NOT NULL,
+					username VARCHAR(200),
+					ip  VARCHAR(255),
+					email VARCHAR(80),
+					message VARCHAR(255),
+					expire INTEGER,
+					ban_creator INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."categories (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					cat_name VARCHAR(80) NOT NULL DEFAULT 'New Category',
+					disp_position INT(10) NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."categories (
+					id SERIAL,
+					cat_name VARCHAR(80) NOT NULL DEFAULT 'New Category',
+					disp_position INT NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."categories (
+					id INTEGER NOT NULL,
+					cat_name VARCHAR(80) NOT NULL DEFAULT 'New Category',
+					disp_position INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."censoring (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					search_for VARCHAR(60) NOT NULL DEFAULT '',
+					replace_with VARCHAR(60) NOT NULL DEFAULT '',
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."censoring (
+					id SERIAL,
+					search_for VARCHAR(60) NOT NULL DEFAULT '',
+					replace_with VARCHAR(60) NOT NULL DEFAULT '',
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."censoring (
+					id INTEGER NOT NULL,
+					search_for VARCHAR(60) NOT NULL DEFAULT '',
+					replace_with VARCHAR(60) NOT NULL DEFAULT '',
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."config (
+					conf_name VARCHAR(255) NOT NULL DEFAULT '',
+					conf_value TEXT,
+					PRIMARY KEY (conf_name)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."config (
+					conf_name VARCHAR(255) NOT NULL DEFAULT '',
+					conf_value TEXT,
+					PRIMARY KEY (conf_name)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."config (
+					conf_name VARCHAR(255) NOT NULL DEFAULT '',
+					conf_value TEXT,
+					PRIMARY KEY (conf_name)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."extensions (
+					id VARCHAR(50) NOT NULL DEFAULT '',
+					title VARCHAR(255) NOT NULL DEFAULT '',
+					version VARCHAR(25) NOT NULL DEFAULT '',
+					description TEXT,
+					author VARCHAR(50) NOT NULL DEFAULT '',
+					uninstall TEXT,
+					uninstall_note TEXT,
+					disabled TINYINT(1) NOT NULL DEFAULT 0,
+					PRIMARY KEY(id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."extensions (
+					id VARCHAR(50) NOT NULL DEFAULT '',
+					title VARCHAR(255) NOT NULL DEFAULT '',
+					version VARCHAR(25) NOT NULL DEFAULT '',
+					description TEXT,
+					author VARCHAR(50) NOT NULL DEFAULT '',
+					uninstall TEXT,
+					uninstall_note TEXT,
+					disabled SMALLINT NOT NULL DEFAULT 0,
+					PRIMARY KEY(id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."extensions (
+					id VARCHAR(50) NOT NULL DEFAULT '',
+					title VARCHAR(255) NOT NULL DEFAULT '',
+					version VARCHAR(25) NOT NULL DEFAULT '',
+					description TEXT,
+					author VARCHAR(50) NOT NULL DEFAULT '',
+					uninstall TEXT,
+					uninstall_note TEXT,
+					disabled INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY(id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."extension_hooks (
+					id VARCHAR(50) NOT NULL DEFAULT '',
+					extension_id VARCHAR(50) NOT NULL DEFAULT '',
+					code TEXT,
+					installed INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					PRIMARY KEY(id, extension_id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."extension_hooks (
+					id VARCHAR(50) NOT NULL DEFAULT '',
+					extension_id VARCHAR(50) NOT NULL DEFAULT '',
+					code TEXT,
+					installed INT NOT NULL DEFAULT 0,
+					PRIMARY KEY(id, extension_id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."extension_hooks (
+					id VARCHAR(50) NOT NULL DEFAULT '',
+					extension_id VARCHAR(50) NOT NULL DEFAULT '',
+					code TEXT,
+					installed INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY(id, extension_id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."forum_perms (
+					group_id INT(10) NOT NULL DEFAULT 0,
+					forum_id INT(10) NOT NULL DEFAULT 0,
+					read_forum TINYINT(1) NOT NULL DEFAULT 1,
+					post_replies TINYINT(1) NOT NULL DEFAULT 1,
+					post_topics TINYINT(1) NOT NULL DEFAULT 1,
+					PRIMARY KEY (group_id, forum_id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."forum_perms (
+					group_id INT NOT NULL DEFAULT 0,
+					forum_id INT NOT NULL DEFAULT 0,
+					read_forum SMALLINT NOT NULL DEFAULT 1,
+					post_replies SMALLINT NOT NULL DEFAULT 1,
+					post_topics SMALLINT NOT NULL DEFAULT 1,
+					PRIMARY KEY (group_id, forum_id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."forum_perms (
+					group_id INTEGER NOT NULL DEFAULT 0,
+					forum_id INTEGER NOT NULL DEFAULT 0,
+					read_forum INTEGER NOT NULL DEFAULT 1,
+					post_replies INTEGER NOT NULL DEFAULT 1,
+					post_topics INTEGER NOT NULL DEFAULT 1,
+					PRIMARY KEY (group_id, forum_id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."forums (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					forum_name VARCHAR(80) NOT NULL DEFAULT 'New forum',
+					forum_desc TEXT,
+					redirect_url VARCHAR(100),
+					moderators TEXT,
+					num_topics MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0,
+					num_posts MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0,
+					last_post INT(10) UNSIGNED,
+					last_post_id INT(10) UNSIGNED,
+					last_poster VARCHAR(200),
+					sort_by TINYINT(1) NOT NULL DEFAULT 0,
+					disp_position INT(10) NOT NULL DEFAULT 0,
+					cat_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."forums (
+					id SERIAL,
+					forum_name VARCHAR(80) NOT NULL DEFAULT 'New forum',
+					forum_desc TEXT,
+					redirect_url VARCHAR(100),
+					moderators TEXT,
+					num_topics INT NOT NULL DEFAULT 0,
+					num_posts INT NOT NULL DEFAULT 0,
+					last_post INT,
+					last_post_id INT,
+					last_poster VARCHAR(200),
+					sort_by SMALLINT NOT NULL DEFAULT 0,
+					disp_position INT NOT NULL DEFAULT 0,
+					cat_id INT NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."forums (
+					id INTEGER NOT NULL,
+					forum_name VARCHAR(80) NOT NULL DEFAULT 'New forum',
+					forum_desc TEXT,
+					redirect_url VARCHAR(100),
+					moderators TEXT,
+					num_topics INTEGER NOT NULL DEFAULT 0,
+					num_posts INTEGER NOT NULL DEFAULT 0,
+					last_post INTEGER,
+					last_post_id INTEGER,
+					last_poster VARCHAR(200),
+					sort_by INTEGER NOT NULL DEFAULT 0,
+					disp_position INTEGER NOT NULL DEFAULT 0,
+					cat_id INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."groups (
+					g_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					g_title VARCHAR(50) NOT NULL DEFAULT '',
+					g_user_title VARCHAR(50),
+					g_moderator TINYINT(1) NOT NULL DEFAULT 0,
+					g_mod_edit_users TINYINT(1) NOT NULL DEFAULT 0,
+					g_mod_rename_users TINYINT(1) NOT NULL DEFAULT 0,
+					g_mod_change_passwords TINYINT(1) NOT NULL DEFAULT 0,
+					g_mod_ban_users TINYINT(1) NOT NULL DEFAULT 0,
+					g_read_board TINYINT(1) NOT NULL DEFAULT 1,
+					g_view_users TINYINT(1) NOT NULL DEFAULT 1,
+					g_post_replies TINYINT(1) NOT NULL DEFAULT 1,
+					g_post_topics TINYINT(1) NOT NULL DEFAULT 1,
+					g_edit_posts TINYINT(1) NOT NULL DEFAULT 1,
+					g_delete_posts TINYINT(1) NOT NULL DEFAULT 1,
+					g_delete_topics TINYINT(1) NOT NULL DEFAULT 1,
+					g_set_title TINYINT(1) NOT NULL DEFAULT 1,
+					g_search TINYINT(1) NOT NULL DEFAULT 1,
+					g_search_users TINYINT(1) NOT NULL DEFAULT 1,
+					g_edit_subjects_interval SMALLINT(6) NOT NULL DEFAULT 300,
+					g_post_flood SMALLINT(6) NOT NULL DEFAULT 30,
+					g_search_flood SMALLINT(6) NOT NULL DEFAULT 30,
+					PRIMARY KEY (g_id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."groups (
+					g_id SERIAL,
+					g_title VARCHAR(50) NOT NULL DEFAULT '',
+					g_user_title VARCHAR(50),
+					g_moderator SMALLINT NOT NULL DEFAULT 0,
+					g_mod_edit_users SMALLINT NOT NULL DEFAULT 0,
+					g_mod_rename_users SMALLINT NOT NULL DEFAULT 0,
+					g_mod_change_passwords SMALLINT NOT NULL DEFAULT 0,
+					g_mod_ban_users SMALLINT NOT NULL DEFAULT 0,
+					g_read_board SMALLINT NOT NULL DEFAULT 1,
+					g_view_users SMALLINT NOT NULL DEFAULT 1,
+					g_post_replies SMALLINT NOT NULL DEFAULT 1,
+					g_post_topics SMALLINT NOT NULL DEFAULT 1,
+					g_edit_posts SMALLINT NOT NULL DEFAULT 1,
+					g_delete_posts SMALLINT NOT NULL DEFAULT 1,
+					g_delete_topics SMALLINT NOT NULL DEFAULT 1,
+					g_set_title SMALLINT NOT NULL DEFAULT 1,
+					g_search SMALLINT NOT NULL DEFAULT 1,
+					g_search_users SMALLINT NOT NULL DEFAULT 1,
+					g_edit_subjects_interval SMALLINT NOT NULL DEFAULT 300,
+					g_post_flood SMALLINT NOT NULL DEFAULT 30,
+					g_search_flood SMALLINT NOT NULL DEFAULT 30,
+					PRIMARY KEY (g_id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."groups (
+					g_id INTEGER NOT NULL,
+					g_title VARCHAR(50) NOT NULL DEFAULT '',
+					g_user_title VARCHAR(50),
+					g_moderator INTEGER NOT NULL DEFAULT 0,
+					g_mod_edit_users INTEGER NOT NULL DEFAULT 0,
+					g_mod_rename_users INTEGER NOT NULL DEFAULT 0,
+					g_mod_change_passwords INTEGER NOT NULL DEFAULT 0,
+					g_mod_ban_users INTEGER NOT NULL DEFAULT 0,
+					g_read_board INTEGER NOT NULL DEFAULT 1,
+					g_view_users INTEGER NOT NULL DEFAULT 1,
+					g_post_replies INTEGER NOT NULL DEFAULT 1,
+					g_post_topics INTEGER NOT NULL DEFAULT 1,
+					g_edit_posts INTEGER NOT NULL DEFAULT 1,
+					g_delete_posts INTEGER NOT NULL DEFAULT 1,
+					g_delete_topics INTEGER NOT NULL DEFAULT 1,
+					g_set_title INTEGER NOT NULL DEFAULT 1,
+					g_search INTEGER NOT NULL DEFAULT 1,
+					g_search_users INTEGER NOT NULL DEFAULT 1,
+					g_edit_subjects_interval INTEGER NOT NULL DEFAULT 300,
+					g_post_flood INTEGER NOT NULL DEFAULT 30,
+					g_search_flood INTEGER NOT NULL DEFAULT 30,
+					PRIMARY KEY (g_id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."online (
+					user_id INT(10) UNSIGNED NOT NULL DEFAULT 1,
+					ident VARCHAR(200) NOT NULL DEFAULT '',
+					logged INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					idle TINYINT(1) NOT NULL DEFAULT 0,
+					csrf_token VARCHAR(40) NOT NULL DEFAULT '',
+					prev_url VARCHAR(255)
+					) TYPE=HEAP;";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."online (
+					user_id INT NOT NULL DEFAULT 1,
+					ident VARCHAR(200) NOT NULL DEFAULT '',
+					logged INT NOT NULL DEFAULT 0,
+					idle SMALLINT NOT NULL DEFAULT 0,
+					csrf_token VARCHAR(40) NOT NULL DEFAULT '',
+					prev_url VARCHAR(255)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."online (
+					user_id INTEGER NOT NULL DEFAULT 1,
+					ident VARCHAR(200) NOT NULL DEFAULT '',
+					logged INTEGER NOT NULL DEFAULT 0,
+					idle INTEGER NOT NULL DEFAULT 0,
+					csrf_token VARCHAR(40) NOT NULL DEFAULT '',
+					prev_url VARCHAR(255)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."posts (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					poster VARCHAR(200) NOT NULL DEFAULT '',
+					poster_id INT(10) UNSIGNED NOT NULL DEFAULT 1,
+					poster_ip VARCHAR(15),
+					poster_email VARCHAR(80),
+					message TEXT,
+					hide_smilies TINYINT(1) NOT NULL DEFAULT 0,
+					posted INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					edited INT(10) UNSIGNED,
+					edited_by VARCHAR(200),
+					topic_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."posts (
+					id SERIAL,
+					poster VARCHAR(200) NOT NULL DEFAULT '',
+					poster_id INT NOT NULL DEFAULT 1,
+					poster_ip VARCHAR(15),
+					poster_email VARCHAR(80),
+					message TEXT,
+					hide_smilies SMALLINT NOT NULL DEFAULT 0,
+					posted INT NOT NULL DEFAULT 0,
+					edited INT,
+					edited_by VARCHAR(200),
+					topic_id INT NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."posts (
+					id INTEGER NOT NULL,
+					poster VARCHAR(200) NOT NULL DEFAULT '',
+					poster_id INTEGER NOT NULL DEFAULT 1,
+					poster_ip VARCHAR(15),
+					poster_email VARCHAR(80),
+					message TEXT,
+					hide_smilies INTEGER NOT NULL DEFAULT 0,
+					posted INTEGER NOT NULL DEFAULT 0,
+					edited INTEGER,
+					edited_by VARCHAR(200),
+					topic_id INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."ranks (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					rank VARCHAR(50) NOT NULL DEFAULT '',
+					min_posts MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."ranks (
+					id SERIAL,
+					rank VARCHAR(50) NOT NULL DEFAULT '',
+					min_posts INT NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."ranks (
+					id INTEGER NOT NULL,
+					rank VARCHAR(50) NOT NULL DEFAULT '',
+					min_posts INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."reports (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					post_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					topic_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					forum_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					reported_by INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					created INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					message TEXT,
+					zapped INT(10) UNSIGNED,
+					zapped_by INT(10) UNSIGNED,
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."reports (
+					id SERIAL,
+					post_id INT NOT NULL DEFAULT 0,
+					topic_id INT NOT NULL DEFAULT 0,
+					forum_id INT NOT NULL DEFAULT 0,
+					reported_by INT NOT NULL DEFAULT 0,
+					created INT NOT NULL DEFAULT 0,
+					message TEXT,
+					zapped INT,
+					zapped_by INT,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."reports (
+					id INTEGER NOT NULL,
+					post_id INTEGER NOT NULL DEFAULT 0,
+					topic_id INTEGER NOT NULL DEFAULT 0,
+					forum_id INTEGER NOT NULL DEFAULT 0,
+					reported_by INTEGER NOT NULL DEFAULT 0,
+					created INTEGER NOT NULL DEFAULT 0,
+					message TEXT,
+					zapped INTEGER,
+					zapped_by INTEGER,
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."search_cache (
+					id INT NOT NULL DEFAULT 0,
+					ident VARCHAR(200) NOT NULL DEFAULT '',
+					search_data TEXT,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."search_cache (
+					id INTEGER NOT NULL DEFAULT 0,
+					ident VARCHAR(200) NOT NULL DEFAULT '',
+					search_data TEXT,
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	if ($db_type != 'mysql' && $db_type != 'mysqli')
+		$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."search_matches (
+					post_id INT NOT NULL DEFAULT 0,
+					word_id INT NOT NULL DEFAULT 0,
+					subject_match SMALLINT NOT NULL DEFAULT 0
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."search_matches (
+					post_id INTEGER NOT NULL DEFAULT 0,
+					word_id INTEGER NOT NULL DEFAULT 0,
+					subject_match INTEGER NOT NULL DEFAULT 0
+					)";
+			break;
+	}
+
+	if ($db_type != 'mysql' && $db_type != 'mysqli')
+		$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."search_words (
+					id SERIAL,
+					word VARCHAR(20) NOT NULL DEFAULT '',
+					PRIMARY KEY (word)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."search_words (
+					id INTEGER NOT NULL,
+					word VARCHAR(20) NOT NULL DEFAULT '',
+					PRIMARY KEY (id),
+					UNIQUE (word)
+					)";
+			break;
+	}
+
+	if ($db_type != 'mysql' && $db_type != 'mysqli')
+		$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."subscriptions (
+					user_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					topic_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					PRIMARY KEY (user_id, topic_id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."subscriptions (
+					user_id INT NOT NULL DEFAULT 0,
+					topic_id INT NOT NULL DEFAULT 0,
+					PRIMARY KEY (user_id, topic_id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."subscriptions (
+					user_id INTEGER NOT NULL DEFAULT 0,
+					topic_id INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY (user_id, topic_id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."topics (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					poster VARCHAR(200) NOT NULL DEFAULT '',
+					subject VARCHAR(255) NOT NULL DEFAULT '',
+					posted INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					first_post_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					last_post INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					last_post_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					last_poster VARCHAR(200),
+					num_views MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0,
+					num_replies MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT 0,
+					closed TINYINT(1) NOT NULL DEFAULT 0,
+					sticky TINYINT(1) NOT NULL DEFAULT 0,
+					moved_to INT(10) UNSIGNED,
+					forum_id INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."topics (
+					id SERIAL,
+					poster VARCHAR(200) NOT NULL DEFAULT '',
+					subject VARCHAR(255) NOT NULL DEFAULT '',
+					posted INT NOT NULL DEFAULT 0,
+					first_post_id INT NOT NULL DEFAULT 0,
+					last_post INT NOT NULL DEFAULT 0,
+					last_post_id INT NOT NULL DEFAULT 0,
+					last_poster VARCHAR(200),
+					num_views INT NOT NULL DEFAULT 0,
+					num_replies INT NOT NULL DEFAULT 0,
+					closed SMALLINT NOT NULL DEFAULT 0,
+					sticky SMALLINT NOT NULL DEFAULT 0,
+					moved_to INT,
+					forum_id INT NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."topics (
+					id INTEGER NOT NULL,
+					poster VARCHAR(200) NOT NULL DEFAULT '',
+					subject VARCHAR(255) NOT NULL DEFAULT '',
+					posted INTEGER NOT NULL DEFAULT 0,
+					first_post_id INTEGER NOT NULL DEFAULT 0,
+					last_post INTEGER NOT NULL DEFAULT 0,
+					last_post_id INTEGER NOT NULL DEFAULT 0,
+					last_poster VARCHAR(200),
+					num_views INTEGER NOT NULL DEFAULT 0,
+					num_replies INTEGER NOT NULL DEFAULT 0,
+					closed INTEGER NOT NULL DEFAULT 0,
+					sticky INTEGER NOT NULL DEFAULT 0,
+					moved_to INTEGER,
+					forum_id INTEGER NOT NULL DEFAULT 0,
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			$sql = 'CREATE TABLE '.$db_prefix."users (
+					id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+					group_id INT(10) UNSIGNED NOT NULL DEFAULT 4,
+					username VARCHAR(200) NOT NULL DEFAULT '',
+					password VARCHAR(40) NOT NULL DEFAULT '',
+					salt VARCHAR(12),
+					email VARCHAR(80) NOT NULL DEFAULT '',
+					title VARCHAR(50),
+					realname VARCHAR(40),
+					url VARCHAR(100),
+					jabber VARCHAR(80),
+					icq VARCHAR(12),
+					msn VARCHAR(80),
+					aim VARCHAR(30),
+					yahoo VARCHAR(30),
+					location VARCHAR(30),
+					signature TEXT,
+					disp_topics TINYINT(3) UNSIGNED,
+					disp_posts TINYINT(3) UNSIGNED,
+					email_setting TINYINT(1) NOT NULL DEFAULT 1,
+					save_pass TINYINT(1) NOT NULL DEFAULT 1,
+					notify_with_post TINYINT(1) NOT NULL DEFAULT 0,
+					auto_notify TINYINT(1) NOT NULL DEFAULT 0,
+					show_smilies TINYINT(1) NOT NULL DEFAULT 1,
+					show_img TINYINT(1) NOT NULL DEFAULT 1,
+					show_img_sig TINYINT(1) NOT NULL DEFAULT 1,
+					show_avatars TINYINT(1) NOT NULL DEFAULT 1,
+					show_sig TINYINT(1) NOT NULL DEFAULT 1,
+					timezone FLOAT NOT NULL DEFAULT 0,
+					dst TINYINT(1) NOT NULL DEFAULT 0,
+					time_format INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					date_format INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					language VARCHAR(25) NOT NULL DEFAULT 'English',
+					style VARCHAR(25) NOT NULL DEFAULT 'Oxygen',
+					num_posts INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					last_post INT(10) UNSIGNED,
+					registered INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					registration_ip VARCHAR(15) NOT NULL DEFAULT '0.0.0.0',
+					last_visit INT(10) UNSIGNED NOT NULL DEFAULT 0,
+					admin_note VARCHAR(30),
+					activate_string VARCHAR(80),
+					activate_key VARCHAR(8),
+					PRIMARY KEY (id)
+					) ENGINE = MyISAM CHARACTER SET utf8";
+			break;
+
+		case 'pgsql':
+			$sql = 'CREATE TABLE '.$db_prefix."users (
+					id SERIAL,
+					group_id INT NOT NULL DEFAULT 4,
+					username VARCHAR(200) NOT NULL DEFAULT '',
+					password VARCHAR(40) NOT NULL DEFAULT '',
+					salt VARCHAR(12),
+					email VARCHAR(80) NOT NULL DEFAULT '',
+					title VARCHAR(50),
+					realname VARCHAR(40),
+					url VARCHAR(100),
+					jabber VARCHAR(80),
+					icq VARCHAR(12),
+					msn VARCHAR(80),
+					aim VARCHAR(30),
+					yahoo VARCHAR(30),
+					location VARCHAR(30),
+					signature TEXT,
+					disp_topics SMALLINT,
+					disp_posts SMALLINT,
+					email_setting SMALLINT NOT NULL DEFAULT 1,
+					save_pass SMALLINT NOT NULL DEFAULT 1,
+					notify_with_post SMALLINT NOT NULL DEFAULT 0,
+					auto_notify SMALLINT NOT NULL DEFAULT 0,
+					show_smilies SMALLINT NOT NULL DEFAULT 1,
+					show_img SMALLINT NOT NULL DEFAULT 1,
+					show_img_sig SMALLINT NOT NULL DEFAULT 1,
+					show_avatars SMALLINT NOT NULL DEFAULT 1,
+					show_sig SMALLINT NOT NULL DEFAULT 1,
+					timezone REAL NOT NULL DEFAULT 0,
+					dst SMALLINT NOT NULL DEFAULT 0,
+					time_format INT NOT NULL DEFAULT 0,
+					date_format INT NOT NULL DEFAULT 0,
+					language VARCHAR(25) NOT NULL DEFAULT 'English',
+					style VARCHAR(25) NOT NULL DEFAULT 'Oxygen',
+					num_posts INT NOT NULL DEFAULT 0,
+					last_post INT,
+					registered INT NOT NULL DEFAULT 0,
+					registration_ip VARCHAR(15) NOT NULL DEFAULT '0.0.0.0',
+					last_visit INT NOT NULL DEFAULT 0,
+					admin_note VARCHAR(30),
+					activate_string VARCHAR(80),
+					activate_key VARCHAR(8),
+					PRIMARY KEY (id)
+					)";
+			break;
+
+		case 'sqlite':
+			$sql = 'CREATE TABLE '.$db_prefix."users (
+					id INTEGER NOT NULL,
+					group_id INTEGER NOT NULL DEFAULT 4,
+					username VARCHAR(200) NOT NULL DEFAULT '',
+					password VARCHAR(40) NOT NULL DEFAULT '',
+					salt VARCHAR(12),
+					email VARCHAR(80) NOT NULL DEFAULT '',
+					title VARCHAR(50),
+					realname VARCHAR(40),
+					url VARCHAR(100),
+					jabber VARCHAR(80),
+					icq VARCHAR(12),
+					msn VARCHAR(80),
+					aim VARCHAR(30),
+					yahoo VARCHAR(30),
+					location VARCHAR(30),
+					signature TEXT,
+					disp_topics INTEGER,
+					disp_posts INTEGER,
+					email_setting INTEGER NOT NULL DEFAULT 1,
+					save_pass INTEGER NOT NULL DEFAULT 1,
+					notify_with_post INTEGER NOT NULL DEFAULT 0,
+					auto_notify INTEGER NOT NULL DEFAULT 0,
+					show_smilies INTEGER NOT NULL DEFAULT 1,
+					show_img INTEGER NOT NULL DEFAULT 1,
+					show_img_sig INTEGER NOT NULL DEFAULT 1,
+					show_avatars INTEGER NOT NULL DEFAULT 1,
+					show_sig INTEGER NOT NULL DEFAULT 1,
+					timezone FLOAT NOT NULL DEFAULT 0,
+					dst INTEGER NOT NULL DEFAULT 0,
+					time_format INTEGER NOT NULL DEFAULT 0,
+					date_format INTEGER NOT NULL DEFAULT 0,
+					language VARCHAR(25) NOT NULL DEFAULT 'English',
+					style VARCHAR(25) NOT NULL DEFAULT 'Oxygen',
+					num_posts INTEGER NOT NULL DEFAULT 0,
+					last_post INTEGER,
+					registered INTEGER NOT NULL DEFAULT 0,
+					registration_ip VARCHAR(15) NOT NULL DEFAULT '0.0.0.0',
+					last_visit INTEGER NOT NULL DEFAULT 0,
+					admin_note VARCHAR(30),
+					activate_string VARCHAR(80),
+					activate_key VARCHAR(8),
+					PRIMARY KEY (id)
+					)";
+			break;
+	}
+
+	$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+	// Add some indexes
+	switch ($db_type)
+	{
+		case 'mysql':
+		case 'mysqli':
+			// We use MySQL's ALTER TABLE ... ADD INDEX syntax instead of CREATE INDEX to avoid problems with users lacking the INDEX privilege
+			$queries[] = 'ALTER TABLE '.$db_prefix.'online ADD UNIQUE INDEX '.$db_prefix.'online_user_id_ident_idx(user_id,ident(25))';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'online ADD INDEX '.$db_prefix.'online_user_id_idx(user_id)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'posts ADD INDEX '.$db_prefix.'posts_topic_id_idx(topic_id)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'posts ADD INDEX '.$db_prefix.'posts_multi_idx(poster_id, topic_id)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'posts ADD FULLTEXT '.$db_prefix.'posts_message_idx(message)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'reports ADD INDEX '.$db_prefix.'reports_zapped_idx(zapped)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'topics ADD INDEX '.$db_prefix.'topics_forum_id_idx(forum_id)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'topics ADD INDEX '.$db_prefix.'topics_moved_to_idx(moved_to)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'topics ADD INDEX '.$db_prefix.'topics_last_post_idx(last_post)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'topics ADD INDEX '.$db_prefix.'topics_first_post_id_idx(first_post_id)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'topics ADD FULLTEXT '.$db_prefix.'topics_subject_idx(subject)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'users ADD INDEX '.$db_prefix.'users_registered_idx(registered)';
+			$queries[] = 'ALTER TABLE '.$db_prefix.'users ADD INDEX '.$db_prefix.'users_username_idx(username(8))';
+			break;
+
+		default:
+			$queries[] = 'CREATE UNIQUE INDEX '.$db_prefix.'online_user_id_ident_idx ON '.$db_prefix.'online(user_id,ident)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'online_user_id_idx ON '.$db_prefix.'online(user_id)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'posts_topic_id_idx ON '.$db_prefix.'posts(topic_id)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'posts_multi_idx ON '.$db_prefix.'posts(poster_id, topic_id)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'reports_zapped_idx ON '.$db_prefix.'reports(zapped)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'search_matches_word_id_idx ON '.$db_prefix.'search_matches(word_id)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'search_matches_post_id_idx ON '.$db_prefix.'search_matches(post_id)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'topics_forum_id_idx ON '.$db_prefix.'topics(forum_id)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'topics_moved_to_idx ON '.$db_prefix.'topics(moved_to)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'topics_last_post_idx ON '.$db_prefix.'topics(last_post)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'topics_first_post_id_idx ON '.$db_prefix.'topics(first_post_id)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'users_registered_idx ON '.$db_prefix.'users(registered)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'users_username_idx ON '.$db_prefix.'users(username)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'search_cache_ident_idx ON '.$db_prefix.'search_cache(ident)';
+			$queries[] = 'CREATE INDEX '.$db_prefix.'search_words_id_idx ON '.$db_prefix.'search_words(id)';
+			break;
+	}
+
+	@reset($queries);
+	while (list(, $sql) = @each($queries))
+		$pun_db->query($sql) or error(__FILE__, __LINE__);
+
+
+
+	$now = time();
+
+	// Insert the four preset groups
+	$pun_db->query('INSERT INTO '.$pun_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_edit_subjects_interval, g_post_flood, g_search_flood) VALUES('Administrators', 'Administrator', 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0)") or error(__FILE__, __LINE__);
+	$pun_db->query('INSERT INTO '.$pun_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_edit_subjects_interval, g_post_flood, g_search_flood) VALUES('Guest', NULL, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0)") or error(__FILE__, __LINE__);
+	$pun_db->query('INSERT INTO '.$pun_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_edit_subjects_interval, g_post_flood, g_search_flood) VALUES('Members', NULL, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 300, 60, 30)") or error(__FILE__, __LINE__);
+	$pun_db->query('INSERT INTO '.$pun_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_edit_subjects_interval, g_post_flood, g_search_flood) VALUES('Moderators', 'Moderator', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0)") or error(__FILE__, __LINE__);
+
+	// Insert guest and first admin user
+	$pun_db->query('INSERT INTO '.$db_prefix."users (group_id, username, password, email) VALUES(2, 'Guest', 'Guest', 'Guest')") or error(__FILE__, __LINE__);
+
+	$salt = random_key(12);
+
+	$pun_db->query('INSERT INTO '.$db_prefix."users (group_id, username, password, email, num_posts, last_post, registered, registration_ip, last_visit, salt) VALUES(1, '".$pun_db->escape($username)."', '".sha1($salt.sha1($password1))."', '$email', 1, ".$now.", ".$now.", '127.0.0.1', ".$now.", '".$pun_db->escape($salt)."')") or error(__FILE__, __LINE__);
+
+	// Enable/disable avatars depending on file_uploads setting in PHP configuration
+	$avatars = in_array(strtolower(@ini_get('file_uploads')), array('on', 'true', '1')) ? 1 : 0;
+
+	// Enable/disable automatic check for updates depending on PHP environment (require cURL, fsockopen or allow_url_fopen)
+	$check_for_updates = (function_exists('curl_init') || function_exists('fsockopen') || in_array(strtolower(@ini_get('allow_url_fopen')), array('on', 'true', '1'))) ? 1 : 0;
+
+	// Insert config data
+	$config = array(
+		'o_cur_version'				=> "'".PUN_VERSION."'",
+		'o_board_title'				=> "'".$pun_db->escape($board_title)."'",
+		'o_board_desc'				=> "'".$pun_db->escape($board_descrip)."'",
+		'o_default_timezone'		=> "'0'",
+		'o_time_format'				=> "'H:i:s'",
+		'o_date_format'				=> "'Y-m-d'",
+		'o_check_for_updates'		=> "'$check_for_updates'",
+		'o_timeout_visit'			=> "'1800'",
+		'o_timeout_online'			=> "'300'",
+		'o_redirect_delay'			=> "'1'",
+		'o_show_version'			=> "'0'",
+		'o_show_user_info'			=> "'1'",
+		'o_show_post_count'			=> "'1'",
+		'o_signatures'				=> "'1'",
+		'o_smilies'					=> "'1'",
+		'o_smilies_sig'				=> "'1'",
+		'o_make_links'				=> "'1'",
+		'o_default_lang'			=> "'English'",
+		'o_default_style'			=> "'Oxygen'",
+		'o_default_user_group'		=> "'3'",
+		'o_topic_review'			=> "'15'",
+		'o_disp_topics_default'		=> "'30'",
+		'o_disp_posts_default'		=> "'25'",
+		'o_indent_num_spaces'		=> "'4'",
+		'o_quickpost'				=> "'1'",
+		'o_users_online'			=> "'1'",
+		'o_censoring'				=> "'0'",
+		'o_ranks'					=> "'1'",
+		'o_show_dot'				=> "'0'",
+		'o_topic_views'				=> "'1'",
+		'o_quickjump'				=> "'1'",
+		'o_gzip'					=> "'0'",
+		'o_additional_navlinks'		=> "''",
+		'o_report_method'			=> "'0'",
+		'o_regs_report'				=> "'0'",
+		'o_mailing_list'			=> "'$email'",
+		'o_avatars'					=> "'$avatars'",
+		'o_avatars_dir'				=> "'img/avatars'",
+		'o_avatars_width'			=> "'60'",
+		'o_avatars_height'			=> "'60'",
+		'o_avatars_size'			=> "'10240'",
+		'o_search_all_forums'		=> "'1'",
+		'o_sef'						=> "'Default'",
+		'o_admin_email'				=> "'$email'",
+		'o_webmaster_email'			=> "'$email'",
+		'o_subscriptions'			=> "'1'",
+		'o_smtp_host'				=> "NULL",
+		'o_smtp_user'				=> "NULL",
+		'o_smtp_pass'				=> "NULL",
+		'o_smtp_ssl'				=> "'0'",
+		'o_regs_allow'				=> "'1'",
+		'o_regs_verify'				=> "'0'",
+		'o_announcement'			=> "'0'",
+		'o_announcement_heading'	=> "'Sample announcement'",
+		'o_announcement_message'	=> "'<p>Enter your announcement here.</p>'",
+		'o_rules'					=> "'0'",
+		'o_rules_message'			=> "'Enter your rules here.'",
+		'o_maintenance'				=> "'0'",
+		'o_maintenance_message'		=> "'The forums are temporarily down for maintenance. Please try again in a few minutes.<br />\\n<br />\\n/Administrator'",
+		'p_message_bbcode'			=> "'1'",
+		'p_message_img_tag'			=> "'1'",
+		'p_message_all_caps'		=> "'1'",
+		'p_subject_all_caps'		=> "'1'",
+		'p_sig_all_caps'			=> "'1'",
+		'p_sig_bbcode'				=> "'1'",
+		'p_sig_img_tag'				=> "'0'",
+		'p_sig_length'				=> "'400'",
+		'p_sig_lines'				=> "'4'",
+		'p_allow_banned_email'		=> "'1'",
+		'p_allow_dupe_email'		=> "'0'",
+		'p_force_guest_email'		=> "'1'"
+	);
+
+	while (list($conf_name, $conf_value) = @each($config))
+		$pun_db->query('INSERT INTO '.$db_prefix."config (conf_name, conf_value) VALUES('$conf_name', $conf_value)") or error(__FILE__, __LINE__);
+
+	// Insert some other default data
+	$pun_db->query('INSERT INTO '.$db_prefix."categories (cat_name, disp_position) VALUES('Test category', 1)") or error(__FILE__, __LINE__);
+
+	$pun_db->query('INSERT INTO '.$db_prefix."forums (forum_name, forum_desc, num_topics, num_posts, last_post, last_post_id, last_poster, disp_position, cat_id) VALUES('Test forum', 'This is just a test forum', 1, 1, ".$now.", 1, '".$pun_db->escape($username)."', 1, 1)") or error(__FILE__, __LINE__);
+
+	$subject = 'Test post';
+	$pun_db->query('INSERT INTO '.$db_prefix.'topics (poster, subject, posted, first_post_id, last_post, last_post_id, last_poster, forum_id) VALUES(\''.$pun_db->escape($username).'\', \''.$subject.'\', '.$now.', 1, '.$now.', 1, \''.$pun_db->escape($username).'\', 1)') or error(__FILE__, __LINE__);
+
+	$message = 'If you are looking at this (which I guess you are), the install of PunBB appears to have worked! Now log in and head over to the administration control panel to configure your forum.';
+	$pun_db->query('INSERT INTO '.$db_prefix.'posts (poster, poster_id, poster_ip, message, posted, topic_id) VALUES(\''.$pun_db->escape($username).'\', 2, \'127.0.0.1\', \''.$message.'\', '.$now.', 1)') or error(__FILE__, __LINE__);
+
+	// Add new post to search table
+	if ($db_type != 'mysql' && $db_type != 'mysqli')
+	{
+		require PUN_ROOT.'include/search_idx.php';
+		update_search_index('post', $pun_db->insert_id(), $message, $subject);
+	}
+
+	$pun_db->query('INSERT INTO '.$db_prefix."ranks (rank, min_posts) VALUES('New member', 0)") or error(__FILE__, __LINE__);
+	$pun_db->query('INSERT INTO '.$db_prefix."ranks (rank, min_posts) VALUES('Member', 10)") or error(__FILE__, __LINE__);
+
+
+	if ($db_type == 'pgsql' || $db_type == 'sqlite')
+		$pun_db->end_transaction();
+
+
+
+	$alerts = array();
+	// Check if the cache directory is writable
+	if (!@is_writable('./cache/'))
+		$alerts[] = '<li>'.$lang_install['No cache write'].'</li>';
+
+	// Check if default avatar directory is writable
+	if (!@is_writable('./img/avatars/'))
+		$alerts[] = '<li>'.$lang_install['No avatar write'].'</li>';
+
+	// Check if we disabled uploading avatars because file_uploads was disabled
+	if ($avatars == '0')
+		$alerts[] = '<li>'.$lang_install['File upload alert'].'</li>';
+
+	// Add some random bytes at the end of the cookie name to prevent collisions
+	$cookie_name = 'punbb_cookie_'.random_key(6, false, true);
+
+	/// Generate the config.php file data
+	$config = get_config_file();
+
+	// Attempt to write config.php and serve it up for download if writing fails
+	$written = false;
+	if (is_writable(PUN_ROOT))
+	{
+		$fh = @fopen(PUN_ROOT.'config.php', 'wb');
+		if ($fh)
+		{
+			fwrite($fh, $config);
+			fclose($fh);
+
+			$written = true;
+		}
+	}
+
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>PunBB Installation</title>
+<link rel="stylesheet" type="text/css" href="style/Oxygen/Oxygen.css" />
+<link rel="stylesheet" type="text/css" href="style/Oxygen/Oxygen_forms.css" />
+<link rel="stylesheet" type="text/css" href="style/Oxygen/Oxygen_cs.css" />
+<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="style/Oxygen/Oxygen_ie.css" /><![endif]-->
+</head>
+
+<body>
+
+<div id="pun-install" class="pun-page">
+<div class="pun">
+
+<div id="pun-title">
+	<div id="logo"><strong><?php printf($lang_install['Install PunBB'], PUN_VERSION) ?></strong></div>
+</div>
+
+<div id="pun-desc">
+	<div id="desc"><?php printf($lang_install['Success description'], PUN_VERSION) ?></div>
+</div>
+
+<div id="pun-visit">
+	<p><?php echo $lang_install['Success welcome'] ?></p>
+</div>
+
+<?php
+?>
+
+<div id="pun-main" class="main">
+
+	<div class="main-head">
+		<h1><span><?php echo $lang_install['Final instructions'] ?></span></h1>
+	</div>
+
+	<div class="main-content frm">
+<?php
+
+if (!$written)
+{
+
+?>
+		<div class="frm-info">
+			<p class="warn"><?php echo $lang_install['No write info 1'] ?></p>
+			<p class="warn"><?php printf($lang_install['No write info 2'], '<a href="index.php">'.$lang_install['Go to index'].'</a>') ?></p>
+		</div>
+<?php if (!empty($alerts)): ?>		<div class="frm-error">
+			<?php echo $lang_install['Warning'] ?></p>
+			<ul>
+				<?php echo implode("\n\t\t\t\t", $alerts)."\n" ?>
+			</ul>
+		</div>
+<?php endif; ?>		<form class="frm-form" method="post" accept-charset="utf-8" action="install.php">
+			<div class="hidden">
+			<input type="hidden" name="generate_config" value="1" />
+			<input type="hidden" name="db_type" value="<?php echo $db_type; ?>" />
+			<input type="hidden" name="db_host" value="<?php echo $db_host; ?>" />
+			<input type="hidden" name="db_name" value="<?php echo htmlspecialchars($db_name); ?>" />
+			<input type="hidden" name="db_username" value="<?php echo htmlspecialchars($db_username); ?>" />
+			<input type="hidden" name="db_password" value="<?php echo htmlspecialchars($db_password); ?>" />
+			<input type="hidden" name="db_prefix" value="<?php echo htmlspecialchars($db_prefix); ?>" />
+			<input type="hidden" name="base_url" value="<?php echo htmlspecialchars($base_url); ?>" />
+			<input type="hidden" name="cookie_name" value="<?php echo htmlspecialchars($cookie_name); ?>" />
+			</div>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" value="<?php echo $lang_install['Download config'] ?>" /></span>
+			</div>
+		</form>
+<?php
+
+}
+else
+{
+
+?>
+		<div class="frm-info">
+			<p class="warn"><?php printf($lang_install['Write info'], '<a href="index.php">'.$lang_install['Go to index'].'</a>') ?></p>
+		</div>
+<?php
+}
+
+?>
+	</div>
+
+</div>
+</div>
+</div>
+</body>
+</html>
+
+<?php
+
+}
+
+function get_config_file ()
+{
+	global $db_type, $db_host, $db_name, $db_username, $db_password, $db_prefix, $base_url, $cookie_name;
+
+	return '<?php'."\n\n".'$db_type = \''.$db_type."';\n".'$db_host = \''.$db_host."';\n".'$db_name = \''.addslashes($db_name)."';\n".'$db_username = \''.addslashes($db_username)."';\n".'$db_password = \''.addslashes($db_password)."';\n".'$db_prefix = \''.addslashes($db_prefix)."';\n".'$p_connect = false;'."\n\n".'$base_url = \''.$base_url.'\';'."\n\n".'$cookie_name = '."'".$cookie_name."';\n".'$cookie_domain = '."'';\n".'$cookie_path = '."'/';\n".'$cookie_secure = 0;'."\n\ndefine('PUN', 1);";
+}
--- a/punbb/lang/English/admin.php	Sat Apr 05 23:56:45 2008 -0400
+++ b/punbb/lang/English/admin.php	Sun Apr 06 00:28:50 2008 -0400
@@ -303,6 +303,8 @@
 'Welcome info'					=>	'From here you can control vital aspects of the forum. Depending on whether you are an administrator or a moderator you can enable and disable features, manage users and groups, create and manage categories and forums, manage extensions and maintain your PunBB installation in good order.',
 'Forum information head'		=>	'Forum information',
 'PunBB version'					=>	'PunBB version',
+'Enano version'         =>  'Enano version',
+'PunBB port version'    =>  'Bridge version',
 'Check for updates enabled'		=>	'This board is setup to automatically check for updates and hotfixes against the PunBB.org updates service.',
 'Check for updates manual'		=>	'Check for updates',	// Link text
 'Server load'					=>	'Server load',
@@ -359,7 +361,7 @@
 'Board description help'		=>	'(You may use HTML in the description)',
 'URL scheme'					=>	'URL scheme',
 'URL scheme help'				=>	'(Make sure you have read and understood the information above)',
-'URL scheme info'				=>	'<strong>WARNING!</strong> If you select any scheme other than the default scheme you must copy/upload the file .htaccess from the extras directory into the forum root directory. The server that hosts the forums must be configured with mod_rewrite support and must allow the use of .htaccess files. For servers other than Apache, please refer to your servers documentation.',
+'URL scheme info'				=>	'<strong>WARNING!</strong> Under normal circumstances you should be able to use any of the URL schemes listed here even if your server doesn\'t have mod_rewrite support. However, your URLs will still not be search-engine friendly unless you selected Shortened or Rewritten URLs when you installed Enano. Consult the Enano documentation for more information.',
 'Default timezone'				=>	'Default timezone',
 'Default language'				=>	'Default language',
 'Default language help'			=>	'(If you remove a language pack you must update this setting)',
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/common.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,171 @@
+<?php
+
+// Language definitions for frequently used strings
+$lang_common = array(
+
+// Text orientation and encoding
+'lang_direction'		=>	'ltr',	// ltr (Left-To-Right) or rtl (Right-To-Left)
+'lang_identifier'		=>	'en',
+
+// Notices
+'Bad request'			=>	'Bad request. The link you followed is incorrect or outdated.',
+'No view'				=>	'You do not have permission to view these forums.',
+'No permission'			=>	'You do not have permission to access this page.',
+'CSRF token mismatch'	=>	'Unable to confirm security token. A likely cause for this is that some time passed between when you first entered the page and when you submitted a form or clicked a link. If that is the case and you would like to continue with your action, please click the Confirm button. Otherwise, you should click the Cancel button to return to where you were.',
+'No cookie'				=>	'You appear to have logged in successfully, however a cookie has not been set. Please check your settings and if applicable, enable cookies for this website.',
+
+// Topic/forum indicators
+'Closed'				=>	'[Closed]',
+'Redirected forum'		=>	'Redirected forum',
+
+// Miscellaneous
+'Forum index'			=>	'Forum index',
+'Submit'				=>	'Submit',	// "name" of submit buttons
+'Cancel'				=>	'Cancel', // "name" of cancel buttons
+'Submit title'			=>	'Accesskey: s', // "title" for submit buttons
+'Preview'				=>	'Preview',	// submit button to preview message
+'Preview title'			=>	'Accesskey: p', // "title" for preview buttons
+'Delete'				=>	'Delete',
+'Ban message'			=>	'You are banned from this forum.',
+'Ban message 2'			=>	'The ban expires at the end of %s.',
+'Ban message 3'			=>	'The administrator or moderator that banned you left the following message:',
+'Ban message 4'			=>	'Please direct any inquiries to the forum administrator at %s.',
+'Unknown'				=>	'Unknown',
+'Never'					=>	'Never',
+'Today'					=>	'Today',
+'Yesterday'				=>	'Yesterday',
+'Info'					=>	'Info',		// a common message box header
+'Forum message'			=>	'Forum message',
+'Maintenance'			=>	'Maintenance',
+'Redirecting'			=>	'Redirecting',
+'Forwarding info'		=>	'You should automatically be forwarded to a new page in %s seconds.',
+'Click redirect'		=>	'Click here if you do not want to wait any longer (or if your browser does not automatically forward you)',
+'Invalid e-mail'		=>	'The e-mail address you entered is invalid.',
+'Last post'				=>	'Last post',
+'By user'				=>	'by&#160;%s',
+'by'					=>	'by',
+'Posted by'				=>	'Posted by',
+'New posts'				=>	'New posts',	// the link that leads to the first new post
+'New posts info'		=>	'Go to the first new post in this topic.',	// the popup text for new posts links
+'Username'				=>	'Username',
+'Password'				=>	'Password',
+'E-mail'				=>	'E-mail',
+'E-mail address'		=>	'E-mail address',
+'Send e-mail'			=>	'Send&#160;e-mail',
+'Send forum e-mail'		=>	'Send e-mail via forum',
+'Registered'			=>	'Registered',
+'Subject'				=>	'Subject',
+'Message'				=>	'Message',
+'Write message'			=>	'Write message:',
+'Topic'					=>	'Topic',
+'Topics'				=>	'Topics',
+'Forum'					=>	'Forum',
+'Posts'					=>	'Posts',
+'Replies'				=>	'Replies',
+'Author'				=>	'Author',
+'Pages'					=>	'Pages',
+'Page'					=>	'Page',
+'BBCode'				=>	'BBCode',	// You probably shouldn't change this
+'Smilies'				=>	'Smilies',
+'Images'				=>	'Images',
+'You may use'			=>	'You may use: %s',
+'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 (e.g., User wrote:)
+'Code'					=>	'Code',		// For [code]'s
+'Forum mailer'			=>	'%s Mailer',	// As in "MyForums Mailer" in the signature of outgoing e-mails
+'Write message legend'	=>	'Compose your post',
+'Required information'	=>	'Required information',
+'Required mark'			=>	'*',
+'Required'				=>	'(Required)',
+'Required warn'			=>	'<strong>Important!</strong> All fields marked %s must be completed before submitting this form.',
+'You are here'			=>	'You are here: ',
+'Crumb separator'		=>	' -&#160;', // The character or text that seperates links in breadcrumbs
+'Title separator'		=>	' - ',
+'Page separator'		=>	'&#160;', //The character or text that seperates page numbers
+'Previous'				=>	'Previous',
+'Next'					=>	'Next',
+'Cancel redirect'		=>	'Operation cancelled. Redirecting ...',
+'No confirm redirect'	=>	'No confirmation provided. Operation cancelled. Redirecting...',
+'Please confirm'		=>	'Please confirm:',
+'Help page'				=>	'Help with: %s',
+'Re'					=>	'Re:',
+'Forum rules'			=>	'Forum rules.',
+
+// CSRF confirmation form
+'Confirm'				=>	'Confirm',	// Button
+'Confirm action'		=>	'Confirm action',
+'Confirm action head'	=>	'Please confirm or cancel your last action',
+
+// Title
+'Title'					=>	'Title',
+'Member'				=>	'Member',	// Default title
+'Moderator'				=>	'Moderator',
+'Administrator'			=>	'Administrator',
+'Banned'				=>	'Banned',
+'Guest'					=>	'Guest',
+
+// Stuff for include/parser.php
+'BBCode error'			=>	'The BBCode syntax in the message is incorrect.',
+'BBCode error 1'		=>	'Missing start tag for [/quote].',
+'BBCode error 2'		=>	'Missing end tag for [code].',
+'BBCode error 3'		=>	'Missing start tag for [/code].',
+'BBCode error 4'		=>	'Missing one or more end tags for [quote].',
+'BBCode error 5'		=>	'Missing one or more start tags for [/quote].',
+
+// Stuff for the navigator (top of every page)
+'Navigation'			=>	'Forum navigation',
+'Index'					=>	'Index',
+'User list'				=>	'User list',
+'Rules'					=>  'Rules',
+'Search'				=>  'Search',
+'Register'				=>  'Register',
+'Login'					=>  'Login',
+'Not logged in'			=>  'You are not logged in.',
+'Profile'				=>	'Profile',
+'Logout'				=>	'Logout',
+'Logged in as'			=>	'Logged in as %s.',
+'Admin'					=>	'Administration',
+'Last visit'			=>	'Last visit: %s',
+'Mark all as read'		=>	'Mark all topics as read',
+'Login nag'				=>	'Please login or register',
+'New reports'			=>	'New reports',
+'Attention'				=>	'Attention!',
+
+// Alerts
+'Maintenance mode'		=>	'Maintenance mode is enabled!',
+'Maintenance alert'		=>	'This board is in maintenance mode. DO NOT logout, if you do you will not be able to login.',
+'Updates'				=>	'PunBB updates',
+'Updates failed'		=>	'The latest attempt at checking for updates against the PunBB.org updates service failed. This probably just means that the service is temporarily overloaded or out of order. However, if this alert does not disappear within a day or two, you should disable the automatic check for updates and check for updates manually in the future.',
+'Updates version n hf'	=>	'A newer version of PunBB, version %s, is available for download at <a href="http://punbb.org/">PunBB.org</a>. Furthermore, one or more hotfix extensions are available for install on the Extensions tab of the admin interface.',
+'Updates version'		=>	'A newer version of PunBB, version %s, is available for download at <a href="http://punbb.org/">PunBB.org</a>.',
+'Updates hf'			=>	'One or more hotfix extensions are available for install on the Extensions tab of the admin interface.',
+
+// Stuff for Search links and jump menu
+'New posts info'		=>	'Lists topics that have new posts since your last visit',
+'Recent posts'			=>	'Recent posts',
+'Unanswered topics'		=>	'Unanswered topics',
+'Your posts'			=>	'Your posts',
+'Your topics'			=>	'Your topics',
+'Your subscriptions'	=>	'Your subscriptions',
+'Page info'				=>	'%s [ %s ]',
+'Page number'			=>	'Page [ %s of %s ]',
+'Paged info'			=>	'%s [ %s to %s of %s ]',
+'Jump to'				=>	'Go to selected forum',
+'Quick jump legend'		=>	'Forum quick jump menu',
+'Go'					=>	'Go',		// submit button in forum jump
+'Debug table'			=>	'Debug information',
+
+// For extern.php RSS feed
+'ATOM Feed'				=>	'Atom Feed',
+'RSS Feed'				=>	'RSS Feed',
+'RSS description'		=>	'The most recent topics at %s.',
+'RSS description topic'	=>	'The most recent posts in %s.',
+'RSS reply'				=>	'Re: ',	// The topic subject will be appended to this string (to signify a reply)
+
+// Accessibility
+'Skip to content'		=>	'Skip to forum content',
+'New window warn'		=>	'Opens in a new window if javascript is enabled.',
+'Back to'				=>	'Back to:',
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/delete.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,18 @@
+<?php
+
+// Language definitions used in delete.php
+$lang_delete = array(
+
+'Delete post'			=>	'Delete post',
+'Delete topic'			=>	'Delete topic',
+'Delete post head'		=>	'Delete post by %s posted %s',
+'Delete topic head'		=>	'Delete topic by %s (including replies) created %s',
+'Delete topic info'		=>	'Created by %s %s.',
+'Delete post info'		=>	'Post by %s %s',
+'Confirm delete'		=>	'You must confirm:',
+'Posted'				=>	'Posted',
+'Delete'				=>	'Delete',	// The submit button
+'Post del redirect'		=>	'Post deleted. Redirecting …',
+'Topic del redirect'	=>	'Topic deleted. Redirecting …',
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/forum.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,25 @@
+<?php
+
+// Language definitions used in viewforum.php
+$lang_forum = array(
+
+'Post topic'				=>	'Post new topic',
+'Views'						=>	'Views',
+'Moved'						=>	'Topic moved',
+'Sticky'					=>	'[Sticky]',
+'Empty forum'				=>	'[ Forum is empty ]',
+'Never'						=>	'Never',
+'No topics'					=>	'No topics have been posted',
+'First topic nag'			=>	'Be the first to post a topic in this forum',
+'Table summary'				=>	'Topics in the %s forum. ',
+'Guest post disabled'		=>  'Guests may not create new topics in this forum.',
+'You posted'				=>	'You have posted in this topic',
+'You posted indicator'		=>	'&#183;&#160;',
+'Table summary mods'		=>	'Select which of the listed topics you would like to move, open, close or delete from the forum: ',
+'Permalink forum'			=>	'Permanent link to this forum.',
+'Forum login nag'			=>	'Guest posting is disabled. You must %s or %s to post a new topic.',
+'Moderate forum'			=>	'Moderate forum',
+'Mark forum read'			=>	'Mark forum as read',
+'New posts info'			=>	'Go to the first new post since your last visit.'
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/help.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,47 @@
+<?php
+
+// Language definitions used in help.php
+$lang_help = array(
+
+'Help'					=>	'Help',
+'Help with'				=>	'Help with %s',
+'produces'				=>	'produces',
+
+'BBCode info 1'			=>	'Administrators have the ability to enable or disable BBCode. If BBCode is enabled a link to BBCode help will appear when you compose/edit a post or your signature.',
+'BBCode info 2'			=>	'BBCode is a collection of formatting tags that are used to change the look of text in this forum. BBCode is based on the same principal as, and is very similar to, HTML. Below is a list of all the available BBCodes and instructions on how to use them.',
+'Image info 1'			=>	'Administrators have the ability to enable or disable the display of images in posts and/or signatures. If image display is enabled a link to Image help will appear when you compose/edit a post or your signature.',
+'Image info 2'			=>	'Images are inserted using the BBCode [img] tag. The text appearing after the "=" sign in the opening tag is used for the alt attribute and should be included whenever possible.',
+
+'Text style'			=>	'Text appearance can be changed with the following tags which can be nested.',
+'Bold text'				=>	'Bold text',
+'Underlined text'		=>	'Underlined text',
+'Italic text'			=>	'Italic text',
+'Red text'				=>	'Red text',
+'Blue text'				=>	'Blue text',
+
+'Links'					=>	'Links',
+'Images'				=>	'Images',
+'Links info'			=>	'You can create links to other documents or to e-mail addresses using the following tags:',
+'My e-mail address'		=>	'My e-mail address',
+
+'Quotes with name'		=>	'Quote with name',
+'Quotes without name'	=>	'Quote without name',
+'Quotes info'			=>	'To quote someone use the quote tag. You can use the quote tag without specifying a name.',
+'Quote text'			=>	'This is the text i want to quote.',
+'produces named'		=>	'produces a quote box citing the person being quoted.',
+'produces unnamed'		=>	'produces a bare quote box.',
+
+'Code'					=>	'Code',
+'Code info'				=>	'When displaying source code you should make sure that you use the code tag. Text displayed with the code tag will use a monospaced font and will not be affected by other tags. Long items of code will cause the text to scroll.',
+'Code text'				=>	'This is some code.',
+'Code text long'		=>	'This is a long piece of code. This is a long piece of code. This is a long piece of code. This is a long piece of code. This is a long piece of code.',
+'produces code box'		=>	'produces a code box.',
+'produces scroll box'	=>	'produces a scrolling code box.',
+
+'Nested tags'			=>	'Nested tags',
+'Nested tags info'		=>	'BBCode can be nested to create more advanced formatting. For example:',
+'Bold, underlined text'	=>	'Bold, underlined text',
+
+'Smilies info'			=>	'If you like (and if it is enabled), the forum can convert a selection of smilies to image representations of those smilies. This forum recognizes the smilies listed below and replaces them with images.'
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/index.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,22 @@
+<?php
+
+// Language definitions used in index.php
+$lang_index = array(
+
+'Moderated by'			=>  'Moderated by %s',
+'Link to'				=>	'Link to %s',	// As in "Link to http://www.punbb.org/"
+'Empty board'			=>	'Board is empty',
+'Newest user'			=>	'Newest registered user',
+'No of users'			=>	'Total number of registered users',
+'No of topics'			=>	'Total number of topics',
+'No of posts'			=>	'Total number of posts',
+'Online'				=>	'<strong>Online</strong> ( Guests: <strong>%s</strong> | Registered users: <strong>%s</strong> )',	// As in "Online: User A, User B etc."
+'Guests online'			=>	'Guests',
+'Users online'			=>	'Registered users',
+'Statistics'			=>	'Forum statistics',
+'Forum information'		=>	'Forum information',
+'Table summary'			=>	'Listing of forums in the category %s.',
+'External forum'		=>	'Forum located on an external site.',
+'Forum has new'			=>	'Forum containing new posts since your last visit.',
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/login.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,29 @@
+<?php
+
+// Language definitions used in delete.php
+$lang_login = array(
+
+// Miscellaneous
+'Login info'				=>	'Login to %s',
+'Username'					=>	'Username:',
+'Password'					=>	'Password:',
+'E-mail address'			=>	'E-mail address:',
+'E-mail address help'		=>	'Enter the e-mail address set in your profile.',
+'Wrong user/pass'			=>	'Wrong username and/or password.',
+'Login redirect'			=>	'Logged in successfully. Redirecting …',
+'Login information'			=>	'Required login information:',
+'Send password legend'		=>	'Required address for new password:',
+'Profile e-mail address'	=>	'E-mail address:',
+'Profile e-mail info'		=>	'The e-mail address currently appearing in your profile',
+'Logout redirect'			=>	'Logged out. Redirecting …',
+'No e-mail match'			=>	'There is no user registered with the e-mail address %s.',
+'Request pass'				=>	'request a new password',
+'New password request'		=>	'New password request',
+'New password head'			=>	'Please send me a new password by e-mail',
+'New password info'			=>	'<strong>Important!</strong> A new password and a link to activate the new password will be sent by e-mail.',
+'Forgotten password'		=>	'If you have forgotten your password %s to regain access.',
+'Must be registered'		=>	'If you have not already registered please %s to gain access.',
+'Register now'				=>	'register now',
+'Forget mail'				=>	'An e-mail has been sent to the specified address with instructions on how to change your password. If it does not arrive you can contact the forum administrator at %s.'
+
+);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/mail_templates/activate_email.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,12 @@
+Subject: Change e-mail address requested
+
+Hello <username>,
+
+You have requested to have a new e-mail address assigned to your account in the discussion forum at <base_url>. If you didn't request this or if you don't want to change your e-mail address you should just ignore this message. Only if you visit the activation page below will your e-mail address be changed. In order for the activation page to work, you must be logged in to the forum.
+
+To change your e-mail address, please visit the following page:
+<activation_url>
+
+-- 
+<board_mailer>
+(Do not reply to this message)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/mail_templates/activate_password.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,12 @@
+Subject: New password requested
+
+Hello <username>,
+
+You have requested to have a new password assigned to your account in the discussion forum at <base_url>. If you didn't request this or if you don't want to change your password you should just ignore this message. Only if you visit the activation page below will your password be changed.
+
+To change your password, please visit the following page:
+<activation_url>
+
+-- 
+<board_mailer>
+(Do not reply to this message)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/mail_templates/form_email.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,13 @@
+Subject: <mail_subject>
+
+<sender> from <board_title> has sent you a message. You can reply to <sender> by replying to this e-mail.
+
+The message reads as follows:
+-----------------------------------------------------------------------
+
+<mail_message>
+
+-----------------------------------------------------------------------
+
+-- 
+<board_mailer>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/mail_templates/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/mail_templates/new_reply.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,11 @@
+Subject: Reply to topic: <topic_subject>
+
+<replier> has replied to the topic <topic_subject> to which you are subscribed. There may be more new replies, but this is the only notification you will receive until you visit the board again.
+
+The post is located at <post_url>
+
+You can unsubscribe by going to <unsubscribe_url>
+
+-- 
+<board_mailer>
+(Do not reply to this message)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/mail_templates/new_reply_full.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,18 @@
+Subject: Reply to topic: <topic_subject>
+
+<replier> has replied to the topic <topic_subject> to which you are subscribed. There may be more new replies, but this is the only notification you will receive until you visit the board again.
+
+The message reads as follows:
+-----------------------------------------------------------------------
+
+<message>
+
+-----------------------------------------------------------------------
+
+The post is located at <post_url>
+
+You can unsubscribe by going to <unsubscribe_url>
+
+-- 
+<board_mailer>
+(Do not reply to this message)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/mail_templates/welcome.tpl	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,10 @@
+Subject: Welcome to <board_title>!
+
+Thank you for registering in the forums at <base_url>. Your username on the forums is <username>, as you requested. To complete your registration, you need to set a password for your account.
+
+To set your password, please visit the following page:
+<activation_url>
+
+--
+<board_mailer>
+(Do not reply to this message)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/misc.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,75 @@
+<?php
+
+// Language definitions used in various scripts
+$lang_misc = array(
+
+'Mark read redirect'		=>	'All topics and forums have been marked as read. Redirecting …',
+'Mark forum read redirect'	=>	'All topics and forums in the specified forum have been marked as read. Redirecting …',
+
+// Send e-mail
+'Form e-mail disabled'		=>	'The user you are trying to send an e-mail to has disabled form e-mail.',
+'No e-mail subject'			=>	'You must enter a subject.',
+'No e-mail message'			=>	'You must enter a message.',
+'Too long e-mail message'	=>	'Messages cannot be longer than 65535 characters (64 KB).',
+'E-mail sent redirect'		=>	'E-mail sent. Redirecting …',
+'E-mail subject'			=>	'Subject:',
+'E-mail message'			=>	'Message:',
+'E-mail disclosure note'	=>	'<strong>Important!</strong> When you send an e-mail using this form your e-mail address will be disclosed to the recipient.',
+'Write e-mail'				=>	'Compose e-mail:',
+'Send forum e-mail'			=>	'Write your e-mail to %s and send it via the forum',
+
+// Report
+'No reason'					=>	'You must enter a reason.',
+'Report redirect'			=>	'Post reported. Redirecting …',
+'Report post'				=>	'Report post',
+'Reason'					=>	'Reason:',
+'Reason help'				=>	'Enter a short reason why you are reporting this post.',
+'Send report'				=>	'Send a message about this post to forum administrators and/or moderators',
+
+// Subscriptions
+'Already subscribed'		=>	'You are already subscribed to this topic.',
+'Subscribe redirect'		=>	'Your subscription has been added. Redirecting …',
+'Not subscribed'			=>	'You are not subscribed to this topic.',
+'Unsubscribe redirect'		=>	'Your subscription has been removed. Redirecting …',
+
+// General forum and topic moderation
+'Moderate forum'			=>	'Moderate forum',
+'Select'					=>	'Select',	// the header of a column of checkboxes
+'Select posts'				=>	'Select posts to delete (Post 1 cannot be deleted)',
+'Select topics'				=>	'Select topics to delete, move, open or close',
+'Move'						=>	'Move',
+'Open'						=>  'Open',
+'Close'						=>  'Close',
+'Confirm topic delete'		=>	'Confirm topic deletion',
+
+// Moderate forum
+'Move topic'				=>	'Move topic',
+'Move topics'				=>	'Move topics',
+'Delete topics'				=>	'Delete topics',
+'To new forum'				=>	'to a new forum',
+'Move legend'				=>	'Move:',
+'Move to'					=>	'Destination forum:',
+'Redirect topic'			=>	'Redirect setting:',
+'Nowhere to move'			=>	'There are no forums into which you can move topics.',
+'Leave redirect'			=>	'Leave a redirect topic in the forum from which the topic was moved.',
+'Leave redirects'			=>	'Leave redirect topics in the forum from which topics were moved.',
+'Move topic redirect'		=>	'Topic moved. Redirecting …',
+'Move topics redirect'		=>	'Topics moved. Redirecting …',
+'Delete topics comply'		=>	'Are you sure you want to delete all the selected topics?',
+'Delete topics redirect'	=>	'Topics deleted. Redirecting …',
+'Open topic redirect'		=>	'Topic opened. Redirecting …',
+'Open topics redirect'		=>	'Topics opened. Redirecting …',
+'Close topic redirect'		=>	'Topic closed. Redirecting …',
+'Close topics redirect'		=>	'Topics closed. Redirecting …',
+'No topics selected'		=>	'You must select at least one topic to move/delete/open/close.',
+'Stick topic redirect'		=>	'Topic is now sticky. Redirecting …',
+'Unstick topic redirect'	=>	'Topic no longer sticky. Redirecting …',
+
+// Delete multiple posts in topic
+'Delete posts'				=>	'Delete posts',
+'Select post'				=>	'Select post', // Label for checkbox
+'Confirm post delete'		=>	'Confirm deletion of all selected posts',
+'Delete posts redirect'		=>	'Posts deleted. Redirecting …',
+'No posts selected'			=>	'You must select at least one post.'
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/post.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,49 @@
+<?php
+
+// Language definitions used in post.php and edit.php
+$lang_post = array(
+
+// Post validation stuff (many are similiar to those in edit.php)
+'No subject'			=>	'Topics must contain a subject.',
+'Too long subject'		=>	'Subjects cannot be longer than 70 characters.',
+'No message'			=>	'You must enter a message.',
+'Too long message'		=>	'Posts cannot be longer that 65535 characters (64 KB).',
+'CSRF token mismatch'	=>	'Unable to confirm security token. A likely cause for this is that some time passed between when you first entered the page and when you posted the form. Clicking "Submit" again should solve the problem.',
+
+// Posting
+'Compose your'			=>	'Compose your',
+'New topic'				=>	'new topic',
+'New reply'				=>	'new reply',
+'Topic'					=>	'topic',
+'Reply'					=>	'reply',
+'Guest post legend'		=>	'Required information for guests',
+'Post errors'			=>	'<strong>Warning!</strong> The following errors must be corrected before your message can be posted:',
+'Guest name'			=>	'Guest name:',	// For guests (instead of Username)
+'Guest e-mail'			=>	'Guest e-mail:',
+'Post redirect'			=>	'Post entered. Redirecting …',
+'Post reply'			=>	'Post reply',
+'Post new topic'		=>	'Post new topic',
+'Topic subject'			=>	'Topic subject:',
+'Write message'			=>	'Write message:',
+'Hide smilies'			=>	'Never show smilies as icons (images) for this post.',
+'Subscribe'				=>	'Subscribe to this topic.',
+'Stay subscribed'		=>	'Stay subscribed to this topic.',
+'Topic review'			=>	'Topic review (newest first)',
+'Flood'					=>	'At least %s seconds have to pass between posts. Please wait a while and try posting again.',
+'Permalink post'		=>	'Permanent link to this post',
+'Optional legend'		=>	'Optional',
+'Post settings'			=>	'Post settings:',
+'Preview reply'			=>	'Preview of your reply',
+'Preview new topic'		=>	'Preview of your new topic',
+'Preview info'			=>	'This is how your post will appear once submitted.',
+'Skip to preview'		=>	'Go to post preview',
+'Skip to review'		=>	'Go to topic review',
+
+// Edit post
+'Edit post legend'		=>	'Edit message',
+'Edit this'				=>	'Edit this %s by %s',
+'Silent edit'			=>	'Silent edit (don\'t display "Last edited by …" in topic view).',
+'Edit post'				=>	'Edit ',
+'Edit redirect'			=>	'Post updated. Redirecting …'
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/profile.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,212 @@
+<?php
+
+$lang_profile = array(
+
+// Navigation and sections
+'Update forums redirect'	=>	'Forum moderator rights updated. Redirecting ...',
+'Profile redirect'			=>	'Profile updated. Redirecting ...',
+'Instructions'				=>	'You will be redirected back to this page',
+'Update profile'			=>	'Update profile',
+
+// Administration stuff
+'User delete redirect'		=>	'User deleted. Redirecting ...',
+'Section admin'				=>	'Administration',
+'Delete user'				=>	'Delete user',
+'Delete'					=>	'Delete',
+'Delete warning'			=>	'<strong>Warning!</strong> Once deleted a user and/or their posts cannot be restored.',
+'Delete posts info'			=>	'<strong>Warning!</strong> If you choose not to delete this user\'s posts they can only be deleted manually at a later time.',
+'Delete posts'				=>	'Delete posts:',
+'Delete posts label'		=>	'Delete any posts and topics %s has made.',
+'Group membership redirect'	=>	'Group membership saved. Redirecting ...',
+'Ban redirect'				=>	'Redirecting ...',
+'Ban user'					=>	'Ban user',
+'Ban user info'				=>	'[ via the administration console ]',
+'Ban'						=>	'Ban',
+'Delete user info'			=>	'[ following confirmation via a separate form ]',
+'Admin settings'			=>	'Perform user administration functions',
+'User management'			=>	'User management:',
+'Group membership'			=>	'Make member of:',
+'User group'				=>	'User group:',
+'Moderator assignment'		=>	'Moderator assignment',
+'Manage ban'				=>	'You may ban this user via the advanced ban settings page in the administration console.',
+'Manage delete'				=>	'You may delete this user and, optionally, you may delete all their posts.',
+'Manage groups'				=>	'This user is an administrator. In order to delete or ban them you must first assign them to a different group.',
+'Save'						=>	'Save',
+'Moderator in info'			=>	'Below you can choose which forums this user should be allowed to moderate.',
+'Moderator in info 2'		=>	'Your choice will only apply to moderators. Administrators always have full permissions in all forums.',
+'Update forums'				=>	'Update forums',
+
+// Avatar stuff
+'Avatar deleted redirect'	=>	'Avatar deleted. Redirecting ...',
+'Avatars disabled'			=>	'The administrator has disabled avatar support.',
+'No file'					=>	'You did not select a file for upload.',
+'Too large ini'				=>	'The selected file was too large to upload. The server didn\'t allow the upload.',
+'Partial upload'			=>	'The selected file was only partially uploaded. Please try again.',
+'No tmp directory'			=>	'PHP was unable to save the uploaded file to a temporary location.',
+'Bad type'					=>	'The file you tried to upload is not of an allowed type. Allowed file types are gif, jpeg and png.',
+'Too large'					=>	'The file you tried to upload is larger than the maximum allowed %s bytes.',
+'Move failed'				=>	'The server was unable to save the uploaded file. Please contact the forum administrator at %s.',
+'Too wide or high'			=>	'The file you tried to upload is wider and/or higher than the maximum allowed %sx%s pixels.',
+'Unknown failure'			=>	'An unknown error occurred. Please try again.',
+'Avatar'					=>	'Avatar',
+'Avatar info change'		=>	'To change your avatar upload a new one and it will automatically replace the old one.',
+'Avatar info none'			=>	'You do not currently have an avatar. To display an avatar with your posts you first need to upload one.',
+'Avatar info remove'		=>	'[ if you no longer wish to display an avatar ]',
+'Avatar info type'			=>	'The allowed image file types are gif, jpeg and png.',
+'Avatar info size'			=>	'The maximum image size allowed is %sx%s pixels and %s bytes (%s KB).',
+'Delete avatar'				=>	'Delete avatar file',
+'Upload avatar file'		=>	'Upload avatar file:',
+'Remove avatar file'		=>	'Delete avatar file:',
+
+// About and Identity sections
+'Users profile'				=>	'%s\'s profile',
+'Section about'				=>	'About',
+'User information'			=>	'User information',
+'User settings'				=>	'User settings',
+'User actions'				=>	'User actions',
+'Preview profile'			=>	'Preview public profile',
+'Show posts'				=>	'Show all posts',
+'Show topics'				=>	'Show all topics',
+'Realname'					=>	'Real name:',
+'Unknown'					=>	'(Unknown)',	// This is displayed when a user hasn't filled out profile field (e.g. Location)
+'Location'					=>	'Location:',
+'From'						=>	'From:',
+'Registered'				=>	'Registered:',
+'Private'					=>	'(Private)',	// This is displayed when a user does not want to receive e-mails
+'Website'					=>	'Website:',
+'IP'						=>	'IP:',
+'Note'						=>	'Note:',
+'Posts'						=>	'Posts:',
+'Last post'					=>	'Last post:',
+'Send forum e-mail'			=>	'Send forum e-mail',
+'Jabber'					=>	'Jabber:',
+'ICQ'						=>	'ICQ:',
+'MSN'						=>	'MSN Messenger:',
+'AOL IM'					=>	'AOL IM:',
+'Forbidden title'			=>	'The title you entered contains a forbidden word. You must choose a different title.',
+'Bad ICQ'					=>	'You entered an invalid ICQ UIN. Please go back and correct.',
+'Yahoo'						=>	'Yahoo! Messenger:',
+'Change password settings'	=>	'You may %s if you wish to',
+'Identity settings'			=>	'Enhance user %s by changing personal, contact and messaging information',
+'Section identity'			=>	'Identity',
+'Settings settings'			=>	'Specify %s for localization, email, subscriptions, login and display',
+'Section settings'			=>	'Settings',
+'Avatar settings'			=>	'Upload an %s image to make your posts stand out from the crowd',
+'Section avatar'			=>	'Avatar',
+'Section signature'			=>	'Signature',
+'Sig settings'				=>	'Create a %s to give your posts a personal touch',
+'Signature info'			=>	'Your signature will appear at the foot of your posts. It can contain almost anything such as your favourite quote or star sign. It\'s up to you!',
+'About settings'			=>	'Welcome to %s\'s profile',
+'Profile welcome'			=>	'From this control panel you can apply settings for interacting with the forum, preview your public profile and carry out various actions. Any changes made to profile settings will be enabled each time you login.',
+'Personal legend'			=>	'Personal details',
+'Title'						=>	'Title:',
+'Leave blank'				=>	'Leave blank to use forum default.',
+'Edit count'				=>	'Edit post count:',
+'Admin note'				=>	'Admin note:',
+'Contact legend'			=>	'Contact details',
+
+// Settings section
+'Timezone info'				=>	'Must be set for correct time display.',
+'Time format'				=>  'Time format:',
+'Default'					=>  'default',
+'Date format'				=>  'Date format:',
+'Display settings'			=>	'Display settings',
+'Styles'					=>	'Available styles:',
+'Image display'				=>	'Image display:',
+'Show avatars'				=>	'Show user avatars in posts.',
+'Show images sigs'			=>	'Show images in user signatures.',
+'Show images'				=>	'Show images in posts.',
+'Show sigs'					=>	'Show user signatures in posts.',
+'Show smilies'				=>	'Show smilies as graphic icons.',
+'Signature display'			=>	'Signature display:',
+'Pagination settings'		=>	'Pagination settings',
+'Topics per page'			=>	'Topics per page:',
+'Posts per page'			=>	'Posts per page:',
+'Subscription settings'		=>	'Subscription settings:',
+'Notify full'				=>	'Include a plain text copy of posts in subscription e-mails.',
+'Subscribe by default'		=>	'Subscribe to topics by default when posting.',
+
+// Change Password stuff
+'Pass logout'				=>	'A user is currently logged in. Please logout and try again.',
+'Pass key bad'				=>	'The specified password activation key was incorrect or has expired. Please re-request a new password. If that fails, contact the forum administrator at %s.',
+'Pass updated'				=>	'Password updated. Login with your new password. Redirecting ...',
+'Change password'			=>	'Change password',
+'New password'				=>	'New password:',
+'Confirm new password'		=>	'Confirm new password:',
+'Wrong old password'		=>	'Wrong old password.',
+'Pass updated redirect'		=>	'Password updated. Redirecting ...',
+'Old password'				=>	'Old password:',
+'Old password help'			=>	'You must enter your existing password',
+
+// Change E-mail stuff
+'E-mail key bad'			=>	'The specified e-mail activation key was incorrect or has expired. Please re-request change of e-mail address. If that fails, contact the forum administrator at %s.',
+'E-mail updated'			=>	'Your e-mail address has been updated.',
+'Wrong password'			=>	'Wrong password.',
+'Activate e-mail sent'		=>	'An email has been sent to the specified address with instructions on how to activate the new e-mail address. If it doesn\'t arrive you can contact the forum administrator at %s.',
+'Change e-mail'				=>	'Change e-mail address',
+'New e-mail'				=>	'New e-mail address:',
+
+// Signatures
+'Signatures disabled'		=>	'The administrator has disabled signatures support.',
+'Sig too long'				=>	'Signatures cannot be longer than %s characters.',
+'Sig too many lines'		=>	'Signatures cannot have more than %s lines.',
+'Preview signature'			=>	'Preview signature:',
+'No signature'				=>	'You have not yet created a signature.',
+'Signature'					=>	'Signature',
+'Compose signature'			=>	'Create signature:',
+'Sig max size'				=>	'Maximum size %s characters long and %s lines high.',
+
+// Registration stuff (some of these also used by profile)
+'No new regs'				=>	'This forum is not accepting new registrations.',
+'Reg cancel redirect'		=>	'Registration cancelled. Redirecting ...',
+'Agree to rules'			=>	'You must agree to the rules to register.',
+'Agreement'					=>	'Agreement:',
+'Agreement label'			=>	'I agree to the rules set out above and wish to register.',
+'Agree'						=>	'Agree',
+'Registration flood'		=>	'A new user was registered with the same IP address as you within the last hour. To prevent registration flooding, at least an hour has to pass between registrations from the same IP. Sorry for the inconvenience.',
+'Pass too short'			=>	'Passwords must be at least 4 characters long. Please choose another (longer) password.',
+'Pass not match'			=>	'Passwords do not match. Please go back and correct.',
+'E-mail not match'			=>	'E-mail addresses do not match. Please go back and correct.',
+'Banned e-mail'				=>	'The e-mail address you entered is banned in this forum. Please choose another e-mail address.',
+'Dupe e-mail'				=>	'Someone else is already registered with that e-mail address. Please choose another e-mail address.',
+'Reg e-mail'				=>	'Thank you for registering. Your password has been sent to the specified address. If it doesn\'t arrive you can contact the forum administrator at %s.',
+'Reg complete'				=>	'Registration complete. Logging in and redirecting ...',
+'E-mail info'				=>	'<strong>Important!</strong> An e-mail will be sent to your new address with an activation link. You must click the link in the e-mail you receive to activate the new address. You must therefore ensure that you enter a valid and current e-mail address.',
+'Register at'				=>	'Register at %s',
+'Register intro'			=>	'Registration enables you to use features such as editing and deleting posts, designing your own signature, uploading an avatar and much more. The fields below only make up a small part of all the settings you can alter in your profile. If you have any questions regarding this forum you should ask an administrator. Please complete the form below in order to register.',
+'Username'					=>	'Username:',
+'Username help'				=>	'Between 2 and 25 characters.',
+'Password'					=>	'Password:',
+'Password help'				=>	'Minimum 4 characters. Case sensitive.',
+'Confirm password'			=>	'Confirm password:',
+'Confirm password help'		=>	'Re-enter your password exactly as before.',
+'E-mail'					=>	'E-mail:',
+'E-mail help'				=>	'Enter a current and valid e-mail address.',
+'Confirm e-mail'			=>	'Confirm e-mail:',
+'Confirm e-mail help'		=>	'Re-enter your e-mail address exactly as before.',
+'Local legend'				=>	'Localization settings',
+'Language'					=>	'Language',
+'Timezone'					=>	'Your timezone:',
+'Adjust for DST'			=>	'Adjust for DST:',
+'DST label'					=>	'Daylight savings is in effect (advance times by 1 hour).',
+'Other settings'			=>	'Other settings',
+'E-mail settings'			=>	'E-mail settings:',
+'E-mail setting 1'			=>	'Display your e-mail address to other users.',
+'E-mail setting 2'			=>	'Hide your e-mail address but allow e-mail via the forum.',
+'E-mail setting 3'			=>	'Hide your e-mail address and disallow e-mail via the forum.',
+'Persistent login'			=>	'Persistent login:',
+'Save user/pass'			=>	'Remain logged in between visits (recommended).',
+
+// Form validation stuff
+'Username BBCode'			=>	'Usernames may not contain any of the text formatting tags (BBCode) that the forum uses. Please choose another username.',
+'Username IP'				=>	'Usernames may not be in the form of an IP address. Please choose another username.',
+'Username censor'			=>	'The username you entered contains one or more censored words. Please choose a different username.',
+'Username dupe'				=>	'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 another username.',
+'Username guest'			=>	'The username guest is reserved. Please choose another username.',
+'Username info'				=>	'2 to 25 characters.',
+'Username reserved chars'	=>	'Usernames may not contain all the characters \', " and [ or ] at once. Please choose another username.',
+'Username too long'			=>	'Usernames must not be more than 25 characters long. Please choose another (shorter) username.',
+'Username too short'		=>	'Usernames must be at least 2 characters long. Please choose another (longer) username.',
+'Signature quote/code'		=>	'The quote and code BBCodes are not allowed in signatures. Please go back and correct.',
+
+);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/search.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,63 @@
+<?php
+
+// Language definitions used in search.php
+$lang_search = array(
+
+// The search form
+'No search permission'		=>	'You do not have permission to use the search feature.',
+'Search heading'			=>	'Search forums using your own criteria or predefined searches',
+'Predefined searches'		=>	'Predefined searches',
+'Using criteria'			=>	'Using your own criteria',
+'Search legend'				=>	'Search criteria:',
+'Results legend'			=>	'Search results:',
+'Search info'				=>	'Search for posts by keyword, author\'s username or both.',
+'Keyword info'				=>	'Enter a term or multiple terms separated with spaces.',
+'Refine info'				=>	'You may use <strong>AND</strong>, <strong>OR</strong> and <strong>NOT</strong> to refine your searches by keyword.',
+'Refine info fulltext'		=>	'You may use <strong>+</strong> and <strong>-</strong> before keywords to refine your search.',
+'Author info'				=>	'Enter the author\'s username.',
+'Wildcard info'				=>	'Use the wildcard character <strong>*</strong> for partial keyword or username matches.',
+'Wildcard info fulltext'	=>	'Use the wildcard character <strong>*</strong> for partial username matches or as a keyword suffix.',
+'User defined search'		=>	'User defined search:',
+'Keyword search'			=>	'Keyword:',
+'Author search'				=>	'Author:',
+'Forum search'				=>	'Forum to search:',
+'All forums'				=>	'All forums',
+'Sort by'					=>	'Sort results by:',
+'Sort order'				=>	'Results sort order:',
+'Sort by post time'			=>	'Post time',
+'Sort by author'			=>	'Author',
+'Sort by subject'			=>	'Subject',
+'Sort by forum'				=>	'Forum',
+'Sort by relevance'			=>	'Relevance',
+'Ascending'					=>	'Ascending',
+'Descending'				=>	'Descending',
+'Display results'			=>	'Display results:',
+'Show as topics'			=>	'As topics',
+'Show as posts'				=>	'As posts',
+'Submit search'				=>	'Submit search',
+
+// Results
+'Search results'			=>	'Search results',
+'Topic'						=>	'Topic:',
+'Topics by'					=>	'Topics by %s',
+'Post by'					=>	'Post by %s',
+'Posts by'					=>	'Posts by %s',
+'Topic info'				=>	'[ Started by %s in %s : %s replies ]',
+'Topics with new'			=>	'Topics with new posts',
+'Topics with recent'		=>	'Topics with recent posts',
+'Perform new search'		=>	'Perform new search',
+'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.',
+'No user topics'			=>	'There are no topics by this user in this forum.',
+'No subscriptions'			=>	'You are currently not subscribed to any topics.',
+'No new posts'				=>	'There are no topics with new posts since your last visit.',
+'No recent posts'			=>	'No posts have been made recently.',
+'No unanswered'				=>	'There are no unanswered posts in this forum.',
+'Go to post'				=>	'Go to post',
+'Go to forum'				=>	'Go to forum',
+'Go to topic'				=>	'Go to topic',
+'Table summary'				=>	'Search results listed by topic',
+'Go to profile'				=>	'Go to %s\'s profile',
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/stopwords.txt	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,150 @@
+about
+after
+ago
+all
+almost
+along
+also
+any
+anybody
+anywhere
+are
+arent
+around
+ask
+been
+before
+being
+between
+but
+came
+can
+cant
+come
+could
+couldnt
+did
+didnt
+does
+doesnt
+dont
+each
+either
+else
+even
+every
+everybody
+everyone
+find
+for
+from
+get
+going
+gone
+got
+had
+has
+have
+havent
+having
+her
+here
+hers
+him
+his
+how
+ill
+into
+isnt
+its
+ive
+just
+know
+less
+like
+make
+many
+may
+more
+most
+much
+must
+near
+never
+none
+nothing
+now
+off
+often
+once
+one
+only
+other
+our
+ours
+out
+over
+please
+rather
+really
+said
+see
+she
+should
+small
+some
+something
+sometime
+somewhere
+take
+than
+thank
+thanks
+that
+thats
+the
+their
+theirs
+them
+then
+there
+these
+they
+thing
+think
+this
+those
+though
+through
+thus
+too
+true
+two
+under
+until
+upon
+use
+very
+want
+was
+way
+well
+were
+what
+when
+where
+which
+who
+whom
+whose
+why
+will
+with
+within
+without
+would
+yes
+yet
+you
+your
+yours
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/topic.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,45 @@
+<?php
+
+// Language definitions used in viewtopic.php
+$lang_topic = array(
+
+'Topic by'				=>	'Topic by %s:',
+'Reply by'				=>	'Reply by %s:',
+'Post reply'			=>	'Post reply',
+'Topic closed'			=>	'Topic closed',
+'Guest reply disabled'	=>  'Guests may not reply to topics in this forum.',
+'Title'					=>	'Title:',
+'Status'				=>	'Status:',				// Online or Offline
+'From'					=>	'From:',				// User location
+'Registered'			=>	'Registered:',
+'Note'					=>	'Note:',				// Admin note
+'Posts'					=>	'Posts:',
+'IP'					=>	'IP:',
+'Visit website'			=>	'<span>%s\'s </span>Website', 			// As in "Author's website"
+'Guest'					=>	'Guest',
+'Online'				=>	'Online',
+'Offline'				=>	'Offline',
+'Last edited'			=>	'Last edited by %s (%s)',
+'Report'				=>	'Report',
+'Delete'				=>	'Delete',
+'Delete topic'			=>	'Delete topic',
+'Edit'					=>	'Edit',
+'Quote'					=>	'Quote',
+'Cancel subscription'	=>	'Unsubscribe from topic',
+'Subscription'			=>	'Subscribe to topic',
+'Topic login nag'		=>	'Guest posting is disabled. You must %s or %s to post a reply.',
+'Quick post'			=>	'Quick post',
+'Avatar'				=>	'Avatar',
+'Post'					=>	'Post',
+'Cannot delete'			=>	'You cannot delete the first post',
+'Permalink post'		=>	'Permanent link to this post',
+'Permalink topic'		=>	'Permanent link to this topic',
+'Go to profile'			=>	'Go to %s\'s profile',
+'Move'					=>	'Move topic',
+'Open'					=>  'Open topic',
+'Close'					=>  'Close topic',
+'Unstick'				=>  'Unstick topic',
+'Stick'					=>  'Stick topic',
+'Delete posts'			=>	'Delete posts',
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/English/userlist.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,19 @@
+<?php
+
+// Language definitions used in userlist.php
+$lang_ul = array(
+
+'User find legend'		=>	'Find users:',
+'User filter legend'	=>	'Filter user search results:',
+'Username help'			=>	'May be left blank. Use wildcard character <strong>*</strong> for partial matches.',
+'Search for username'	=>	'Search by username:',
+'User group'			=>	'Show from group:',
+'No of posts'			=>	'No. of posts',
+'No users found'		=>	'No users were found matching your criteria.',
+'All users'				=>	'All users',
+'Users'					=>	'Users',
+'Users found'			=>	'Users found',
+'Perform new search'	=>	'Perform new user search',
+'Table summary'			=>	'List of users filtered and sorted according to the criteria (if any) you have chosen.'
+
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/lang/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/login.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,394 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+if (isset($_GET['action']))
+	define('PUN_QUIET_VISIT', 1);
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('li_start')) ? eval($hook) : null;
+
+// Load the login.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/login.php';
+
+
+$action = isset($_GET['action']) ? $_GET['action'] : null;
+
+
+// Login
+if (isset($_POST['form_sent']) && $action == 'in')
+{
+	$form_username = trim($_POST['req_username']);
+	$form_password = trim($_POST['req_password']);
+
+	($hook = get_hook('li_login_form_submitted')) ? eval($hook) : null;
+
+	// Get user info matching login attempt
+	$query = array(
+		'SELECT'	=> 'u.id, u.group_id, u.password, u.save_pass, u.salt',
+		'FROM'		=> 'users AS u'
+	);
+
+	if ($db_type == 'mysql' || $db_type == 'mysqli')
+		$query['WHERE'] = 'username=\''.$pun_db->escape($form_username).'\'';
+	else
+		$query['WHERE'] = 'LOWER(username)=LOWER(\''.$pun_db->escape($form_username).'\')';
+
+	($hook = get_hook('li_qr_get_login_data')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	list($user_id, $group_id, $db_password_hash, $save_pass, $salt) = $pun_db->fetch_row($result);
+
+	$authorized = false;
+	if (!empty($db_password_hash))
+	{
+		$sha1_in_db = (strlen($db_password_hash) == 40) ? true : false;
+		$form_password_hash = sha1($salt.sha1($form_password));
+
+		if ($sha1_in_db && $db_password_hash == $form_password_hash)
+			$authorized = true;
+		else if ((!$sha1_in_db && $db_password_hash == md5($form_password)) || ($sha1_in_db && $db_password_hash == sha1($form_password)))
+		{
+			$authorized = true;
+
+			$salt = random_key(12);
+			$form_password_hash = sha1($salt.sha1($form_password));
+
+			// There's an old MD5 hash or an unsalted SHA1 hash in the database, so we replace it
+			// with a randomly generated salt and a new, salted SHA1 hash
+			$query = array(
+				'UPDATE'	=> 'users',
+				'SET'		=> 'password=\''.$form_password_hash.'\', salt=\''.$pun_db->escape($salt).'\'',
+				'WHERE'		=> 'id='.$user_id
+			);
+
+			($hook = get_hook('li_qr_update_user_hash')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+		}
+	}
+
+	($hook = get_hook('li_login_pre_auth_message')) ? eval($hook) : null;
+
+	if (!$authorized)
+		message($lang_login['Wrong user/pass'], sprintf($lang_login['Forgotten password'], '<a href="'.pun_link($pun_url['request_password']).'">'.$lang_login['Request pass'].'</a>'));
+
+	// Update the status if this is the first time the user logged in
+	if ($group_id == PUN_UNVERIFIED)
+	{
+		$query = array(
+			'UPDATE'	=> 'users',
+			'SET'		=> 'group_id='.$pun_config['o_default_user_group'],
+			'WHERE'		=> 'id='.$user_id
+		);
+
+		($hook = get_hook('li_qr_update_user_group')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	}
+
+	// Remove this user's guest entry from the online list
+	$query = array(
+		'DELETE'	=> 'online',
+		'WHERE'		=> 'ident=\''.$pun_db->escape(get_remote_address()).'\''
+	);
+
+	($hook = get_hook('li_qr_delete_online_user')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	$expire = ($save_pass == '1') ? time() + 31536000 : 0;
+	pun_setcookie($cookie_name, base64_encode($user_id.'|'.$form_password_hash), $expire);
+
+	pun_redirect(htmlspecialchars($_POST['redirect_url']).((substr_count($_POST['redirect_url'], '?') == 1) ? '&amp;' : '?').'login=1', $lang_login['Login redirect']);
+}
+
+
+// Logout
+else if ($action == 'out')
+{
+	if ($pun_user['is_guest'] || !isset($_GET['id']) || $_GET['id'] != $pun_user['id'])
+	{
+		header('Location: '.pun_link($pun_url['index']));
+		exit;
+	}
+
+	// We validate the CSRF token. If it's set in POST and we're at this point, the token is valid.
+	// If it's in GET, we need to make sure it's valid.
+	if (!isset($_POST['csrf_token']) && (!isset($_GET['csrf_token']) || $_GET['csrf_token'] !== generate_form_token('logout'.$pun_user['id'])))
+		csrf_confirm_form();
+
+	($hook = get_hook('li_logout_selected')) ? eval($hook) : null;
+
+	// Remove user from "users online" list.
+	$query = array(
+		'DELETE'	=> 'online',
+		'WHERE'		=> 'user_id='.$pun_user['id']
+	);
+
+	($hook = get_hook('li_qr_delete_online_user2')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	// Update last_visit (make sure there's something to update it with)
+	if (isset($pun_user['logged']))
+	{
+		$query = array(
+			'UPDATE'	=> 'users',
+			'SET'		=> 'last_visit='.$pun_user['logged'],
+			'WHERE'		=> 'id='.$pun_user['id']
+		);
+
+		($hook = get_hook('li_qr_update_last_visit')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	}
+
+	pun_setcookie($cookie_name, base64_encode('1|'.random_key(8, true)), time() + 31536000);
+
+	// Reset tracked topics
+	set_tracked_topics(null);
+
+	($hook = get_hook('li_logout_pre_redirect')) ? eval($hook) : null;
+
+	pun_redirect(pun_link($pun_url['index']), $lang_login['Logout redirect']);
+}
+
+
+// New password
+else if ($action == 'forget' || $action == 'forget_2')
+{
+	if (!$pun_user['is_guest'])
+		header('Location: '.pun_link($pun_url['index']));
+
+	($hook = get_hook('li_forgot_pass_selected')) ? eval($hook) : null;
+
+	if (isset($_POST['form_sent']))
+	{
+		require PUN_ROOT.'include/email.php';
+
+		// Validate the email-address
+		$email = strtolower(trim($_POST['req_email']));
+		if (!is_valid_email($email))
+			message($lang_common['Invalid e-mail']);
+
+		// Fetch user matching $email
+		$query = array(
+			'SELECT'	=> 'u.id, u.username, u.salt',
+			'FROM'		=> 'users AS u',
+			'WHERE'		=> 'u.email=\''.$pun_db->escape($email).'\''
+		);
+
+		($hook = get_hook('li_qr_get_user_data')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if ($pun_db->num_rows($result))
+		{
+			($hook = get_hook('li_forgot_pass_pre_email')) ? eval($hook) : null;
+
+			// Load the "activate password" template
+			$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/activate_password.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));
+
+			// Do the generic replacements first (they apply to all e-mails sent out here)
+			$mail_message = str_replace('<base_url>', $base_url.'/', $mail_message);
+			$mail_message = str_replace('<board_mailer>', sprintf($lang_common['Forum mailer'], $pun_config['o_board_title']), $mail_message);
+
+			// Loop through users we found
+			while ($cur_hit = $pun_db->fetch_assoc($result))
+			{
+				// Generate a new password activation key
+				$new_password_key = random_key(8, true);
+
+				$query = array(
+					'UPDATE'	=> 'users',
+					'SET'		=> 'activate_key=\''.$new_password_key.'\'',
+					'WHERE'		=> 'id='.$cur_hit['id']
+				);
+
+				($hook = get_hook('li_qr_set_activate_key')) ? eval($hook) : null;
+				$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+				// Do the user specific replacements to the template
+				$cur_mail_message = str_replace('<username>', $cur_hit['username'], $mail_message);
+				$cur_mail_message = str_replace('<activation_url>', str_replace('&amp;', '&', pun_link($pun_url['change_password_key'], array($cur_hit['id'], $new_password_key))), $cur_mail_message);
+
+				pun_mail($email, $mail_subject, $cur_mail_message);
+			}
+
+			message(sprintf($lang_login['Forget mail'], '<a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>'));
+		}
+		else
+			message(sprintf($lang_login['No e-mail match'], htmlspecialchars($email)));
+	}
+
+	// Setup form
+	$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+	$pun_page['form_action'] = $base_url.'/login.php?action=forget_2';
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		$lang_login['New password request']
+	);
+
+	($hook = get_hook('li_forgot_pass_pre_header_load')) ? eval($hook) : null;
+
+	define ('PUN_PAGE', 'dialogue');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_login['New password head'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="frm-info">
+			<p class="important"><?php echo $lang_login['New password info'] ?></p>
+		</div>
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<input type="hidden" name="form_sent" value="1" />
+			</div>
+<?php ($hook = get_hook('li_forgot_pass_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_login['E-mail address'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="req_email" size="35" maxlength="80" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_login['E-mail address help'] ?></span>
+					</label>
+				</div>
+			</fieldset>
+<?php ($hook = get_hook('li_forgot_pass_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="request_pass" value="<?php echo $lang_common['Submit'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+if (!$pun_user['is_guest'])
+	header('Location: '.pun_link($pun_url['index']));
+
+// Setup form
+$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+$pun_page['form_action'] = $base_url.'/login.php?action=in';
+
+$pun_page['hidden_fields'] = array(
+	'<input type="hidden" name="form_sent" value="1" />',
+	'<input type="hidden" name="redirect_url" value="'.htmlspecialchars($pun_user['prev_url']).'" />'
+);
+
+// Setup form information
+$pun_page['frm_info'] = array(
+	'<li><span>'.sprintf($lang_login['Must be registered'], '<a href="'.pun_link($pun_url['register']).'">'.$lang_login['Register now'].'</a>').'</span></li>',
+	'<li><span>'.sprintf($lang_login['Forgotten password'], '<a href="'.pun_link($pun_url['request_password']).'">'.$lang_login['Request pass'].'</a>').'</span></li>'
+);
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+	$lang_common['Login']
+);
+
+($hook = get_hook('li_login_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_PAGE', 'login');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php printf($lang_login['Login info'], htmlspecialchars($pun_config['o_board_title'])) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="frm-info">
+			<ul>
+				<?php echo implode("\n\t\t\t\t\t", $pun_page['frm_info'])."\n" ?>
+			</ul>
+		</div>
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('li_login_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_login['Login information'] ?></strong></legend>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_login['Username'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_username" size="30" maxlength="25" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_login['Password'] ?></span><br />
+						<span class="fld-input"><input type="password" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_password" size="30" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+			</fieldset>
+<?php ($hook = get_hook('li_login_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="login" value="<?php echo $lang_common['Login'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+($hook = get_hook('li_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/misc.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,490 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+if (isset($_GET['action']))
+	define('PUN_QUIET_VISIT', 1);
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('mi_start')) ? eval($hook) : null;
+
+// Load the misc.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/misc.php';
+
+
+$action = isset($_GET['action']) ? $_GET['action'] : null;
+
+
+// Show the forum rules?
+if ($action == 'rules')
+{
+	if ($pun_config['o_rules'] == '0')
+		message($lang_common['Bad request']);
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		$lang_common['Rules']
+	);
+
+	($hook = get_hook('mi_rules_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'rules');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_common['Forum rules'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="userbox">
+			<?php echo $pun_config['o_rules_message']."\n" ?>
+		</div>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+// Mark all topics/posts as read?
+else if ($action == 'markread')
+{
+	if ($pun_user['is_guest'])
+		message($lang_common['No permission']);
+
+	($hook = get_hook('mi_markread_selected')) ? eval($hook) : null;
+
+	$query = array(
+		'UPDATE'	=> 'users',
+		'SET'		=> 'last_visit='.$pun_user['logged'],
+		'WHERE'		=> 'id='.$pun_user['id']
+	);
+
+	($hook = get_hook('mi_qr_update_last_visit')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	// Reset tracked topics
+	set_tracked_topics(null);
+
+	pun_redirect($pun_user['prev_url'], $lang_misc['Mark read redirect']);
+}
+
+
+// Mark the topics/posts in a forum as read?
+else if ($action == 'markforumread')
+{
+	if ($pun_user['is_guest'])
+		message($lang_common['No permission']);
+
+	($hook = get_hook('mi_markforumread_selected')) ? eval($hook) : null;
+
+	$tracked_topics = get_tracked_topics();
+	$tracked_topics['forums'][intval($_GET['fid'])] = time();
+	set_tracked_topics($tracked_topics);
+
+	pun_redirect($pun_user['prev_url'], $lang_misc['Mark forum read redirect']);
+}
+
+
+// Send form e-mail?
+else if (isset($_GET['email']))
+{
+	if ($pun_user['is_guest'])
+		message($lang_common['No permission']);
+
+	($hook = get_hook('mi_email_selected')) ? eval($hook) : null;
+
+	// User pressed the cancel button
+	if (isset($_POST['cancel']))
+		pun_redirect(htmlspecialchars($_POST['redirect_url']), $lang_common['Cancel']);
+
+	$recipient_id = intval($_GET['email']);
+	if ($recipient_id < 2)
+		message($lang_common['Bad request']);
+
+	$query = array(
+		'SELECT'	=> 'u.username, u.email, u.email_setting',
+		'FROM'		=> 'users AS u',
+		'WHERE'		=> 'u.id='.$recipient_id
+	);
+
+	($hook = get_hook('mi_qr_get_form_email_data')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if (!$pun_db->num_rows($result))
+		message($lang_common['Bad request']);
+
+	list($recipient, $recipient_email, $email_setting) = $pun_db->fetch_row($result);
+
+	if ($email_setting == 2 && !$pun_user['is_admmod'])
+		message($lang_misc['Form e-mail disabled']);
+
+
+	if (isset($_POST['form_sent']))
+	{
+		($hook = get_hook('mi_email_form_submitted')) ? eval($hook) : null;
+
+		// Clean up message and subject from POST
+		$subject = trim($_POST['req_subject']);
+		$message = trim($_POST['req_message']);
+
+		if ($subject == '')
+			message($lang_misc['No e-mail subject']);
+		else if ($message == '')
+			message($lang_misc['No e-mail message']);
+		else if (strlen($message) > 65535)
+			message($lang_misc['Too long e-mail message']);
+
+		// Load the "form e-mail" template
+		$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/form_email.tpl'));
+
+		// The first row contains the subject
+		$first_crlf = strpos($mail_tpl, "\n");
+		$mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8));
+		$mail_message = trim(substr($mail_tpl, $first_crlf));
+
+		$mail_subject = str_replace('<mail_subject>', $subject, $mail_subject);
+		$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>', sprintf($lang_common['Forum mailer'], $pun_config['o_board_title']), $mail_message);
+
+		require_once PUN_ROOT.'include/email.php';
+
+		pun_mail($recipient_email, $mail_subject, $mail_message, '"'.str_replace('"', '', $pun_user['username']).'" <'.$pun_user['email'].'>');
+
+		pun_redirect(htmlspecialchars($_POST['redirect_url']), $lang_misc['E-mail sent redirect']);
+	}
+
+	// Setup form
+	$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+	$pun_page['form_action'] = pun_link($pun_url['email'], $recipient_id);
+
+	$pun_page['hidden_fields'] = array(
+		'<input type="hidden" name="form_sent" value="1" />',
+		'<input type="hidden" name="redirect_url" value="'.htmlspecialchars($pun_user['prev_url']).'" />'
+	);
+	if ($pun_user['is_admmod'])
+		$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+	// Setup main heading
+	$pun_page['main_head'] = sprintf($lang_misc['Send forum e-mail'], htmlspecialchars($recipient));
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		$lang_common['Send forum e-mail']
+	);
+
+	($hook = get_hook('mi_email_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'formemail');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $pun_page['main_head'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="frm-info">
+			<p class="important"><?php echo $lang_misc['E-mail disclosure note'] ?></p>
+		</div>
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('mi_email_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_misc['Write e-mail'] ?></strong></legend>
+				<div class="frm-fld text required longtext">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_misc['E-mail subject'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_subject" size="75" maxlength="70" /></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+<?php ($hook = get_hook('mi_email_pre_message_contents')) ? eval($hook) : null; ?>
+				<div class="frm-fld text textarea required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_misc['E-mail message'] ?></span><br />
+						<span class="fld-input"><textarea id="fld<?php echo $pun_page['fld_count'] ?>" name="req_message" rows="10" cols="95"></textarea></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+			</fieldset>
+<?php ($hook = get_hook('mi_email_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" accesskey="s" title="<?php echo $lang_common['Submit title'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+// Report a post?
+else if (isset($_GET['report']))
+{
+	if ($pun_user['is_guest'])
+		message($lang_common['No permission']);
+
+	($hook = get_hook('mi_report_selected')) ? eval($hook) : null;
+
+	$post_id = intval($_GET['report']);
+	if ($post_id < 1)
+		message($lang_common['Bad request']);
+
+	// User pressed the cancel button
+	if (isset($_POST['cancel']))
+		pun_redirect(pun_link($pun_url['post'], $post_id), $lang_common['Cancel redirect']);
+
+
+	if (isset($_POST['form_sent']))
+	{
+		($hook = get_hook('mi_report_form_submitted')) ? eval($hook) : null;
+
+		// Clean up reason from POST
+		$reason = pun_linebreaks(trim($_POST['req_reason']));
+		if ($reason == '')
+			message($lang_misc['No reason']);
+
+		// Get some info about the topic we're reporting
+		$query = array(
+			'SELECT'	=> 't.id, t.subject, t.forum_id',
+			'FROM'		=> 'posts AS p',
+			'JOINS'		=> array(
+				array(
+					'INNER JOIN'	=> 'topics AS t',
+					'ON'			=> 't.id=p.topic_id'
+				)
+			),
+			'WHERE'		=> 'p.id='.$post_id
+		);
+
+		($hook = get_hook('mi_qr_get_report_topic_data')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if (!$pun_db->num_rows($result))
+			message($lang_common['Bad request']);
+
+		list($topic_id, $subject, $forum_id) = $pun_db->fetch_row($result);
+
+		($hook = get_hook('mi_report_pre_reports_sent')) ? eval($hook) : null;
+
+		// Should we use the internal report handling?
+		if ($pun_config['o_report_method'] == 0 || $pun_config['o_report_method'] == 2)
+		{
+			$query = array(
+				'INSERT'	=> 'post_id, topic_id, forum_id, reported_by, created, message',
+				'INTO'		=> 'reports',
+				'VALUES'	=> $post_id.', '.$topic_id.', '.$forum_id.', '.$pun_user['id'].', '.time().', \''.$pun_db->escape($reason).'\''
+			);
+
+			($hook = get_hook('mi_add_report')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+		}
+
+		// Should we e-mail the report?
+		if ($pun_config['o_report_method'] == 1 || $pun_config['o_report_method'] == 2)
+		{
+			// We send it to the complete mailing-list in one swoop
+			if ($pun_config['o_mailing_list'] != '')
+			{
+				$mail_subject = 'Report('.$forum_id.') - \''.$subject.'\'';
+				$mail_message = 'User \''.$pun_user['username'].'\' has reported the following message:'."\n".pun_link($pun_url['post'], $post_id)."\n\n".'Reason:'."\n".$reason;
+
+				require PUN_ROOT.'include/email.php';
+
+				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
+			}
+		}
+
+		pun_redirect(pun_link($pun_url['post'], $post_id), $lang_misc['Report redirect']);
+	}
+
+	// Setup form
+	$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+	$pun_page['form_action'] = pun_link($pun_url['report'], $post_id);
+
+	$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+	if ($pun_user['is_admmod'])
+		$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		$lang_misc['Report post']
+	);
+
+	($hook = get_hook('mi_report_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'report');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_misc['Send report'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('mi_report_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+				<div class="frm-fld text textarea required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_misc['Reason'] ?></span><br />
+						<span class="fld-input"><textarea id="fld<?php echo $pun_page['fld_count'] ?>" name="req_reason" rows="5" cols="60"></textarea></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_misc['Reason help'] ?></span>
+					</label>
+				</div>
+			</fieldset>
+<?php ($hook = get_hook('mi_report_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" accesskey="s" title="<?php echo $lang_common['Submit title'] ?>" /></span>
+ 				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+// Subscribe to a topic?
+else if (isset($_GET['subscribe']))
+{
+	if ($pun_user['is_guest'] || $pun_config['o_subscriptions'] != '1')
+		message($lang_common['No permission']);
+
+	($hook = get_hook('mi_subscribe_selected')) ? eval($hook) : null;
+
+	$topic_id = intval($_GET['subscribe']);
+	if ($topic_id < 1)
+		message($lang_common['Bad request']);
+
+	$query = array(
+		'SELECT'	=> '1',
+		'FROM'		=> 'subscriptions AS s',
+		'WHERE'		=> 'user_id='.$pun_user['id'].' AND topic_id='.$topic_id
+	);
+
+	($hook = get_hook('mi_qr_check_subscribed')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if ($pun_db->num_rows($result))
+		message($lang_misc['Already subscribed']);
+
+	$query = array(
+		'INSERT'	=> 'user_id, topic_id',
+		'INTO'		=> 'subscriptions',
+		'VALUES'	=> $pun_user['id'].' ,'.$topic_id
+	);
+
+	($hook = get_hook('mi_add_subscription')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	pun_redirect(pun_link($pun_url['topic'], $topic_id), $lang_misc['Subscribe redirect']);
+}
+
+
+// Unsubscribe from a topic?
+else if (isset($_GET['unsubscribe']))
+{
+	if ($pun_user['is_guest'] || $pun_config['o_subscriptions'] != '1')
+		message($lang_common['No permission']);
+
+	($hook = get_hook('mi_unsubscribe_selected')) ? eval($hook) : null;
+
+	$topic_id = intval($_GET['unsubscribe']);
+	if ($topic_id < 1)
+		message($lang_common['Bad request']);
+
+	$query = array(
+		'SELECT'	=> '1',
+		'FROM'		=> 'subscriptions AS s',
+		'WHERE'		=> 'user_id='.$pun_user['id'].' AND topic_id='.$topic_id
+	);
+
+	($hook = get_hook('mi_qr_check_subscribed2')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if (!$pun_db->num_rows($result))
+		message($lang_misc['Not subscribed']);
+
+	$query = array(
+		'DELETE'	=> 'subscriptions',
+		'WHERE'		=> 'user_id='.$pun_user['id'].' AND topic_id='.$topic_id
+	);
+
+	($hook = get_hook('mi_qr_delete_subscription')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	pun_redirect(pun_link($pun_url['topic'], $topic_id), $lang_misc['Unsubscribe redirect']);
+}
+
+
+($hook = get_hook('mi_new_action')) ? eval($hook) : null;
+
+message($lang_common['Bad request']);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/moderate.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,1206 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('mr_start')) ? eval($hook) : null;
+
+
+// This particular function doesn't require forum-based moderator access. It can be used
+// by all moderators and admins.
+if (isset($_GET['get_host']))
+{
+	if (!$pun_user['is_admmod'])
+		message($lang_common['No permission']);
+
+	($hook = get_hook('mr_view_ip_selected')) ? eval($hook) : null;
+
+	// 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']))
+		$ip = $_GET['get_host'];
+	else
+	{
+		$get_host = intval($_GET['get_host']);
+		if ($get_host < 1)
+			message($lang_common['Bad request']);
+
+		$query = array(
+			'SELECT'	=> 'p.poster_ip',
+			'FROM'		=> 'posts AS p',
+			'WHERE'		=> 'p.id='.$get_host
+		);
+
+		($hook = get_hook('mr_qr_get_poster_ip')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if (!$pun_db->num_rows($result))
+			message($lang_common['Bad request']);
+
+		$ip = $pun_db->result($result);
+	}
+
+	message('The IP address is: '.$ip.'<br />The host name is: '.@gethostbyaddr($ip).'<br /><br /><a href="'.pun_link($pun_url['admin_users']).'&show_users='.$ip.'">Show more users for this IP</a>');
+}
+
+
+// All other functions require moderator/admin access
+$fid = isset($_GET['fid']) ? intval($_GET['fid']) : 0;
+if ($fid < 1)
+	message($lang_common['Bad request']);
+
+// Get some info about the forum we're moderating
+$query = array(
+	'SELECT'	=> 'f.forum_name, f.redirect_url, f.num_topics, f.moderators',
+	'FROM'		=> 'forums AS f',
+	'JOINS'		=> array(
+		array(
+			'LEFT JOIN'		=> 'forum_perms AS fp',
+			'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+		)
+	),
+	'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$fid
+);
+
+($hook = get_hook('mr_qr_get_forum_data')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+if (!$pun_db->num_rows($result))
+	message($lang_common['Bad request']);
+
+$cur_forum = $pun_db->fetch_assoc($result);
+
+// Make sure we're not trying to moderate a redirect forum
+if ($cur_forum['redirect_url'] != '')
+	message($lang_common['Bad request']);
+
+// Setup the array of moderators
+$mods_array = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array();
+
+if ($pun_user['g_id'] != PUN_ADMIN && ($pun_user['g_moderator'] != '1' || !array_key_exists($pun_user['username'], $mods_array)))
+	message($lang_common['No permission']);
+
+// Get topic/forum tracking data
+if (!$pun_user['is_guest'])
+	$tracked_topics = get_tracked_topics();
+
+// Load the misc.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/misc.php';
+
+
+// Did someone click a cancel button?
+if (isset($_POST['cancel']))
+	pun_redirect(pun_link($pun_url['forum'], $fid), $lang_common['Cancel redirect']);
+
+
+// All other topic moderation features require a topic id in GET
+if (isset($_GET['tid']))
+{
+	($hook = get_hook('mr_post_actions_selected')) ? eval($hook) : null;
+
+	$tid = intval($_GET['tid']);
+	if ($tid < 1)
+		message($lang_common['Bad request']);
+
+	// User pressed the cancel button
+	if (isset($_POST['delete_posts_cancel']))
+		pun_redirect(pun_link($pun_url['topic'], $tid), $lang_common['Cancel redirect']);
+
+	// Fetch some info about the topic
+	$query = array(
+		'SELECT'	=> 't.subject, t.poster, t.first_post_id, t.posted, t.num_replies',
+		'FROM'		=> 'topics AS t',
+		'WHERE'		=> 't.id='.$tid.' AND t.moved_to IS NULL'
+	);
+
+	($hook = get_hook('mr_qr_get_topic_info')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if (!$pun_db->num_rows($result))
+		message($lang_common['Bad request']);
+
+	$cur_topic = $pun_db->fetch_assoc($result);
+
+	// Delete one or more posts
+	if (isset($_POST['delete_posts']) || isset($_POST['delete_posts_comply']))
+	{
+		($hook = get_hook('mr_delete_posts_form_submitted')) ? eval($hook) : null;
+
+		$posts = $_POST['posts'];
+		if (empty($posts))
+			message($lang_misc['No posts selected']);
+
+		if (isset($_POST['delete_posts_comply']))
+		{
+			if (!isset($_POST['req_confirm']))
+				pun_redirect(pun_link($pun_url['topic'], $tid), $lang_common['No confirm redirect']);
+
+			($hook = get_hook('mr_confirm_delete_posts_form_submitted')) ? eval($hook) : null;
+
+			if (@preg_match('/[^0-9,]/', $posts))
+				message($lang_common['Bad request']);
+
+			// Verify that the post IDs are valid
+			$query = array(
+				'SELECT'	=> '1',
+				'FROM'		=> 'posts AS p',
+				'WHERE'		=> 'p.id IN('.$posts.') AND p.id!='.$cur_topic['first_post_id'].' AND p.topic_id='.$tid
+			);
+
+			($hook = get_hook('mr_qr_verify_post_ids')) ? eval($hook) : null;
+			$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+			if ($pun_db->num_rows($result) != substr_count($posts, ',') + 1)
+				message($lang_common['Bad request']);
+
+			// Delete the posts
+			$query = array(
+				'DELETE'	=> 'posts',
+				'WHERE'		=> 'id IN('.$posts.')'
+			);
+
+			($hook = get_hook('mr_qr_delete_topics')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			if ($db_type != 'mysql' && $db_type != 'mysqli')
+			{
+				require PUN_ROOT.'include/search_idx.php';
+				strip_search_index($posts);
+			}
+
+			// Get last_post, last_post_id, and last_poster for the topic after deletion
+			$query = array(
+				'SELECT'	=> 'p.id, p.poster, p.posted',
+				'FROM'		=> 'posts AS p',
+				'WHERE'		=> 'p.topic_id='.$tid,
+				'ORDER BY'	=> 'p.id',
+				'LIMIT'		=> '1'
+			);
+
+			($hook = get_hook('mr_qr_get_topic_last_post_data')) ? eval($hook) : null;
+			$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+			$last_post = $pun_db->fetch_assoc($result);
+
+			// How many posts did we just delete?
+			$num_posts_deleted = substr_count($posts, ',') + 1;
+
+			// Update the topic
+			$query = array(
+				'UPDATE'	=> 'topics',
+				'SET'		=> 'last_post='.$last_post['posted'].', last_post_id='.$last_post['id'].', last_poster=\''.$pun_db->escape($last_post['poster']).'\', num_replies=num_replies-'.$num_posts_deleted,
+				'WHERE'		=> 'id='.$tid
+			);
+
+			($hook = get_hook('mr_qr_update_topic')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			sync_forum($fid);
+
+			pun_redirect(pun_link($pun_url['topic'], $tid), $lang_misc['Delete posts redirect']);
+		}
+
+		// Setup form
+		$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+		$pun_page['form_action'] = pun_link($pun_url['delete_multiple'], array($fid, $tid));
+
+		$pun_page['hidden_fields'] = array(
+			'<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />',
+			'<input type="hidden" name="posts" value="'.implode(',', array_keys($posts)).'" />'
+		);
+
+		// Setup breadcrumbs
+		$pun_page['crumbs'] = array(
+			array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+			array($cur_forum['forum_name'], pun_link($pun_url['forum'], $fid)),
+			array($cur_topic['subject'], pun_link($pun_url['topic'], $tid)),
+			$lang_misc['Delete posts']
+		);
+
+		($hook = get_hook('mr_confirm_delete_posts_pre_header_load')) ? eval($hook) : null;
+
+		define('PUN_PAGE', 'dialogue');
+		require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_misc['Confirm post delete'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_misc['Delete posts'] ?></strong></legend>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_common['Please confirm'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_confirm" value="1" checked="checked" /> <?php echo $lang_misc['Confirm post delete'] ?>.</label>
+				</div>
+			</fieldset>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="delete_posts_comply" value="<?php echo $lang_common['Delete'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+		require PUN_ROOT.'footer.php';
+	}
+
+
+	// Show the delete multiple posts view
+
+	// Load the viewtopic.php language file
+	require PUN_ROOT.'lang/'.$pun_user['language'].'/topic.php';
+
+	// Used to disable the Move and Delete buttons if there are no replies to this topic
+	$pun_page['button_status'] = ($cur_topic['num_replies'] == 0) ? ' disabled="disabled"' : '';
+
+
+	// Determine the post offset (based on $_GET['p'])
+	$pun_page['num_pages'] = ceil(($cur_topic['num_replies'] + 1) / $pun_user['disp_posts']);
+	$pun_page['page'] = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $pun_page['num_pages']) ? 1 : $_GET['p'];
+	$pun_page['start_from'] = $pun_user['disp_posts'] * ($pun_page['page'] - 1);
+	$pun_page['finish_at'] = min(($pun_page['start_from'] + $pun_user['disp_posts']), ($cur_topic['num_replies'] + 1));
+
+	// Generate paging links
+	$pun_page['page_post'] = '<p class="paging"><strong>'.$lang_common['Pages'].'</strong> '.pun_paginate($pun_page['num_pages'], $pun_page['page'], $pun_url['delete_multiple'], array($fid, $tid)).'</p>';
+
+	// Navigation links for header and page numbering for title/meta description
+	if ($pun_page['page'] < $pun_page['num_pages'])
+	{
+		$pun_page['nav'][] = '<link rel="last" href="'.pun_sublink($pun_url['delete_multiple'], $pun_url['page'], $pun_page['num_pages'], array($fid, $tid)).'" title="'.$lang_common['Page'].' '.$pun_page['num_pages'].'" />';
+		$pun_page['nav'][] = '<link rel="next" href="'.pun_sublink($pun_url['delete_multiple'], $pun_url['page'], ($pun_page['page'] + 1), array($fid, $tid)).'" title="'.$lang_common['Page'].' '.($pun_page['page'] + 1).'" />';
+	}
+	if ($pun_page['page'] > 1)
+	{
+		$pun_page['nav'][] = '<link rel="prev" href="'.pun_sublink($pun_url['delete_multiple'], $pun_url['page'], ($pun_page['page'] - 1), array($fid, $tid)).'" title="'.$lang_common['Page'].' '.($pun_page['page'] - 1).'" />';
+		$pun_page['nav'][] = '<link rel="first" href="'.pun_link($pun_url['delete_multiple'], array($fid, $tid)).'" title="'.$lang_common['Page'].' 1" />';
+	}
+
+	// Generate page information
+	if ($pun_page['num_pages'] > 1)
+		$pun_page['main_info'] = '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_common['Posts'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $cur_topic['num_replies'] + 1);
+	else
+		$pun_page['main_info'] = sprintf($lang_common['Page info'], $lang_common['Posts'], ($cur_topic['num_replies'] + 1));
+
+	if ($pun_config['o_censoring'] == '1')
+		$cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+	// Setup form
+	$pun_page['form_action'] = pun_link($pun_url['delete_multiple'], array($fid, $tid));
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		array($cur_forum['forum_name'], pun_link($pun_url['forum'], $fid)),
+		array($cur_topic['subject'], pun_link($pun_url['topic'], $tid)),
+		$lang_topic['Delete posts']
+	);
+
+	($hook = get_hook('mr_post_actions_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'modtopic');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main paged">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<form method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+
+	<div class="hidden">
+		<input type="hidden" name="csrf_token" value="<?php echo generate_form_token($pun_page['form_action']) ?>" />
+	</div>
+
+	<div class="paged-head">
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+	<div class="main-head">
+		<h2><span><?php echo $pun_page['main_info'] ?></span></h2>
+		<p class="main-options"><?php echo $lang_misc['Select posts'] ?></p>
+	</div>
+
+	<div class="main-content topic">
+<?php
+
+	require PUN_ROOT.'include/parser.php';
+
+	$pun_page['item_count'] = 0;	// Keep track of post numbers
+
+	// Retrieve the posts (and their respective poster)
+	$query = array(
+		'SELECT'	=> 'u.title, u.num_posts, g.g_id, g.g_user_title, p.id, p.poster, p.poster_id, p.message, p.hide_smilies, p.posted, p.edited, p.edited_by',
+		'FROM'		=> 'posts AS p',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'users AS u',
+				'ON'			=> 'u.id=p.poster_id'
+			),
+			array(
+				'INNER JOIN'	=> 'groups AS g',
+				'ON'			=> 'g.g_id=u.group_id'
+			)
+		),
+		'WHERE'		=> 'p.topic_id='.$tid,
+		'ORDER BY'	=> 'p.id',
+		'LIMIT'		=> $pun_page['start_from'].','.$pun_user['disp_posts']
+	);
+
+	($hook = get_hook('mr_qr_get_topic_info')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+	while ($cur_post = $pun_db->fetch_assoc($result))
+	{
+		++$pun_page['item_count'];
+
+		$pun_page['post_options'] = $pun_page['message'] = array();
+		$pun_page['user_ident'] = '';
+		$pun_page['user_info'] = '';
+		$cur_post['username'] = $cur_post['poster'];
+
+		// Generate the post heading
+		$pun_page['item_ident'] = array(
+			'num'	=> '<strong>'.($pun_page['start_from'] + $pun_page['item_count']).'</strong>',
+			'user'	=> '<cite>'.($cur_topic['posted'] == $cur_post['posted'] ? sprintf($lang_topic['Topic by'], htmlspecialchars($cur_post['username'])) : sprintf($lang_topic['Reply by'], htmlspecialchars($cur_post['username']))).'</cite>',
+			'date'	=> '<span>'.format_time($cur_post['posted']).'</span>'
+		);
+
+		$pun_page['item_head'] = '<a class="permalink" rel="bookmark" title="'.$lang_topic['Permalink post'].'" href="'.pun_link($pun_url['post'], $cur_post['id']).'">'.implode(' ', $pun_page['item_ident']).'</a>';
+
+		// Generate the checkbox field
+		if ($cur_post['id'] != $cur_topic['first_post_id'])
+			$pun_page['item_select'] = '<div class="checkbox radbox item-select"><label for="fld'.$cur_post['id'].'"><span class="fld-label">'.$lang_misc['Select post'].'</span> <input type="checkbox" id="fld'.$cur_post['id'].'" name="posts['.$cur_post['id'].']" value="1" /> '.$pun_page['item_ident']['num'].'</label></div>';
+
+		// Generate author identification
+		$pun_page['user_ident'] = (($cur_post['poster_id'] > 1) ? '<strong class="username"><a title="'.sprintf($lang_topic['Go to profile'], htmlspecialchars($cur_post['username'])).'" href="'.pun_link($pun_url['user'], $cur_post['poster_id']).'">'.htmlspecialchars($cur_post['username']).'</a></strong>' : '<strong class="username">'.htmlspecialchars($cur_post['username']).'</strong>');
+		$pun_page['user_info'] = '<li class="title"><span><strong>'.$lang_topic['Title'].'</strong> '.get_title($cur_post).'</span></li>';
+
+		// Give the post some class
+		$pun_page['item_status'] = array(
+			'post',
+			($pun_page['item_count'] % 2 == 0) ? 'odd' : 'even'
+		);
+
+		if ($pun_page['item_count'] == 1)
+			$pun_page['item_status'][] = 'firstpost';
+
+		if (($pun_page['start_from'] + $pun_page['item_count']) == $pun_page['finish_at'])
+			$pun_page['item_status'][] = 'lastpost';
+
+		if ($cur_post['id'] == $cur_topic['first_post_id'])
+			$pun_page['item_status'][] = 'topicpost';
+
+		if ($cur_post['id'] == $cur_topic['first_post_id'])
+			$pun_page['item_subject'] = $lang_common['Topic'].': '.$cur_topic['subject'];
+		else
+			$pun_page['item_subject'] = $lang_common['Re'].' '.$cur_topic['subject'];
+
+		// Perform the main parsing of the message (BBCode, smilies, censor words etc)
+		$pun_page['message'][] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
+
+		if ($cur_post['edited'] != '')
+			$pun_page['message'][] = '<p class="lastedit"><em>'.sprintf($lang_topic['Last edited'], htmlspecialchars($cur_post['edited_by']), format_time($cur_post['edited'])).'</em></p>';
+
+		($hook = get_hook('mr_post_actions_row_pre_display')) ? eval($hook) : null;
+
+?>
+		<div class="<?php echo implode(' ', $pun_page['item_status']) ?>">
+			<div class="postmain">
+				<div id="p<?php echo $cur_post['id'] ?>" class="posthead">
+					<h3><?php echo $pun_page['item_head'] ?></h3>
+				</div>
+				<?php if (isset($pun_page['item_select'])) echo $pun_page['item_select']."\n" ?>
+				<div class="postbody">
+					<div class="user">
+						<h4 class="user-ident"><?php echo $pun_page['user_ident'] ?></h4>
+						<ul class="user-info">
+							<?php echo $pun_page['user_info']."\n" ?>
+						</ul>
+					</div>
+					<div class="post-entry">
+						<h4 class="entry-title"><?php echo $pun_page['item_subject'] ?></h4>
+						<div class="entry-content">
+							<?php echo implode("\n\t\t\t\t\t\t\t", $pun_page['message'])."\n" ?>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+<?php
+
+	}
+
+?>
+	</div>
+
+	<div class="main-foot">
+		<p class="h2"><strong><?php echo $pun_page['main_info'] ?></strong></p>
+	</div>
+
+	<div class="paged-foot">
+		<p class="submitting"><span class="submit"><input type="submit" name="delete_posts" value="<?php echo $lang_misc['Delete posts'] ?>"<?php echo $pun_page['button_status'] ?> /></span></p>
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+	</form>
+
+</div>
+
+<div id="pun-crumbs-foot">
+	<p class="crumbs"><?php echo generate_crumbs(false) ?></p>
+</div>
+
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+// Move one or more topics
+if (isset($_REQUEST['move_topics']) || isset($_POST['move_topics_to']))
+{
+	if (isset($_POST['move_topics_to']))
+	{
+		($hook = get_hook('mr_confirm_move_topics_form_submitted')) ? eval($hook) : null;
+
+		if (@preg_match('/[^0-9,]/', $_POST['topics']))
+			message($lang_common['Bad request']);
+
+		$topics = explode(',', $_POST['topics']);
+		$move_to_forum = isset($_POST['move_to_forum']) ? intval($_POST['move_to_forum']) : 0;
+		if (empty($topics) || $move_to_forum < 1)
+			message($lang_common['Bad request']);
+
+		// Verify that the topic IDs are valid
+		$query = array(
+			'SELECT'	=> '1',
+			'FROM'		=> 'topics AS t',
+			'WHERE'		=> 't.id IN('.implode(',', $topics).') AND t.forum_id='.$fid
+		);
+
+		($hook = get_hook('mr_qr_verify_topic_ids')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if ($pun_db->num_rows($result) != count($topics))
+			message($lang_common['Bad request']);
+
+		// Delete any redirect topics if there are any (only if we moved/copied the topic back to where it where it was once moved from)
+		$query = array(
+			'DELETE'	=> 'topics',
+			'WHERE'		=> 'forum_id='.$move_to_forum.' AND moved_to IN('.implode(',', $topics).')'
+		);
+
+		($hook = get_hook('mr_qr_delete_redirect_topics')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		// Move the topic(s)
+		$query = array(
+			'UPDATE'	=> 'topics',
+			'SET'		=> 'forum_id='.$move_to_forum,
+			'WHERE'		=> 'id IN('.implode(',', $topics).')'
+		);
+
+		($hook = get_hook('mr_qr_move_topics')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		// Should we create redirect topics?
+		if (isset($_POST['with_redirect']))
+		{
+			while (list(, $cur_topic) = @each($topics))
+			{
+				// Fetch info for the redirect topic
+				$query = array(
+					'SELECT'	=> 't.poster, t.subject, t.posted, t.last_post',
+					'FROM'		=> 'topics AS t',
+					'WHERE'		=> 't.id='.$cur_topic
+				);
+
+				($hook = get_hook('mr_qr_get_redirect_topic_data')) ? eval($hook) : null;
+				$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+				$moved_to = $pun_db->fetch_assoc($result);
+
+				// Create the redirect topic
+				$query = array(
+					'INSERT'	=> 'poster, subject, posted, last_post, moved_to, forum_id',
+					'INTO'		=> 'topics',
+					'VALUES'	=> '\''.$pun_db->escape($moved_to['poster']).'\', \''.$pun_db->escape($moved_to['subject']).'\', '.$moved_to['posted'].', '.$moved_to['last_post'].', '.$cur_topic.', '.$fid
+				);
+
+				($hook = get_hook('mr_qr_add_redirect_topic')) ? eval($hook) : null;
+				$pun_db->query_build($query) or error(__FILE__, __LINE__);
+			}
+		}
+
+		sync_forum($fid);			// Synchronize the forum FROM which the topic was moved
+		sync_forum($move_to_forum);	// Synchronize the forum TO which the topic was moved
+
+		$pun_page['redirect_msg'] = (count($topics) > 1) ? $lang_misc['Move topics redirect'] : $lang_misc['Move topic redirect'];
+		pun_redirect(pun_link($pun_url['forum'], $move_to_forum), $pun_page['redirect_msg']);
+	}
+
+	if (isset($_POST['move_topics']))
+	{
+		$topics = isset($_POST['topics']) ? $_POST['topics'] : array();
+		if (empty($topics))
+			message($lang_misc['No topics selected']);
+
+		$topics = implode(',', array_keys($topics));
+		$action = 'multi';
+	}
+	else
+	{
+		$topics = intval($_GET['move_topics']);
+		if ($topics < 1)
+			message($lang_common['Bad request']);
+
+		$action = 'single';
+
+		// Fetch the topic subject
+		$query = array(
+			'SELECT'	=> 't.subject',
+			'FROM'		=> 'topics AS t',
+			'WHERE'		=> 't.id='.$topics
+		);
+
+		($hook = get_hook('mr_qr_get_topic_subject')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		$subject = $pun_db->result($result);
+	}
+
+	// Get forums we can move the post into
+	$query = array(
+		'SELECT'	=> 'c.id AS cid, c.cat_name, f.id AS fid, f.forum_name',
+		'FROM'		=> 'categories AS c',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'forums AS f',
+				'ON'			=> 'c.id=f.cat_id'
+			),
+			array(
+				'LEFT JOIN'		=> '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 AND f.id!='.$fid,
+		'ORDER BY'	=> 'c.disp_position, c.id, f.disp_position'
+	);
+
+	($hook = get_hook('mr_qr_get_target_forums')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$num_forums = $pun_db->num_rows($result);
+
+	if (!$num_forums)
+		message($lang_misc['Nowhere to move']);
+
+	$forum_list = array();
+	for ($i = 0; $i < $num_forums; ++$i)
+		$forum_list[] = $pun_db->fetch_assoc($result);
+
+	// Setup form
+	$pun_page['fld_count'] = $pun_page['set_count'] = 0;
+	$pun_page['form_action'] = pun_link($pun_url['moderate_forum'], $fid);
+
+	$pun_page['hidden_fields'] = array(
+		'<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />',
+		'<input type="hidden" name="topics" value="'.$topics.'" />'
+	);
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'][] = array($pun_config['o_board_title'], pun_link($pun_url['index']));
+	$pun_page['crumbs'][] = array($cur_forum['forum_name'], pun_link($pun_url['forum'], $fid));
+	if ($action == 'single')
+		$pun_page['crumbs'][] = array($subject, pun_link($pun_url['topic'], $topics));
+	else
+		$pun_page['crumbs'][] = array($lang_misc['Moderate forum'], pun_link($pun_url['moderate_forum'], $fid));
+	$pun_page['crumbs'][] =	($action == 'single') ? $lang_misc['Move topic'] : $lang_misc['Move topics'];
+
+	($hook = get_hook('mr_move_topics_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'dialogue');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo end($pun_page['crumbs']).' '.$lang_misc['To new forum'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_misc['Move topic'] ?></strong></legend>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_misc['Move to'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="move_to_forum">
+<?php
+
+	$pun_page['cur_category'] = 0;
+	foreach ($forum_list as $cur_forum)
+	{
+		if ($cur_forum['cid'] != $pun_page['cur_category'])	// A new category since last iteration?
+		{
+			if ($pun_page['cur_category'])
+				echo "\t\t\t\t\t\t".'</optgroup>'."\n";
+
+			echo "\t\t\t\t\t\t".'<optgroup label="'.htmlspecialchars($cur_forum['cat_name']).'">'."\n";
+			$pun_page['cur_category'] = $cur_forum['cid'];
+		}
+
+		if ($cur_forum['fid'] != $fid)
+			echo "\t\t\t\t\t\t".'<option value="'.$cur_forum['fid'].'">'.htmlspecialchars($cur_forum['forum_name']).'</option>'."\n";
+	}
+
+?>
+						</optgroup>
+						</select></span>
+					</label>
+				</div>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_misc['Redirect topic'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="with_redirect" value="1"<?php if ($action == 'single') echo ' checked="checked"' ?> /> <?php echo ($action == 'single') ? $lang_misc['Leave redirect'] : $lang_misc['Leave redirects'] ?></label>
+				</div>
+			</fieldset>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="move_topics_to" value="<?php echo $lang_misc['Move'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+// Delete one or more topics
+else if (isset($_REQUEST['delete_topics']) || isset($_POST['delete_topics_comply']))
+{
+	$topics = isset($_POST['topics']) ? $_POST['topics'] : array();
+	if (empty($topics))
+		message($lang_misc['No topics selected']);
+
+	if (isset($_POST['delete_topics_comply']))
+	{
+		if (!isset($_POST['req_confirm']))
+			pun_redirect(pun_link($pun_url['forum'], $fid), $lang_common['Cancel redirect']);
+
+		($hook = get_hook('mr_confirm_delete_topics_form_submitted')) ? eval($hook) : null;
+
+		if (@preg_match('/[^0-9,]/', $topics))
+			message($lang_common['Bad request']);
+
+		// Verify that the topic IDs are valid
+		$query = array(
+			'SELECT'	=> '1',
+			'FROM'		=> 'topics AS t',
+			'WHERE'		=> 't.id IN('.implode(',', $topics).') AND t.forum_id='.$fid
+		);
+
+		($hook = get_hook('mr_qr_verify_topic_ids2')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if ($pun_db->num_rows($result) != substr_count($topics, ',') + 1)
+			message($lang_common['Bad request']);
+
+		// Delete the topics and any redirect topics
+		$query = array(
+			'DELETE'	=> 'topics',
+			'WHERE'		=> 'id IN('.$topics.') OR moved_to IN('.$topics.')'
+		);
+
+		($hook = get_hook('mr_qr_delete_topics')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		// Delete any subscriptions
+		$query = array(
+			'DELETE'	=> 'subscriptions',
+			'WHERE'		=> 'topic_id IN('.$topics.')'
+		);
+
+		($hook = get_hook('mr_qr_delete_subscriptions')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		if ($db_type != 'mysql' && $db_type != 'mysqli')
+		{
+			// Create a list of the post ID's in the deleted topic and strip the search index
+			$query = array(
+				'SELECT'	=> 'p.id',
+				'FROM'		=> 'posts AS p',
+				'WHERE'		=> 'p.topic_id IN('.$topics.')'
+			);
+
+			($hook = get_hook('mr_qr_get_deleted_posts')) ? eval($hook) : null;
+			$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			$post_ids = '';
+			while ($row = $pun_db->fetch_row($result))
+				$post_ids .= ($post_ids != '') ? ','.$row[0] : $row[0];
+
+			// Strip the search index provided we're not just deleting redirect topics
+			if ($post_ids != '')
+			{
+				require PUN_ROOT.'include/search_idx.php';
+				strip_search_index($post_ids);
+			}
+		}
+
+		// Delete posts
+		$query = array(
+			'DELETE'	=> 'posts',
+			'WHERE'		=> 'topic_id IN('.$topics.')'
+		);
+
+		($hook = get_hook('mr_qr_delete_posts')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		sync_forum($fid);
+
+		pun_redirect(pun_link($pun_url['forum'], $fid), $lang_misc['Delete topics redirect']);
+	}
+
+
+	// Setup form
+	$pun_page['fld_count'] = $pun_page['set_count'] = 0;
+	$pun_page['form_action'] = pun_link($pun_url['moderate_forum'], $fid);
+
+	$pun_page['hidden_fields'] = array(
+		'<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />',
+		'<input type="hidden" name="topics" value="'.implode(',', array_keys($topics)).'" />'
+	);
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		array($cur_forum['forum_name'], pun_link($pun_url['forum'], $fid)),
+		array($lang_misc['Moderate forum'], pun_link($pun_url['moderate_forum'], $fid)),
+		$lang_misc['Delete topics']
+	);
+
+	($hook = get_hook('mr_delete_topics_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'dialogue');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_misc['Confirm topic delete'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_misc['Delete topics'] ?></strong></legend>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_common['Please confirm'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_confirm" value="1" checked="checked" /> <?php echo $lang_misc['Delete topics comply'] ?></label>
+				</div>
+			</fieldset>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="delete_topics_comply" value="<?php echo $lang_common['Delete'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+// Open or close one or more topics
+else if (isset($_REQUEST['open']) || isset($_REQUEST['close']))
+{
+	$action = (isset($_REQUEST['open'])) ? 0 : 1;
+
+	($hook = get_hook('mr_open_close_topic_selected')) ? eval($hook) : null;
+
+	// There could be an array of topic ID's in $_POST
+	if (isset($_POST['open']) || isset($_POST['close']))
+	{
+		$topics = isset($_POST['topics']) ? @array_map('intval', @array_keys($_POST['topics'])) : array();
+		if (empty($topics))
+			message($lang_misc['No topics selected']);
+
+		$query = array(
+			'UPDATE'	=> 'topics',
+			'SET'		=> 'closed='.$action,
+			'WHERE'		=> 'id IN('.implode(',', $topics).') AND forum_id='.$fid
+		);
+
+		($hook = get_hook('mr_qr_open_close_topics')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		$pun_page['redirect_msg'] = ($action) ? $lang_misc['Close topics redirect'] : $lang_misc['Open topics redirect'];
+		pun_redirect(pun_link($pun_url['moderate_forum'], $fid), $pun_page['redirect_msg']);
+	}
+	// Or just one in $_GET
+	else
+	{
+		$topic_id = ($action) ? intval($_GET['close']) : intval($_GET['open']);
+		if ($topic_id < 1)
+			message($lang_common['Bad request']);
+
+		// We validate the CSRF token. If it's set in POST and we're at this point, the token is valid.
+		// If it's in GET, we need to make sure it's valid.
+		if (!isset($_POST['csrf_token']) && (!isset($_GET['csrf_token']) || $_GET['csrf_token'] !== generate_form_token(($action ? 'close' : 'open').$topic_id)))
+			csrf_confirm_form();
+
+		$query = array(
+			'UPDATE'	=> 'topics',
+			'SET'		=> 'closed='.$action,
+			'WHERE'		=> 'id='.$topic_id.' AND forum_id='.$fid
+		);
+
+		($hook = get_hook('mr_qr_open_close_topic')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		$pun_page['redirect_msg'] = ($action) ? $lang_misc['Close topic redirect'] : $lang_misc['Open topic redirect'];
+		pun_redirect(pun_link($pun_url['topic'], $topic_id), $pun_page['redirect_msg']);
+	}
+}
+
+
+// Stick a topic
+else if (isset($_GET['stick']))
+{
+	$stick = intval($_GET['stick']);
+	if ($stick < 1)
+		message($lang_common['Bad request']);
+
+	// We validate the CSRF token. If it's set in POST and we're at this point, the token is valid.
+	// If it's in GET, we need to make sure it's valid.
+	if (!isset($_POST['csrf_token']) && (!isset($_GET['csrf_token']) || $_GET['csrf_token'] !== generate_form_token('stick'.$stick)))
+		csrf_confirm_form();
+
+	($hook = get_hook('mr_stick_topic_selected')) ? eval($hook) : null;
+
+	$query = array(
+		'UPDATE'	=> 'topics',
+		'SET'		=> 'sticky=1',
+		'WHERE'		=> 'id='.$stick.' AND forum_id='.$fid
+	);
+
+	($hook = get_hook('mr_qr_stick_topic')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	pun_redirect(pun_link($pun_url['topic'], $stick), $lang_misc['Stick topic redirect']);
+}
+
+
+// Unstick a topic
+else if (isset($_GET['unstick']))
+{
+	$unstick = intval($_GET['unstick']);
+	if ($unstick < 1)
+		message($lang_common['Bad request']);
+
+	// We validate the CSRF token. If it's set in POST and we're at this point, the token is valid.
+	// If it's in GET, we need to make sure it's valid.
+	if (!isset($_POST['csrf_token']) && (!isset($_GET['csrf_token']) || $_GET['csrf_token'] !== generate_form_token('unstick'.$unstick)))
+		csrf_confirm_form();
+
+	($hook = get_hook('mr_unstick_topic_selected')) ? eval($hook) : null;
+
+	$query = array(
+		'UPDATE'	=> 'topics',
+		'SET'		=> 'sticky=0',
+		'WHERE'		=> 'id='.$unstick.' AND forum_id='.$fid
+	);
+
+	($hook = get_hook('mr_qr_unstick_topic')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	pun_redirect(pun_link($pun_url['topic'], $unstick), $lang_misc['Unstick topic redirect']);
+}
+
+
+($hook = get_hook('mr_new_action')) ? eval($hook) : null;
+
+
+// No specific forum moderation action was specified in the query string, so we'll display the moderate forum view
+
+// Load the viewforum.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/forum.php';
+
+// Determine the topic offset (based on $_GET['p'])
+$pun_page['num_pages'] = ceil($cur_forum['num_topics'] / $pun_user['disp_topics']);
+
+$pun_page['page'] = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $pun_page['num_pages']) ? 1 : $_GET['p'];
+$pun_page['start_from'] = $pun_user['disp_topics'] * ($pun_page['page'] - 1);
+$pun_page['finish_at'] = min(($pun_page['start_from'] + $pun_user['disp_topics']), ($cur_forum['num_topics']));
+
+// Generate paging links
+$pun_page['page_post'] = '<p class="paging"><strong>'.$lang_common['Pages'].'</strong> '.pun_paginate($pun_page['num_pages'], $pun_page['page'], $pun_url['moderate_forum'], $fid).'</p>';
+
+// Navigation links for header and page numbering for title/meta description
+if ($pun_page['page'] < $pun_page['num_pages'])
+{
+	$pun_page['nav'][] = '<link rel="last" href="'.pun_sublink($pun_url['moderate_forum'], $pun_url['page'], $pun_page['num_pages'], $fid).'" title="'.$lang_common['Page'].' '.$pun_page['num_pages'].'" />';
+	$pun_page['nav'][] = '<link rel="next" href="'.pun_sublink($pun_url['moderate_forum'], $pun_url['page'], ($pun_page['page'] + 1), $fid).'" title="'.$lang_common['Page'].' '.($pun_page['page'] + 1).'" />';
+}
+if ($pun_page['page'] > 1)
+{
+	$pun_page['nav'][] = '<link rel="prev" href="'.pun_sublink($pun_url['moderate_forum'], $pun_url['page'], ($pun_page['page'] - 1), $fid).'" title="'.$lang_common['Page'].' '.($pun_page['page'] - 1).'" />';
+	$pun_page['nav'][] = '<link rel="first" href="'.pun_link($pun_url['moderate_forum'], $fid).'" title="'.$lang_common['Page'].' 1" />';
+}
+
+// Generate page information
+if ($pun_page['num_pages'] > 1)
+	$pun_page['main_info'] = '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_common['Topics'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $cur_forum['num_topics']);
+else
+	$pun_page['main_info'] = (($pun_db->num_rows($result)) ? sprintf($lang_common['Page info'], $lang_common['Topics'], $cur_forum['num_topics']) : $lang_forum['No topics']);
+
+// Setup form
+$pun_page['fld_count'] = 0;
+$pun_page['form_action'] = pun_link($pun_url['moderate_forum'], $fid);
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+	array($cur_forum['forum_name'], pun_link($pun_url['forum'], $fid)),
+	$lang_forum['Moderate forum']
+);
+
+($hook = get_hook('mr_topic_actions_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_PAGE', 'modforum');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main paged">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<form method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+
+	<div class="paged-head">
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+	<div class="main-head">
+		<h2><span><?php echo $pun_page['main_info'] ?></span></h2>
+		<p class="main-options"><?php echo $lang_misc['Select topics'] ?></p>
+	</div>
+
+	<div id="forum<?php echo $fid ?>" class="main-content forum">
+		<div class="hidden">
+			<input type="hidden" name="csrf_token" value="<?php echo generate_form_token($pun_page['form_action']) ?>" />
+		</div>
+		<table cellspacing="0" summary="<?php echo $lang_forum['Table summary mods'].htmlspecialchars($cur_forum['forum_name']) ?>">
+			<thead>
+				<tr>
+					<th class="tcl" scope="col"><?php echo $lang_common['Topic'] ?></th>
+					<th class="tc2" scope="col"><?php echo $lang_common['Replies'] ?></th>
+<?php if ($pun_config['o_topic_views'] == '1'): ?>					<th class="tc3" scope="col"><?php echo $lang_forum['Views'] ?></th>
+<?php endif; ?>					<th class="tcr" scope="col"><?php echo $lang_common['Last post'] ?></th>
+					<th class="tcmod" scope="col"><?php echo $lang_misc['Select'] ?></th>
+				</tr>
+			</thead>
+			<tbody class="statused">
+<?php
+
+// Select topics
+$query = array(
+	'SELECT'	=> 't.id, t.poster, t.subject, t.posted, t.last_post, t.last_post_id, t.last_poster, t.num_views, t.num_replies, t.closed, t.sticky, t.moved_to',
+	'FROM'		=> 'topics AS t',
+	'WHERE'		=> 'forum_id='.$fid,
+	'ORDER BY'	=> 't.sticky DESC, last_post DESC',
+	'LIMIT'		=>	$pun_page['start_from'].', '.$pun_user['disp_topics']
+);
+
+($hook = get_hook('mr_qr_get_topics')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+// If there are topics in this forum.
+if ($pun_db->num_rows($result))
+{
+	$pun_page['button_status'] = '';
+	$pun_page['item_count'] = 0;
+
+	while ($cur_topic = $pun_db->fetch_assoc($result))
+	{
+		++$pun_page['item_count'];
+
+		// Start from scratch
+		$pun_page['item_subject'] = $pun_page['item_status'] = $pun_page['item_last_post'] = $pun_page['item_alt_message'] = $pun_page['item_nav'] = array();
+		$pun_page['item_indicator'] = '';
+		$pun_page['item_alt_message'][] = $lang_common['Topic'].' '.($pun_page['start_from'] + $pun_page['item_count']);
+
+		if ($pun_config['o_censoring'] == '1')
+			$cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+		if ($cur_topic['moved_to'] != null)
+		{
+			$pun_page['item_status'][] = 'moved';
+			$pun_page['item_last_post'][] = $pun_page['item_alt_message'][] = $lang_forum['Moved'];
+			$pun_page['item_subject'][] = '<a href="'.pun_link($pun_url['topic'], array($cur_topic['moved_to'], sef_friendly($cur_topic['subject']))).'">'.htmlspecialchars($cur_topic['subject']).'</a>';
+			$pun_page['item_subject'][] = '<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($cur_topic['poster'])).'</span>';
+			$cur_topic['num_replies'] = $cur_topic['num_views'] = ' - ';
+			$pun_page['ghost_topic'] = true;
+		}
+		else
+		{
+			$pun_page['ghost_topic'] = false;
+
+			if ($cur_topic['sticky'] == '1')
+			{
+				$pun_page['item_subject'][] = $lang_forum['Sticky'];
+				$pun_page['item_status'][] = 'sticky';
+			}
+
+			if ($cur_topic['closed'] == '1')
+			{
+				$pun_page['item_subject'][] = $lang_common['Closed'];
+				$pun_page['item_status'][] = 'closed';
+			}
+
+			$pun_page['item_subject'][] = '<a href="'.pun_link($pun_url['topic'], $cur_topic['id']).'">'.htmlspecialchars($cur_topic['subject']).'</a>';
+
+			$pun_page['item_pages'] = ceil(($cur_topic['num_replies'] + 1) / $pun_user['disp_posts']);
+
+			if ($pun_page['item_pages'] > 1)
+				$pun_page['item_nav'][] = pun_paginate($pun_page['item_pages'], -1, $pun_url['topic'], $cur_topic['id']);
+
+			// Does this topic contains posts we haven't read? If so, tag it accordingly.
+			if ($cur_topic['last_post'] > $pun_user['last_visit'] && (!isset($tracked_topics['topics'][$cur_topic['id']]) || $tracked_topics['topics'][$cur_topic['id']] < $cur_topic['last_post']) && (!isset($tracked_topics['forums'][$pun_page['fid']]) || $tracked_topics['forums'][$pun_page['fid']] < $cur_topic['last_post']) && !$ghost_topic)
+			{
+				$pun_page['item_nav'][] = '<a href="'.pun_link($pun_url['topic_new_posts'], $cur_topic['id']).'" title="'.$lang_forum['New posts info'].'">'.$lang_common['New posts'].'</a>';
+				$pun_page['item_status'][] = 'new';
+			}
+
+			if (!empty($pun_page['item_nav']))
+				$pun_page['item_subject'][] = '<span class="topic-nav">[&#160;'.implode('&#160;&#160;', $pun_page['item_nav']).'&#160;]</span>';
+
+			$pun_page['item_subject'][] = '<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($cur_topic['poster'])).'</span>';
+			$pun_page['item_last_post'][] = '<a href="'.pun_link($pun_url['post'], $cur_topic['last_post_id']).'">'.format_time($cur_topic['last_post']).'</a>';
+			$pun_page['item_last_post'][] = '<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($cur_topic['last_poster'])).'</span>';
+
+			if (empty($pun_page['item_status']))
+				$pun_page['item_status'][] = 'normal';
+
+			$pun_page['subject_label'] = $cur_topic['subject'];
+		}
+
+		$pun_page['item_style'] = (($pun_page['item_count'] % 2 != 0) ? 'odd' : 'even').' '.implode(' ', $pun_page['item_status']);
+		$pun_page['item_indicator'] = '<span class="status '.implode(' ', $pun_page['item_status']).'" title="'.implode(' - ', $pun_page['item_alt_message']).'"><img src="'.$base_url.'/style/'.$pun_user['style'].'/status.png" alt="'.implode(' - ', $pun_page['item_alt_message']).'" />'.$pun_page['item_indicator'].'</span>';
+
+		($hook = get_hook('mr_topic_actions_row_pre_display')) ? eval($hook) : null;
+
+?>
+				<tr class="<?php echo $pun_page['item_style'] ?>">
+					<td class="tcl"><?php echo $pun_page['item_indicator'].' '.implode(' ', $pun_page['item_subject']) ?></td>
+					<td class="tc2"><?php echo (!$pun_page['ghost_topic']) ? $cur_topic['num_replies'] : ' - ' ?></td>
+<?php if ($pun_config['o_topic_views'] == '1'): ?>					<td class="tc3"><?php echo (!$pun_page['ghost_topic']) ? $cur_topic['num_views'] : ' - ' ?></td>
+<?php endif; ?>					<td class="tcr"><?php echo implode(' ', $pun_page['item_last_post']) ?></td>
+					<td class="tcmod"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="checkbox" name="topics[<?php echo $cur_topic['id'] ?>]" value="1" /> <span><?php echo $pun_page['subject_label'] ?></span></label></td>
+				</tr>
+<?php
+
+	}
+}
+else
+{
+	$pun_page['button_status'] = ' disabled="disabled"';
+	$pun_page['item_indicator'] = '<span class="status empty" title="'.$lang_forum['No topics'].'"><img src="'.$base_url.'/style/'.$pun_user['style'].'/status.png" alt="'.$lang_forum['No topics'].'" /></span>';
+
+	($hook = get_hook('mr_topic_actions_forum_empty')) ? eval($hook) : null;
+
+?>
+				<tr class="odd empty">
+					<td class="tcl"><?php echo $pun_page['item_indicator'].' '.$lang_forum['First topic nag'] ?></td>
+					<td class="tc2"> - </td>
+<?php if ($pun_config['o_topic_views'] == '1'): ?>					<td class="tc3"> - </td>
+<?php endif; ?>					<td class="tcr"><?php echo $lang_forum['Never'] ?></td>
+					<td class="tcmod"> - </td>
+				</tr>
+<?php
+
+}
+
+?>
+			</tbody>
+		</table>
+<?php
+
+// Setup moderator control buttons
+$pun_page['main_mod_submit'] = array(
+	'<span class="submit"><input type="submit" name="move_topics" value="'.$lang_misc['Move'].'"'.$pun_page['button_status'].' /></span>',
+	'<span class="submit"><input type="submit" name="delete_topics" value="'.$lang_common['Delete'].'"'.$pun_page['button_status'].' /></span>',
+	'<span class="submit"><input type="submit" name="open" value="'.$lang_misc['Open'].'"'.$pun_page['button_status'].' /></span>',
+	'<span class="submit"><input type="submit" name="close" value="'.$lang_misc['Close'].'"'.$pun_page['button_status'].' /></span>'
+);
+
+($hook = get_hook('mr_topic_actions_post_topic_list')) ? eval($hook) : null;
+
+?>
+	</div>
+
+	<div class="main-foot">
+		<p class="h2"><strong><?php echo $pun_page['main_info'] ?></strong></p>
+	</div>
+
+	<div class="paged-foot">
+		<p class="submitting"><?php echo implode("\n\t\t\t", $pun_page['main_mod_submit'])."\n" ?></p>
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+	</form>
+
+</div>
+
+<div id="pun-crumbs-foot">
+	<p class="crumbs"><?php echo generate_crumbs(false) ?></p>
+</div>
+<?php
+
+($hook = get_hook('mr_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/post.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,633 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('po_start')) ? eval($hook) : null;
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+
+// Load the post.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/post.php';
+
+
+$tid = isset($_GET['tid']) ? intval($_GET['tid']) : 0;
+$fid = isset($_GET['fid']) ? intval($_GET['fid']) : 0;
+if ($tid < 1 && $fid < 1 || $tid > 0 && $fid > 0)
+	message($lang_common['Bad request']);
+
+
+// Fetch some info about the topic and/or the forum
+if ($tid)
+{
+	$query = array(
+		'SELECT'	=> 'f.id, f.forum_name, f.moderators, f.redirect_url, fp.post_replies, fp.post_topics, t.subject, t.closed, s.user_id AS is_subscribed',
+		'FROM'		=> 'topics AS t',
+		'JOINS'		=> array(
+			array(
+				'INNER JOIN'	=> 'forums AS f',
+				'ON'			=> 'f.id=t.forum_id'
+			),
+			array(
+				'LEFT JOIN'		=> 'forum_perms AS fp',
+				'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+			),
+			array(
+				'LEFT JOIN'		=> 'subscriptions AS s',
+				'ON'			=> '(t.id=s.topic_id AND s.user_id='.$pun_user['id'].')'
+			)
+		),
+		'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND t.id='.$tid
+	);
+}
+else
+{
+	$query = array(
+		'SELECT'	=> 'f.id, f.forum_name, f.moderators, f.redirect_url, fp.post_replies, fp.post_topics',
+		'FROM'		=> 'forums AS f',
+		'JOINS'		=> array(
+			array(
+				'LEFT JOIN'		=> 'forum_perms AS fp',
+				'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+			)
+		),
+		'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$fid
+	);
+}
+
+($hook = get_hook('po_qr_get_forum_info')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+if (!$pun_db->num_rows($result))
+	message($lang_common['Bad request']);
+
+$cur_posting = $pun_db->fetch_assoc($result);
+$is_subscribed = $tid && $cur_posting['is_subscribed'];
+
+
+// Is someone trying to post into a redirect forum?
+if ($cur_posting['redirect_url'] != '')
+	message($lang_common['Bad request']);
+
+// Sort out who the moderators are and if we are currently a moderator (or an admin)
+$mods_array = ($cur_posting['moderators'] != '') ? unserialize($cur_posting['moderators']) : array();
+// $pun_user['is_admmod'] = ($session->user_level >= USER_LEVEL_ADMIN || ($pun_user['g_moderator'] == '1' && array_key_exists($pun_user['username'], $mods_array))) ? true : false;
+$pun_user['is_admmod'] = $session->user_level >= USER_LEVEL_MOD || ($pun_user['g_moderator'] == '1' && array_key_exists($pun_user['username'], $mods_array));
+
+// Do we have permission to post?
+if ((($tid && (($cur_posting['post_replies'] == '' && $pun_user['g_post_replies'] == '0') || $cur_posting['post_replies'] == '0')) ||
+	($fid && (($cur_posting['post_topics'] == '' && $pun_user['g_post_topics'] == '0') || $cur_posting['post_topics'] == '0')) ||
+	(isset($cur_posting['closed']) && $cur_posting['closed'] == '1')) &&
+	!$pun_user['is_admmod'])
+	message($lang_common['No permission']);
+
+
+// Start with a clean slate
+$errors = array();
+
+// Did someone just hit "Submit" or "Preview"?
+if (isset($_POST['form_sent']))
+{
+	($hook = get_hook('po_form_submitted')) ? eval($hook) : null;
+
+	// 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 (!$pun_user['is_guest'] && !isset($_POST['preview']) && $pun_user['last_post'] != '' && (time() - $pun_user['last_post']) < $pun_user['g_post_flood'] && (time() - $pun_user['last_post']) >= 0)
+		$errors[] = sprintf($lang_post['Flood'], $pun_user['g_post_flood']);
+
+	// If it's a new topic
+	if ($fid)
+	{
+		$subject = trim($_POST['req_subject']);
+
+		if ($subject == '')
+			$errors[] = $lang_post['No subject'];
+		else if (pun_strlen($subject) > 70)
+			$errors[] = $lang_post['Too long subject'];
+		else if ($pun_config['p_subject_all_caps'] == '0' && strtoupper($subject) == $subject && !$pun_user['is_admmod'])
+			$subject = ucwords(strtolower($subject));
+	}
+
+	// If the user is logged in we get the username and e-mail from $pun_user
+	if (!$pun_user['is_guest'])
+	{
+		$username = $pun_user['username'];
+		$email = $pun_user['email'];
+	}
+	// Otherwise it should be in $_POST
+	else
+	{
+		$username = trim($_POST['req_username']);
+		$email = strtolower(trim(($pun_config['p_force_guest_email'] == '1') ? $_POST['req_email'] : $_POST['email']));
+
+		// Load the profile.php language file
+		require PUN_ROOT.'lang/'.$pun_user['language'].'/profile.php';
+
+		// It's a guest, so we have to validate the username
+		$errors = array_merge($errors, validate_username($username));
+
+		if ($pun_config['p_force_guest_email'] == '1' || $email != '')
+		{
+			require PUN_ROOT.'include/email.php';
+			if (!is_valid_email($email))
+				$errors[] = $lang_common['Invalid e-mail'];
+		}
+	}
+
+	// If we're an administrator or moderator, make sure the CSRF token in $_POST is valid
+	if (($session->user_level >= USER_LEVEL_ADMIN || $pun_user['g_moderator'] == '1') && $_POST['csrf_token'] !== generate_form_token(get_current_url()))
+		$errors[] = $lang_post['CSRF token mismatch'];
+
+	// Clean up message from POST
+	$message = pun_linebreaks(trim($_POST['req_message']));
+
+	if ($message == '')
+		$errors[] = $lang_post['No message'];
+	else if (strlen($message) > 65535)
+		$errors[] = $lang_post['Too long message'];
+	else if ($pun_config['p_message_all_caps'] == '0' && strtoupper($message) == $message && !$pun_user['is_admmod'])
+		$message = ucwords(strtolower($message));
+
+	// Validate BBCode syntax
+	if ($pun_config['p_message_bbcode'] == '1' && strpos($message, '[') !== false && strpos($message, ']') !== false)
+	{
+		require PUN_ROOT.'include/parser.php';
+		$message = preparse_bbcode($message, $errors);
+	}
+
+	$hide_smilies = isset($_POST['hide_smilies']) ? 1 : 0;
+	$subscribe = isset($_POST['subscribe']) ? 1 : 0;
+
+	$now = time();
+
+	// Did everything go according to plan?
+	if (empty($errors) && !isset($_POST['preview']))
+	{
+		($hook = get_hook('po_pre_post_added')) ? eval($hook) : null;
+
+		// If it's a reply
+		if ($tid)
+		{
+			add_post(array(
+					'is_guest'		=>	$pun_user['is_guest'],
+					'poster'		=>	$username,
+					'poster_id'		=>	$pun_user['id'],	// Always 1 for guest posts
+					'poster_email'	=>	($pun_user['is_guest'] && $email != '') ? $email : null,	// Always null for non-guest posts
+					'subject'		=>	$cur_posting['subject'],
+					'message'		=>	$message,
+					'hide_smilies'	=>	$hide_smilies,
+					'posted'		=>	$now,
+					'subscr_action'	=>	($pun_config['o_subscriptions'] == '1' && $subscribe && !$is_subscribed) ? 1 : (($pun_config['o_subscriptions'] == '1' && !$subscribe && $is_subscribed) ? 2 : 0),
+					'topic_id'		=>	$tid,
+					'forum_id'		=>	$cur_posting['id']
+				),
+				$new_pid	// By ref
+			);
+		}
+		// If it's a new topic
+		else if ($fid)
+		{
+			add_topic(array(
+				'is_guest'		=>	$pun_user['is_guest'],
+				'poster'		=>	$username,
+				'poster_id'		=>	$pun_user['id'],	// Always 1 for guest posts
+				'poster_email'	=>	($pun_user['is_guest'] && $email != '') ? $email : null,	// Always null for non-guest posts
+				'subject'		=>	$subject,
+				'message'		=>	$message,
+				'hide_smilies'	=>	$hide_smilies,
+				'posted'		=>	$now,
+				'subscribe'		=>	($pun_config['o_subscriptions'] == '1' && (isset($_POST['subscribe']) && $_POST['subscribe'] == '1')),
+				'forum_id'		=>	$fid
+				),
+				$new_tid,	// By ref
+				$new_pid	// By ref
+			);
+		}
+
+		if (!$pun_user['is_guest'])
+		{
+			// If the posting user is logged in, increment his/her post count
+			$query = array(
+				'UPDATE'	=> 'users',
+				'SET'		=> 'num_posts=num_posts+1, last_post='.$now,
+				'WHERE'		=> 'id='.$pun_user['id'],
+				'PARAMS'	=> array(
+					'LOW_PRIORITY'	=> 1	// MySQL only
+				)
+			);
+
+			($hook = get_hook('po_qr_increment_num_posts')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			// Add/update the topic in our list of tracked topics
+			$tracked_topics = get_tracked_topics();
+			$tracked_topics['topics'][$tid ? $tid : $new_tid] = time();
+			set_tracked_topics($tracked_topics);
+		}
+
+		pun_redirect(pun_link($pun_url['post'], $new_pid), $lang_post['Post redirect']);
+	}
+}
+
+
+// Are we quoting someone?
+if ($tid && isset($_GET['qid']))
+{
+	$qid = intval($_GET['qid']);
+	if ($qid < 1)
+		message($lang_common['Bad request']);
+
+	// Get the quote and quote poster
+	$query = array(
+		'SELECT'	=> 'p.poster, p.message',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'id='.$qid.' AND topic_id='.$tid
+	);
+
+	($hook = get_hook('po_qr_get_quote')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if (!$pun_db->num_rows($result))
+		message($lang_common['Bad request']);
+
+	list($q_poster, $q_message) = $pun_db->fetch_row($result);
+
+	$q_message = str_replace('[img]', '[url]', $q_message);
+	$q_message = str_replace('[/img]', '[/url]', $q_message);
+	$q_message = htmlspecialchars($q_message);
+
+	if ($pun_config['p_message_bbcode'] == '1')
+	{
+		// If username contains a square bracket, we add "" or '' around it (so we know when it starts and ends)
+		if (strpos($q_poster, '[') !== false || strpos($q_poster, ']') !== false)
+		{
+			if (strpos($q_poster, '\'') !== false)
+				$q_poster = '"'.$q_poster.'"';
+			else
+				$q_poster = '\''.$q_poster.'\'';
+		}
+		else
+		{
+			// Get the characters at the start and end of $q_poster
+			$ends = substr($q_poster, 0, 1).substr($q_poster, -1, 1);
+
+			// Deal with quoting "Username" or 'Username' (becomes '"Username"' or "'Username'")
+			if ($ends == '\'\'')
+				$q_poster = '"'.$q_poster.'"';
+			else if ($ends == '""')
+				$q_poster = '\''.$q_poster.'\'';
+		}
+
+		$pun_page['quote'] = '[quote='.$q_poster.']'.$q_message.'[/quote]'."\n";
+	}
+	else
+		$pun_page['quote'] = '> '.sprintf($lang_common['User wrote'], $q_poster).':'."\n\n".'> '.$q_message."\n";
+}
+
+// Setup error messages
+if (!empty($errors))
+{
+	$pun_page['errors'] = array();
+
+	while (list(, $cur_error) = each($errors))
+		$pun_page['errors'][] = '<li class="warn"><span>'.$cur_error.'</span></li>';
+}
+
+// Setup form
+$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+$pun_page['form_action'] = ($tid ? pun_link($pun_url['new_reply'], $tid) : pun_link($pun_url['new_topic'], $fid));
+
+$pun_page['hidden_fields'] = array(
+	'<input type="hidden" name="form_sent" value="1" />',
+	'<input type="hidden" name="form_user" value="'.((!$pun_user['is_guest']) ? htmlspecialchars($pun_user['username']) : 'Guest').'" />'
+);
+if ($pun_user['is_admmod'])
+{
+	$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token(get_current_url()).'" />';
+}
+
+// Setup help
+$pun_page['main_head_options'] = array();
+if ($pun_config['p_message_bbcode'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'bbcode').'" title="'.sprintf($lang_common['Help page'], $lang_common['BBCode']).'"><span>'.$lang_common['BBCode'].'</span></a>';
+if ($pun_config['p_message_img_tag'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'img').'" title="'.sprintf($lang_common['Help page'], $lang_common['Images']).'"><span>'.$lang_common['Images'].'</span></a>';
+if ($pun_config['o_smilies'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'smilies').'" title="'.sprintf($lang_common['Help page'], $lang_common['Smilies']).'"><span>'.$lang_common['Smilies'].'</span></a>';
+
+// Setup breadcrumbs
+$pun_page['crumbs'][] = array($pun_config['o_board_title'], pun_link($pun_url['index']));
+$pun_page['crumbs'][] = array($cur_posting['forum_name'], pun_link($pun_url['forum'], $cur_posting['id']));
+if ($tid) $pun_page['crumbs'][] = array($cur_posting['subject'], pun_link($pun_url['topic'], $tid));
+$pun_page['crumbs'][] = $tid ? $lang_post['Post reply'] : $lang_post['Post new topic'];
+
+($hook = get_hook('po_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_PAGE', 'post');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+<?php
+
+// If preview selected and there are no errors
+if (isset($_POST['preview']) && empty($pun_page['errors']))
+{
+	require_once PUN_ROOT.'include/parser.php';
+	$pun_page['preview_message'] = parse_message(trim($_POST['req_message']), $hide_smilies);
+
+?>
+	<div class="main-head">
+		<h2><span><?php echo $tid ? $lang_post['Preview reply'] : $lang_post['Preview new topic']; ?></span></h2>
+	</div>
+
+	<div id="post-preview" class="main-content topic">
+		<div class="post firstpost">
+			<div class="postmain">
+				<div class="posthead">
+					<h3><?php echo $lang_post['Preview info'] ?></h3>
+				</div>
+				<div class="postbody">
+					<div class="user">
+						<h4 class="user-ident"><strong class="username"><?php echo $pun_user['username'] ?></strong></h4>
+					</div>
+					<div class="post-entry">
+						<div class="entry-content">
+						<?php echo $pun_page['preview_message']."\n" ?>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+<?php
+
+}
+
+?>
+	<div class="main-head">
+		<h2><span><?php echo $lang_post['Compose your'].' '.($tid ? $lang_post['New reply'] : $lang_post['New topic']) ?></span></h2>
+<?php if (!empty($pun_page['main_head_options'])): ?>		<p class="main-options"><?php printf($lang_common['You may use'], implode(' ', $pun_page['main_head_options'])) ?></p>
+<?php endif; ?>	</div>
+
+	<div class="main-content frm">
+<?php
+
+// If there were any errors, show them
+if (isset($pun_page['errors']))
+{
+
+?>
+		<div class="frm-error">
+			<h3 class="warn"><?php echo $lang_post['Post errors'] ?></h3>
+			<ul>
+				<?php echo implode("\n\t\t\t\t\t", $pun_page['errors'])."\n" ?>
+			</ul>
+		</div>
+<?php
+
+}
+
+?>
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php
+
+($hook = get_hook('po_pre_guest_info_fieldset')) ? eval($hook) : null;
+
+if ($pun_user['is_guest'])
+{
+	$pun_page['email_form_name'] = ($pun_config['p_force_guest_email'] == '1') ? 'req_email' : 'email';
+
+?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_post['Guest post legend'] ?></strong></legend>
+<?php ($hook = get_hook('po_guest_info_start')) ? eval($hook) : null; ?>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_post['Guest name'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_username" value="<?php if (isset($_POST['req_username'])) echo htmlspecialchars($username); ?>" size="35" maxlength="25" /></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+<?php ($hook = get_hook('po_post_guest_name_div')) ? eval($hook) : null; ?>
+				<div class="frm-fld text<?php if ($pun_config['p_force_guest_email'] == '1') echo ' required' ?>">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_post['Guest e-mail'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="<?php echo $pun_page['email_form_name'] ?>" value="<?php if (isset($_POST[$pun_page['email_form_name']])) echo htmlspecialchars($email); ?>" size="35" maxlength="80" /></span>
+						<?php if ($pun_config['p_force_guest_email'] == '1') echo '<em class="req-text">'.$lang_common['Required'].'</em>' ?>
+					</label>
+				</div>
+<?php ($hook = get_hook('po_guest_info_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php
+
+}
+
+($hook = get_hook('po_pre_req_info_fieldset')) ? eval($hook) : null;
+
+?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+<?php
+
+($hook = get_hook('po_req_info_fieldset_start')) ? eval($hook) : null;
+
+if ($fid)
+{
+
+?>
+				<div class="frm-fld text required longtext">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_post['Topic subject'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="req_subject" value="<?php if (isset($_POST['req_subject'])) echo htmlspecialchars($subject); ?>" size="80" maxlength="70" /></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+<?php
+
+}
+
+($hook = get_hook('po_pre_post_contents')) ? eval($hook) : null;
+
+?>
+				<div class="frm-fld text textarea required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_post['Write message'] ?></span><br />
+						<span class="fld-input"><textarea id="fld<?php echo $pun_page['fld_count'] ?>" name="req_message" rows="14" cols="95"><?php echo isset($_POST['req_message']) ? htmlspecialchars($message) : (isset($pun_page['quote']) ? $pun_page['quote'] : ''); ?></textarea></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+			</fieldset>
+<?php
+
+$pun_page['checkboxes'] = array();
+if ($pun_config['o_smilies'] == '1')
+	$pun_page['checkboxes'][] = '<div class="radbox"><label for="fld'.(++$pun_page['fld_count']).'"><input type="checkbox" id="fld'.$pun_page['fld_count'].'" name="hide_smilies" value="1"'.(isset($_POST['hide_smilies']) ? ' checked="checked"' : '').' /> '.$lang_post['Hide smilies'].'</label></div>';
+
+// Check/uncheck the checkbox for subscriptions depending on scenario
+if (!$pun_user['is_guest'] && $pun_config['o_subscriptions'] == '1')
+{
+	$subscr_checked = false;
+
+	// If it's a preview
+	if (isset($_POST['preview']))
+		$subscr_checked = isset($_POST['subscribe']) ? true : false;
+	// If auto subscribed
+	else if ($pun_user['auto_notify'])
+		$subscr_checked = true;
+	// If already subscribed to the topic
+	else if ($is_subscribed)
+		$subscr_checked = true;
+
+	$pun_page['checkboxes'][] = '<div class="radbox"><label for="fld'.(++$pun_page['fld_count']).'"><input type="checkbox" id="fld'.$pun_page['fld_count'].'" name="subscribe" value="1"'.($subscr_checked ? ' checked="checked"' : '').' /> '.($is_subscribed ? $lang_post['Stay subscribed'] : $lang_post['Subscribe']).'</label></div>';
+}
+
+($hook = get_hook('po_pre_optional_fieldset')) ? eval($hook) : null;
+
+if (!empty($pun_page['checkboxes']))
+{
+
+?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_post['Optional legend'] ?></strong></legend>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_post['Post settings'] ?></span></legend>
+					<?php echo implode("\n\t\t\t\t\t\t", $pun_page['checkboxes'])."\n"; ?>
+				</fieldset>
+			</fieldset>
+<?php
+
+}
+
+($hook = get_hook('po_post_optional_fieldset')) ? eval($hook) : null;
+
+?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" accesskey="s" title="<?php echo $lang_common['Submit title'] ?>" /></span>
+				<span class="submit"><input type="submit" name="preview" value="<?php echo $lang_common['Preview'] ?>" accesskey="p" title="<?php echo $lang_common['Preview title'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+<?php
+
+
+// Check if the topic review is to be displayed
+if ($tid && $pun_config['o_topic_review'] != '0')
+{
+	require_once PUN_ROOT.'include/parser.php';
+
+	// Get posts to display in topic review
+	$query = array(
+		'SELECT'	=> 'p.id, p.poster, p.message, p.hide_smilies, p.posted',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'topic_id='.$tid,
+		'ORDER BY'	=>	'id DESC',
+		'LIMIT'		=>	$pun_config['o_topic_review']
+	);
+
+	($hook = get_hook('po_qr_get_topic_review_posts')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+?>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_post['Topic review'] ?></span></h2>
+	</div>
+
+	<div class="main-content topic">
+<?php
+
+	$pun_page['item_count'] = 0;
+
+	while ($cur_post = $pun_db->fetch_assoc($result))
+	{
+		++$pun_page['item_count'];
+
+		$pun_page['item_head'] = array(
+			'<strong>'.$pun_page['item_count'].'</strong>',
+			'<cite class="author">'.$lang_common['Posted by'].' '.htmlspecialchars($cur_post['poster']).'</cite>',
+			'<a class="permalink" rel="bookmark" title="'.$lang_post['Permalink post'].'" href="'.pun_link($pun_url['post'], $cur_post['id']).'">'.format_time($cur_post['posted']).'</a>'
+		);
+
+		$pun_page['message'] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
+
+		($hook = get_hook('po_topic_review_row_pre_display')) ? eval($hook) : null;
+
+?>
+		<div class="post<?php echo ($pun_page['item_count'] == 1) ? ' firstpost' : '' ?>">
+			<div class="postmain">
+				<div class="posthead">
+					<h3><?php echo implode(' ', $pun_page['item_head']) ?></h3>
+				</div>
+				<div class="postbody">
+					<div class="user">
+						<h4 class="user-ident"><strong class="username"><?php echo $cur_post['poster'] ?></strong></h4>
+					</div>
+					<div class="post-entry">
+						<div class="entry-content">
+						<?php echo $pun_page['message']."\n" ?>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+<?php
+
+	}
+
+?>
+	</div>
+<?php
+
+}
+
+?>
+</div>
+<?php
+
+($hook = get_hook('po_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/profile.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,2199 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('pf_start')) ? eval($hook) : null;
+
+$action = isset($_GET['action']) ? $_GET['action'] : null;
+$section = isset($_GET['section']) ? $_GET['section'] : 'about';	// Default to section "about"
+$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
+if ($id < 2)
+	message($lang_common['Bad request']);
+
+if ($action != 'change_pass' || !isset($_GET['key']))
+{
+	if ($pun_user['g_read_board'] == '0')
+		message($lang_common['No view']);
+	else if ($pun_user['g_view_users'] == '0' && ($pun_user['is_guest'] || $pun_user['id'] != $id))
+		message($lang_common['No permission']);
+}
+
+// Load the profile.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/profile.php';
+$GLOBALS['lang_profile'] = $lang_profile;
+
+// Fetch info about the user whose profile we're viewing
+$query = array(
+	'SELECT'	=> 'u.*, eu.username, g.g_id, g.g_user_title, g.g_moderator',
+	'FROM'		=> $pun_db->prefix . 'users AS u',
+	'JOINS'		=> array(
+		array(
+			'LEFT JOIN'	=> $pun_db->prefix . 'groups AS g',
+			'ON'		=> 'g.g_id=u.group_id'
+		),
+    array(
+       'LEFT JOIN' => table_prefix . 'users AS eu',
+       'ON'        => 'eu.user_id = u.id'
+    )
+	),
+	'WHERE'		=> 'u.id='.$id,
+  'PARAMS' => array(
+    'NO_PREFIX' => ''
+  )
+);
+
+($hook = get_hook('pf_qr_get_user_info')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+if (!$pun_db->num_rows($result))
+	message($lang_common['Bad request']);
+
+$user = $pun_db->fetch_assoc($result);
+
+
+if ($action == 'change_pass')
+{
+	($hook = get_hook('pf_change_pass_selected')) ? eval($hook) : null;
+
+	// User pressed the cancel button
+	if (isset($_POST['cancel']))
+		pun_redirect(pun_link($pun_url['profile_about'], $id), $lang_common['Cancel redirect']);
+
+	if (isset($_GET['key']))
+	{
+		// If the user is already logged in we shouldn't be here :)
+		if (!$pun_user['is_guest'])
+			message($lang_profile['Pass logout']);
+
+		($hook = get_hook('pf_change_pass_key_supplied')) ? eval($hook) : null;
+
+		$key = $_GET['key'];
+
+		if ($key == '' || $key != $user['activate_key'])
+			message(sprintf($lang_profile['Pass key bad'], '<a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>'));
+		else
+		{
+			if (isset($_POST['form_sent']))
+			{
+				($hook = get_hook('pf_change_pass_key_form_submitted')) ? eval($hook) : null;
+
+				$new_password1 = trim($_POST['req_new_password1']);
+				$new_password2 = trim($_POST['req_new_password2']);
+
+				if ($new_password1 != $new_password2)
+					message($lang_profile['Pass not match']);
+				if (pun_strlen($new_password1) < 4)
+					message($lang_profile['Pass too short']);
+
+				$new_password_hash = sha1($user['salt'].sha1($new_password1));
+
+				$query = array(
+					'UPDATE'	=> 'users',
+					'SET'		=> 'password=\''.$new_password_hash.'\', activate_key=NULL',
+					'WHERE'		=> 'id='.$id
+				);
+
+				($hook = get_hook('pf_qr_update_password')) ? eval($hook) : null;
+				$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+				pun_redirect(pun_link($pun_url['index']), $lang_profile['Pass updated']);
+			}
+
+			// Setup form
+			$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+			$pun_page['form_action'] = pun_link($pun_url['change_password_key'], array($id, $key));
+
+			// Setup breadcrumbs
+			$pun_page['crumbs'] = array(
+				array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+				array(sprintf($lang_profile['Users profile'], htmlspecialchars($user['username']), $lang_profile['Section about']), pun_link($pun_url['profile_about'], $id)),
+				$lang_profile['Change password']
+			);
+
+			($hook = get_hook('pf_change_pass_key_pre_header_load')) ? eval($hook) : null;
+
+			define('PUN_PAGE', 'profile-changepass');
+			require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php printf($lang_profile['Users profile'], htmlspecialchars($user['username'])) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_profile['Change password'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<input type="hidden" name="form_sent" value="1" />
+			</div>
+<?php ($hook = get_hook('pf_change_pass_key_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['New password'] ?></span><br />
+						<span class="fld-input"><input type="password" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_new_password1" size="35" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Password help'] ?></span>
+					</label>
+				</div>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Confirm new password'] ?></span><br />
+						<span class="fld-input"><input type="password" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_new_password2" size="35" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Confirm password help'] ?></span>
+					</label>
+				</div>
+			</fieldset>
+<?php ($hook = get_hook('pf_change_pass_key_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="update" value="<?php echo $lang_common['Submit'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+			require PUN_ROOT.'footer.php';
+		}
+	}
+
+	// Make sure we are allowed to change this user's password
+	if ($pun_user['id'] != $id &&
+		$pun_user['g_id'] != PUN_ADMIN &&
+		($pun_user['g_moderator'] != '1' || $pun_user['g_mod_edit_users'] == '0' || $pun_user['g_mod_change_passwords'] == '0' || $user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1'))
+		message($lang_common['No permission']);
+
+	if (isset($_POST['form_sent']))
+	{
+		($hook = get_hook('pf_change_pass_normal_form_submitted')) ? eval($hook) : null;
+
+		$old_password = isset($_POST['req_old_password']) ? trim($_POST['req_old_password']) : '';
+		$new_password1 = trim($_POST['req_new_password1']);
+		$new_password2 = trim($_POST['req_new_password2']);
+
+		if ($new_password1 != $new_password2)
+			message($lang_profile['Pass not match']);
+		if (pun_strlen($new_password1) < 4)
+			message($lang_profile['Pass too short']);
+
+		$pun_page['authorized'] = false;
+		if (!empty($user['password']))
+		{
+			$old_password_hash = sha1($user['salt'].sha1($old_password));
+
+			if (($user['password'] == $old_password_hash) || $pun_user['is_admmod'])
+				$authorized = true;
+		}
+
+		if (!$authorized)
+			message($lang_profile['Wrong old password']);
+
+		$new_password_hash = sha1($user['salt'].sha1($new_password1));
+
+		$query = array(
+			'UPDATE'	=> 'users',
+			'SET'		=> 'password=\''.$new_password_hash.'\'',
+			'WHERE'		=> 'id='.$id
+		);
+
+		($hook = get_hook('pf_qr_update_password2')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		if ($pun_user['id'] == $id)
+		{
+			$expire = ($user['save_pass'] == '1') ? time() + 31536000 : 0;
+			pun_setcookie($cookie_name, base64_encode($pun_user['id'].'|'.$new_password_hash), $expire);
+		}
+
+		pun_redirect(pun_link($pun_url['profile_about'], $id), $lang_profile['Pass updated redirect']);
+	}
+
+	// Setup form
+	$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+	$pun_page['form_action'] = pun_link($pun_url['change_password'], $id);
+
+	$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+	if ($pun_user['is_admmod'])
+		$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		array(sprintf($lang_profile['Users profile'], htmlspecialchars($user['username']), $lang_profile['Section about']), pun_link($pun_url['profile_about'], $id)),
+		$lang_profile['Change password']
+	);
+
+	($hook = get_hook('pf_change_pass_normal_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'profile-changepass');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main sectioned">
+
+	<h1><span><?php printf($lang_profile['Users profile'], htmlspecialchars($user['username'])) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_profile['Change password'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action']  ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('pf_change_pass_normal_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+<?php if (!$pun_user['is_admmod']): ?>					<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Old password'] ?></span><br />
+						<span class="fld-input"><input type="password" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_old_password" size="35" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Old password help'] ?></span>
+					</label>
+				</div>
+<?php endif; ?>				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['New password'] ?></span><br />
+						<span class="fld-input"><input type="password" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_new_password1" size="35" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Password help'] ?></span>
+					</label>
+				</div>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Confirm new password'] ?></span><br />
+						<span class="fld-input"><input type="password" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_new_password2" size="35" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Confirm password help'] ?></span>
+					</label>
+				</div>
+			</fieldset>
+<?php ($hook = get_hook('pf_change_pass_normal_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="update" value="<?php echo $lang_common['Submit'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+else if ($action == 'change_email')
+{
+	// Make sure we are allowed to change this user's e-mail
+	if ($pun_user['id'] != $id &&
+		$pun_user['g_id'] != PUN_ADMIN &&
+		($pun_user['g_moderator'] != '1' || $pun_user['g_mod_edit_users'] == '0' || $user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1'))
+		message($lang_common['No permission']);
+
+	($hook = get_hook('pf_change_email_selected')) ? eval($hook) : null;
+
+	// User pressed the cancel button
+	if (isset($_POST['cancel']))
+		pun_redirect(pun_link($pun_url['profile_about'], $id), $lang_common['Cancel redirect']);
+
+	if (isset($_GET['key']))
+	{
+		$key = $_GET['key'];
+
+		($hook = get_hook('pf_change_email_key_supplied')) ? eval($hook) : null;
+
+		if ($key == '' || $key != $user['activate_key'])
+			message(sprintf($lang_profile['E-mail key bad'], '<a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>'));
+		else
+		{
+			$query = array(
+				'UPDATE'	=> 'users',
+				'SET'		=> 'email=activate_string, activate_string=NULL, activate_key=NULL',
+				'WHERE'		=> 'id='.$id
+			);
+
+			($hook = get_hook('pf_qr_update_email')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			message($lang_profile['E-mail updated']);
+		}
+	}
+	else if (isset($_POST['form_sent']))
+	{
+		($hook = get_hook('pf_change_email_normal_form_submitted')) ? eval($hook) : null;
+
+		if (sha1($_POST['req_password']) !== $pun_user['password'])
+			message($lang_profile['Wrong password']);
+
+		require PUN_ROOT.'include/email.php';
+
+		// Validate the email-address
+		$new_email = strtolower(trim($_POST['req_new_email']));
+		if (!is_valid_email($new_email))
+			message($lang_common['Invalid e-mail']);
+
+		// Check it it's a banned e-mail address
+		if (is_banned_email($new_email))
+		{
+			($hook = get_hook('pf_change_email_normal_banned_email')) ? eval($hook) : null;
+
+			if ($pun_config['p_allow_banned_email'] == '0')
+				message($lang_profile['Banned e-mail']);
+			else if ($pun_config['o_mailing_list'] != '')
+			{
+				$mail_subject = 'Alert - Banned e-mail detected';
+				$mail_message = 'User \''.$pun_user['username'].'\' changed to banned e-mail address: '.$new_email."\n\n".'User profile: '.pun_link($pun_url['user'], $id)."\n\n".'-- '."\n".'Forum Mailer'."\n".'(Do not reply to this message)';
+
+				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
+			}
+		}
+
+		// Check if someone else already has registered with that e-mail address
+		$query = array(
+			'SELECT'	=> 'u.id, u.username',
+			'FROM'		=> 'users AS u',
+			'WHERE'		=> 'u.email=\''.$pun_db->escape($new_email).'\''
+		);
+
+		($hook = get_hook('pf_qr_check_email_dupe')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if ($pun_db->num_rows($result))
+		{
+			($hook = get_hook('pf_change_email_normal_dupe_email')) ? eval($hook) : null;
+
+			if ($pun_config['p_allow_dupe_email'] == '0')
+				message($lang_profile['Dupe e-mail']);
+			else if ($pun_config['o_mailing_list'] != '')
+			{
+				while ($cur_dupe = $pun_db->fetch_assoc($result))
+					$dupe_list[] = $cur_dupe['username'];
+
+				$mail_subject = 'Alert - Duplicate e-mail detected';
+				$mail_message = 'User \''.$pun_user['username'].'\' changed to an e-mail address that also belongs to: '.implode(', ', $dupe_list)."\n\n".'User profile: '.pun_link($pun_url['user'], $id)."\n\n".'-- '."\n".'Forum Mailer'."\n".'(Do not reply to this message)';
+
+				pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
+			}
+		}
+
+		$new_email_key = random_key(8, true);
+
+		// Save new e-mail and activation key
+		$query = array(
+			'UPDATE'	=> 'users',
+			'SET'		=> 'activate_string=\''.$pun_db->escape($new_email).'\', activate_key=\''.$new_email_key.'\'',
+			'WHERE'		=> 'id='.$id
+		);
+
+		($hook = get_hook('pf_qr_update_email_activation')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		// Load the "activate e-mail" template
+		$mail_tpl = trim(file_get_contents(PUN_ROOT.'lang/'.$pun_user['language'].'/mail_templates/activate_email.tpl'));
+
+		// The first row contains the subject
+		$first_crlf = strpos($mail_tpl, "\n");
+		$mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8));
+		$mail_message = trim(substr($mail_tpl, $first_crlf));
+
+		$mail_message = str_replace('<username>', $pun_user['username'], $mail_message);
+		$mail_message = str_replace('<base_url>', $base_url.'/', $mail_message);
+		$mail_message = str_replace('<activation_url>', str_replace('&amp;', '&', pun_link($pun_url['change_email_key'], array($id, $new_email_key))), $mail_message);
+		$mail_message = str_replace('<board_mailer>', sprintf($lang_common['Forum mailer'], $pun_config['o_board_title']), $mail_message);
+
+		($hook = get_hook('pf_change_email_normal_pre_activation_email_sent')) ? eval($hook) : null;
+
+		pun_mail($new_email, $mail_subject, $mail_message);
+
+		message(sprintf($lang_profile['Activate e-mail sent'], '<a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>'));
+	}
+
+	// Setup form
+	$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+	$pun_page['form_action'] = pun_link($pun_url['change_email'], $id);
+
+	$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+	if ($pun_user['is_admmod'])
+		$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+	// Setup form information
+	$pun_page['frm_info'] = '<p class="important"><span>'.$lang_profile['E-mail info'].'</span></p>';
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		array(sprintf($lang_profile['Users profile'], htmlspecialchars($user['username']), $lang_profile['Section about']), pun_link($pun_url['profile_about'], $id)),
+		$lang_profile['Change e-mail']
+	);
+
+	($hook = get_hook('pf_change_email_normal_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'profile-changemail');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php printf($lang_profile['Users profile'], htmlspecialchars($user['username'])) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_profile['Change e-mail'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="frm-info">
+			<?php echo $pun_page['frm_info']."\n" ?>
+		</div>
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('pf_change_email_normal_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['New e-mail'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_new_email" size="50" maxlength="80" /></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Password'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_password" size="25" /></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+			</fieldset>
+<?php ($hook = get_hook('pf_change_email_normal_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="update" value="<?php echo $lang_common['Submit'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+else if ($action == 'delete_user' || isset($_POST['delete_user_comply']) || isset($_POST['cancel']))
+{
+	// User pressed the cancel button
+	if (isset($_POST['cancel']))
+		pun_redirect(pun_link($pun_url['profile_admin'], $id), $lang_common['Cancel redirect']);
+
+	($hook = get_hook('pf_delete_user_selected')) ? eval($hook) : null;
+
+	if ($pun_user['g_id'] != PUN_ADMIN)
+		message($lang_common['No permission']);
+
+	if ($user['g_id'] == PUN_ADMIN)
+		message('Administrators cannot be deleted. In order to delete this user, you must first move him/her to a different user group.');
+
+	if (isset($_POST['delete_user_comply']))
+	{
+		($hook = get_hook('pf_delete_user_form_submitted')) ? eval($hook) : null;
+
+		delete_user($id);
+
+		pun_redirect(pun_link($pun_url['index']), $lang_profile['User delete redirect']);
+	}
+
+	// Setup form
+	$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+	$pun_page['form_action'] = pun_link($pun_url['delete_user'], $id);
+
+	// Setup form information
+	$pun_page['frm_info'] = array(
+		'<li class="warn"><span>'.$lang_profile['Delete warning'].'</span></li>',
+		'<li class="warn"><span>'.$lang_profile['Delete posts info'].'</span></li>'
+	);
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		array(sprintf($lang_profile['Users profile'], htmlspecialchars($user['username']), $lang_profile['Section admin']), pun_link($pun_url['profile_admin'], $id)),
+		$lang_profile['Delete user']
+	);
+
+	($hook = get_hook('pf_delete_user_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'dialogue');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php printf($lang_profile['Users profile'], htmlspecialchars($user['username'])) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_common['Delete'].' '.htmlspecialchars($user['username']) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="frm-info">
+			<ul>
+				<?php echo implode("\n\t\t\t\t\t", $pun_page['frm_info'])."\n" ?>
+			</ul>
+		</div>
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<input type="hidden" name="csrf_token" value="<?php echo generate_form_token($pun_page['form_action']) ?>" />
+			</div>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_profile['Delete posts'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="delete_posts" value="1" checked="checked" /> <?php printf($lang_profile['Delete posts label'], htmlspecialchars($user['username'])) ?></label>
+				</div>
+			</fieldset>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="delete_user_comply" value="<?php echo $lang_common['Submit'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+else if ($action == 'delete_avatar')
+{
+	// Make sure we are allowed to delete this user's avatar
+	if ($pun_user['id'] != $id &&
+		$pun_user['g_id'] != PUN_ADMIN &&
+		($pun_user['g_moderator'] != '1' || $pun_user['g_mod_edit_users'] == '0' || $user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1'))
+		message($lang_common['No permission']);
+
+	($hook = get_hook('pf_delete_avatar_selected')) ? eval($hook) : null;
+
+	if (file_exists($pun_config['o_avatars_dir'].'/'.$id.'.jpg'))
+		@unlink($pun_config['o_avatars_dir'].'/'.$id.'.jpg');
+	if (file_exists($pun_config['o_avatars_dir'].'/'.$id.'.png'))
+		@unlink($pun_config['o_avatars_dir'].'/'.$id.'.png');
+	if (file_exists($pun_config['o_avatars_dir'].'/'.$id.'.gif'))
+		@unlink($pun_config['o_avatars_dir'].'/'.$id.'.gif');
+
+	pun_redirect(pun_link($pun_url['profile_avatar'], $id), $lang_profile['Avatar deleted redirect']);
+}
+
+
+else if (isset($_POST['update_group_membership']))
+{
+	if ($pun_user['g_id'] != PUN_ADMIN)
+		message($lang_common['No permission']);
+
+	($hook = get_hook('pf_change_group_form_submitted')) ? eval($hook) : null;
+
+	$new_group_id = intval($_POST['group_id']);
+
+	$query = array(
+		'UPDATE'	=> 'users',
+		'SET'		=> 'group_id='.$new_group_id,
+		'WHERE'		=> 'id='.$id
+	);
+
+	($hook = get_hook('pf_qr_update_group')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+	$query = array(
+		'SELECT'	=> 'g.g_moderator',
+		'FROM'		=> 'groups AS g',
+		'WHERE'		=> 'g.g_id='.$new_group_id
+	);
+
+	($hook = get_hook('pf_qr_check_new_group_mod')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$new_group_mod = $pun_db->result($result);
+
+	// If the user was a moderator or an administrator (and no longer is), we remove him/her from the moderator list in all forums
+	if (($user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1') && $new_group_id != PUN_ADMIN && $new_group_mod != '1')
+		clean_forum_moderators();
+
+	pun_redirect(pun_link($pun_url['profile_admin'], $id), $lang_profile['Group membership redirect']);
+}
+
+
+else if (isset($_POST['update_forums']))
+{
+	if ($pun_user['g_id'] != PUN_ADMIN)
+		message($lang_common['No permission']);
+
+	($hook = get_hook('pf_forum_moderators_form_submitted')) ? eval($hook) : null;
+
+	$moderator_in = (isset($_POST['moderator_in'])) ? array_keys($_POST['moderator_in']) : array();
+
+	// Loop through all forums
+	$query = array(
+		'SELECT'	=> 'f.id, f.moderators',
+		'FROM'		=> 'forums AS f'
+	);
+
+	($hook = get_hook('pf_qr_get_all_forum_mods')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	while ($cur_forum = $pun_db->fetch_assoc($result))
+	{
+		$cur_moderators = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array();
+
+		// If the user should have moderator access (and he/she doesn't already have it)
+		if (in_array($cur_forum['id'], $moderator_in) && !in_array($id, $cur_moderators))
+		{
+			$cur_moderators[$user['username']] = $id;
+			ksort($cur_moderators);
+		}
+		// If the user shouldn't have moderator access (and he/she already has it)
+		else if (!in_array($cur_forum['id'], $moderator_in) && in_array($id, $cur_moderators))
+			unset($cur_moderators[$user['username']]);
+
+		$cur_moderators = (!empty($cur_moderators)) ? '\''.$pun_db->escape(serialize($cur_moderators)).'\'' : 'NULL';
+
+		$query = array(
+			'UPDATE'	=> 'forums',
+			'SET'		=> 'moderators='.$cur_moderators,
+			'WHERE'		=> 'id='.$cur_forum['id']
+		);
+
+		($hook = get_hook('pf_qr_update_forum_moderators')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+	}
+
+	pun_redirect(pun_link($pun_url['profile_admin'], $id), $lang_profile['Update forums redirect']);
+}
+
+
+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']);
+
+	($hook = get_hook('pf_ban_user_selected')) ? eval($hook) : null;
+
+	pun_redirect(pun_link($pun_url['admin_bans']).'&add_ban='.$id, $lang_profile['Ban redirect']);
+}
+
+
+else if (isset($_POST['form_sent']))
+{
+	// Make sure we are allowed to edit this user's profile
+	if ($pun_user['id'] != $id &&
+		$pun_user['g_id'] != PUN_ADMIN &&
+		($pun_user['g_moderator'] != '1' || $pun_user['g_mod_edit_users'] == '0' || $user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1'))
+		message($lang_common['No permission']);
+
+	($hook = get_hook('pf_change_details_form_submitted')) ? eval($hook) : null;
+
+	// Extract allowed elements from $_POST['form']
+	function extract_elements($allowed_elements)
+	{
+		$form = array();
+
+		while (list($key, $value) = @each($_POST['form']))
+		{
+			if (in_array($key, $allowed_elements))
+				$form[$key] = $value;
+		}
+
+		return $form;
+	}
+
+	$username_updated = false;
+
+	// Validate input depending on section
+	switch ($section)
+	{
+		case 'identity':
+		{
+			$form = extract_elements(array('realname', 'url', 'location', 'jabber', 'icq', 'msn', 'aim', 'yahoo'));
+
+			($hook = get_hook('pf_change_details_identity_validation')) ? eval($hook) : null;
+
+			if ($pun_user['is_admmod'])
+			{
+				// Are we allowed to change usernames?
+				if ($session->user_level >= USER_LEVEL_ADMIN || ($pun_user['g_moderator'] == '1' && $pun_user['g_mod_rename_users'] == '1'))
+				{
+					$form['username'] = trim($_POST['req_username']);
+					$old_username = trim($_POST['old_username']);
+
+					// Validate the new username
+					$errors = validate_username($form['username'], $id);
+					if (!empty($errors))
+						message(current($errors));
+
+					if ($form['username'] != $old_username)
+						$username_updated = true;
+				}
+
+				// We only allow administrators to update the post count
+				if ($session->user_level >= USER_LEVEL_ADMIN)
+					$form['num_posts'] = intval($_POST['num_posts']);
+			}
+
+			if ($pun_config['o_regs_verify'] == '0' || $pun_user['is_admmod'])
+			{
+				require PUN_ROOT.'include/email.php';
+
+				// Validate the email-address
+				$form['email'] = strtolower(trim($_POST['req_email']));
+				if (!is_valid_email($form['email']))
+					message($lang_common['Invalid e-mail']);
+			}
+
+			if ($pun_user['is_admmod'])
+				$form['admin_note'] = trim($_POST['admin_note']);
+
+			if ($session->user_level >= USER_LEVEL_ADMIN)
+				$form['title'] = trim($_POST['title']);
+			else if ($pun_user['g_set_title'] == '1')
+			{
+				$form['title'] = trim($_POST['title']);
+
+				if ($form['title'] != '')
+				{
+					// A list of words that the title may not contain
+					// If the language is English, there will be some duplicates, but it's not the end of the world
+					$forbidden = array('Member', 'Moderator', 'Administrator', 'Banned', 'Guest', $lang_common['Member'], $lang_common['Moderator'], $lang_common['Administrator'], $lang_common['Banned'], $lang_common['Guest']);
+
+					if (in_array($form['title'], $forbidden))
+						message($lang_profile['Forbidden title']);
+				}
+			}
+
+			// Add http:// if the URL doesn't contain it already
+			if ($form['url'] != '' && strpos(strtolower($form['url']), 'http://') !== 0)
+				$form['url'] = 'http://'.$form['url'];
+
+			// If the ICQ UIN contains anything other than digits it's invalid
+			if ($form['icq'] != '' && !ctype_digit($form['icq']))
+				message($lang_profile['Bad ICQ']);
+
+			break;
+		}
+
+		case 'settings':
+		{
+			$form = extract_elements(array('dst', 'timezone', 'language', 'email_setting', 'save_pass', 'notify_with_post', 'auto_notify', 'time_format', 'date_format', 'disp_topics', 'disp_posts', 'show_smilies', 'show_img', 'show_img_sig', 'show_avatars', 'show_sig', 'style'));
+
+			($hook = get_hook('pf_change_details_settings_validation')) ? eval($hook) : null;
+
+			$form['dst'] = (isset($form['dst'])) ? 1 : 0;
+			$form['time_format'] = (isset($form['time_format'])) ? intval($form['time_format']) : 0;
+			$form['date_format'] = (isset($form['date_format'])) ? intval($form['date_format']) : 0;
+
+			$form['email_setting'] = intval($form['email_setting']);
+			if ($form['email_setting'] < 0 && $form['email_setting'] > 2) $form['email_setting'] = 1;
+
+			if (!isset($form['save_pass']) || $form['save_pass'] != '1') $form['save_pass'] = '0';
+			if (!isset($form['notify_with_post']) || $form['notify_with_post'] != '1') $form['notify_with_post'] = '0';
+			if (!isset($form['auto_notify']) || $form['auto_notify'] != '1') $form['auto_notify'] = '0';
+
+			// If the save_pass setting has changed, we need to set a new cookie with the appropriate expire date
+			if ($pun_user['id'] == $id && $form['save_pass'] != $pun_user['save_pass'])
+				pun_setcookie($cookie_name, base64_encode($id.'|'.$user['password']), ($form['save_pass'] == '1') ? time() + 31536000 : 0);
+
+			// Make sure we got a valid language string
+			if (isset($form['language']))
+			{
+				$form['language'] = preg_replace('#[\.\\\/]#', '', $form['language']);
+				if (!file_exists(PUN_ROOT.'lang/'.$form['language'].'/common.php'))
+					message($lang_common['Bad request']);
+			}
+
+			if ($form['disp_topics'] != '' && intval($form['disp_topics']) < 3) $form['disp_topics'] = 3;
+			if ($form['disp_topics'] != '' && intval($form['disp_topics']) > 75) $form['disp_topics'] = 75;
+			if ($form['disp_posts'] != '' && intval($form['disp_posts']) < 3) $form['disp_posts'] = 3;
+			if ($form['disp_posts'] != '' && intval($form['disp_posts']) > 75) $form['disp_posts'] = 75;
+
+			if (!isset($form['show_smilies']) || $form['show_smilies'] != '1') $form['show_smilies'] = '0';
+			if (!isset($form['show_img']) || $form['show_img'] != '1') $form['show_img'] = '0';
+			if (!isset($form['show_img_sig']) || $form['show_img_sig'] != '1') $form['show_img_sig'] = '0';
+			if (!isset($form['show_avatars']) || $form['show_avatars'] != '1') $form['show_avatars'] = '0';
+			if (!isset($form['show_sig']) || $form['show_sig'] != '1') $form['show_sig'] = '0';
+
+			// Make sure we got a valid style string
+			if (isset($form['style']))
+			{
+				$form['style'] = preg_replace('#[\.\\\/]#', '', $form['style']);
+				if (!file_exists(PUN_ROOT.'style/'.$form['style'].'/'.$form['style'].'.css'))
+					message($lang_common['Bad request']);
+			}
+			break;
+		}
+
+		case 'signature':
+		{
+			if ($pun_config['o_signatures'] == '0')
+				message($lang_profile['Signatures disabled']);
+
+			($hook = get_hook('pf_change_details_signature_validation')) ? eval($hook) : null;
+
+			// Clean up signature from POST
+			$form['signature'] = pun_linebreaks(trim($_POST['signature']));
+
+			// Validate signature
+			if (pun_strlen($form['signature']) > $pun_config['p_sig_length'])
+				message(sprintf($lang_profile['Sig too long'], $pun_config['p_sig_length']));
+			else if (substr_count($form['signature'], "\n") > ($pun_config['p_sig_lines'] - 1))
+				message(sprintf($lang_profile['Sig too many lines'], $pun_config['p_sig_lines']));
+			else if ($form['signature'] && $pun_config['p_sig_all_caps'] == '0' && strtoupper($form['signature']) == $form['signature'] && !$pun_user['is_admmod'])
+				$form['signature'] = ucwords(strtolower($form['signature']));
+
+			// Validate BBCode syntax
+			if ($pun_config['p_sig_bbcode'] == '1' && strpos($form['signature'], '[') !== false && strpos($form['signature'], ']') !== false)
+			{
+				require PUN_ROOT.'include/parser.php';
+				$form['signature'] = preparse_bbcode($form['signature'], $foo, true);
+			}
+
+			break;
+		}
+
+		case 'avatar':
+		{
+			if ($pun_config['o_avatars'] == '0')
+				message($lang_profile['Avatars disabled']);
+
+			($hook = get_hook('pf_change_details_avatar_validation')) ? eval($hook) : null;
+
+			if (!isset($_FILES['req_file']))
+				message($lang_profile['No file']);
+
+			$uploaded_file = $_FILES['req_file'];
+
+			// Make sure the upload went smooth
+			if (isset($uploaded_file['error']))
+			{
+				switch ($uploaded_file['error'])
+				{
+					case 1:	// UPLOAD_ERR_INI_SIZE
+					case 2:	// UPLOAD_ERR_FORM_SIZE
+						message($lang_profile['Too large ini']);
+						break;
+
+					case 3:	// UPLOAD_ERR_PARTIAL
+						message($lang_profile['Partial upload']);
+						break;
+
+					case 4:	// UPLOAD_ERR_NO_FILE
+						message($lang_profile['No file']);
+						break;
+
+					case 6:	// UPLOAD_ERR_NO_TMP_DIR
+						message($lang_profile['No tmp directory']);
+						break;
+
+					default:
+						// No error occured, but was something actually uploaded?
+						if ($uploaded_file['size'] == 0)
+							message($lang_profile['No file']);
+						break;
+				}
+			}
+
+			if (is_uploaded_file($uploaded_file['tmp_name']))
+			{
+				$allowed_types = array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png');
+				if (!in_array($uploaded_file['type'], $allowed_types))
+					message($lang_profile['Bad type']);
+
+				// Make sure the file isn't too big
+				if ($uploaded_file['size'] > $pun_config['o_avatars_size'])
+					message(sprintf($lang_profile['Too large'], $pun_config['o_avatars_size']));
+
+				// Determine type
+				$extensions = null;
+				if ($uploaded_file['type'] == 'image/gif')
+					$extensions = array('.gif', '.jpg', '.png');
+				else if ($uploaded_file['type'] == 'image/jpeg' || $uploaded_file['type'] == 'image/pjpeg')
+					$extensions = array('.jpg', '.gif', '.png');
+				else
+					$extensions = array('.png', '.gif', '.jpg');
+
+				// Move the file to the avatar directory. We do this before checking the width/height to circumvent open_basedir restrictions.
+				if (!@move_uploaded_file($uploaded_file['tmp_name'], $pun_config['o_avatars_dir'].'/'.$id.'.tmp'))
+					message(sprintf($lang_profile['Move failed'], '<a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>'));
+
+				// Now check the width/height
+				list($width, $height, $type,) = getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.tmp');
+				if (empty($width) || empty($height) || $width > $pun_config['o_avatars_width'] || $height > $pun_config['o_avatars_height'])
+				{
+					@unlink($pun_config['o_avatars_dir'].'/'.$id.'.tmp');
+					message(sprintf($lang_profile['Too wide or high'], $pun_config['o_avatars_width'], $pun_config['o_avatars_height']));
+				}
+				else if ($type == 1 && $uploaded_file['type'] != 'image/gif')	// Prevent dodgy uploads
+				{
+					@unlink($pun_config['o_avatars_dir'].'/'.$id.'.tmp');
+					message($lang_profile['Bad type']);
+				}
+
+				// Delete any old avatars
+				if (file_exists($pun_config['o_avatars_dir'].'/'.$id.$extensions[0]))
+					@unlink($pun_config['o_avatars_dir'].'/'.$id.$extensions[0]);
+				if (file_exists($pun_config['o_avatars_dir'].'/'.$id.$extensions[1]))
+					@unlink($pun_config['o_avatars_dir'].'/'.$id.$extensions[1]);
+				if (file_exists($pun_config['o_avatars_dir'].'/'.$id.$extensions[2]))
+					@unlink($pun_config['o_avatars_dir'].'/'.$id.$extensions[2]);
+
+				// Put the new avatar in its place
+				@rename($pun_config['o_avatars_dir'].'/'.$id.'.tmp', $pun_config['o_avatars_dir'].'/'.$id.$extensions[0]);
+				@chmod($pun_config['o_avatars_dir'].'/'.$id.$extensions[0], 0644);
+			}
+			else
+				message($lang_profile['Unknown failure']);
+
+			break;
+		}
+
+		default:
+		{
+			($hook = get_hook('pf_change_details_new_section_validation')) ? eval($hook) : null;
+			break;
+		}
+	}
+
+	// All sections apart from avatar potentially affect the database
+	if ($section != 'avatar')
+	{
+		($hook = get_hook('pf_change_details_database_validation')) ? eval($hook) : null;
+
+		// Singlequotes around non-empty values and NULL for empty values
+		$temp = array();
+		while (list($key, $input) = @each($form))
+		{
+			$value = ($input !== '') ? '\''.$pun_db->escape($input).'\'' : 'NULL';
+
+			$temp[] = $key.'='.$value;
+		}
+
+		// Make sure we have something to update
+		if (empty($temp))
+			message($lang_common['Bad request']);
+
+		// Run the update
+		$query = array(
+			'UPDATE'	=> 'users',
+			'SET'		=> implode(',', $temp),
+			'WHERE'		=> 'id='.$id
+		);
+
+		($hook = get_hook('pf_qr_update_user')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		// If we changed the username we have to update some stuff
+		if ($username_updated)
+		{
+			($hook = get_hook('pf_change_details_username_changed')) ? eval($hook) : null;
+
+			$query = array(
+				'UPDATE'	=> 'posts',
+				'SET'		=> 'poster=\''.$pun_db->escape($form['username']).'\'',
+				'WHERE'		=> 'poster_id='.$id
+			);
+
+			($hook = get_hook('pf_qr_update_username1')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			$query = array(
+				'UPDATE'	=> 'topics',
+				'SET'		=> 'poster=\''.$pun_db->escape($form['username']).'\'',
+				'WHERE'		=> 'poster=\''.$pun_db->escape($old_username).'\''
+			);
+
+			($hook = get_hook('pf_qr_update_username2')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			$query = array(
+				'UPDATE'	=> 'topics',
+				'SET'		=> 'last_poster=\''.$pun_db->escape($form['username']).'\'',
+				'WHERE'		=> 'last_poster=\''.$pun_db->escape($old_username).'\''
+			);
+
+			($hook = get_hook('pf_qr_update_username3')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			$query = array(
+				'UPDATE'	=> 'forums',
+				'SET'		=> 'last_poster=\''.$pun_db->escape($form['username']).'\'',
+				'WHERE'		=> 'last_poster=\''.$pun_db->escape($old_username).'\''
+			);
+
+			($hook = get_hook('pf_qr_update_username4')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			$query = array(
+				'UPDATE'	=> 'online',
+				'SET'		=> 'ident=\''.$pun_db->escape($form['username']).'\'',
+				'WHERE'		=> 'ident=\''.$pun_db->escape($old_username).'\''
+			);
+
+			($hook = get_hook('pf_qr_update_username5')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			// If the user is a moderator or an administrator we have to update the moderator lists and bans cache
+			if ($user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1')
+			{
+				$query = array(
+					'SELECT'	=> 'f.id, f.moderators',
+					'FROM'		=> 'forums AS f'
+				);
+
+				($hook = get_hook('pf_qr_get_all_forum_mods2')) ? eval($hook) : null;
+				$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+				while ($cur_forum = $pun_db->fetch_assoc($result))
+				{
+					$cur_moderators = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array();
+
+					if (in_array($id, $cur_moderators))
+					{
+						unset($cur_moderators[$old_username]);
+						$cur_moderators[$form['username']] = $id;
+						ksort($cur_moderators);
+
+						$query = array(
+							'UPDATE'	=> 'forums',
+							'SET'		=> 'moderators=\''.$pun_db->escape(serialize($cur_moderators)).'\'',
+							'WHERE'		=> 'id='.$cur_forum['id']
+						);
+
+						($hook = get_hook('pf_qr_update_forum_moderators2')) ? eval($hook) : null;
+						$pun_db->query_build($query) or error(__FILE__, __LINE__);
+					}
+				}
+
+				// Regenerate the bans cache
+				require_once PUN_ROOT.'include/cache.php';
+				generate_bans_cache();
+			}
+		}
+	}
+
+	pun_redirect(pun_link($pun_url['profile_'.$section], $id), $lang_profile['Profile redirect']);
+}
+
+
+if ($user['signature'] != '')
+{
+	require PUN_ROOT.'include/parser.php';
+	$parsed_signature = parse_signature($user['signature']);
+}
+
+
+// View or edit?
+if ($pun_user['id'] != $id &&
+	$pun_user['g_id'] != PUN_ADMIN &&
+	($pun_user['g_moderator'] != '1' || $pun_user['g_mod_edit_users'] == '0' || $user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1'))
+{
+	($hook = get_hook('pf_view_details_selected')) ? eval($hook) : null;
+
+	// Setup user identification
+	$pun_page['user_ident'] = array();
+
+	if ($pun_config['o_avatars'] == '1')
+	{
+		if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.gif'))
+			$pun_page['avatar_format'] = 'gif';
+		else if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.jpg'))
+			$pun_page['avatar_format'] = 'jpg';
+		else if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.png'))
+			$pun_page['avatar_format'] = 'png';
+		else
+			$pun_page['avatar_format'] = '';
+
+		if ($pun_page['avatar_format'] != '')
+			$pun_page['user_ident'][] = '<img src="'.$base_url.'/'.$pun_config['o_avatars_dir'].'/'.$id.'.'.$pun_page['avatar_format'].'" '.$pun_page['img_size'][3].' alt="'.$lang_profile['Avatar'].'" />';
+	}
+
+	$pun_page['user_ident'][] = '<strong class="username'.(($user['realname'] =='') ? ' fn nickname' : ' nickname').'">'.htmlspecialchars($user['username']).'</strong>';
+
+	// Setup user information
+	$pun_page['user_info'] = array(
+		'<li class="title"><span><strong>'.$lang_profile['Title'].'</strong> '.get_title($user).'</span></li>',
+		'<li><span><strong>'.$lang_profile['From'].'</strong> '.(($user['location'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['location']) : $user['location']) : $lang_profile['Unknown']).'</span></li>',
+		'<li><span><strong>'.$lang_profile['Registered'].'</strong> '.format_time($user['registered'], true).'</span></li>'
+	);
+
+	if ($pun_config['o_show_post_count'] == '1' || $pun_user['is_admmod'])
+		$pun_page['user_info'][] = '<li><span><strong>'.$lang_profile['Posts'].'</strong> '.$user['num_posts'].'</span></li>';
+
+
+	// Setup user actions
+	$pun_page['user_actions'] = array();
+
+	if ($user['email_setting'] != '2' && !$pun_user['is_guest'])
+		$pun_page['user_actions'][] =  '<li><a href="'.pun_link($pun_url['email'], $id).'">'.$lang_common['Send forum e-mail'].'</a></li>';
+
+	if ($pun_user['g_search'] == '1')
+	{
+		$pun_page['user_actions'][] = '<li><a href="'.pun_link($pun_url['search_user_posts'], $id).'">'.$lang_profile['Show posts'].'</a></li>';
+		$pun_page['user_actions'][] = '<li><a href="'.pun_link($pun_url['search_user_topics'], $id).'">'.$lang_profile['Show topics'].'</a></li>';
+	}
+
+	// Setup user data
+	$pun_page['user_data'] = array(
+		'<li><span'.(($user['realname'] !='') ? ' class="fn"' : '').'><strong>'.$lang_profile['Realname'].'</strong> '.(($user['realname'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['realname']) : $user['realname']) : $lang_profile['Unknown']).'</span></li>',
+		'<li><span><strong>'.$lang_profile['Last post'].'</strong> '.format_time($user['last_post']).'</span></li>'
+	);
+
+	if ($user['email_setting'] == '0' && !$pun_user['is_guest'])
+		$pun_page['user_data'][] = '<li><strong>'.$lang_profile['E-mail'].'</strong> <span><a href="mailto:'.$user['email'].'" class="email">'.$user['email'].'</a></span></li>';
+	else
+		$pun_page['user_data'][] = '<li><strong>'.$lang_profile['E-mail'].'</strong> <span>'.$lang_profile['Private'].'</span></li>';
+
+	if ($user['url'] != '')
+	{
+		if ($pun_config['o_censoring'] == '1')
+			$user['url'] = censor_words($user['url']);
+
+		$user['url'] = htmlspecialchars($user['url']);
+		$pun_page['url'] = '<a href="'.$user['url'].'" class="external url" rel="me">'.$user['url'].'</a>';
+	}
+	else
+		$pun_page['url'] = $lang_profile['Unknown'];
+
+	array_push(
+		$pun_page['user_data'],
+		'<li><span><strong>'.$lang_profile['Website'].'</strong> '.$pun_page['url'].'</span></li>',
+		'<li><span><strong>'.$lang_profile['Jabber'].'</strong> '.(($user['jabber'] !='') ? htmlspecialchars($user['jabber']) : $lang_profile['Unknown']).'</span></li>',
+		'<li><span><strong>'.$lang_profile['ICQ'].'</strong> '.(($user['icq'] !='') ? htmlspecialchars($user['icq']) : $lang_profile['Unknown']).'</span></li>',
+		'<li><span><strong>'.$lang_profile['MSN'].'</strong> '.(($user['msn'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['msn']) : $user['msn']) : $lang_profile['Unknown']).'</span></li>',
+		'<li><span><strong>'.$lang_profile['AOL IM'].'</strong> '.(($user['aim'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['aim']) : $user['aim']) : $lang_profile['Unknown']).'</span></li>',
+		'<li><span><strong>'.$lang_profile['Yahoo'].'</strong> '.(($user['yahoo'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['yahoo']) : $user['yahoo']) : $lang_profile['Unknown']).'</span></li>'
+	);
+
+	if ($pun_config['o_signatures'] == '1' && isset($parsed_signature))
+		$pun_page['sig_demo'] = $parsed_signature;
+
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		sprintf($lang_profile['Users profile'], htmlspecialchars($user['username']))
+	);
+
+	($hook = get_hook('pf_view_details_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_ALLOW_INDEX', 1);
+	define('PUN_PAGE', 'profile');
+	require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php printf($lang_profile['About settings'], htmlspecialchars($user['username'])) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="profile vcard">
+			<h3><?php echo $lang_profile['User information'] ?></h3>
+			<div class="user">
+				<h4 class="user-ident"><?php echo implode(' ', $pun_page['user_ident']) ?></h4>
+				<ul class="user-info">
+					<?php echo implode("\n\t\t\t\t\t\t", $pun_page['user_info'])."\n" ?>
+				</ul>
+			</div>
+<?php ($hook = get_hook('pf_view_details_pre_user_data')) ? eval($hook) : null; ?>
+			<ul class="user-data">
+				<?php echo implode("\n\t\t\t\t\t\t", $pun_page['user_data'])."\n" ?>
+			</ul>
+			<h3><?php echo $lang_profile['User actions'] ?></h3>
+<?php if (!empty($pun_page['user_actions'])): ?>			<ul class="user-actions">
+				<?php echo implode("\n\t\t\t\t", $pun_page['user_actions'])."\n" ?>
+			</ul>
+<?php endif; if (isset($pun_page['sig_demo'])): ?>			<h3><?php echo $lang_profile['Preview signature'] ?></h3>
+			<div class="sig-demo">
+				<?php echo $pun_page['sig_demo']."\n" ?>
+			</div>
+<?php endif; ?>		</div>
+<?php ($hook = get_hook('pf_view_details_end')) ? eval($hook) : null; ?>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+
+else
+{
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		sprintf($lang_profile['Users profile'], htmlspecialchars($user['username']))
+	);
+
+	if ($section == 'about')
+	{
+		// Setup user identification
+		$pun_page['user_ident'] = array();
+
+		if ($pun_config['o_avatars'] == '1')
+		{
+			if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.gif'))
+				$pun_page['avatar_format'] = 'gif';
+			else if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.jpg'))
+				$pun_page['avatar_format'] = 'jpg';
+			else if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.png'))
+				$pun_page['avatar_format'] = 'png';
+			else
+				$pun_page['avatar_format'] = '';
+
+			if ($pun_page['avatar_format'] != '')
+				$pun_page['user_ident'][] = '<img src="'.$base_url.'/'.$pun_config['o_avatars_dir'].'/'.$id.'.'.$pun_page['avatar_format'].'" '.$pun_page['img_size'][3].' alt="'.$lang_profile['Avatar'].'" />';
+		}
+
+		$pun_page['user_ident'][] = '<strong class="username'.(($user['realname'] =='') ? ' fn nickname' :  ' nickname').'">'.htmlspecialchars($user['username']).'</strong>';
+
+		// Setup user information
+		$pun_page['user_info'] = array(
+			'<li class="title"><span><strong>'.$lang_profile['Title'].'</strong> '.get_title($user).'</span></li>',
+			'<li><span><strong>'.$lang_profile['From'].'</strong> '.(($user['location'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['location']) : $user['location']) : $lang_profile['Unknown']).'</span></li>',
+			'<li><span><strong>'.$lang_profile['Registered'].'</strong> '.format_time($user['registered'], true).'</span></li>'
+ 		);
+
+ 		if ($pun_config['o_show_post_count'] == '1' || $pun_user['is_admmod'])
+			$pun_page['user_info'][] = '<li><span><strong>'.$lang_profile['Posts'].'</strong> '.$user['num_posts'].'</span></li>';
+
+		if ($pun_user['is_admmod'])
+			$pun_page['user_info'][]= '<li><span><strong>'.$lang_profile['IP'].'</strong> <a href="'.pun_link($pun_url['get_host'], htmlspecialchars($user['registration_ip'])).'">'.htmlspecialchars($user['registration_ip']).'</a></span></li>';
+
+		if ($pun_user['is_admmod'] && $user['admin_note'] != '')
+				$pun_page['user_info'][] = '<li><span><strong>'.$lang_profile['Note'].'</strong> '.htmlspecialchars($user['admin_note']).'</span></li>';
+
+
+		// Setup user actions
+		$pun_page['user_actions'] = array();
+
+		if ($pun_user['id'] == $id || $session->user_level >= USER_LEVEL_ADMIN || ($pun_user['g_moderator'] == '1' && $pun_user['g_mod_change_passwords'] == '1'))
+			$pun_page['user_actions'][] = '<li><a href="'.pun_link($pun_url['change_password'], $id).'">'.$lang_profile['Change password'].'</a></li>';
+
+		if (!$pun_user['is_admmod'] && $pun_config['o_regs_verify'] == '1')
+			$pun_page['user_actions'][] = '<li><a href="'.pun_link($pun_url['change_email'], $id).'">'.$lang_profile['Change e-mail'].'</a></li>';
+
+		if ($user['email_setting'] != '2' || $pun_user['is_admmod'])
+			$pun_page['user_actions'][] = '<li><a href="'.pun_link($pun_url['email'], $id).'">'.$lang_profile['Send forum e-mail'].'</a></li>';
+
+		if ($pun_user['g_search'] == '1' || $pun_user['is_admmod'])
+		{
+			$pun_page['user_actions'][] = '<li><a href="'.pun_link($pun_url['search_user_posts'], $id).'">'.$lang_profile['Show posts'].'</a></li>';
+			$pun_page['user_actions'][] = '<li><a href="'.pun_link($pun_url['search_user_topics'], $id).'">'.$lang_profile['Show topics'].'</a></li>';
+		}
+
+
+		// Setup user data
+		$pun_page['user_data'] = array(
+			'<li><strong>'.$lang_profile['Realname'].'</strong> <span'.(($user['realname'] !='') ? ' class="fn"' : '').'>'.(($user['realname'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['realname']) : $user['realname']) : $lang_profile['Unknown']).'</span></li>',
+			'<li><strong>'.$lang_profile['Last post'].'</strong> <span>'.format_time($user['last_post']).'</span></li>'
+		);
+
+		if ($user['email_setting'] == '0' && !$pun_user['is_guest'])
+			$pun_page['user_data'][] = '<li><strong>'.$lang_profile['E-mail'].'</strong> <a href="mailto:'.$user['email'].'" class="email"><span>'.$user['email'].'</span></a></li>';
+		else
+			$pun_page['user_data'][] = '<li><strong>'.$lang_profile['E-mail'].'</strong> <span>'.$lang_profile['Private'].'</span></li>';
+
+		if ($user['url'] != '')
+		{
+			$user['url'] = htmlspecialchars($user['url']);
+
+			if ($pun_config['o_censoring'] == '1')
+				$user['url'] = censor_words($user['url']);
+
+			$pun_page['url'] = '<a href="'.$user['url'].'" class="external url" rel="me">'.$user['url'].'</a>';
+		}
+		else
+			$pun_page['url'] = $lang_profile['Unknown'];
+
+		array_push(
+			$pun_page['user_data'],
+			'<li><span><strong>'.$lang_profile['Website'].'</strong> '.$pun_page['url'].'</span></li>',
+			'<li><span><strong>'.$lang_profile['Jabber'].'</strong> '.(($user['jabber'] !='') ? htmlspecialchars($user['jabber']) : $lang_profile['Unknown']).'</span></li>',
+			'<li><span><strong>'.$lang_profile['ICQ'].'</strong> '.(($user['icq'] !='') ? htmlspecialchars($user['icq']) : $lang_profile['Unknown']).'</span></li>',
+			'<li><span><strong>'.$lang_profile['MSN'].'</strong> '.(($user['msn'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['msn']) : $user['msn']) : $lang_profile['Unknown']).'</span></li>',
+			'<li><span><strong>'.$lang_profile['AOL IM'].'</strong> '.(($user['aim'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['aim']) : $user['aim']) : $lang_profile['Unknown']).'</span></li>',
+			'<li><span><strong>'.$lang_profile['Yahoo'].'</strong> '.(($user['yahoo'] !='') ? htmlspecialchars(($pun_config['o_censoring'] == '1') ? censor_words($user['yahoo']) : $user['yahoo']) : $lang_profile['Unknown']).'</span></li>'
+		);
+
+		if ($pun_config['o_signatures'] == '1' && isset($parsed_signature))
+			$pun_page['sig_demo'] = $parsed_signature;
+
+		($hook = get_hook('pf_change_details_about_pre_header_load')) ? eval($hook) : null;
+
+		define('PUN_PAGE', 'profile-about');
+		require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main sectioned">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+<?php generate_profile_menu(); ?>
+
+	<div class="main-head">
+		<h2><span><?php printf($lang_profile['About settings'], htmlspecialchars($user['username'])) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+<?php if ($id == $pun_user['id']): ?>		<div class="frm-info">
+			<p><?php echo $lang_profile['Profile welcome'] ?></p>
+		</div>
+<?php endif; ($hook = get_hook('pf_change_details_about_pre_user_info')) ? eval($hook) : null; ?>
+		<div class="profile vcard">
+			<h3><?php echo $lang_profile['Preview profile'] ?></h3>
+			<div class="user">
+				<h4 class="user-ident"><?php echo implode(' ', $pun_page['user_ident']) ?></h4>
+				<ul class="user-info">
+					<?php echo implode("\n\t\t\t\t\t", $pun_page['user_info'])."\n" ?>
+				</ul>
+			</div>
+			<ul class="user-data">
+				<?php echo implode("\n\t\t\t\t", $pun_page['user_data'])."\n" ?>
+			</ul>
+			<h3><?php echo $lang_profile['User actions'] ?></h3>
+<?php if (!empty($pun_page['user_actions'])): ?>			<ul class="user-actions">
+				<?php echo implode("\n\t\t\t\t", $pun_page['user_actions'])."\n" ?>
+			</ul>
+<?php endif; if (isset($pun_page['sig_demo'])): ?>			<h3><?php echo $lang_profile['Preview signature'] ?></h3>
+			<div class="sig-demo">
+				<?php echo $pun_page['sig_demo']."\n" ?>
+			</div>
+<?php endif; ?>		</div>
+<?php ($hook = get_hook('pf_change_details_about_end')) ? eval($hook) : null; ?>
+	</div>
+</div>
+<?php
+
+		require PUN_ROOT.'footer.php';
+	}
+
+	else if ($section == 'identity')
+	{
+		// Setup the form
+		$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+		$pun_page['form_action'] = pun_link($pun_url['profile_identity'], $id);
+
+		$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+		if ($pun_user['is_admmod'])
+			$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+		if ($pun_user['is_admmod'] && ($session->user_level >= USER_LEVEL_ADMIN || $pun_user['g_mod_rename_users'] == '1'))
+			$pun_page['hidden_fields'][] = '<input type="hidden" name="old_username" value="'.htmlspecialchars($user['username']).'" />';
+
+		// Does the form have required fields
+		$pun_page['has_required'] = ((($pun_user['is_admmod'] && ($session->user_level >= USER_LEVEL_ADMIN || $pun_user['g_mod_rename_users'] == '1')) || ($pun_user['is_admmod'] || $pun_config['o_regs_verify'] != '1')) ? true : false);
+
+		($hook = get_hook('pf_change_details_identity_pre_header_load')) ? eval($hook) : null;
+
+		define('PUN_PAGE', 'profile-identity');
+		require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main sectioned">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+<?php generate_profile_menu(); ?>
+
+	<div class="main-head">
+		<h2><span><span><?php echo $lang_profile['Section identity'] ?>:</span> <?php printf($lang_profile['Identity settings'], strtolower($lang_profile['Section identity'])) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+<?php if ($pun_page['has_required']): ?>		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+<?php endif; ?>		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php if ($pun_page['has_required']): ?>			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+<?php if ($pun_user['is_admmod'] && ($session->user_level >= USER_LEVEL_ADMIN || $pun_user['g_mod_rename_users'] == '1')): ?>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Username'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_username" value="<?php echo htmlspecialchars($user['username']) ?>" size="35" maxlength="25" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Username help'] ?></span>
+					</label>
+				</div>
+<?php endif; if ($pun_user['is_admmod'] || $pun_config['o_regs_verify'] != '1'): ?>				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['E-mail'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_email" value="<?php echo $user['email'] ?>" size="35" maxlength="80" /></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+<?php endif; ($hook = get_hook('pf_change_details_identity_req_info_end')) ? eval($hook) : null; ?>			</fieldset>
+<?php endif; ($hook = get_hook('pf_change_details_identity_post_req_info_fieldset')) ? eval($hook) : null; ?>			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Personal legend'] ?></strong></legend>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Realname'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[realname]" value="<?php echo htmlspecialchars($user['realname']) ?>" size="35" maxlength="40" /></span>
+					</label>
+				</div>
+<?php if ($pun_user['g_set_title'] == '1'): ?>				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Title'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="title" value="<?php echo htmlspecialchars($user['title']) ?>" size="35" maxlength="50" /></span><br />
+						<span class="fld-help"><?php echo $lang_profile['Leave blank'] ?></span>
+					</label>
+				</div>
+<?php endif; ?>				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Location'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[location]" value="<?php echo htmlspecialchars($user['location']) ?>" size="35" maxlength="30" /></span>
+					</label>
+				</div>
+<?php if ($session->user_level >= USER_LEVEL_ADMIN): ?>				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Edit count'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="num_posts" value="<?php echo $user['num_posts'] ?>" size="8" maxlength="8" /></span>
+					</label>
+				</div>
+<?php endif; if ($pun_user['is_admmod']): ?>				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Admin note'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="admin_note" value="<?php echo htmlspecialchars($user['admin_note']) ?>" size="35" maxlength="30" /></span>
+					</label>
+				</div>
+<?php endif; ($hook = get_hook('pf_change_details_identity_personal_end')) ? eval($hook) : null; ?>			</fieldset>
+<?php ($hook = get_hook('pf_change_details_identity_post_personal_fieldset')) ? eval($hook) : null; ?>			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Contact legend'] ?></strong></legend>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Website'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[url]" value="<?php echo htmlspecialchars($user['url']) ?>" size="50" maxlength="80" /></span>
+					</label>
+				</div>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Jabber'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="form[jabber]" value="<?php echo htmlspecialchars($user['jabber']) ?>" size="40" maxlength="80" /></span>
+					</label>
+				</div>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['ICQ'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="form[icq]" value="<?php echo $user['icq'] ?>" size="12" maxlength="12" /></span>
+					</label>
+				</div>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['MSN'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="form[msn]" value="<?php echo htmlspecialchars($user['msn']) ?>" size="40" maxlength="80" /></span>
+					</label>
+				</div>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['AOL IM'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="form[aim]" value="<?php echo htmlspecialchars($user['aim']) ?>" size="20" maxlength="30" /></span>
+					</label>
+				</div>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Yahoo'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="form[yahoo]" value="<?php echo htmlspecialchars($user['yahoo']) ?>" size="20" maxlength="30" /></span>
+					</label>
+				</div>
+<?php ($hook = get_hook('pf_change_details_identity_contact_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('pf_change_details_identity_post_contact_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="update" value="<?php echo $lang_profile['Update profile'] ?>" /> <?php echo $lang_profile['Instructions'] ?></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+		require PUN_ROOT.'footer.php';
+	}
+
+	else if ($section == 'settings')
+	{
+		$pun_page['styles'] = array();
+		$pun_page['d'] = dir(PUN_ROOT.'style');
+		while (($pun_page['entry'] = $pun_page['d']->read()) !== false)
+		{
+			if ($pun_page['entry'] != '.' && $pun_page['entry'] != '..' && is_dir(PUN_ROOT.'style/'.$pun_page['entry']) && file_exists(PUN_ROOT.'style/'.$pun_page['entry'].'/'.$pun_page['entry'].'.css'))
+				$pun_page['styles'][] = $pun_page['entry'];
+		}
+		$pun_page['d']->close();
+
+		// Setup the form
+		$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+		$pun_page['form_action'] = pun_link($pun_url['profile_settings'], $id);
+
+		$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+		if ($pun_user['is_admmod'])
+			$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+		($hook = get_hook('pf_change_details_settings_pre_header_load')) ? eval($hook) : null;
+
+		define('PUN_PAGE', 'profile-settings');
+		require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main sectioned">
+
+	<h1 class="pun main-title"><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+<?php generate_profile_menu(); ?>
+
+	<div class="main-head">
+		<h2><span><span><?php echo $lang_profile['Section settings'] ?>:</span> <?php printf($lang_profile['Settings settings'], strtolower($lang_profile['Section settings'])) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action']  ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('pf_change_details_settings_pre_local_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Local legend'] ?></strong></legend>
+<?php
+
+		$pun_page['languages'] = array();
+		$pun_page['d'] = dir(PUN_ROOT.'lang');
+		while (($pun_page['entry'] = $pun_page['d']->read()) !== false)
+		{
+			if ($pun_page['entry'] != '.' && $pun_page['entry'] != '..' && is_dir(PUN_ROOT.'lang/'.$pun_page['entry']) && file_exists(PUN_ROOT.'lang/'.$pun_page['entry'].'/common.php'))
+				$pun_page['languages'][] = $pun_page['entry'];
+		}
+		$pun_page['d']->close();
+
+		// Only display the language selection box if there's more than one language available
+		if (count($pun_page['languages']) > 1)
+		{
+			natcasesort($pun_page['languages']);
+
+?>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Language'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="form[language]">
+<?php
+
+			while (list(, $temp) = @each($pun_page['languages']))
+			{
+				if ($pun_user['language'] == $temp)
+					echo "\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.$temp.'</option>'."\n";
+				else
+					echo "\t\t\t\t\t\t".'<option value="'.$temp.'">'.$temp.'</option>'."\n";
+			}
+
+?>
+						</select></span>
+					</label>
+				</div>
+<?php
+
+		}
+
+?>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Timezone'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="form[timezone]">
+							<option value="-12"<?php if ($user['timezone'] == -12) echo ' selected="selected"' ?>>-12</option>
+							<option value="-11"<?php if ($user['timezone'] == -11) echo ' selected="selected"' ?>>-11</option>
+							<option value="-10"<?php if ($user['timezone'] == -10) echo ' selected="selected"' ?>>-10</option>
+							<option value="-9.5"<?php if ($user['timezone'] == -9.5) echo ' selected="selected"' ?>>-09.5</option>
+							<option value="-9"<?php if ($user['timezone'] == -9) echo ' selected="selected"' ?>>-09</option>
+							<option value="-8.5"<?php if ($user['timezone'] == -8.5) echo ' selected="selected"' ?>>-08.5</option>
+							<option value="-8"<?php if ($user['timezone'] == -8) echo ' selected="selected"' ?>>-08 PST</option>
+							<option value="-7"<?php if ($user['timezone'] == -7) echo ' selected="selected"' ?>>-07 MST</option>
+							<option value="-6"<?php if ($user['timezone'] == -6) echo ' selected="selected"' ?>>-06 CST</option>
+							<option value="-5"<?php if ($user['timezone'] == -5) echo ' selected="selected"' ?>>-05 EST</option>
+							<option value="-4"<?php if ($user['timezone'] == -4) echo ' selected="selected"' ?>>-04 AST</option>
+							<option value="-3.5"<?php if ($user['timezone'] == -3.5) echo ' selected="selected"' ?>>-03.5</option>
+							<option value="-3"<?php if ($user['timezone'] == -3) echo ' selected="selected"' ?>>-03 ADT</option>
+							<option value="-2"<?php if ($user['timezone'] == -2) echo ' selected="selected"' ?>>-02</option>
+							<option value="-1"<?php if ($user['timezone'] == -1) echo ' selected="selected"' ?>>-01</option>
+							<option value="0"<?php if ($user['timezone'] == 0) echo ' selected="selected"' ?>>00 GMT</option>
+							<option value="1"<?php if ($user['timezone'] == 1) echo ' selected="selected"' ?>>+01 CET</option>
+							<option value="2"<?php if ($user['timezone'] == 2) echo ' selected="selected"' ?>>+02</option>
+							<option value="3"<?php if ($user['timezone'] == 3) echo ' selected="selected"' ?>>+03</option>
+							<option value="3.5"<?php if ($user['timezone'] == 3.5) echo ' selected="selected"' ?>>+03.5</option>
+							<option value="4"<?php if ($user['timezone'] == 4) echo ' selected="selected"' ?>>+04</option>
+							<option value="4.5"<?php if ($user['timezone'] == 4.5) echo ' selected="selected"' ?>>+04.5</option>
+							<option value="5"<?php if ($user['timezone'] == 5) echo ' selected="selected"' ?>>+05</option>
+							<option value="5.5"<?php if ($user['timezone'] == 5.5) echo ' selected="selected"' ?>>+05.5</option>
+							<option value="6"<?php if ($user['timezone'] == 6) echo ' selected="selected"' ?>>+06</option>
+							<option value="6.5"<?php if ($user['timezone'] == 6.5) echo ' selected="selected"' ?>>+06.5</option>
+							<option value="7"<?php if ($user['timezone'] == 7) echo ' selected="selected"' ?>>+07</option>
+							<option value="8"<?php if ($user['timezone'] == 8) echo ' selected="selected"' ?>>+08</option>
+							<option value="9"<?php if ($user['timezone'] == 9) echo ' selected="selected"' ?>>+09</option>
+							<option value="9.5"<?php if ($user['timezone'] == 9.5) echo ' selected="selected"' ?>>+09.5</option>
+							<option value="10"<?php if ($user['timezone'] == 10) echo ' selected="selected"' ?>>+10</option>
+							<option value="10.5"<?php if ($user['timezone'] == 10.5) echo ' selected="selected"' ?>>+10.5</option>
+							<option value="11"<?php if ($user['timezone'] == 11) echo ' selected="selected"' ?>>+11</option>
+							<option value="11.5"<?php if ($user['timezone'] == 11.5) echo ' selected="selected"' ?>>+11.5</option>
+							<option value="12"<?php if ($user['timezone'] == 12) echo ' selected="selected"' ?>>+12</option>
+							<option value="13"<?php if ($user['timezone'] == 13) echo ' selected="selected"' ?>>+13</option>
+							<option value="14"<?php if ($user['timezone'] == 14) echo ' selected="selected"' ?>>+14</option>
+						</select></span><br />
+						<span class="fld-extra"><?php echo $lang_profile['Timezone info'] ?></span>
+					</label>
+				</div>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_profile['Adjust for DST'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[dst]" value="1" <?php if ($user['dst'] == 1) echo ' checked="checked"' ?> /> <?php echo $lang_profile['DST label'] ?></label>
+				</div>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Time format'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="form[time_format]">
+<?php
+
+		foreach (array_unique($pun_time_formats) as $key => $time_format)
+		{
+			echo "\t\t\t\t\t\t".'<option value="'.$key.'"';
+			if ($user['time_format'] == $key)
+				echo ' selected="selected"';
+			echo '>'. gmdate($time_format);
+			if ($key == 0)
+				echo ' ('.$lang_profile['Default'].')';
+			echo "</option>\n";
+		}
+
+?>
+						</select></span>
+					</label>
+				</div>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Date format'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="form[date_format]">
+<?php
+
+		foreach (array_unique($pun_date_formats) as $key => $date_format)
+		{
+			echo "\t\t\t\t\t\t\t".'<option value="'.$key.'"';
+			if ($user['date_format'] == $key)
+				echo ' selected="selected"';
+			echo '>'. gmdate($date_format);
+			if ($key == 0)
+				echo ' ('.$lang_profile['Default'].')';
+			echo "</option>\n";
+		}
+
+?>
+						</select></span>
+					</label>
+				</div>
+<?php ($hook = get_hook('pf_change_details_settings_local_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('pf_change_details_settings_pre_display_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Display settings'] ?></strong></legend>
+<?php
+
+		// Only display the style selection box if there's more than one style available
+		if (count($pun_page['styles']) == 1)
+			echo "\t\t\t\t".'<input type="hidden" name="form[style]" value="'.$pun_page['styles'][0].'" />'."\n";
+		else if (count($pun_page['styles']) > 1)
+		{
+			natcasesort($pun_page['styles']);
+
+?>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Styles'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="form[style]">
+<?php
+
+			while (list(, $temp) = @each($pun_page['styles']))
+			{
+				if ($user['style'] == $temp)
+					echo "\t\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.str_replace('_', ' ', $temp).'</option>'."\n";
+				else
+					echo "\t\t\t\t\t\t\t".'<option value="'.$temp.'">'.str_replace('_', ' ', $temp).'</option>'."\n";
+			}
+
+?>
+						</select></span>
+					</label>
+				</div>
+<?php
+
+		}
+
+?>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_profile['Image display'] ?></span></legend>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[show_smilies]" value="1"<?php if ($user['show_smilies'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['Show smilies'] ?></label></div>
+<?php if ($pun_config['o_avatars'] == '1'): ?>					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[show_avatars]" value="1"<?php if ($user['show_avatars'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['Show avatars'] ?></label></div>
+<?php endif; ?>					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[show_img]" value="1"<?php if ($user['show_img'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['Show images'] ?></label></div>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[show_img_sig]" value="1"<?php if ($user['show_img_sig'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['Show images sigs'] ?></label></div>
+				</fieldset>
+<?php if ($pun_config['o_signatures'] == '1'): ?>				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_profile['Signature display'] ?></span></legend>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[show_sig]" value="1"<?php if ($user['show_sig'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['Show sigs'] ?></label></div>
+				</fieldset>
+<?php ($hook = get_hook('pf_change_details_settings_display_end')) ? eval($hook) : null; ?>
+<?php endif; ?>			</fieldset>
+<?php ($hook = get_hook('pf_change_details_settings_pre_pagination_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Pagination settings'] ?></strong></legend>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Topics per page'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[disp_topics]" value="<?php echo $user['disp_topics'] ?>" size="6" maxlength="3" /></span>
+						<span class="fld-extra"><?php echo $lang_profile['Leave blank'] ?></span>
+					</label>
+				</div>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Posts per page'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[disp_posts]" value="<?php echo $user['disp_posts'] ?>" size="6" maxlength="3" /></span>
+						<span class="fld-extra"><?php echo $lang_profile['Leave blank'] ?></span>
+					</label>
+				</div>
+<?php ($hook = get_hook('pf_change_details_settings_pagination_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('pf_change_details_settings_pre_other_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Other settings'] ?></strong></legend>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_profile['E-mail settings'] ?></span></legend>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[email_setting]" value="0"<?php if ($user['email_setting'] == '0') echo ' checked="checked"' ?> /> <?php echo $lang_profile['E-mail setting 1'] ?></label></div>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[email_setting]" value="1"<?php if ($user['email_setting'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['E-mail setting 2'] ?></label></div>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[email_setting]" value="2"<?php if ($user['email_setting'] == '2') echo ' checked="checked"' ?> /> <?php echo $lang_profile['E-mail setting 3'] ?></label></div>
+				</fieldset>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_profile['Subscription settings'] ?></span></legend>
+						<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[notify_with_post]" value="1"<?php if ($user['notify_with_post'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['Notify full'] ?></label></div>
+						<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[auto_notify]" value="1"<?php if ($user['auto_notify'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['Subscribe by default'] ?></label></div>
+				</fieldset>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_profile['Persistent login'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="form[save_pass]" value="1"<?php if ($user['save_pass'] == '1') echo ' checked="checked"' ?> /> <?php echo $lang_profile['Save user/pass'] ?></label>
+				</div>
+<?php ($hook = get_hook('pf_change_details_settings_other_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('pf_change_details_settings_post_other_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="update" value="<?php echo $lang_profile['Update profile'] ?>" /> <?php echo $lang_profile['Instructions'] ?></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+		require PUN_ROOT.'footer.php';
+	}
+
+	else if ($section == 'signature')
+	{
+		$pun_page['sig_info'][] = '<li>'.$lang_profile['Signature info'].'</li>';
+
+		if ($user['signature'] != '')
+			$pun_page['sig_demo'] = $parsed_signature;
+
+		// Setup the form
+		$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+		$pun_page['form_action'] = pun_link($pun_url['profile_signature'], $id);
+
+		$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+		if ($pun_user['is_admmod'])
+			$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+		// Setup help
+		$pun_page['main_head_options'] = array();
+		if ($pun_config['p_message_bbcode'] == '1')
+			$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'bbcode').'" title="'.sprintf($lang_common['Help page'], $lang_common['BBCode']).'"><span>'.$lang_common['BBCode'].'</span></a>';
+		if ($pun_config['p_message_img_tag'] == '1')
+			$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'img').'" title="'.sprintf($lang_common['Help page'], $lang_common['Images']).'"><span>'.$lang_common['Images'].'</span></a>';
+		if ($pun_config['o_smilies'] == '1')
+			$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'smilies').'" title="'.sprintf($lang_common['Help page'], $lang_common['Smilies']).'"><span>'.$lang_common['Smilies'].'</span></a>';
+
+		($hook = get_hook('pf_change_details_signature_pre_header_load')) ? eval($hook) : null;
+
+		define('PUN_PAGE', 'profile-signature');
+		require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main sectioned">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+<?php generate_profile_menu(); ?>
+
+	<div class="main-head">
+		<h2><span><span><?php echo $lang_profile['Section signature'] ?>:</span> <?php printf($lang_profile['Sig settings'], strtolower($lang_profile['Section signature'])) ?></span></h2>
+<?php if (!empty($pun_page['main_head_options'])) echo "\t\t\t".'<p class="main-options">'.sprintf($lang_common['You may use'], implode(' ', $pun_page['main_head_options'])).'</p>'."\n" ?>
+	</div>
+
+	<div class="main-content frm">
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('pf_change_details_signature_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Signature'] ?></strong></legend>
+<?php ($hook = get_hook('pf_change_details_signature_fieldset_start')) ? eval($hook) : null; ?>
+				<div class="frm-fld text textarea">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Compose signature'] ?></span><br />
+						<span class="fld-input">
+							<textarea id="fld<?php echo $pun_page['fld_count'] ?>" name="signature" rows="4" cols="65"><?php echo htmlspecialchars($user['signature']) ?></textarea></span><br />
+						<span class="fld-help"><?php printf($lang_profile['Sig max size'], $pun_config['p_sig_length'], $pun_config['p_sig_lines']) ?></span>
+					</label>
+				</div>
+			</fieldset>
+<?php if (isset($pun_page['sig_demo'])): ?>			<div class="sig-demo">
+				<?php echo $pun_page['sig_demo']."\n" ?>
+			</div>
+<?php endif; ($hook = get_hook('pf_change_details_signature_pre_buttons')) ? eval($hook) : null; ?>			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="update" value="<?php echo $lang_profile['Update profile'] ?>" /> <?php echo $lang_profile['Instructions'] ?></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+		require PUN_ROOT.'footer.php';
+	}
+
+	else if ($section == 'avatar' && $pun_config['o_avatars'] == '1')
+	{
+		if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.gif'))
+			$pun_page['avatar_format'] = 'gif';
+		else if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.jpg'))
+			$pun_page['avatar_format'] = 'jpg';
+		else if ($pun_page['img_size'] = @getimagesize($pun_config['o_avatars_dir'].'/'.$id.'.png'))
+			$pun_page['avatar_format'] = 'png';
+		else
+			$pun_page['avatar_format'] = '';
+
+		// Setup the form
+		$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+		$pun_page['form_action'] = pun_link($pun_url['profile_avatar'], $id);
+
+		$pun_page['hidden_fields'] = array(
+			'<input type="hidden" name="form_sent" value="1" />',
+			'<input type="hidden" name="MAX_FILE_SIZE" value="'.$pun_config['o_avatars_size'].'" />'
+		);
+		if ($pun_user['is_admmod'])
+			$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+		// Setup form information
+		$pun_page['frm_info'] = array();
+
+		if ($pun_page['avatar_format'] != '')
+		{
+			$pun_page['frm_info'][] = '<li><span>'.$lang_profile['Avatar info change'].'</span></li>';
+			$pun_page['frm_info'][] = '<li><span>'.$lang_profile['Avatar info type'].'</span></li>';
+			$pun_page['frm_info'][] = '<li><span>'.sprintf($lang_profile['Avatar info size'], $pun_config['o_avatars_width'], $pun_config['o_avatars_height'], $pun_config['o_avatars_size'], ceil($pun_config['o_avatars_size'] / 1024)).'</span></li>';
+			$pun_page['avatar_demo'] = '<img src="'.$base_url.'/'.$pun_config['o_avatars_dir'].'/'.$id.'.'.$pun_page['avatar_format'].'" '.$pun_page['img_size'][3].' alt="'.$lang_profile['Avatar'].'" />';
+		}
+		else
+		{
+			$pun_page['frm_info'][] = '<li><span>'.$lang_profile['Avatar info none'].'</span></li>';
+			$pun_page['frm_info'][] = '<li><span>'.sprintf($lang_profile['Avatar info size'], $pun_config['o_avatars_width'], $pun_config['o_avatars_height'], $pun_config['o_avatars_size'], ceil($pun_config['o_avatars_size'] / 1024)).'</span></li>';
+		}
+
+		($hook = get_hook('pf_change_details_avatar_pre_header_load')) ? eval($hook) : null;
+
+		define('PUN_PAGE', 'profile-avatar');
+		require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main sectioned">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+<?php generate_profile_menu(); ?>
+
+	<div class="main-head">
+		<h2><span><span><?php echo $lang_profile['Section avatar'] ?>:</span> <?php printf($lang_profile['Avatar settings'], strtolower($lang_profile['Section avatar'])) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="frm-info<?php echo ($pun_page['avatar_format'] != '') ? ' av-preview' : '' ?>">
+			<?php echo (isset($pun_page['avatar_demo'])) ? $pun_page['avatar_demo']."\n" : ''."\n" ?>
+			<ul>
+				<?php echo implode("\n\t\t\t\t", $pun_page['frm_info'])."\n\t\t\t" ?>
+			</ul>
+		</div>
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>" enctype="multipart/form-data">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php if ($pun_page['avatar_format'] != ''): ?>			<div class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<p class="frm-fld link"><span class="fld-label"><a href="<?php echo pun_link($pun_url['delete_avatar'], $id) ?>"><?php echo $lang_profile['Delete avatar'] ?></a>:</span> <span class="fm-input"><?php echo $lang_profile['Avatar info remove'] ?></span></p>
+			</div>
+<?php endif; ?>			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Avatar'] ?></strong></legend>
+<?php ($hook = get_hook('pf_change_details_avatar_fieldset_start')) ? eval($hook) : null; ?>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Upload avatar file'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" name="req_file" type="file" size="40" /></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+<?php ($hook = get_hook('pf_change_details_avatar_fieldset_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('pf_change_details_avatar_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="update" value="<?php echo $lang_profile['Update profile'] ?>" /> <?php echo $lang_profile['Instructions'] ?></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+		require PUN_ROOT.'footer.php';
+	}
+
+	else if ($section == 'admin')
+	{
+		if ($pun_user['g_id'] != PUN_ADMIN && ($pun_user['g_moderator'] != '1' || $pun_user['g_mod_ban_users'] == '0'))
+			message($lang_common['Bad request']);
+
+		$pun_page['user_actions'] = array();
+		$pun_page['user_management'] = array();
+
+		if ($pun_user['g_moderator'] == '1')
+		{
+			$pun_page['user_actions'][] = '<li class="frm-fld link"><span class="fld-label"><a href="'.pun_link($pun_url['admin_bans']).'&add_ban='.$id.'">'.$lang_profile['Ban user'].'</a>:</span> <span class="fld-input">'.$lang_profile['Ban user info'].'</span></li>';
+			$pun_page['user_management'][] = '<li><span>'.$lang_profile['Manage ban'].'</span></li>';
+		}
+		else if ($pun_user['g_moderator'] != '1' && $user['g_id'] != PUN_ADMIN )
+		{
+			$pun_page['user_actions'][] = '<li class="frm-fld link"><span class="fld-label"><a href="'.pun_link($pun_url['admin_bans']).'&add_ban='.$id.'">'.$lang_profile['Ban user'].'</a>:</span> <span class="fld-input">'.$lang_profile['Ban user info'].'</span></li>';
+			$pun_page['user_actions'][] = '<li class="frm-fld link"><span class="fld-label"><a href="'.pun_link($pun_url['delete_user'], $id).'">'.$lang_profile['Delete user'].'</a>:</span> <span class="fld-input">'.$lang_profile['Delete user info'].'</span></li>';
+			$pun_page['user_management'][] = '<li><span>'.$lang_profile['Manage ban'].'</span></li>';
+			$pun_page['user_management'][] = '<li><span>'.$lang_profile['Manage delete'].'</span></li>';
+		}
+
+		if ($pun_user['g_moderator'] != '1' &&  $pun_user['id'] != $id && $user['g_id'] == PUN_ADMIN )
+			$pun_page['user_management'][] = '<li><span>'.$lang_profile['Manage groups'].'</span></li>';
+
+		// Setup form
+		$pun_page['fld_count'] = $pun_page['set_count'] = 0;
+		$pun_page['form_action'] = pun_link($pun_url['profile_admin'], $id);
+
+		$pun_page['hidden_fields'][] = '<input type="hidden" name="form_sent" value="1" />';
+		if ($pun_user['is_admmod'])
+			$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+		($hook = get_hook('pf_change_details_admin_pre_header_load')) ? eval($hook) : null;
+
+		define('PUN_PAGE', 'profile-admin');
+		require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main sectioned">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+<?php generate_profile_menu(); ?>
+
+	<div class="main-head">
+		<h2><span><span><?php echo $lang_profile['Section admin'] ?>:</span> <?php printf($lang_profile['Admin settings'], strtolower($lang_profile['Section admin'])) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+<?php if (!empty($pun_page['user_management'])): ?>		<div class="frm-info">
+			<h3><?php echo $lang_profile['User management'] ?></h3>
+			<ul>
+				<?php echo implode("\n\t\t\t\t", $pun_page['user_management'])."\n" ?>
+			</ul>
+		</div>
+<?php endif; ?>		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php if (!empty($pun_page['user_actions'])): ?>			<ul class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<?php echo implode("\n\t\t\t\t", $pun_page['user_actions'])."\n" ?>
+			</ul>
+<?php endif;
+
+		($hook = get_hook('pf_change_details_admin_pre_group_membership')) ? eval($hook) : null;
+
+		if ($pun_user['g_moderator'] != '1')
+		{
+			if ($pun_user['id'] != $id)
+			{
+
+?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Group membership'] ?></strong></legend>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['User group'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="group_id">
+<?php
+
+				$query = array(
+					'SELECT'	=> 'g.g_id, g.g_title',
+					'FROM'		=> 'groups AS g',
+					'WHERE'		=> 'g.g_id!='.PUN_GUEST,
+					'ORDER BY'	=> 'g.g_title'
+				);
+
+				($hook = get_hook('pf_qr_get_groups')) ? eval($hook) : null;
+				$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+				while ($cur_group = $pun_db->fetch_assoc($result))
+				{
+					if ($cur_group['g_id'] == $user['g_id'] || ($cur_group['g_id'] == $pun_config['o_default_user_group'] && $user['g_id'] == ''))
+						echo "\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'" selected="selected">'.htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+					else
+						echo "\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'">'.htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+				}
+
+?>
+						</select></span>
+					</label>
+					<input type="submit" name="update_group_membership" value="<?php echo $lang_profile['Save'] ?>" />
+				</div>
+			</fieldset>
+<?php if ($user['g_id'] != PUN_ADMIN && $user['g_moderator'] != '1'): ?>			<div class="frm-buttons">
+				<span><?php echo $lang_profile['Instructions'] ?></span>
+			</div>
+<?php endif;
+
+			}
+
+			if ($user['g_id'] == PUN_ADMIN || $user['g_moderator'] == '1')
+			{
+				$pun_page['set_count'] = 0;
+
+?>
+			<div class="frm-info">
+				<h3><?php echo $lang_profile['Moderator assignment'] ?></h3>
+				<ul>
+					<li><span><?php echo $lang_profile['Moderator in info'] ?></span></li>
+					<li><span><?php echo $lang_profile['Moderator in info 2'] ?></span></li>
+				</ul>
+			</div>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+<?php
+
+				$query = array(
+					'SELECT'	=> 'c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.moderators',
+					'FROM'		=> 'categories AS c',
+					'JOINS'		=> array(
+						array(
+							'INNER JOIN'	=> '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'
+				);
+
+				($hook = get_hook('pf_qr_get_cats_and_forums')) ? eval($hook) : null;
+				$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+				$cur_category = 0;
+				while ($cur_forum = $pun_db->fetch_assoc($result))
+				{
+					if ($cur_forum['cid'] != $cur_category)	// A new category since last iteration?
+					{
+						if ($cur_category)
+							echo "\n\t\t\t\t\t".'</fieldset>'."\n";
+
+						echo "\t\t\t\t".'<fieldset class="frm-group">'."\n\t\t\t\t\t".'<legend><span>'.$cur_forum['cat_name'].':</span></legend>'."\n";
+						$cur_category = $cur_forum['cid'];
+					}
+
+					$moderators = ($cur_forum['moderators'] != '') ? unserialize($cur_forum['moderators']) : array();
+
+					echo "\t\t\t\t\t".'<div class="radbox"><label for="fld'.(++$pun_page['fld_count']).'"><input type="checkbox" id="fld'.$pun_page['fld_count'].'" name="moderator_in['.$cur_forum['fid'].']" value="1"'.((in_array($id, $moderators)) ? ' checked="checked"' : '').' /> '.htmlspecialchars($cur_forum['forum_name']).'</label></div>'."\n";
+				}
+
+?>
+				</fieldset>
+			</fieldset>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="update_forums" value="<?php echo $lang_profile['Update forums'] ?>" /> <?php echo $lang_profile['Instructions'] ?></span>
+			</div>
+<?php
+
+			}
+		}
+
+		($hook = get_hook('pf_change_details_admin_form_end')) ? eval($hook) : null;
+
+?>
+		</form>
+	</div>
+
+</div>
+<?php
+
+		require PUN_ROOT.'footer.php';
+	}
+
+	($hook = get_hook('pf_change_details_new_section')) ? eval($hook) : null;
+
+	message($lang_common['Bad request']);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/register.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,464 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('rg_start')) ? eval($hook) : null;
+
+// If we are logged in, we shouldn't be here
+if (!$pun_user['is_guest'])
+{
+	header('Location: '.pun_link($pun_url['index']));
+	exit;
+}
+
+// Load the register.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/profile.php';
+
+
+if ($pun_config['o_regs_allow'] == '0')
+	message($lang_profile['No new regs']);
+
+
+// User pressed the cancel button
+if (isset($_GET['cancel']))
+	pun_redirect(pun_link($pun_url['index']), $lang_profile['Reg cancel redirect']);
+
+// User pressed agree but failed to tick checkbox
+else if (isset($_GET['agree']) && !isset($_GET['req_agreement']))
+	pun_redirect(pun_link($pun_url['index']), $lang_profile['Reg cancel redirect']);
+
+// Show the rules
+else if ($pun_config['o_rules'] == '1' && !isset($_GET['agree']) && !isset($_POST['form_sent']))
+{
+	// Setup breadcrumbs
+	$pun_page['crumbs'] = array(
+		array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+		array($lang_common['Register'], pun_link($pun_url['register'])),
+		$lang_common['Rules']
+	);
+
+	($hook = get_hook('rg_rules_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', 'rules');
+	require PUN_ROOT.'header.php';
+
+	$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_common['Forum rules'].' '.$lang_profile['Agree to rules'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="userbox">
+			<?php echo $pun_config['o_rules_message'] ?>
+		</div>
+		<form class="frm-form" method="get" accept-charset="utf-8" action="<?php echo $base_url ?>/register.php">
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_profile['Agreement'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_agreement" value="1" /> <?php echo $lang_profile['Agreement label'] ?></label>
+				</div>
+			</fieldset>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="agree" value="<?php echo $lang_profile['Agree'] ?>" /></span>
+				<span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+else if (isset($_POST['form_sent']))
+{
+	($hook = get_hook('rg_register_form_submitted')) ? eval($hook) : null;
+
+	// Check that someone from this IP didn't register a user within the last hour (DoS prevention)
+	$query = array(
+		'SELECT'	=> '1',
+		'FROM'		=> 'users AS u',
+		'WHERE'		=> 'u.registration_ip=\''.get_remote_address().'\' AND u.registered>'.(time() - 3600)
+	);
+
+	($hook = get_hook('rg_qr_check_register_flood')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if ($pun_db->num_rows($result))
+		message($lang_profile['Registration flood']);
+
+	$username = trim($_POST['req_username']);
+	$email1 = strtolower(trim($_POST['req_email1']));
+
+	if ($pun_config['o_regs_verify'] == '1')
+	{
+		$email2 = strtolower(trim($_POST['req_email2']));
+
+		$password1 = random_key(8, true);
+		$password2 = $password1;
+	}
+	else
+	{
+		$password1 = trim($_POST['req_password1']);
+		$password2 = trim($_POST['req_password2']);
+	}
+
+	// Validate the username
+	$errors = validate_username($username);
+	if (!empty($errors))
+		message(current($errors));
+
+	// ... and the password
+	if (pun_strlen($password1) < 4)
+		message($lang_profile['Pass too short']);
+	else if ($password1 != $password2)
+		message($lang_profile['Pass not match']);
+
+	// ... and the e-mail address
+	require PUN_ROOT.'include/email.php';
+
+	if (!is_valid_email($email1))
+		message($lang_common['Invalid e-mail']);
+	else if ($pun_config['o_regs_verify'] == '1' && $email1 != $email2)
+		message($lang_profile['E-mail not match']);
+
+	// Check if it's a banned e-mail address
+	$banned_email = is_banned_email($email1);
+	if ($banned_email && $pun_config['p_allow_banned_email'] == '0')
+		message($lang_profile['Banned e-mail']);
+
+	// Check if someone else already has registered with that e-mail address
+	$dupe_list = array();
+
+	$query = array(
+		'SELECT'	=> 'u.username',
+		'FROM'		=> 'users AS u',
+		'WHERE'		=> 'u.email=\''.$email1.'\''
+	);
+
+	($hook = get_hook('rg_qr_check_email_dupe')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if ($pun_db->num_rows($result))
+	{
+		if ($pun_config['p_allow_dupe_email'] == '0')
+			message($lang_profile['Dupe e-mail']);
+
+		while ($cur_dupe = $pun_db->fetch_assoc($result))
+			$dupe_list[] = $cur_dupe['username'];
+	}
+
+	// Make sure we got a valid language string
+	if (isset($_POST['language']))
+	{
+		$language = preg_replace('#[\.\\\/]#', '', $_POST['language']);
+		if (!file_exists(PUN_ROOT.'lang/'.$language.'/common.php'))
+			message($lang_common['Bad request']);
+	}
+	else
+		$language = $pun_config['o_default_lang'];
+
+	$save_pass = (!isset($_POST['save_pass']) || $_POST['save_pass'] != '1') ? 0 : 1;
+	$email_setting = intval($_POST['email_setting']);
+	if ($email_setting < 0 || $email_setting > 2) $email_setting = 1;
+
+	$initial_group_id = ($pun_config['o_regs_verify'] == '0') ? $pun_config['o_default_user_group'] : PUN_UNVERIFIED;
+	$salt = random_key(12);
+	$password_hash = sha1($salt.sha1($password1));
+
+	($hook = get_hook('rg_register_pre_add_user')) ? eval($hook) : null;
+
+	// Insert the new user into the database. We do this now to get the last inserted id for later use.
+	$errors = add_user(array(
+			'username'				=>	$username,
+			'group_id'				=>	$initial_group_id,
+			'salt'					=>	$salt,
+			'password'				=>	$password1,
+			'password_hash'			=>	$password_hash,
+			'email'					=>	$email1,
+			'email_setting'			=>	$email_setting,
+			'save_pass'				=>	$save_pass,
+			'timezone'				=>	$_POST['timezone'],
+			'language'				=>	$language,
+			'style'					=>	$pun_config['o_default_style'],
+			'registered'			=>	time(),
+			'registration_ip'		=>	get_remote_address(),
+			'activate_key'			=>	($pun_config['o_regs_verify'] == '1') ? '\''.random_key(8, true).'\'' : 'NULL',
+			'require_verification'	=>	($pun_config['o_regs_verify'] == '1'),
+			'notify_admins'			=>	($pun_config['o_regs_report'] == '1')
+		),
+		$new_uid	// By ref
+	);
+
+	// If we previously found out that the e-mail was banned
+	if ($banned_email && $pun_config['o_mailing_list'] != '')
+	{
+		($hook = get_hook('rg_register_banned_email')) ? eval($hook) : null;
+
+		$mail_subject = 'Alert - Banned e-mail detected';
+		$mail_message = 'User \''.$username.'\' registered with banned e-mail address: '.$email1."\n\n".'User profile: '.pun_link($pun_url['user'], $new_uid)."\n\n".'-- '."\n".'Forum Mailer'."\n".'(Do not reply to this message)';
+
+		pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
+	}
+
+	// If we previously found out that the e-mail was a dupe
+	if (!empty($dupe_list) && $pun_config['o_mailing_list'] != '')
+	{
+		($hook = get_hook('rg_register_dupe_email')) ? eval($hook) : null;
+
+		$mail_subject = 'Alert - Duplicate e-mail detected';
+		$mail_message = 'User \''.$username.'\' registered with an e-mail address that also belongs to: '.implode(', ', $dupe_list)."\n\n".'User profile: '.pun_link($pun_url['user'], $new_uid)."\n\n".'-- '."\n".'Forum Mailer'."\n".'(Do not reply to this message)';
+
+		pun_mail($pun_config['o_mailing_list'], $mail_subject, $mail_message);
+	}
+
+	($hook = get_hook('rg_register_pre_login_redirect')) ? eval($hook) : null;
+
+	// Must the user verify the registration or do we log him/her in right now?
+	if ($pun_config['o_regs_verify'] == '1')
+		message(sprintf($lang_profile['Reg e-mail'], '<a href="mailto:'.$pun_config['o_admin_email'].'">'.$pun_config['o_admin_email'].'</a>'));
+
+	pun_setcookie($cookie_name, base64_encode($new_uid.'|'.$password_hash), ($save_pass != '0') ? time() + 31536000 : 0);
+
+	pun_redirect(pun_link($pun_url['index']), $lang_profile['Reg complete']);
+}
+
+// Setup form
+$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+$pun_page['form_action'] = $base_url.'/register.php?action=register';
+
+// Setup form information
+$pun_page['frm_info'][] = '<p>'.$lang_profile['Register intro'].'</p>';
+if ($pun_config['o_regs_verify'] != '0')
+	$pun_page['frm_info'][] = '<p class="warn">'.$lang_profile['E-mail info'].'</p>';
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+	$lang_common['Register']
+);
+
+($hook = get_hook('rg_register_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_PAGE', 'register');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php printf($lang_profile['Register at'], htmlspecialchars($pun_config['o_board_title'])) ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<div class="frm-info">
+			<?php echo implode("\n\t\t\t\t", $pun_page['frm_info'])."\n" ?>
+		</div>
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form class="frm-form" id="afocus" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<input type="hidden" name="form_sent" value="1" />
+			</div>
+<?php ($hook = get_hook('rg_register_pre_req_info_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Required information'] ?></strong></legend>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Username'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_username" size="35" maxlength="25" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Username help'] ?></span>
+					</label>
+				</div>
+<?php if ($pun_config['o_regs_verify'] == '0'): ?>				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Password'] ?></span><br />
+						<span class="fld-input"><input type="password" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_password1" size="35" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Password help'] ?></span>
+					</label>
+				</div>
+				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Confirm password'] ?></span><br />
+						<span class="fld-input"><input type="password" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_password2" size="35" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Confirm password help'] ?></span>
+					</label>
+				</div>
+<?php endif; ($hook = get_hook('rg_register_pre_email_field')) ? eval($hook) : null; ?>				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['E-mail'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_email1" size="35" maxlength="80" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['E-mail help'] ?></span>
+					</label>
+				</div>
+<?php if ($pun_config['o_regs_verify'] == '1'): ?>				<div class="frm-fld text required">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Confirm e-mail'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="req_email2" size="35" maxlength="80" /></span><br />
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+						<span class="fld-help"><?php echo $lang_profile['Confirm e-mail help'] ?></span>
+					</label>
+				</div>
+<?php endif; ($hook = get_hook('rg_register_req_info_end')) ? eval($hook) : null; ?>			</fieldset>
+<?php ($hook = get_hook('rg_register_post_req_info_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Local legend'] ?></strong></legend>
+<?php
+
+		$languages = array();
+		$d = dir(PUN_ROOT.'lang');
+		while (($entry = $d->read()) !== false)
+		{
+			if ($entry != '.' && $entry != '..' && is_dir(PUN_ROOT.'lang/'.$entry) && file_exists(PUN_ROOT.'lang/'.$entry.'/common.php'))
+				$languages[] = $entry;
+		}
+		$d->close();
+
+		// Only display the language selection box if there's more than one language available
+		if (count($languages) > 1)
+		{
+			natcasesort($languages);
+
+?>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Language'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="language">
+<?php
+
+			while (list(, $temp) = @each($languages))
+			{
+				if ($pun_config['o_default_lang'] == $temp)
+					echo "\t\t\t\t\t\t".'<option value="'.$temp.'" selected="selected">'.$temp.'</option>'."\n";
+				else
+					echo "\t\t\t\t\t\t".'<option value="'.$temp.'">'.$temp.'</option>'."\n";
+			}
+
+?>
+						</select></span>
+					</label>
+				</div>
+<?php
+
+		}
+
+?>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_profile['Timezone'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="timezone">
+						<option value="-12"<?php if ($pun_config['o_default_timezone'] == -12 ) echo ' selected="selected"' ?>>-12</option>
+						<option value="-11"<?php if ($pun_config['o_default_timezone'] == -11) echo ' selected="selected"' ?>>-11</option>
+						<option value="-10"<?php if ($pun_config['o_default_timezone'] == -10) echo ' selected="selected"' ?>>-10</option>
+						<option value="-9.5"<?php if ($pun_config['o_default_timezone'] == -9.5) echo ' selected="selected"' ?>>-9.5</option>
+						<option value="-9"<?php if ($pun_config['o_default_timezone'] == -9 ) echo ' selected="selected"' ?>>-09</option>
+						<option value="-8.5"<?php if ($pun_config['o_default_timezone'] == -8.5) echo ' selected="selected"' ?>>-8.5</option>
+						<option value="-8"<?php if ($pun_config['o_default_timezone'] == -8 ) echo ' selected="selected"' ?>>-08 PST</option>
+						<option value="-7"<?php if ($pun_config['o_default_timezone'] == -7 ) echo ' selected="selected"' ?>>-07 MST</option>
+						<option value="-6"<?php if ($pun_config['o_default_timezone'] == -6 ) echo ' selected="selected"' ?>>-06 CST</option>
+						<option value="-5"<?php if ($pun_config['o_default_timezone'] == -5 ) echo ' selected="selected"' ?>>-05 EST</option>
+						<option value="-4"<?php if ($pun_config['o_default_timezone'] == -4 ) echo ' selected="selected"' ?>>-04 AST</option>
+						<option value="-3.5"<?php if ($pun_config['o_default_timezone'] == -3.5) echo ' selected="selected"' ?>>-3.5</option>
+						<option value="-3"<?php if ($pun_config['o_default_timezone'] == -3 ) echo ' selected="selected"' ?>>-03 ADT</option>
+						<option value="-2"<?php if ($pun_config['o_default_timezone'] == -2 ) echo ' selected="selected"' ?>>-02</option>
+						<option value="-1"<?php if ($pun_config['o_default_timezone'] == -1) echo ' selected="selected"' ?>>-01</option>
+						<option value="0"<?php if ($pun_config['o_default_timezone'] == 0) echo ' selected="selected"' ?>>00 GMT</option>
+						<option value="1"<?php if ($pun_config['o_default_timezone'] == 1) echo ' selected="selected"' ?>>+01 CET</option>
+						<option value="2"<?php if ($pun_config['o_default_timezone'] == 2 ) echo ' selected="selected"' ?>>+02</option>
+						<option value="3"<?php if ($pun_config['o_default_timezone'] == 3 ) echo ' selected="selected"' ?>>+03</option>
+						<option value="3.5"<?php if ($pun_config['o_default_timezone'] == 3.5 ) echo ' selected="selected"' ?>>+03.5</option>
+						<option value="4"<?php if ($pun_config['o_default_timezone'] == 4 ) echo ' selected="selected"' ?>>+04</option>
+						<option value="4.5"<?php if ($pun_config['o_default_timezone'] == 4.5 ) echo ' selected="selected"' ?>>+04.5</option>
+						<option value="5"<?php if ($pun_config['o_default_timezone'] == 5 ) echo ' selected="selected"' ?>>+05</option>
+						<option value="5.5"<?php if ($pun_config['o_default_timezone'] == 5.5 ) echo ' selected="selected"' ?>>+05.5</option>
+						<option value="6"<?php if ($pun_config['o_default_timezone'] == 6 ) echo ' selected="selected"' ?>>+06</option>
+						<option value="6.5"<?php if ($pun_config['o_default_timezone'] == 6.5 ) echo ' selected="selected"' ?>>+06.5</option>
+						<option value="7"<?php if ($pun_config['o_default_timezone'] == 7 ) echo ' selected="selected"' ?>>+07</option>
+						<option value="8"<?php if ($pun_config['o_default_timezone'] == 8 ) echo ' selected="selected"' ?>>+08</option>
+						<option value="9"<?php if ($pun_config['o_default_timezone'] == 9 ) echo ' selected="selected"' ?>>+09</option>
+						<option value="9.5"<?php if ($pun_config['o_default_timezone'] == 9.5 ) echo ' selected="selected"' ?>>+09.5</option>
+						<option value="10"<?php if ($pun_config['o_default_timezone'] == 10) echo ' selected="selected"' ?>>+10</option>
+						<option value="10.5"<?php if ($pun_config['o_default_timezone'] == 10.5 ) echo ' selected="selected"' ?>>+10.5</option>
+						<option value="11"<?php if ($pun_config['o_default_timezone'] == 11) echo ' selected="selected"' ?>>+11</option>
+						<option value="11.5"<?php if ($pun_config['o_default_timezone'] == 11.5 ) echo ' selected="selected"' ?>>+11.5</option>
+						<option value="12"<?php if ($pun_config['o_default_timezone'] == 12 ) echo ' selected="selected"' ?>>+12</option>
+						<option value="13"<?php if ($pun_config['o_default_timezone'] == 13 ) echo ' selected="selected"' ?>>+13</option>
+						<option value="14"<?php if ($pun_config['o_default_timezone'] == 14 ) echo ' selected="selected"' ?>>+14</option>
+						</select></span>
+					</label>
+				</div>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_profile['Adjust for DST'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" /> <?php echo $lang_profile['DST label'] ?></label>
+				</div>
+<?php ($hook = get_hook('rg_register_local_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('rg_register_post_local_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_profile['Other settings'] ?></strong></legend>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_profile['E-mail settings'] ?></span></legend>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="email_setting" value="0" /> <?php echo $lang_profile['E-mail setting 1'] ?></label></div>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="email_setting" value="1" checked="checked" /> <?php echo $lang_profile['E-mail setting 2'] ?></label></div>
+					<div class="radbox"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="email_setting" value="2" /> <?php echo $lang_profile['E-mail setting 3'] ?></label></div>
+				</fieldset>
+				<div class="checkbox radbox">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>"><span class="fld-label"><?php echo $lang_profile['Persistent login'] ?></span><br /><input type="checkbox" id="fld<?php echo $pun_page['fld_count'] ?>" name="save_pass" value="1" checked="checked" /> <?php echo $lang_profile['Save user/pass'] ?></label>
+				</div>
+<?php ($hook = get_hook('rg_register_other_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('rg_register_post_other_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="register" value="<?php echo $lang_common['Register'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+($hook = get_hook('rg_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/search.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,1250 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('se_start')) ? eval($hook) : null;
+
+// Load the search.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/search.php';
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+else if ($pun_user['g_search'] == '0')
+	message($lang_search['No search permission']);
+
+
+// Figure out what to do :-)
+if (isset($_GET['action']) || isset($_GET['search_id']))
+{
+	// Grab and validate all the submitted data
+	$action = (isset($_GET['action'])) ? $_GET['action'] : null;
+	$value = (isset($_GET['value'])) ? intval($_GET['value']) : 86400;
+	$forum = (isset($_GET['forum'])) ? intval($_GET['forum']) : -1;
+	$sort_dir = (isset($_GET['sort_dir'])) ? (($_GET['sort_dir'] == 'DESC') ? 'DESC' : 'ASC') : 'DESC';
+	if (isset($search_id)) unset($search_id);
+
+	// If a search_id was supplied
+	if (isset($_GET['search_id']))
+	{
+		$search_id = intval($_GET['search_id']);
+		if ($db_type == 'mysql' || $db_type == 'mysqli')
+			message($lang_common['Bad request']);
+		if ($search_id < 1)
+			message($lang_common['Bad request']);
+	}
+
+	// A list of valid actions (extensions can add their own actions to the array)
+	$valid_actions = array('search', 'show_new', 'show_recent', 'show_user_posts', 'show_user_topics', 'show_subscriptions', 'show_unanswered');
+
+	($hook = get_hook('se_search_selected')) ? eval($hook) : null;
+
+	// Validate action
+	if ($action && !in_array($action, $valid_actions))
+		message($lang_common['Bad request']);
+
+	// If it's a regular search (keywords and/or author)
+	if ($action == 'search')
+	{
+		$keywords = (isset($_GET['keywords'])) ? strtolower(trim($_GET['keywords'])) : null;
+		$author = (isset($_GET['author'])) ? strtolower(trim($_GET['author'])) : null;
+
+		if (preg_match('#^[\*%]+$#', $keywords) || pun_strlen(str_replace(array('*', '%'), '', $keywords)) < 3)
+			$keywords = '';
+
+		if (preg_match('#^[\*%]+$#', $author) || pun_strlen(str_replace(array('*', '%'), '', $author)) < 2)
+			$author = '';
+
+		if (!$keywords && !$author)
+			message($lang_search['No terms']);
+
+		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);
+
+	}
+	// If it's a user search (by id), make sure we have a user_id
+	else if ($action == 'show_user_posts' || $action == 'show_user_topics')
+	{
+		$user_id = isset($_GET['user_id']) ? intval($_GET['user_id']) : 0;
+		if ($user_id < 2)
+			message($lang_common['Bad request']);
+	}
+
+	// First of all lets find out if we need to cache the results, we only need to do this for detailed queries, not quicksearches or for mysql(i)
+	if ($db_type != 'mysql' && $db_type != 'mysqli' && (isset($keywords) || isset($author)))
+	{
+		// We need to grab results, insert them into the cache and reload with a search id before showing them
+		$keyword_results = $author_results = array();
+
+		// If it's a search for keywords
+		if ($keywords)
+		{
+			$stopwords = (array)@file(PUN_ROOT.'lang/'.$pun_user['language'].'/stopwords.txt');
+			$stopwords = array_map('trim', $stopwords);
+
+			// Filter out non-alphabetical chars
+			$noise_match = array('^', '$', '&', '(', ')', '<', '>', '`', '\'', '"', '|', ',', '@', '_', '?', '%', '~', '[', ']', '{', '}', ':', '\\', '/', '=', '#', '\'', ';', '!', '¤');
+			$noise_replace = array(' ', ' ', ' ', ' ', ' ', ' ', ' ', '',  '',   ' ', ' ', ' ', ' ', '',  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '' ,  ' ', ' ', ' ', ' ',  ' ', ' ', ' ');
+			$keywords = str_replace($noise_match, $noise_replace, $keywords);
+
+			// Strip out excessive whitespace
+			$keywords = trim(preg_replace('#\s+#', ' ', $keywords));
+
+			// Fill an array with all the words
+			$keywords_array = explode(' ', $keywords);
+			if (empty($keywords_array))
+				message($lang_search['No hits']);
+
+			while (list($i, $word) = @each($keywords_array))
+			{
+				$num_chars = pun_strlen($word);
+
+				if ($word !== 'or' && ($num_chars < 3 || $num_chars > 20 || in_array($word, $stopwords)))
+					unset($keywords_array[$i]);
+			}
+
+			$word_count = 0;
+			$match_type = 'and';
+			$result_list = array();
+			@reset($keywords_array);
+			while (list(, $cur_word) = @each($keywords_array))
+			{
+				switch ($cur_word)
+				{
+					case 'and':
+					case 'or':
+					case 'not':
+						$match_type = $cur_word;
+						break;
+
+					default:
+					{
+						$cur_word = str_replace('*', '%', $cur_word);
+
+						$query = array(
+							'SELECT'	=> 'm.post_id',
+							'FROM'		=> 'search_words AS w',
+							'JOINS'		=> array(
+								array(
+									'INNER JOIN'	=> 'search_matches AS m',
+									'ON'			=> 'm.word_id=w.id'
+								)
+							),
+							'WHERE'		=> 'w.word LIKE \''.$cur_word.'\''
+						);
+
+						// Search in what?
+						if ($search_in)
+							$query['WHERE'] .= ($search_in > 0 ? ' AND m.subject_match=0' : ' AND m.subject_match=1');
+
+						($hook = get_hook('se_qr_get_keyword_hits')) ? eval($hook) : null;
+						$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+						$row = array();
+						while ($temp = $pun_db->fetch_row($result))
+						{
+							$row[$temp[0]] = 1;
+
+							if (!$word_count)
+								$result_list[$temp[0]] = 1;
+							else if ($match_type == 'or')
+								$result_list[$temp[0]] = 1;
+							else if ($match_type == 'not')
+								$result_list[$temp[0]] = 0;
+						}
+
+						if ($match_type == 'and' && $word_count)
+						{
+							@reset($result_list);
+							while (list($post_id,) = @each($result_list))
+							{
+								if (!isset($row[$post_id]))
+									$result_list[$post_id] = 0;
+							}
+						}
+
+						++$word_count;
+						$pun_db->free_result($result);
+
+						break;
+					}
+				}
+			}
+
+			@reset($result_list);
+			while (list($post_id, $matches) = @each($result_list))
+			{
+				if ($matches)
+					$keyword_results[] = $post_id;
+			}
+
+			unset($result_list);
+		}
+
+		// If it's a search for author name (and that author name isn't Guest)
+		if ($author && strtolower($author) != 'guest' && strtolower($author) != strtolower($lang_common['Guest']))
+		{
+			$query = array(
+				'SELECT'	=> 'u.id',
+				'FROM'		=> 'users AS u',
+				'WHERE'		=> 'u.username '.($db_type == 'pgsql' ? 'ILIKE' : 'LIKE').' \''.$pun_db->escape($author).'\''
+			);
+
+			($hook = get_hook('se_qr_get_author')) ? eval($hook) : null;
+			$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+			if ($pun_db->num_rows($result))
+			{
+				$user_ids = '';
+				while ($row = $pun_db->fetch_row($result))
+					$user_ids .= (($user_ids != '') ? ',' : '').$row[0];
+
+				$query = array(
+					'SELECT'	=> 'p.id',
+					'FROM'		=> 'posts AS p',
+					'WHERE'		=> 'p.poster_id IN('.$user_ids.')'
+				);
+
+				($hook = get_hook('se_qr_get_author_hits')) ? eval($hook) : null;
+				$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+				$search_ids = array();
+				while ($row = $pun_db->fetch_row($result))
+					$author_results[] = $row[0];
+
+				$pun_db->free_result($result);
+			}
+		}
+
+		if ($author && $keywords)
+		{
+			// If we searched for both keywords and author name we want the intersection between the results
+			$search_ids = array_intersect($keyword_results, $author_results);
+			unset($keyword_results, $author_results);
+		}
+		else if ($keywords)
+			$search_ids = $keyword_results;
+		else
+			$search_ids = $author_results;
+
+		if (count($search_ids) == 0)
+			message($lang_search['No hits']);
+
+
+		// Setup the default show_as topics search
+		$query = array(
+			'SELECT'	=> 't.id',
+			'FROM'		=> 'posts AS p',
+			'JOINS'		=> array(
+				array(
+					'INNER JOIN'	=> 'topics AS t',
+					'ON'			=> 't.id=p.topic_id'
+				),
+				array(
+					'LEFT JOIN'		=> 'forum_perms AS fp',
+					'ON'			=> '(fp.forum_id=t.forum_id AND fp.group_id='.$pun_user['g_id'].')'
+				)
+			),
+			'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND p.id IN('.implode(',', $search_ids).')',
+			'GROUP BY'	=> 't.id'
+		);
+
+		// Search a specific forum?
+		if ($forum != -1 || ($forum == -1 && $pun_config['o_search_all_forums'] == '0' && !$pun_user['is_admmod']))
+			$query['WHERE'] .= ' AND t.forum_id = '.$forum;
+
+		// Adjust the query if show_as posts
+		if ($show_as == 'posts')
+		{
+			$query['SELECT'] = 'p.id';
+			unset($query['GROUP BY']);
+		}
+
+		($hook = get_hook('se_qr_get_hits')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+		$search_ids = array();
+		while ($row = $pun_db->fetch_row($result))
+			$search_ids[] = $row[0];
+
+
+		// Prune "old" search results
+		$query = array(
+			'SELECT'	=> 'o.ident',
+			'FROM'		=> 'online AS o'
+		);
+
+		($hook = get_hook('se_qr_get_online_idents')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if ($pun_db->num_rows($result))
+		{
+			$online_idents = array();
+			while ($row = $pun_db->fetch_row($result))
+				$online_idents[] = '\''.$pun_db->escape($row[0]).'\'';
+
+			$query = array(
+				'DELETE'	=> 'search_cache',
+				'WHERE'		=> 'ident NOT IN('.implode(',', $online_idents).')'
+			);
+
+			($hook = get_hook('se_qr_delete_old_cached_searches')) ? eval($hook) : null;
+			$pun_db->query_build($query) or error(__FILE__, __LINE__);
+		}
+
+		// Final search results
+		$search_results = implode(',', $search_ids);
+
+		// Fill an array with our results and search properties
+		$temp['search_results'] = $search_results;
+		$temp['sort_by'] = $sort_by;
+		$temp['sort_dir'] = $sort_dir;
+		$temp['show_as'] = $show_as;
+		$temp = serialize($temp);
+		$search_id = mt_rand(1, 2147483647);
+
+		$ident = ($pun_user['is_guest']) ? get_remote_address() : $pun_user['username'];
+
+		$query = array(
+			'INSERT'	=> 'id, ident, search_data',
+			'INTO'		=> 'search_cache',
+			'VALUES'	=> $search_id.', \''.$pun_db->escape($ident).'\', \''.$pun_db->escape($temp).'\''
+		);
+
+		($hook = get_hook('se_qr_cache_search')) ? eval($hook) : null;
+		$pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+		$pun_db->end_transaction();
+		$pun_db->close();
+
+		// Redirect the user to the cached result page
+		header('Location: '.str_replace('&amp;', '&', pun_link($pun_url['search_results'], $search_id)));
+		exit;
+	}
+
+	// If we're still running we don't need to cache results but we still need to get them, either from the cache or from their respective sources.
+
+	// We're doing a fulltext search!
+	else if (($db_type == 'mysql' || $db_type == 'mysqli') && (isset($keywords) || isset($author)))
+	{
+		// Are we limiting the results to a specific forum?
+		if ($forum != -1 || ($forum == -1 && $pun_config['o_search_all_forums'] == '0' && !$pun_user['is_admmod']))
+			$forum_where = ' AND f.id = '.$forum;
+		else
+			$forum_where = '';
+
+		// Sort out how to order the results
+		switch ($sort_by)
+		{
+			case 1:
+				$sort_by_sql = ($show_as == 'topics') ? 'poster' : 'p.poster';
+				break;
+
+			case 2:
+				$sort_by_sql = 'subject';
+				break;
+
+			case 3:
+				$sort_by_sql = 'forum_id';
+				break;
+
+			case 4:
+				if ($show_as == 'posts')
+					$sort_by_sql = 'MATCH(p.message) AGAINST(\''.$pun_db->escape($keywords).'\')';
+				else
+					$sort_by_sql = 'total_relevance';
+				break;
+
+			default:
+				$sort_by_sql = ($show_as == 'topics') ? 'posted' : 'p.posted';
+				break;
+		}
+
+		// Generate the query to give us our results
+		if ($show_as == 'posts')
+			$query = '
+				SELECT
+					p.id AS pid, p.poster AS pposter, p.posted AS pposted, p.poster_id, SUBSTRING(p.message, 1, 1000) AS message, t.id AS tid, t.poster, t.subject, t.first_post_id, t.posted, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.forum_id, f.forum_name
+				FROM '.$pun_db->prefix.'posts AS p LEFT JOIN '.$pun_db->prefix.'topics AS t ON t.id=p.topic_id LEFT JOIN '.$pun_db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$pun_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)
+					'.($author ? 'AND p.poster LIKE \''.$pun_db->escape($author).'\'' : '').'
+					'.($keywords ? 'AND MATCH(p.message) AGAINST(\''.$pun_db->escape($keywords).'\' IN BOOLEAN MODE)' : '').'
+					'.$forum_where.'
+				ORDER BY '.$sort_by_sql.' '.$sort_dir;
+		else
+		{
+			$query = '
+				SELECT
+					*, SUM(relevance) AS total_relevance FROM
+				(
+					SELECT
+						t.id AS tid, t.poster, t.subject, t.first_post_id, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id, t.posted, f.forum_name, MATCH(t.subject) AGAINST(\''.$pun_db->escape($keywords).'\') AS relevance
+					FROM '.$pun_db->prefix.'topics AS t LEFT JOIN '.$pun_db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$pun_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)
+						'.($keywords ? 'AND MATCH(t.subject) AGAINST(\''.$pun_db->escape($keywords).'\' IN BOOLEAN MODE)' : '').'
+						'.$forum_where.'
+					UNION
+					SELECT
+						t.id AS tid, t.poster, t.subject, t.first_post_id, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id, t.posted, f.forum_name, MATCH(p.message) AGAINST(\''.$pun_db->escape($keywords).'\') AS relevance
+					FROM '.$pun_db->prefix.'posts AS p INNER JOIN '.$pun_db->prefix.'topics AS t ON p.topic_id = t.id LEFT JOIN '.$pun_db->prefix.'forums AS f ON f.id=t.forum_id LEFT JOIN '.$pun_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)
+						'.($author ? 'AND p.poster LIKE \''.$pun_db->escape($author).'\'' : '').'
+						'.($keywords ? 'AND MATCH(p.message) AGAINST(\''.$pun_db->escape($keywords).'\' IN BOOLEAN MODE)' : '').'
+						'.$forum_where.'
+				) AS tmp
+				GROUP BY tid
+				ORDER BY '.$sort_by_sql.' '.$sort_dir;
+		}
+
+		$url_type = $pun_url['search_resultft'];
+
+		$search_id = array($keywords, $forum, $author, ($search_in == 0 ) ? 'all' : (($search_in == 1) ? 'message' : 'subject'), $sort_by, $sort_dir, $show_as);
+	}
+	// We aren't doing a fulltext but we are getting results, if a valid search_id was supplied we attempt to fetch the search results from the cache
+	else if (isset($search_id))
+	{
+		$ident = ($pun_user['is_guest']) ? get_remote_address() : $pun_user['username'];
+
+		$query = array(
+			'SELECT'	=> 'sc.search_data',
+			'FROM'		=> 'search_cache AS sc',
+			'WHERE'		=> 'sc.id='.$search_id.' AND sc.ident=\''.$pun_db->escape($ident).'\''
+		);
+
+		($hook = get_hook('se_qr_get_cached_search_data')) ? eval($hook) : null;
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+		if ($row = $pun_db->fetch_assoc($result))
+		{
+			$temp = unserialize($row['search_data']);
+
+			$search_results = $temp['search_results'];
+			$sort_by = $temp['sort_by'];
+			$sort_dir = $temp['sort_dir'];
+			$show_as = $temp['show_as'];
+
+			unset($temp);
+		}
+		else
+			message($lang_search['No hits']);
+
+		switch ($sort_by)
+		{
+			case 1:
+				$sort_by_sql = ($show_as == 'topics') ? 't.poster' : 'p.poster';
+				break;
+
+			case 2:
+				$sort_by_sql = 't.subject';
+				break;
+
+			case 3:
+				$sort_by_sql = 't.forum_id';
+				break;
+
+			default:
+				$sort_by_sql = ($show_as == 'topics') ? 't.posted' : 'p.posted';
+				break;
+		}
+
+		if ($show_as == 'posts')
+		{
+			$query = array(
+				'SELECT'	=> 'p.id AS pid, p.poster AS pposter, p.posted AS pposted, p.poster_id, '.(($db_type != 'sqlite') ? 'SUBSTRING' : 'SUBSTR').'(p.message, 1, 1000) AS message, t.id AS tid, t.poster, t.subject, t.first_post_id, t.posted, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.forum_id, f.forum_name',
+				'FROM'		=> 'posts AS p',
+				'JOINS'		=> array(
+					array(
+						'INNER JOIN'	=> 'topics AS t',
+						'ON'			=> 't.id=p.topic_id'
+					),
+					array(
+						'INNER JOIN'	=> 'forums AS f',
+						'ON'			=> 'f.id=t.forum_id'
+					)
+				),
+				'WHERE'		=> 'p.id IN('.$search_results.')',
+				'ORDER BY'	=> $sort_by_sql
+			);
+
+			($hook = get_hook('se_qr_get_cached_hits_as_posts')) ? eval($hook) : null;
+		}
+		else
+		{
+			$query = array(
+				'SELECT'	=> 't.id AS tid, t.poster, t.subject, t.first_post_id, t.posted, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id, f.forum_name',
+				'FROM'		=> 'topics AS t',
+				'JOINS'		=> array(
+					array(
+						'INNER JOIN'	=> 'forums AS f',
+						'ON'			=> 'f.id=t.forum_id'
+					)
+				),
+				'WHERE'		=> 't.id IN('.$search_results.')',
+				'ORDER BY'	=> 'p.id, '.$sort_by_sql
+			);
+
+			($hook = get_hook('se_qr_get_cached_hits_as_topics')) ? eval($hook) : null;
+		}
+
+		$url_type = $pun_url['search_results'];
+	}
+	else if (in_array($action, $valid_actions))
+	{
+		$search_id = '';
+		$show_as = 'topics';
+		switch ($action)
+		{
+			case 'show_new':
+				if ($pun_user['is_guest'])
+					message($lang_common['No permission']);
+
+				$query = array(
+					'SELECT'	=> 't.id AS tid, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id, f.forum_name',
+					'FROM'		=> 'topics AS t',
+					'JOINS'		=> array(
+						array(
+							'INNER JOIN'	=> 'forums AS f',
+							'ON'			=> 'f.id=t.forum_id'
+						),
+						array(
+							'LEFT JOIN'		=> 'forum_perms AS fp',
+							'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+						)
+					),
+					'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND t.last_post>'.$pun_user['last_visit'].' AND t.moved_to IS NULL',
+					'ORDER BY'	=> 't.last_post DESC'
+				);
+
+				($hook = get_hook('se_qr_get_new')) ? eval($hook) : null;
+
+				$url_type = $pun_url['search_new'];
+				break;
+
+			case 'show_recent':
+				$query = array(
+					'SELECT'	=> 't.id AS tid, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id, f.forum_name',
+					'FROM'		=> 'topics AS t',
+					'JOINS'		=> array(
+						array(
+							'INNER JOIN'	=> 'posts AS p',
+							'ON'			=> 'p.topic_id=t.id'
+						),
+						array(
+							'INNER JOIN'	=> 'forums AS f',
+							'ON'			=> 'f.id=t.forum_id'
+						),
+						array(
+							'LEFT JOIN'		=> 'forum_perms AS fp',
+							'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+						)
+					),
+					'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND p.posted>'.(time() - $value).' AND t.moved_to IS NULL',
+					'GROUP BY'	=> 't.id',
+					'ORDER BY'	=> 't.last_post DESC'
+				);
+
+				($hook = get_hook('se_qr_get_recent')) ? eval($hook) : null;
+
+				$url_type = $pun_url['search_24h'];
+				break;
+
+			case 'show_user_posts':
+				$query = array(
+					'SELECT'	=> 'p.id AS pid, p.poster AS pposter, p.posted AS pposted, p.poster_id, '.(($db_type != 'sqlite') ? 'SUBSTRING' : 'SUBSTR').'(p.message, 1, 1000) AS message, t.id AS tid, t.poster, t.subject, t.first_post_id, t.posted, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.forum_id, f.forum_name',
+					'FROM'		=> 'posts AS p',
+					'JOINS'		=> array(
+						array(
+							'INNER JOIN'	=> 'topics AS t',
+							'ON'			=> 't.id=p.topic_id'
+						),
+						array(
+							'INNER JOIN'	=> 'forums AS f',
+							'ON'			=> 'f.id=t.forum_id'
+						),
+						array(
+							'LEFT JOIN'		=> 'forum_perms AS fp',
+							'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+						)
+					),
+					'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND p.poster_id='.$user_id,
+					'ORDER BY'	=> 'pposted DESC'
+				);
+
+				($hook = get_hook('se_qr_get_user_posts')) ? eval($hook) : null;
+
+				$url_type = $pun_url['search_user_posts'];
+				$search_id = $user_id;
+				$show_as = 'posts';
+				break;
+
+			case 'show_user_topics':
+				$query = array(
+					'SELECT'	=> 't.id AS tid, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id, f.forum_name',
+					'FROM'		=> 'topics AS t',
+					'JOINS'		=> array(
+						array(
+							'INNER JOIN'	=> 'posts AS p',
+							'ON'			=> 't.first_post_id=p.id'
+						),
+						array(
+							'INNER JOIN'	=> 'forums AS f',
+							'ON'			=> 'f.id=t.forum_id'
+						),
+						array(
+							'LEFT JOIN'		=> 'forum_perms AS fp',
+							'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+						)
+					),
+					'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND p.poster_id='.$user_id,
+					'ORDER BY'	=> 't.last_post DESC'
+				);
+
+				($hook = get_hook('se_qr_get_user_topics')) ? eval($hook) : null;
+
+				$url_type = $pun_url['search_user_topics'];
+				$search_id = $user_id;
+				break;
+
+			case 'show_subscriptions':
+				if ($pun_user['is_guest'])
+					message($lang_common['Bad request']);
+
+				$query = array(
+					'SELECT'	=> 't.id AS tid, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id, f.forum_name',
+					'FROM'		=> 'topics AS t',
+					'JOINS'		=> array(
+						array(
+							'INNER JOIN'	=> 'subscriptions AS s',
+							'ON'			=> '(t.id=s.topic_id AND s.user_id='.$pun_user['id'].')'
+						),
+						array(
+							'INNER JOIN'	=> 'forums AS f',
+							'ON'			=> 'f.id=t.forum_id'
+						),
+						array(
+							'LEFT JOIN'		=> '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)',
+					'ORDER BY'	=> 't.last_post DESC'
+				);
+
+				($hook = get_hook('se_qr_get_subscriptions')) ? eval($hook) : null;
+
+				$url_type = $pun_url['search_subscriptions'];
+				break;
+
+			case 'show_unanswered':
+				$query = array(
+					'SELECT'	=> 't.id AS tid, t.poster, t.subject, t.last_post, t.last_post_id, t.last_poster, t.num_replies, t.closed, t.forum_id, f.forum_name',
+					'FROM'		=> 'topics AS t',
+					'JOINS'		=> array(
+						array(
+							'INNER JOIN'	=> 'posts AS p',
+							'ON'			=> 't.id=p.topic_id'
+						),
+						array(
+							'INNER JOIN'	=> 'forums AS f',
+							'ON'			=> 'f.id=t.forum_id'
+						),
+						array(
+							'LEFT JOIN'		=> 'forum_perms AS fp',
+							'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+						)
+					),
+					'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND t.num_replies=0 AND t.moved_to IS NULL',
+					'GROUP BY'	=> 't.id',
+					'ORDER BY'	=> 't.last_post DESC'
+				);
+
+				($hook = get_hook('se_qr_get_unanswered')) ? eval($hook) : null;
+
+				$url_type = $pun_url['search_unanswered'];
+				break;
+
+			default:
+				// A good place for an extension to add a new search type (action must be added to $valid_actions first)
+				($hook = get_hook('se_new_action')) ? eval($hook) : null;
+				break;
+		}
+	}
+	else
+		message($lang_common['Bad request']);
+
+	// We now have a query that will give us our results in $query, lets get the data!
+	if (is_array($query))
+		$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	else
+		$result = $pun_db->query($query) or error(__FILE__, __LINE__);
+
+	// Make sure we actually have some results
+	$num_hits = $pun_db->num_rows($result);
+	if ($num_hits == 0)
+	{
+		$pun_page['search_again'] = '<a href="'.pun_link($pun_url['search']).'">'.$lang_search['Perform new search'].'</a>';
+
+		switch ($action)
+		{
+			case 'show_new':
+				message($lang_search['No new posts'], $pun_page['search_again']);
+
+			case 'show_recent':
+				message($lang_search['No recent posts'], $pun_page['search_again']);
+
+			case 'show_user_posts':
+				message($lang_search['No user posts'], $pun_page['search_again']);
+
+			case 'show_user_topics':
+				message($lang_search['No user topics'], $pun_page['search_again']);
+
+			case 'show_subscriptions':
+				message($lang_search['No subscriptions'], $pun_page['search_again']);
+
+			case 'show_unanswered':
+				message($lang_search['No unanswered'], $pun_page['search_again']);
+
+			default:
+				($hook = get_hook('se_new_action_no_hits')) ? eval($hook) : null;
+				message($lang_search['No hits'], $pun_page['search_again']);
+		}
+	}
+
+	// Get topic/forum tracking data
+	if (!$pun_user['is_guest'])
+		$tracked_topics = get_tracked_topics();
+
+	// Determine the topic or post offset (based on $_GET['p'])
+	$pun_page['per_page'] = ($show_as == 'posts') ? $pun_user['disp_posts'] : $pun_user['disp_topics'];
+	$pun_page['num_pages'] = ceil($num_hits / $pun_page['per_page']);
+
+	$pun_page['page'] = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $pun_page['num_pages']) ? 1 : $_GET['p'];
+	$pun_page['start_from'] = $pun_page['per_page'] * ($pun_page['page'] - 1);
+	$pun_page['finish_at'] = min(($pun_page['start_from'] + $pun_page['per_page']), $num_hits);
+
+	// Generate paging links
+	$pun_page['page_post'] = '<p class="paging"><strong>'.$lang_common['Pages'].'</strong> '.pun_paginate($pun_page['num_pages'], $pun_page['page'], $url_type, $search_id).'</p>';
+
+
+	// Fill $search_set with out search hits
+	$search_set = array();
+	$row_num = 0;
+	while ($row = $pun_db->fetch_assoc($result))
+	{
+		if ($pun_page['start_from'] <= $row_num && $pun_page['finish_at'] > $row_num)
+			$search_set[] = $row;
+		++$row_num;
+	}
+
+	$pun_db->free_result($result);
+
+
+	// Navigation links for header and page numbering for title/meta description
+	if ($pun_page['page'] < $pun_page['num_pages'])
+	{
+		$pun_page['nav'][] = '<link rel="last" href="'.pun_sublink($url_type, $pun_url['page'], $pun_page['num_pages'], $search_id).'" title="'.$lang_common['Page'].' '.$pun_page['num_pages'].'" />';
+		$pun_page['nav'][] = '<link rel="next" href="'.pun_sublink($url_type, $pun_url['page'], ($pun_page['page'] + 1), $search_id).'" title="'.$lang_common['Page'].' '.($pun_page['page'] + 1).'" />';
+	}
+	if ($pun_page['page'] > 1)
+	{
+		$pun_page['nav'][] = '<link rel="prev" href="'.pun_sublink($url_type, $pun_url['page'], ($pun_page['page'] - 1), $search_id).'" title="'.$lang_common['Page'].' '.($pun_page['page'] - 1).'" />';
+		$pun_page['nav'][] = '<link rel="first" href="'.pun_link($url_type, $search_id).'" title="'.$lang_common['Page'].' 1" />';
+	}
+
+	// Setup breadcrumbs and results header and footer
+	$pun_page['main_foot_options'][] = '<a class="user-option" href="'.pun_link($pun_url['search']).'">'.$lang_search['Perform new search'].'</a>';
+	$pun_page['crumbs'][] = array($pun_config['o_board_title'], pun_link($pun_url['index']));
+
+	switch ($action)
+	{
+		case 'show_new':
+			$pun_page['crumbs'][] = $lang_common['New posts'];
+			$pun_page['main_info'] = (($pun_page['num_pages'] == 1) ? sprintf($lang_common['Page info'], $lang_search['Topics with new'], $num_hits) : '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_search['Topics with new'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $num_hits));
+			$pun_page['main_foot_options'][] = '<a class="user-option" href="'.pun_link($pun_url['mark_read']).'">'.$lang_common['Mark all as read'].'</a>';
+			break;
+
+		case 'show_recent':
+			$pun_page['crumbs'][] = $lang_common['Recent posts'];
+			$pun_page['main_info'] = (($pun_page['num_pages'] == 1) ? sprintf($lang_common['Page info'], $lang_search['Topics with recent'], $num_hits) : '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_search['Topics with recent'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $num_hits));
+			break;
+
+		case 'show_unanswered':
+			$pun_page['crumbs'][] = $lang_common['Unanswered topics'];
+			$pun_page['main_info'] = (($pun_page['num_pages'] == 1) ? sprintf($lang_common['Page info'], $lang_common['Unanswered topics'], $num_hits) : '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_common['Unanswered topics'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $num_hits));
+			break;
+
+		case 'show_user_posts':
+			$pun_page['crumbs'][] = sprintf($lang_search['Posts by'], $search_set[0]['pposter']);
+			$pun_page['main_info'] = (($pun_page['num_pages'] == 1) ? sprintf($lang_common['Page info'], sprintf($lang_search['Posts by'], $search_set[0]['pposter']), $num_hits) : '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], sprintf($lang_search['Posts by'], $search_set[0]['pposter']), $pun_page['start_from'] + 1, $pun_page['finish_at'], $num_hits));
+			$pun_page['main_foot_options'][] = '<a class="user-option" href="'.pun_link($pun_url['search_user_topics'], $search_id).'">'.sprintf($lang_search['Topics by'], $search_set[0]['pposter']).'</a>';
+			break;
+
+		case 'show_user_topics':
+			$pun_page['crumbs'][] = sprintf($lang_search['Topics by'], $search_set[0]['poster']);
+			$pun_page['main_info'] = (($pun_page['num_pages'] == 1) ? sprintf($lang_common['Page info'], sprintf($lang_search['Topics by'], $search_set[0]['poster']), $num_hits) : '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], sprintf($lang_search['Topics by'], $search_set[0]['poster']), $pun_page['start_from'] + 1, $pun_page['finish_at'], $num_hits));
+			$pun_page['main_foot_options'][] = '<a class="user-option" href="'.pun_link($pun_url['search_user_posts'], $search_id).'">'.sprintf($lang_search['Posts by'], $search_set[0]['poster']).'</a>';
+			break;
+
+		case 'show_subscriptions':
+			$pun_page['crumbs'][] = $lang_common['Your subscriptions'];
+			$pun_page['main_info'] = (($pun_page['num_pages'] == 1) ? sprintf($lang_common['Page info'], $lang_common['Your subscriptions'], $num_hits) : '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_common['Your subscriptions'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $num_hits));
+			break;
+
+		default:
+			$pun_page['crumbs'][] = $lang_search['Search results'];
+			$pun_page['main_info'] = (($pun_page['num_pages'] == 1) ? sprintf($lang_common['Page info'], (($show_as=='topics') ? $lang_common['Topics'] : $lang_common['Posts']), $num_hits) : '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], (($show_as=='topics') ? $lang_common['Topics'] : $lang_common['Posts']), $pun_page['start_from'] + 1, $pun_page['finish_at'], $num_hits));
+			break;
+	}
+
+	($hook = get_hook('se_results_pre_header_load')) ? eval($hook) : null;
+
+	define('PUN_PAGE', $show_as == 'topics' ? 'searchtopics' : 'searchposts');
+	require PUN_ROOT.'header.php';
+
+	if ($show_as == 'topics')
+	{
+		// Load the forum.php language file
+		require PUN_ROOT.'lang/'.$pun_user['language'].'/forum.php';
+
+?>
+<div id="pun-main" class="main paged">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="paged-head">
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+	<div class="main-head">
+		<h2><span><?php echo $pun_page['main_info'] ?></span></h2>
+	</div>
+
+	<div class="main-content forum">
+		<table cellspacing="0" summary="<?php echo $lang_search['Table summary'] ?>">
+			<thead>
+				<tr>
+					<th class="tcl" scope="col"><?php echo $lang_common['Topic']; ?></th>
+					<th class="tc2" scope="col"><?php echo $lang_common['Forum'] ?></th>
+					<th class="tc3" scope="col"><?php echo $lang_common['Replies'] ?></th>
+					<th class="tcr" scope="col"><?php echo $lang_common['Last post'] ?></th>
+				</tr>
+			</thead>
+			<tbody class="statused">
+<?php
+
+	}
+	else
+	{
+		// Load the topic.php language file
+		require PUN_ROOT.'lang/'.$pun_user['language'].'/topic.php';
+
+?>
+<div id="pun-main" class="main paged">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="paged-head">
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+	<div class="main-head">
+		<h2><span><?php echo $pun_page['main_info'] ?></span></h2>
+	</div>
+
+	<div class="main-content topic">
+<?php
+
+	}
+
+	$pun_page['item_count'] = 0;
+
+	// Finally, lets loop through the results and output them
+	for ($i = 0; $i < count($search_set); ++$i)
+	{
+		++$pun_page['item_count'];
+
+		if ($pun_config['o_censoring'] == '1')
+			$search_set[$i]['subject'] = censor_words($search_set[$i]['subject']);
+
+		if ($show_as == 'posts')
+		{
+			// Generate the post heading
+			$pun_page['item_head'] = array(
+				'num'	=> '<strong>'.($pun_page['start_from'] + $pun_page['item_count']).'</strong>',
+				'user'	=> '<cite>'.(($search_set[$i]['pid'] == $search_set[$i]['first_post_id']) ? sprintf($lang_topic['Topic by'], htmlspecialchars($search_set[$i]['pposter'])) : sprintf($lang_topic['Reply by'], htmlspecialchars($search_set[$i]['pposter']))).'</cite>',
+				'date'	=> '<span>'.format_time($search_set[$i]['pposted']).'</span>'
+			);
+
+			$pun_page['item_head'] = '<a class="permalink" rel="bookmark" title="'.$lang_topic['Permalink post'].'" href="'.pun_link($pun_url['post'], $search_set[$i]['pid']).'">'.implode(' ', $pun_page['item_head']).'</a>';
+
+			// Generate author identification
+			$pun_page['user_ident'] = (($search_set[$i]['poster_id'] > 1) ? '<strong class="username"><a title="'.sprintf($lang_search['Go to profile'], htmlspecialchars($search_set[$i]['pposter'])).'" href="'.pun_link($pun_url['user'], $search_set[$i]['poster_id']).'">'.htmlspecialchars($search_set[$i]['pposter']).'</a></strong>' : '<strong class="username">'.htmlspecialchars($search_set[$i]['pposter']).'</strong>');
+
+			// Generate the post options links
+			$pun_page['post_options'] = array();
+			$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['forum'], $search_set[$i]['forum_id']).'"><span>'.$lang_search['Go to forum'].'<span>: '.htmlspecialchars($search_set[$i]['forum_name']).'</span></span></a>';
+
+			if ($search_set[$i]['pid'] != $search_set[$i]['first_post_id'])
+				$pun_page['post_options'][] = '<a class="permalink" rel="bookmark" title="'.$lang_topic['Permalink topic'].'" href="'.pun_link($pun_url['topic'], $search_set[$i]['tid']).'"><span>'.$lang_search['Go to topic'].'<span>: '.htmlspecialchars($search_set[$i]['subject']).'</span></span></a>';
+
+			$pun_page['post_options'][] = '<a class="permalink" rel="bookmark" title="'.$lang_topic['Permalink post'].'" href="'.pun_link($pun_url['post'], $search_set[$i]['pid']).'"><span>'.$lang_search['Go to post'].' <span>'.($pun_page['start_from'] + $pun_page['item_count']).'</span></span></a>';
+
+			// Generate the post title
+			$pun_page['item_subject'] = array();
+			if ($search_set[$i]['pid'] == $search_set[$i]['first_post_id'])
+				$pun_page['item_subject'][] = '<strong>'.$lang_common['Topic'].': '.htmlspecialchars($search_set[$i]['subject']).'</strong>';
+			else
+				$pun_page['item_subject'][] = '<strong>'.$lang_common['Re'].' '.htmlspecialchars($search_set[$i]['subject']).'</strong>';
+
+			$pun_page['item_subject'][] = sprintf($lang_search['Topic info'], htmlspecialchars($search_set[$i]['poster']), htmlspecialchars($search_set[$i]['forum_name']), $search_set[$i]['num_replies']);
+
+			// Generate the post message
+			if ($pun_config['o_censoring'] == '1')
+				$search_set[$i]['message'] = censor_words($search_set[$i]['message']);
+
+			$pun_page['message'] = str_replace("\n", '<br />', htmlspecialchars($search_set[$i]['message']));
+
+			if (pun_strlen($pun_page['message']) >= 1000)
+				$pun_page['message'] .= '&#160;&#8230;';
+
+			// Give the post some class
+			$pun_page['item_status'] = array(
+				'post',
+				(($pun_page['item_count'] % 2 == 0) ? 'odd' : 'even' )
+			);
+
+			if ($pun_page['item_count'] == 1)
+				$pun_page['item_status'][] = 'firstpost';
+
+			if (($pun_page['start_from'] + $pun_page['item_count']) == $pun_page['finish_at'])
+				$pun_page['item_status'][] = 'lastpost';
+
+			if ($search_set[$i]['pid'] == $search_set[$i]['first_post_id'])
+				$pun_page['item_status'][] = 'topicpost';
+
+			($hook = get_hook('se_results_posts_row_pre_display')) ? eval($hook) : null;
+
+?>
+		<div class="<?php echo implode(' ', $pun_page['item_status']) ?>">
+			<div class="postmain">
+				<div class="posthead">
+					<h3><?php echo $pun_page['item_head'] ?></h3>
+				</div>
+				<div class="postbody">
+					<div class="user">
+						<h4 class="user-ident"><?php echo $pun_page['user_ident'] ?></h4>
+					</div>
+					<div class="post-entry">
+						<h4 class="entry-title"><?php echo implode(' ', $pun_page['item_subject']) ?></h4>
+						<div class="entry-content">
+							<p><?php echo $pun_page['message'] ?></p>
+						</div>
+					</div>
+				</div>
+				<div class="postfoot">
+					<div class="post-options"><?php echo implode(' ', $pun_page['post_options']) ?></div>
+				</div>
+			</div>
+		</div>
+<?php
+
+		}
+		else
+		{
+			++$pun_page['item_count'];
+
+			// Start from scratch
+			$pun_page['item_subject'] = $pun_page['item_status'] = $pun_page['item_last_post'] = $pun_page['item_nav'] = array();
+			$pun_page['item_indicator'] = '';
+			$pun_page['item_alt_message'] = $lang_common['Topic'].' '.($pun_page['start_from'] + $pun_page['item_count']);
+
+			if ($search_set[$i]['closed'] != '0')
+			{
+				$pun_page['item_subject'][] = $lang_common['Closed'];
+				$pun_page['item_status'][] = 'closed';
+			}
+
+			$pun_page['item_subject'][] = '<a href="'.pun_link($pun_url['topic'], $search_set[$i]['tid']).'">'.htmlspecialchars($search_set[$i]['subject']).'</a>';
+
+			$pun_page['item_pages'] = ceil(($search_set[$i]['num_replies'] + 1) / $pun_user['disp_posts']);
+
+			if ($pun_page['item_pages'] > 1)
+				$pun_page['item_nav'][] = pun_paginate($pun_page['item_pages'], -1, $pun_url['topic'], $search_set[$i]['tid']);
+
+			// Does this topic contains posts we haven't read? If so, tag it accordingly.
+			if (!$pun_user['is_guest'] && $search_set[$i]['last_post'] > $pun_user['last_visit'] && (!isset($tracked_topics['topics'][$search_set[$i]['tid']]) || $tracked_topics['topics'][$search_set[$i]['tid']] < $search_set[$i]['last_post']) && (!isset($tracked_topics['forums'][$search_set[$i]['forum_id']]) || $tracked_topics['forums'][$search_set[$i]['forum_id']] < $search_set[$i]['last_post']))
+			{
+				$pun_page['item_nav'][] = '<a href="'.pun_link($pun_url['topic_new_posts'], $search_set[$i]['tid']).'" title="'.$lang_forum['New posts info'].'">'.$lang_common['New posts'].'</a>';
+				$pun_page['item_status'][] = 'new';
+			}
+
+			if (!empty($pun_page['item_nav']))
+				$pun_page['item_subject'][] = '<span class="topic-nav">[&#160;'.implode('&#160;&#160;', $pun_page['item_nav']).'&#160;]</span>';
+
+			$pun_page['item_subject'][] = '<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($search_set[$i]['poster'])).'</span>';
+			$pun_page['item_last_post'][] = '<a href="'.pun_link($pun_url['post'], $search_set[$i]['last_post_id']).'">'.format_time($search_set[$i]['last_post']).'</a>';
+			$pun_page['item_last_post'][] = '<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($search_set[$i]['last_poster'])).'</span>';
+			$pun_page['item_indicator'] = '<span class="status '.implode(' ', $pun_page['item_status']).'" title="'.$pun_page['item_alt_message'].'"><img src="'.$base_url.'/style/'.$pun_user['style'].'/status.png" alt="'.$pun_page['item_alt_message'].'" />'.$pun_page['item_indicator'].'</span>';
+
+			($hook = get_hook('se_results_topics_row_pre_display')) ? eval($hook) : null;
+
+?>
+				<tr class="<?php echo ($pun_page['item_count'] % 2 != 0) ? 'odd' : 'even' ?>">
+					<td class="tcl"><?php echo $pun_page['item_indicator'].' '.implode(' ', $pun_page['item_subject']) ?></td>
+					<td class="tc2"><?php echo htmlspecialchars($search_set[$i]['forum_name']) ?></td>
+					<td class="tc3"><?php echo $search_set[$i]['num_replies'] ?></td>
+					<td class="tcr"><?php echo implode(' ', $pun_page['item_last_post']) ?></td>
+				</tr>
+<?php
+
+		}
+	}
+
+	if ($show_as == 'topics')
+	{
+
+?>
+			</tbody>
+		</table>
+<?php
+
+	}
+
+?>
+	</div>
+
+	<div class="main-foot">
+		<p class="h2"><strong><?php echo $pun_page['main_info'] ?></strong></p>
+<?php if (!empty($pun_page['main_foot_options'])): ?>			<p class="main-options"><?php echo implode(' ', $pun_page['main_foot_options']) ?></p>
+<?php endif; ?>	</div>
+
+	<div class="paged-foot">
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+</div>
+
+<div id="pun-crumbs-foot">
+	<p class="crumbs"><?php echo generate_crumbs(false) ?></p>
+</div>
+<?php
+
+	require PUN_ROOT.'footer.php';
+}
+
+// Setup form
+$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+
+// Setup form information
+$pun_page['frm-info'] = array('<li><span>'.$lang_search['Search info'].'</span></li>');
+if ($db_type == 'mysql' || $db_type == 'mysqli')
+{
+	$pun_page['frm-info'][] = '<li><span>'.$lang_search['Refine info fulltext'].'</span></li>';
+	$pun_page['frm-info'][] = '<li><span>'.$lang_search['Wildcard info fulltext'].'</span></li>';
+}
+else
+{
+	$pun_page['frm-info'][] = '<li><span>'.$lang_search['Refine info'].'</span></li>';
+	$pun_page['frm-info'][] = '<li><span>'.$lang_search['Wildcard info'].'<span></li>';
+}
+
+// Setup predefined search (pds) links
+$pun_page['pd_searches'] = array(
+	'<a href="'.pun_link($pun_url['search_24h']).'">'.$lang_common['Recent posts'].'</a>',
+	'<a href="'.pun_link($pun_url['search_unanswered']).'">'.$lang_common['Unanswered topics'].'</a>'
+);
+
+if (!$pun_user['is_guest'])
+{
+	array_push(
+		$pun_page['pd_searches'],
+		'<a href="'.pun_link($pun_url['search_new']).'" title="'.$lang_common['New posts info'].'">'.$lang_common['New posts'].'</a>',
+		'<a href="'.pun_link($pun_url['search_user_posts'], $pun_user['id']).'">'.$lang_common['Your posts'].'</a>',
+		'<a href="'.pun_link($pun_url['search_user_topics'], $pun_user['id']).'">'.$lang_common['Your topics'].'</a>'
+	);
+
+	if ($pun_config['o_subscriptions'] == '1')
+		$pun_page['pd_searches'][] = '<a href="'.pun_link($pun_url['search_subscriptions']).'">'.$lang_common['Your subscriptions'].'</a>';
+}
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+	$lang_common['Search']
+);
+
+($hook = get_hook('se_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_PAGE', 'search');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main">
+
+	<h1><span><?php echo $lang_common['Search'] ?></span></h1>
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_search['Search heading'] ?></span></h2>
+	</div>
+	<div class="main-content frm">
+		<div class="frm-info">
+			<h3><?php echo $lang_search['Predefined searches'] ?></h3>
+			<p class="actions"><?php echo implode(' ', $pun_page['pd_searches']) ?></p>
+			<h3><?php echo $lang_search['Using criteria'] ?></h3>
+			<ul>
+				<?php echo implode("\n\t\t\t\t", $pun_page['frm-info'])."\n" ?>
+			</ul>
+		</div>
+		<form id="afocus" class="frm-form" method="get" accept-charset="utf-8" action="<?php echo pun_link($pun_url['search']) ?>">
+			<div class="hidden">
+				<input type="hidden" name="action" value="search" />
+			</div>
+<?php ($hook = get_hook('se_pre_criteria_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_search['Search legend'] ?></strong></legend>
+<?php ($hook = get_hook('se_criteria_start')) ? eval($hook) : null; ?>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_search['Keyword search'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="keywords" size="40" maxlength="100" /></span><br />
+						<span class="fld-help"><?php echo $lang_search['Keyword info'] ?></span>
+					</label>
+				</div>
+<?php ($hook = get_hook('se_criteria_pre_author_field')) ? eval($hook) : null; ?>
+				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_search['Author search'] ?></span><br />
+						<span class="fld-input"><input id="fld<?php echo $pun_page['fld_count'] ?>" type="text" name="author" size="25" maxlength="25" /></span><br />
+						<span class="fld-help"><?php echo $lang_search['Author info'] ?></span>
+					</label>
+				</div>
+<?php ($hook = get_hook('se_criteria_pre_forum_field')) ? eval($hook) : null; ?>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_search['Forum search'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="forum">
+<?php
+
+if ($pun_config['o_search_all_forums'] == '1' || $pun_user['is_admmod'])
+	echo "	\t\t\t\t\t".'<option value="-1">'.$lang_search['All forums'].'</option>'."\n";
+
+// Get the list of categories and forums
+$query = array(
+	'SELECT'	=> 'c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url',
+	'FROM'		=> 'categories AS c',
+	'JOINS'		=> array(
+		array(
+			'INNER JOIN'	=> 'forums AS f',
+			'ON'			=> 'c.id=f.cat_id'
+		),
+		array(
+			'LEFT JOIN'		=> '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'
+);
+
+($hook = get_hook('se_qr_get_cats_and_forums')) ? eval($hook) : null;
+$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+
+$cur_category = 0;
+while ($cur_forum = $pun_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".'</optgroup>'."\n";
+
+		echo "\t\t\t\t\t\t".'<optgroup label="'.htmlspecialchars($cur_forum['cat_name']).'">'."\n";
+		$cur_category = $cur_forum['cid'];
+	}
+
+	echo "\t\t\t\t\t\t".'<option value="'.$cur_forum['fid'].'">'.htmlspecialchars($cur_forum['forum_name']).'</option>'."\n";
+}
+
+?>
+						</optgroup>
+						</select></span><br />
+					</label>
+				</div>
+<?php ($hook = get_hook('se_criteria_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('se_pre_results_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_search['Results legend'] ?></strong></legend>
+<?php ($hook = get_hook('se_results_start')) ? eval($hook) : null; ?>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_search['Sort by'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="sort_by">
+<?php if ($db_type == 'mysql' || $db_type == 'mysqli'):?>
+						<option value="4"><?php echo $lang_search['Sort by relevance'] ?></option>
+<?php endif; ?>						<option value="0"><?php echo $lang_search['Sort by post time'] ?></option>
+						<option value="1"><?php echo $lang_search['Sort by author'] ?></option>
+						<option value="2"><?php echo $lang_search['Sort by subject'] ?></option>
+						<option value="3"><?php echo $lang_search['Sort by forum'] ?></option>
+						</select></span><br />
+					</label>
+				</div>
+<?php ($hook = get_hook('se_results_pre_sort_choices')) ? eval($hook) : null; ?>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_search['Sort order'] ?></span></legend>
+					<div class="radbox frm-yesno"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="sort_dir" value="ASC" /> <?php echo $lang_search['Ascending'] ?></label> <label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="sort_dir" value="DESC" checked="checked" /> <?php echo $lang_search['Descending'] ?></label></div>
+				</fieldset>
+<?php ($hook = get_hook('se_results_pre_display_choices')) ? eval($hook) : null; ?>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_search['Display results'] ?></span></legend>
+					<div class="radbox frm-yesno"><label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="show_as" value="topics" checked="checked" /> <?php echo $lang_search['Show as topics'] ?></label> <label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="show_as" value="posts" /> <?php echo $lang_search['Show as posts'] ?></label></div>
+				</fieldset>
+<?php ($hook = get_hook('se_results_end')) ? eval($hook) : null; ?>
+			</fieldset>
+<?php ($hook = get_hook('se_pre_buttons')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="search" value="<?php echo $lang_search['Submit search'] ?>" accesskey="s" title="<?php echo $lang_common['Submit title'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+($hook = get_hook('se_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/style/index.html	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>.</title>
+</head>
+<body>
+.
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/userlist.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,297 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('ul_start')) ? eval($hook) : null;
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+else if ($pun_user['g_view_users'] == '0')
+	message($lang_common['No permission']);
+
+// Load the userlist.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/userlist.php';
+
+// Load the search.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/search.php';
+
+
+// Miscellaneous setup
+$pun_page['show_post_count'] = ($pun_config['o_show_post_count'] == '1' || $pun_user['is_admmod']) ? true : false;
+$pun_page['username'] = (isset($_GET['username']) && $_GET['username'] != '-' && $pun_user['g_search_users'] == '1') ? $_GET['username'] : '';
+$pun_page['show_group'] = (!isset($_GET['show_group']) || intval($_GET['show_group']) < -1 && intval($_GET['show_group']) > 2) ? -1 : intval($_GET['show_group']);
+$pun_page['sort_by'] = (!isset($_GET['sort_by']) || $_GET['sort_by'] != 'username' && $_GET['sort_by'] != 'registered' && ($_GET['sort_by'] != 'num_posts' || !$pun_page['show_post_count'])) ? 'username' : $_GET['sort_by'];
+$pun_page['sort_dir'] = (!isset($_GET['sort_dir']) || $_GET['sort_dir'] != 'ASC' && $_GET['sort_dir'] != 'DESC') ? 'ASC' : strtoupper($_GET['sort_dir']);
+
+
+// Create any SQL for the WHERE clause
+$where_sql = array();
+$like_command = ($db_type == 'pgsql') ? 'ILIKE' : 'LIKE';
+
+if ($pun_user['g_search_users'] == '1' && $pun_page['username'] != '')
+	$where_sql[] = 'u.username '.$like_command.' \''.$pun_db->escape(str_replace('*', '%', $pun_page['username'])).'\'';
+if ($pun_page['show_group'] > -1)
+	$where_sql[] = 'u.group_id='.$pun_page['show_group'];
+
+
+// Fetch user count
+$query = array(
+	'SELECT'	=> 'COUNT(u.id)',
+	'FROM'		=> 'users AS u',
+	'WHERE'		=> 'u.id>1'
+);
+
+if (!empty($where_sql))
+	$query['WHERE'] .= ' AND '.implode(' AND ', $where_sql);
+
+($hook = get_hook('ul_qr_get_user_count')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+$pun_page['num_users'] = $pun_db->result($result);
+
+// Determine the user offset (based on $_GET['p'])
+$pun_page['num_pages'] = ceil($pun_page['num_users'] / 50);
+$pun_page['page'] = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $pun_page['num_pages']) ? 1 : $_GET['p'];
+$pun_page['start_from'] = 50 * ($pun_page['page'] - 1);
+$pun_page['finish_at'] = min(($pun_page['start_from'] + 50), ($pun_page['num_users']));
+
+// Generate paging links
+$pun_page['page_post'] = '<div class="paging">'.$lang_common['Pages'].': '.pun_paginate($pun_page['num_pages'], $pun_page['page'], $pun_url['users_browse'], array($pun_page['show_group'], $pun_page['sort_by'], strtoupper($pun_page['sort_dir']), ($pun_page['username'] != '') ? urlencode($pun_page['username']) : '-')).'</div>';
+
+// Navigation links for header and page numbering for title/meta description
+if ($pun_page['page'] < $pun_page['num_pages'])
+{
+	$pun_page['nav'][] = '<link rel="last" href="'.pun_sublink($pun_url['users_browse'], $pun_url['page'], $pun_page['num_pages'], array($pun_page['show_group'], $pun_page['sort_by'], strtoupper($pun_page['sort_dir']), ($pun_page['username'] != '') ? urlencode($pun_page['username']) : '-')).'" title="'.$lang_common['Page'].' '.$pun_page['num_pages'].'" />';
+	$pun_page['nav'][] = '<link rel="next" href="'.pun_sublink($pun_url['users_browse'], $pun_url['page'], ($pun_page['page'] + 1), array($pun_page['show_group'], $pun_page['sort_by'], strtoupper($pun_page['sort_dir']), ($pun_page['username'] != '') ? urlencode($pun_page['username']) : '-')).'" title="'.$lang_common['Page'].' '.($pun_page['page'] + 1).'" />';
+}
+if ($pun_page['page'] > 1)
+{
+	$pun_page['nav'][] = '<link rel="prev" href="'.pun_sublink($pun_url['users_browse'], $pun_url['page'], ($pun_page['page'] - 1), array($pun_page['show_group'], $pun_page['sort_by'], strtoupper($pun_page['sort_dir']), ($pun_page['username'] != '') ? urlencode($pun_page['username']) : '-')).'" title="'.$lang_common['Page'].' '.($pun_page['page'] - 1).'" />';
+	$pun_page['nav'][] = '<link rel="first" href="'.pun_link($pun_url['users_browse'], array($pun_page['show_group'], $pun_page['sort_by'], strtoupper($pun_page['sort_dir']), ($pun_page['username'] != '') ? urlencode($pun_page['username']) : '-')).'" title="'.$lang_common['Page'].' 1" />';
+}
+
+$pun_page['main_foot_options'] = array(
+	'<a href="'.pun_link($pun_url['users']).'"><span>'.$lang_ul['Perform new search'].'</span></a>'
+);
+
+// Generate page information
+if (($pun_user['g_search_users'] == '1' && $pun_page['username'] != '') || ($pun_page['show_group'] > -1))
+	$pun_page['main_info'] = (($pun_page['num_pages'] > 1) ? '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_ul['Users found'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $pun_page['num_users']) : sprintf($lang_common['Page info'], $lang_ul['Users found'], $pun_page['num_users']));
+else
+	$pun_page['main_info'] = (($pun_page['num_pages'] > 1) ? '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_ul['Users'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $pun_page['num_users'], $pun_page['page']) : sprintf($lang_common['Page info'], $lang_ul['Users'], $pun_page['num_users']));
+
+// Setup form
+$pun_page['set_count'] = $pun_page['fld_count'] = 0;
+$pun_page['form_action'] = $base_url.'/userlist.php';
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])), $lang_common['User list']
+);
+
+($hook = get_hook('ul_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_ALLOW_INDEX', 1);
+define('PUN_PAGE', 'userlist');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main paged">
+
+	<h1><span><?php echo end($pun_page['crumbs']) ?></span></h1>
+
+	<div class="paged-head">
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+	<div class="main-head">
+		<h2><span><?php echo $pun_page['main_info'] ?></span></h2>
+	</div>
+
+	<div class="main-content frm">
+		<form class="frm-form" id="afocus" method="get" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<fieldset class="frm-set set<?php echo ++$pun_page['set_count'] ?>">
+				<legend class="frm-legend"><strong><?php echo $lang_ul['User find legend'] ?></strong></legend>
+<?php if ($pun_user['g_search_users'] == '1'): ?>				<div class="frm-fld text">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_ul['Search for username'] ?></span><br />
+						<span class="fld-input"><input type="text" id="fld<?php echo $pun_page['fld_count'] ?>" name="username" value="<?php echo htmlspecialchars($pun_page['username']) ?>" size="35" maxlength="25" /></span><br />
+						<span class="fld-help"><?php echo $lang_ul['Username help'] ?></span>
+					</label>
+				</div>
+<?php endif; ?>				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_ul['User group'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="show_group">
+						<option value="-1"<?php if ($pun_page['show_group'] == -1) echo ' selected="selected"' ?>><?php echo $lang_ul['All users'] ?></option>
+<?php
+
+// Get the list of user groups (excluding the guest group)
+$query = array(
+	'SELECT'	=> 'g.g_id, g.g_title',
+	'FROM'		=> 'groups AS g',
+	'WHERE'		=> 'g.g_id!='.PUN_GUEST,
+	'ORDER BY'	=> 'g.g_id'
+);
+
+($hook = get_hook('ul_qr_get_groups')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+while ($cur_group = $pun_db->fetch_assoc($result))
+{
+	if ($cur_group['g_id'] == $pun_page['show_group'])
+		echo "\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'" selected="selected">'.htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+	else
+		echo "\t\t\t\t\t\t\t".'<option value="'.$cur_group['g_id'].'">'.htmlspecialchars($cur_group['g_title']).'</option>'."\n";
+}
+
+?>
+						</select></span>
+					</label>
+				</div>
+				<div class="frm-fld select">
+					<label for="fld<?php echo ++$pun_page['fld_count'] ?>">
+						<span class="fld-label"><?php echo $lang_search['Sort by'] ?></span><br />
+						<span class="fld-input"><select id="fld<?php echo $pun_page['fld_count'] ?>" name="sort_by">
+						<option value="username"<?php if ($pun_page['sort_by'] == 'username') echo ' selected="selected"' ?>><?php echo $lang_common['Username'] ?></option>
+						<option value="registered"<?php if ($pun_page['sort_by'] == 'registered') echo ' selected="selected"' ?>><?php echo $lang_common['Registered'] ?></option>
+<?php if ($pun_page['show_post_count']): ?>						<option value="num_posts"<?php if ($pun_page['sort_by'] == 'num_posts') echo ' selected="selected"' ?>><?php echo $lang_ul['No of posts'] ?></option>
+<?php endif; ?>						</select></span>
+					</label>
+				</div>
+				<fieldset class="frm-group">
+					<legend><span><?php echo $lang_search['Sort order'] ?></span></legend>
+					<div class="radbox frm-yesno"> <label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="sort_dir" value="ASC"<?php if ($pun_page['sort_dir'] == 'ASC') echo ' checked="checked"' ?> /> <?php echo $lang_search['Ascending'] ?></label> <label for="fld<?php echo ++$pun_page['fld_count'] ?>"><input type="radio" id="fld<?php echo $pun_page['fld_count'] ?>" name="sort_dir" value="DESC"<?php if ($pun_page['sort_dir'] == 'DESC') echo ' checked="checked"' ?> /> <?php echo $lang_search['Descending'] ?></label></div>
+				</fieldset>
+			</fieldset>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="search" value="<?php echo $lang_search['Submit search'] ?>" accesskey="s" title="<?php echo $lang_common['Submit title'] ?>" /></span>
+			</div>
+		</form>
+		<div class="frm-form">
+<?php
+
+// Grab the users
+$query = array(
+	'SELECT'	=> 'u.id, eu.username, u.title, u.num_posts, u.registered, g.g_id, g.g_user_title',
+	'FROM'		=> $pun_db->prefix . 'users AS u',
+	'JOINS'		=> array(
+		array(
+			'LEFT JOIN'		=> $pun_db->prefix . 'groups AS g',
+			'ON'			=> 'g.g_id=u.group_id'
+		),
+    array(
+      'LEFT JOIN'   => table_prefix . 'users AS eu',
+      'ON'          => 'eu.user_id = u.id'
+    )
+	),
+	'WHERE'		=> 'u.id>1',
+	'ORDER BY'	=> $pun_page['sort_by'].' '.$pun_page['sort_dir'],
+	'LIMIT'		=> $pun_page['start_from'].', 50',
+  'PARAMS' => array(
+    'NO_PREFIX' => ''
+  )
+);
+
+if (!empty($where_sql))
+	$query['WHERE'] .= ' AND '.implode(' AND ', $where_sql);
+
+($hook = get_hook('ul_qr_get_users')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+$pun_page['item_count'] = 0;
+
+if ($pun_db->num_rows($result))
+{
+
+?>
+			<table cellspacing="0" summary="<?php echo $lang_ul['Table summary'] ?>">
+				<thead>
+					<tr>
+						<th class="tcl" scope="col"><?php echo $lang_common['Username'] ?></th>
+						<th class="tc2" scope="col"><?php echo $lang_common['Title'] ?></th>
+<?php if ($pun_page['show_post_count']): ?>						<th class="tc3" scope="col"><?php echo $lang_common['Posts'] ?></th>
+<?php endif; ($hook = get_hook('ul_table_header_after_num_posts')) ? eval($hook) : null; ?>						<th class="tcr" scope="col"><?php echo $lang_common['Registered'] ?></th>
+<?php ($hook = get_hook('ul_table_header_after_registered')) ? eval($hook) : null; ?>
+					</tr>
+				</thead>
+				<tbody>
+<?php
+
+	while ($user_data = $pun_db->fetch_assoc($result))
+	{
+		++$pun_page['item_count'];
+
+?>
+					<tr class="<?php echo ($pun_page['item_count'] % 2 != 0) ? 'odd' : 'even' ?>">
+						<td class="tcl"><a href="<?php echo pun_link($pun_url['user'], $user_data['id']) ?>"><?php echo htmlspecialchars($user_data['username']) ?></a></td>
+						<td class="tc2"><?php echo get_title($user_data) ?></td>
+<?php if ($pun_page['show_post_count']): ?>						<td class="tc3"><?php echo $user_data['num_posts'] ?></td>
+<?php endif; ($hook = get_hook('ul_table_contents_after_num_posts')) ? eval($hook) : null; ?>						<td class="tcr"><?php echo format_time($user_data['registered'], true) ?></td>
+<?php ($hook = get_hook('ul_table_contents_after_registered')) ? eval($hook) : null; ?>
+					</tr>
+<?php
+
+	}
+
+?>
+				</tbody>
+			</table>
+<?php
+
+}
+else
+	echo "\t\t\t".'<div class="frm-info">'."\n\t\t\t\t".'<p><strong>'.$lang_ul['No users found'].'</strong></p>'."\n\t\t\t".'</div>'."\n";
+
+?>
+		</div>
+	</div>
+
+	<div class="main-foot">
+		<p class="h2"><strong><?php echo $pun_page['main_info'] ?></strong></p>
+<?php if (!empty($pun_page['main_foot_options'])) echo "\t\t\t".'<p class="main-options">'.implode(' ', $pun_page['main_foot_options']).'</p>'."\n" ?>
+	</div>
+
+	<div class="paged-foot">
+		<?php echo $pun_page['page_post']."\n" ?>
+	</div>
+
+</div>
+
+<div id="pun-crumbs-foot">
+	<p class="crumbs"><?php echo generate_crumbs(false) ?></p>
+</div>
+<?php
+
+($hook = get_hook('ul_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/viewforum.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,344 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('vf_start')) ? eval($hook) : null;
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+
+// Load the viewforum.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/forum.php';
+
+
+$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
+if ($id < 1)
+	message($lang_common['Bad request']);
+
+
+// Fetch some info about the forum
+$query = array(
+	'SELECT'	=> 'f.forum_name, f.redirect_url, f.moderators, f.num_topics, f.sort_by, fp.post_topics',
+	'FROM'		=> 'forums AS f',
+	'JOINS'		=> array(
+		array(
+			'LEFT JOIN'		=> 'forum_perms AS fp',
+			'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+		)
+	),
+	'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND f.id='.$id
+);
+
+($hook = get_hook('vf_qr_get_forum_info')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+if (!$pun_db->num_rows($result))
+	message($lang_common['Bad request']);
+
+$cur_forum = $pun_db->fetch_assoc($result);
+
+// Is this a redirect forum? In that case, redirect!
+if ($cur_forum['redirect_url'] != '')
+{
+	($hook = get_hook('vf_redirect_forum_pre_redirect')) ? eval($hook) : null;
+
+	header('Location: '.$cur_forum['redirect_url']);
+	exit;
+}
+
+// Sort out who the moderators are and if we are currently a moderator (or an admin)
+$mods_array = array();
+if ($cur_forum['moderators'] != '')
+	$mods_array = unserialize($cur_forum['moderators']);
+
+$pun_user['is_admmod'] = ($session->user_level >= USER_LEVEL_ADMIN || ($pun_user['g_moderator'] == '1' && array_key_exists($pun_user['username'], $mods_array))) ? true : false;
+
+// Sort out whether or not this user can post
+$pun_user['may_post'] = (($cur_forum['post_topics'] == '' && $pun_user['g_post_topics'] == '1') || $cur_forum['post_topics'] == '1' || $pun_user['is_admmod']) ? true : false;
+
+// Get topic/forum tracking data
+if (!$pun_user['is_guest'])
+	$tracked_topics = get_tracked_topics();
+
+// Determine the topic offset (based on $_GET['p'])
+$pun_page['num_pages'] = ceil($cur_forum['num_topics'] / $pun_user['disp_topics']);
+$pun_page['page'] = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $pun_page['num_pages']) ? 1 : $_GET['p'];
+$pun_page['start_from'] = $pun_user['disp_topics'] * ($pun_page['page'] - 1);
+$pun_page['finish_at'] = min(($pun_page['start_from'] + $pun_user['disp_topics']), ($cur_forum['num_topics']));
+
+// Navigation links for header and page numbering for title/meta description
+if ($pun_page['page'] < $pun_page['num_pages'])
+{
+	$pun_page['nav'][] = '<link rel="last" href="'.pun_sublink($pun_url['forum'], $pun_url['page'], $pun_page['num_pages'], array($id, sef_friendly($cur_forum['forum_name']))).'" title="'.$lang_common['Page'].' '.$pun_page['num_pages'].'" />';
+	$pun_page['nav'][] = '<link rel="next" href="'.pun_sublink($pun_url['forum'], $pun_url['page'], ($pun_page['page'] + 1), array($id, sef_friendly($cur_forum['forum_name']))).'" title="'.$lang_common['Page'].' '.($pun_page['page'] + 1).'" />';
+}
+if ($pun_page['page'] > 1)
+{
+	$pun_page['nav'][] = '<link rel="prev" href="'.pun_sublink($pun_url['forum'], $pun_url['page'], ($pun_page['page'] - 1), array($id, sef_friendly($cur_forum['forum_name']))).'" title="'.$lang_common['Page'].' '.($pun_page['page'] - 1).'" />';
+	$pun_page['nav'][] = '<link rel="first" href="'.pun_link($pun_url['forum'], array($id, sef_friendly($cur_forum['forum_name']))).'" title="'.$lang_common['Page'].' 1" />';
+}
+
+
+// Fetch list of topics
+$query = array(
+	'SELECT'	=> 't.id, t.poster, t.subject, t.posted, t.first_post_id, t.last_post, t.last_post_id, t.last_poster, t.num_views, t.num_replies, t.closed, t.sticky, t.moved_to',
+	'FROM'		=> 'topics AS t',
+	'WHERE'		=> 't.forum_id='.$id,
+	'ORDER BY'	=> 'sticky DESC, '.(($cur_forum['sort_by'] == '1') ? 'posted' : 'last_post').' DESC',
+	'LIMIT'		=> $pun_page['start_from'].', '.$pun_user['disp_topics']
+);
+
+// With "has posted" indication
+if (!$pun_user['is_guest'] && $pun_config['o_show_dot'] == '1')
+{
+	$query['SELECT'] .= ', p.poster_id AS has_posted';
+	$query['JOINS'][] = array(
+		'LEFT JOIN'	=> 'posts AS p',
+		'ON'		=> 't.id=p.topic_id AND p.poster_id='.$pun_user['id']
+	);
+
+	if ($db_type == 'sqlite')
+	{
+		$query['WHERE'] = 't.id IN(SELECT id FROM '.$pun_db->prefix.'topics WHERE forum_id='.$id.' ORDER BY sticky DESC, '.(($cur_forum['sort_by'] == '1') ? 'posted' : 'last_post').' DESC LIMIT '.$pun_page['start_from'].', '.$pun_user['disp_topics'].')';
+		$query['ORDER BY'] = 't.sticky DESC, t.last_post DESC';
+	}
+
+	$query['GROUP BY'] = ($db_type != 'pgsql') ? 't.id' : 't.id, t.subject, t.poster, t.posted, t.first_post_id, t.last_post, t.last_post_id, t.last_poster, t.num_views, t.num_replies, t.closed, t.sticky, t.moved_to, p.poster_id';
+}
+
+($hook = get_hook('vf_qr_get_topics')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+
+// Generate page information
+if ($pun_page['num_pages'] > 1)
+	$pun_page['main_info'] = '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_common['Topics'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $cur_forum['num_topics']);
+else
+	$pun_page['main_info'] = (($pun_db->num_rows($result)) ? sprintf($lang_common['Page info'], $lang_common['Topics'], $cur_forum['num_topics']) : $lang_forum['No topics']);
+
+// Generate paging/posting links
+$pun_page['page_post'][] = '<p class="paging"><strong>'.$lang_common['Pages'].'</strong> '.pun_paginate($pun_page['num_pages'], $pun_page['page'], $pun_url['forum'], array($id, sef_friendly($cur_forum['forum_name']))).'</p>';
+
+if ($pun_user['may_post'])
+	$pun_page['page_post'][] = '<p class="posting"><a class="newpost" href="'.pun_link($pun_url['new_topic'], $id).'"><span>'.$lang_forum['Post topic'].'</span></a></p>';
+
+// Setup main head/foot options
+$pun_page['main_head_options'] = array(
+	'<a class="feed-option" href="'.pun_link($pun_url['forum_atom'], $id).'"><span>'.$lang_common['ATOM Feed'].'</span></a>',
+	'<a class="feed-option" href="'.pun_link($pun_url['forum_rss'], $id).'"><span>'.$lang_common['RSS Feed'].'</span></a>'
+);
+
+$pun_page['main_foot_options'] = array();
+if ($pun_user['is_guest'] && !$pun_user['may_post'])
+	$pun_page['main_foot_options'][] = sprintf($lang_forum['Forum login nag'], '<a href="'.pun_link($pun_url['login']).'">'.strtolower($lang_common['Login']).'</a>', '<a href="'.pun_link($pun_url['register']).'">'.strtolower($lang_common['Register']).'</a>');
+
+if (!$pun_user['is_guest'] && $pun_db->num_rows($result))
+{
+	$pun_page['main_foot_options'][] = '<a class="user-option" href="'.pun_link($pun_url['mark_forum_read'], $id).'"><span>'.$lang_forum['Mark forum read'].'</span></a>';
+
+	if ($pun_user['is_admmod'])
+		$pun_page['main_foot_options'][] = '<a class="mod-option" href="'.pun_sublink($pun_url['moderate_forum'], $pun_url['page'], $pun_page['page'], $id).'"><span>'.$lang_forum['Moderate forum'].'</span></a>';
+}
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+	array($cur_forum['forum_name'], pun_link($pun_url['forum'], array($id, sef_friendly($cur_forum['forum_name']))))
+);
+
+($hook = get_hook('vf_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_ALLOW_INDEX', 1);
+define('PUN_PAGE', 'viewforum');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main paged">
+
+	<h1><span><a class="permalink" href="<?php echo pun_link($pun_url['forum'], array($id, sef_friendly($cur_forum['forum_name']))) ?>" rel="bookmark" title="<?php echo $lang_forum['Permalink forum'] ?>"><?php echo htmlspecialchars($cur_forum['forum_name']) ?></a></span></h1>
+
+	<div class="paged-head">
+		<?php echo implode("\n\t\t", $pun_page['page_post'])."\n" ?>
+	</div>
+
+	<div class="main-head">
+		<p class="main-options"><?php echo implode(' ', $pun_page['main_head_options']) ?></p>
+		<h2><span><?php echo $pun_page['main_info'] ?></span></h2>
+	</div>
+
+	<div id="forum<?php echo $id ?>" class="main-content forum">
+		<table cellspacing="0" summary="<?php printf($lang_forum['Table summary'], htmlspecialchars($cur_forum['forum_name'])) ?>">
+			<thead>
+				<tr>
+					<th class="tcl" scope="col"><?php echo $lang_common['Topic'] ?></th>
+					<th class="tc2" scope="col"><?php echo $lang_common['Replies'] ?></th>
+<?php if ($pun_config['o_topic_views'] == '1'): ?>					<th class="tc3" scope="col"><?php echo $lang_forum['Views'] ?></th>
+<?php endif; ($hook = get_hook('vf_table_header_after_num_views')) ? eval($hook) : null; ?>					<th class="tcr" scope="col"><?php echo $lang_common['Last post'] ?></th>
+<?php ($hook = get_hook('vf_table_header_after_last_post')) ? eval($hook) : null; ?>
+				</tr>
+			</thead>
+			<tbody class="statused">
+<?php
+
+// If there are topics in this forum
+if ($pun_db->num_rows($result))
+{
+	($hook = get_hook('vf_pre_topic_loop_start')) ? eval($hook) : null;
+
+	$pun_page['item_count'] = 0;
+
+	while ($cur_topic = $pun_db->fetch_assoc($result))
+	{
+		++$pun_page['item_count'];
+
+		// Start from scratch
+		$pun_page['item_subject'] = $pun_page['item_status'] = $pun_page['item_last_post'] = $pun_page['item_alt_message'] = $pun_page['item_nav'] = array();
+		$pun_page['item_indicator'] = '';
+		$pun_page['item_alt_message'][] = $lang_common['Topic'].' '.($pun_page['start_from'] + $pun_page['item_count']);
+
+		if ($pun_config['o_censoring'] == '1')
+			$cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+		if ($cur_topic['moved_to'] != null)
+		{
+			$pun_page['item_status'][] = 'moved';
+			$pun_page['item_last_post'][] = $pun_page['item_alt_message'][] = $lang_forum['Moved'];
+			$pun_page['item_subject'][] = '<a href="'.pun_link($pun_url['topic'], array($cur_topic['moved_to'], sef_friendly($cur_topic['subject']))).'">'.htmlspecialchars($cur_topic['subject']).'</a>';
+			$pun_page['item_subject'][] = '<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($cur_topic['poster'])).'</span>';
+			$cur_topic['num_replies'] = $cur_topic['num_views'] = ' - ';
+		}
+		else
+		{
+			// Should we display the dot or not? :)
+			if (!$pun_user['is_guest'] && $pun_config['o_show_dot'] == '1' && $cur_topic['has_posted'] == $pun_user['id'])
+			{
+				$pun_page['item_indicator'] = $lang_forum['You posted indicator'];
+				$pun_page['item_status'][] = 'posted';
+				$pun_page['item_alt_message'][] = $lang_forum['You posted'];
+			}
+
+			if ($cur_topic['sticky'] == '1')
+			{
+				$pun_page['item_subject'][] = $lang_forum['Sticky'];
+				$pun_page['item_status'][] = 'sticky';
+			}
+
+			if ($cur_topic['closed'] == '1')
+			{
+				$pun_page['item_subject'][] = $lang_common['Closed'];
+				$pun_page['item_status'][] = 'closed';
+			}
+
+			$pun_page['item_subject'][] = '<a href="'.pun_link($pun_url['topic'], array($cur_topic['id'], sef_friendly($cur_topic['subject']))).'">'.htmlspecialchars($cur_topic['subject']).'</a>';
+
+			$pun_page['item_pages'] = ceil(($cur_topic['num_replies'] + 1) / $pun_user['disp_posts']);
+
+			if ($pun_page['item_pages'] > 1)
+				$pun_page['item_nav'][] = pun_paginate($pun_page['item_pages'], -1, $pun_url['topic'], array($cur_topic['id'], sef_friendly($cur_topic['subject'])));
+
+			// Does this topic contain posts we haven't read? If so, tag it accordingly.
+			if (!$pun_user['is_guest'] && $cur_topic['last_post'] > $pun_user['last_visit'] && (!isset($tracked_topics['topics'][$cur_topic['id']]) || $tracked_topics['topics'][$cur_topic['id']] < $cur_topic['last_post']) && (!isset($tracked_topics['forums'][$id]) || $tracked_topics['forums'][$id] < $cur_topic['last_post']))
+			{
+				$pun_page['item_nav'][] = '<a href="'.pun_link($pun_url['topic_new_posts'], array($cur_topic['id'], sef_friendly($cur_topic['subject']))).'" title="'.$lang_forum['New posts info'].'">'.$lang_common['New posts'].'</a>';
+				$pun_page['item_status'][] = 'new';
+			}
+
+			if (!empty($pun_page['item_nav']))
+				$pun_page['item_subject'][] = '<span class="topic-nav">[&#160;'.implode('&#160;&#160;', $pun_page['item_nav']).'&#160;]</span>';
+
+			$pun_page['item_subject'][] = '<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($cur_topic['poster'])).'</span>';
+			$pun_page['item_last_post'][] = '<a href="'.pun_link($pun_url['post'], $cur_topic['last_post_id']).'"><span>'.format_time($cur_topic['last_post']).'</span></a>';
+			$pun_page['item_last_post'][] = '<span class="byuser">'.sprintf($lang_common['By user'], htmlspecialchars($cur_topic['last_poster'])).'</span>';
+
+			if (empty($pun_page['item_status']))
+				$pun_page['item_status'][] = 'normal';
+		}
+
+		$pun_page['item_style'] = (($pun_page['item_count'] % 2 != 0) ? 'odd' : 'even').' '.implode(' ', $pun_page['item_status']);
+		$pun_page['item_indicator'] = '<span class="status '.implode(' ', $pun_page['item_status']).'" title="'.implode(' - ', $pun_page['item_alt_message']).'"><img src="'.$base_url.'/style/'.$pun_user['style'].'/status.png" alt="'.implode(' - ', $pun_page['item_alt_message']).'" />'.$pun_page['item_indicator'].'</span>';
+
+		($hook = get_hook('vf_row_pre_display')) ? eval($hook) : null;
+
+?>
+				<tr class="<?php echo $pun_page['item_style'] ?>">
+					<td class="tcl"><?php echo $pun_page['item_indicator'].' '.implode(' ', $pun_page['item_subject']) ?></td>
+					<td class="tc2"><?php echo $cur_topic['num_replies'] ?></td>
+<?php if ($pun_config['o_topic_views'] == '1'): ?>					<td class="tc3"><?php echo $cur_topic['num_views'] ?></td>
+<?php endif; ($hook = get_hook('vf_table_contents_after_num_views')) ? eval($hook) : null; ?>					<td class="tcr"><?php echo implode(' ', $pun_page['item_last_post']) ?></td>
+<?php ($hook = get_hook('vf_table_contents_after_last_post')) ? eval($hook) : null; ?>
+				</tr>
+<?php
+
+	}
+}
+// Else there are no topics in this forum
+else
+{
+	$pun_page['item_indicator'] = '<span class="status empty" title="'.$lang_forum['No topics'].'"><img src="'.$base_url.'/style/'.$pun_user['style'].'/status.png" alt="'.$lang_forum['No topics'].'" /></span>';
+
+?>
+				<tr class="odd empty">
+					<td class="tcl"><?php echo $pun_page['item_indicator'].' '.$lang_forum['First topic nag'] ?></td>
+					<td class="tc2">&#160;</td>
+<?php if ($pun_config['o_topic_views'] == '1'): ?>					<td class="tc3">&#160;</td>
+<?php endif; ?>					<td class="tcr"><?php echo $lang_forum['Never'] ?></td>
+				</tr>
+<?php
+
+}
+
+?>
+			</tbody>
+		</table>
+	</div>
+
+	<div class="main-foot">
+		<p class="h2"><strong><?php echo $pun_page['main_info'] ?></strong></p>
+<?php if (!empty($pun_page['main_foot_options'])): ?>		<p class="main-options"><?php echo implode(' ', $pun_page['main_foot_options']) ?></p>
+<?php endif; ?>	</div>
+
+	<div class="paged-foot">
+		<?php echo implode("\n\t\t", array_reverse($pun_page['page_post']))."\n" ?>
+	</div>
+
+</div>
+
+<div id="pun-crumbs-foot">
+	<p class="crumbs"><?php echo generate_crumbs(false) ?></p>
+</div>
+<?php
+
+$forum_id = $id;
+
+($hook = get_hook('vf_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/punbb/viewtopic.php	Sun Apr 06 00:28:50 2008 -0400
@@ -0,0 +1,615 @@
+<?php
+/***********************************************************************
+
+  Copyright (C) 2002-2008  PunBB.org
+
+  This file is part of PunBB.
+
+  PunBB is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PunBB is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+  MA  02111-1307  USA
+
+************************************************************************/
+
+
+// if (!defined('PUN_ROOT'))
+// 	define('PUN_ROOT', './');
+// require PUN_ROOT.'include/common.php';
+
+// import globals (I really hope this isn't dangerous)
+foreach ( $GLOBALS as $key => $_ )
+{
+  $$key =& $GLOBALS[$key];
+}
+
+($hook = get_hook('vt_start')) ? eval($hook) : null;
+
+if ($pun_user['g_read_board'] == '0')
+	message($lang_common['No view']);
+
+// Load the viewtopic.php language file
+require PUN_ROOT.'lang/'.$pun_user['language'].'/topic.php';
+
+
+$action = isset($_GET['action']) ? $_GET['action'] : null;
+$id = isset($_GET['id']) ? intval($_GET['id']) : 0;
+$pid = isset($_GET['pid']) ? intval($_GET['pid']) : 0;
+if ($id < 1 && $pid < 1)
+	message($lang_common['Bad request']);
+
+
+// If a post ID is specified we determine topic ID and page number so we can redirect to the correct message
+if ($pid)
+{
+	$query = array(
+		'SELECT'	=> 'p.topic_id, p.posted',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.id='.$pid
+	);
+
+	($hook = get_hook('vt_qr_get_post_info')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	if (!$pun_db->num_rows($result))
+		message($lang_common['Bad request']);
+
+	list($id, $posted) = $pun_db->fetch_row($result);
+
+	// Determine on what page the post is located (depending on $pun_user['disp_posts'])
+	$query = array(
+		'SELECT'	=> '1',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$id.' AND p.posted<'.$posted
+	);
+
+	($hook = get_hook('vt_qr_get_post_page')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$num_posts = $pun_db->num_rows($result) + 1;
+
+	$_GET['p'] = ceil($num_posts / $pun_user['disp_posts']);
+}
+
+// If action=new, we redirect to the first new post (if any)
+else if ($action == 'new' && !$pun_user['is_guest'])
+{
+	// We need to check if this topic has been viewed recently by the user
+	$tracked_topics = get_tracked_topics();
+	$last_viewed = isset($tracked_topics['topics'][$id]) ? $tracked_topics['topics'][$id] : $pun_user['last_visit'];
+
+	($hook = get_hook('vt_find_new_post')) ? eval($hook) : null;
+
+	$query = array(
+		'SELECT'	=> 'MIN(p.id)',
+		'FROM'		=> 'posts AS p',
+		'WHERE'		=> 'p.topic_id='.$id.' AND p.posted>'.$last_viewed
+	);
+
+	($hook = get_hook('vt_qr_get_first_new_post')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$first_new_post_id = $pun_db->result($result);
+
+	if ($first_new_post_id)
+		header('Location: '.str_replace('&amp;', '&', pun_link($pun_url['post'], $first_new_post_id)));
+	else	// If there is no new post, we go to the last post
+		header('Location: '.str_replace('&amp;', '&', pun_link($pun_url['topic_last_post'], $id)));
+
+	exit;
+}
+
+// If action=last, we redirect to the last post
+else if ($action == 'last')
+{
+	$query = array(
+		'SELECT'	=> 't.last_post_id',
+		'FROM'		=> 'topics AS t',
+		'WHERE'		=> 't.id='.$id
+	);
+
+	($hook = get_hook('vt_qr_get_last_post')) ? eval($hook) : null;
+	$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+	$last_post_id = $pun_db->result($result);
+
+	if ($last_post_id)
+	{
+		header('Location: '.str_replace('&amp;', '&', pun_link($pun_url['post'], $last_post_id)));
+		exit;
+	}
+}
+
+
+// Fetch some info about the topic
+$query = array(
+	'SELECT'	=> 't.subject, t.posted, t.poster, t.first_post_id, t.closed, t.num_replies, t.sticky, f.id AS forum_id, f.forum_name, f.moderators, fp.post_replies',
+	'FROM'		=> 'topics AS t',
+	'JOINS'		=> array(
+		array(
+			'INNER JOIN'	=> 'forums AS f',
+			'ON'			=> 'f.id=t.forum_id'
+		),
+		array(
+			'LEFT JOIN'		=> 'forum_perms AS fp',
+			'ON'			=> '(fp.forum_id=f.id AND fp.group_id='.$pun_user['g_id'].')'
+		)
+	),
+	'WHERE'		=> '(fp.read_forum IS NULL OR fp.read_forum=1) AND t.id='.$id.' AND t.moved_to IS NULL'
+);
+
+if (!$pun_user['is_guest'])
+{
+	$query['SELECT'] .= ', s.user_id AS is_subscribed';
+	$query['JOINS'][] = array(
+		'LEFT JOIN'	=> 'subscriptions AS s',
+		'ON'		=> '(t.id=s.topic_id AND s.user_id='.$pun_user['id'].')'
+	);
+}
+
+($hook = get_hook('vt_qr_get_topic_info')) ? eval($hook) : null;
+$result = $pun_db->query_build($query) or error(__FILE__, __LINE__);
+if (!$pun_db->num_rows($result))
+	message($lang_common['Bad request']);
+
+$cur_topic = $pun_db->fetch_assoc($result);
+
+// Sort out who the moderators are and if we are currently a moderator (or an admin)
+$mods_array = ($cur_topic['moderators'] != '') ? unserialize($cur_topic['moderators']) : array();
+$pun_user['is_admmod'] = ($session->user_level >= USER_LEVEL_MOD || ($pun_user['g_moderator'] == '1' && array_key_exists($pun_user['username'], $mods_array))) ? true : false;
+
+// Can we or can we not post replies?
+if ($cur_topic['closed'] == '0' || $pun_user['is_admmod'])
+	$pun_user['may_post'] = (($cur_topic['post_replies'] == '' && $pun_user['g_post_replies'] == '1') || $cur_topic['post_replies'] == '1' || $pun_user['is_admmod']) ? true : false;
+else
+	$pun_user['may_post'] = false;
+
+// Add/update this topic in our list of tracked topics
+if (!$pun_user['is_guest'])
+{
+	$tracked_topics = get_tracked_topics();
+	$tracked_topics['topics'][$id] = time();
+	set_tracked_topics($tracked_topics);
+}
+
+// Determine the post offset (based on $_GET['p'])
+$pun_page['num_pages'] = ceil(($cur_topic['num_replies'] + 1) / $pun_user['disp_posts']);
+$pun_page['page'] = (!isset($_GET['p']) || $_GET['p'] <= 1 || $_GET['p'] > $pun_page['num_pages']) ? 1 : $_GET['p'];
+$pun_page['start_from'] = $pun_user['disp_posts'] * ($pun_page['page'] - 1);
+$pun_page['finish_at'] = min(($pun_page['start_from'] + $pun_user['disp_posts']), ($cur_topic['num_replies'] + 1));
+
+// Navigation links for header and page numbering for title/meta description
+if ($pun_page['page'] < $pun_page['num_pages'])
+{
+	$pun_page['nav'][] = '<link rel="last" href="'.pun_sublink($pun_url['topic'], $pun_url['page'], $pun_page['num_pages'], array($id, sef_friendly($cur_topic['subject']))).'" title="'.$lang_common['Page'].' '.$pun_page['num_pages'].'" />';
+	$pun_page['nav'][] = '<link rel="next" href="'.pun_sublink($pun_url['topic'], $pun_url['page'], ($pun_page['page'] + 1), array($id, sef_friendly($cur_topic['subject']))).'" title="'.$lang_common['Page'].' '.($pun_page['page'] + 1).'" />';
+}
+if ($pun_page['page'] > 1)
+{
+	$pun_page['nav'][] = '<link rel="prev" href="'.pun_sublink($pun_url['topic'], $pun_url['page'], ($pun_page['page'] - 1), array($id, sef_friendly($cur_topic['subject']))).'" title="'.$lang_common['Page'].' '.($pun_page['page'] - 1).'" />';
+	$pun_page['nav'][] = '<link rel="first" href="'.pun_link($pun_url['topic'], array($id, sef_friendly($cur_topic['subject']))).'" title="'.$lang_common['Page'].' 1" />';
+}
+
+// Generate page information
+if ($pun_page['num_pages'] > 1)
+	$pun_page['main_info'] = '<span>'.sprintf($lang_common['Page number'], $pun_page['page'], $pun_page['num_pages']).' </span>'.sprintf($lang_common['Paged info'], $lang_common['Posts'], $pun_page['start_from'] + 1, $pun_page['finish_at'], $cur_topic['num_replies'] + 1);
+else
+	$pun_page['main_info'] = sprintf($lang_common['Page info'], $lang_common['Posts'], ($cur_topic['num_replies'] + 1));
+
+// Generate paging and posting links
+$pun_page['page_post'][] = '<p class="paging"><strong>'.$lang_common['Pages'].'</strong> '.pun_paginate($pun_page['num_pages'], $pun_page['page'], $pun_url['topic'], array($id, sef_friendly($cur_topic['subject']))).'</p>';
+
+if ($pun_user['may_post'])
+	$pun_page['page_post'][] = '<p class="posting"><a class="newpost" href="'.pun_link($pun_url['new_reply'], $id).'"><span>'.$lang_topic['Post reply'].'</span></a></p>';
+
+// Setup options for main header and footer
+$pun_page['main_head_options'] = array();
+
+if (!$pun_user['is_guest'] && $pun_config['o_subscriptions'] == '1')
+{
+	if ($cur_topic['is_subscribed'])
+		$pun_page['main_head_options'][] = '<a class="sub-option" href="'.pun_link($pun_url['unsubscribe'], $id).'"><em>'.$lang_topic['Cancel subscription'].'</em></a>';
+	else
+		$pun_page['main_head_options'][] = '<a class="sub-option" href="'.pun_link($pun_url['subscribe'], $id).'">'.$lang_topic['Subscription'].'</a>';
+}
+
+$pun_page['main_head_options'][] = '<a class="feed-option" href="'.pun_link($pun_url['topic_atom'], $id).'">'.$lang_common['ATOM Feed'].'</a>';
+$pun_page['main_head_options'][] = '<a class="feed-option" href="'.pun_link($pun_url['topic_rss'], $id).'">'.$lang_common['RSS Feed'].'</a>';
+
+$pun_page['main_foot_options'] = array();
+if ($pun_user['is_admmod'])
+{
+	$pun_page['main_foot_options'][] = '<a class="mod-option" href="'.pun_link($pun_url['move'], array($cur_topic['forum_id'], $id)).'">'.$lang_topic['Move'].'</a>';
+	$pun_page['main_foot_options'][] = '<a class="mod-option" href="'.pun_link($pun_url['delete'], $cur_topic['first_post_id']).'">'.$lang_topic['Delete topic'].'</a>';
+	$pun_page['main_foot_options'][] = (($cur_topic['closed'] == '1') ? '<a class="mod-option" href="'.pun_link($pun_url['open'], array($cur_topic['forum_id'], $id, generate_form_token('open'.$id))).'">'.$lang_topic['Open'].'</a>' : '<a class="mod-option" href="'.pun_link($pun_url['close'], array($cur_topic['forum_id'], $id, generate_form_token('close'.$id))).'">'.$lang_topic['Close'].'</a>');
+	$pun_page['main_foot_options'][] = (($cur_topic['sticky'] == '1') ? '<a class="mod-option" href="'.pun_link($pun_url['unstick'], array($cur_topic['forum_id'], $id, generate_form_token('unstick'.$id))).'">'.$lang_topic['Unstick'].'</a>' : '<a class="mod-option" href="'.pun_link($pun_url['stick'], array($cur_topic['forum_id'], $id, generate_form_token('stick'.$id))).'">'.$lang_topic['Stick'].'</a>');
+
+	if ($cur_topic['num_replies'] != 0)
+		$pun_page['main_foot_options'][] = '<a class="mod-option" href="'.pun_sublink($pun_url['delete_multiple'], $pun_url['page'], $pun_page['page'], array($cur_topic['forum_id'], $id)).'">'.$lang_topic['Delete posts'].'</a>';
+}
+
+if ($pun_user['is_guest'] && !$pun_user['may_post'])
+	$pun_page['main_foot_options'][] = sprintf($lang_topic['Topic login nag'], '<a href="'.pun_link($pun_url['login']).'">'.strtolower($lang_common['Login']).'</a>', '<a href="'.pun_link($pun_url['register']).'">'.strtolower($lang_common['Register']).'</a>');
+
+if ($pun_config['o_censoring'] == '1')
+	$cur_topic['subject'] = censor_words($cur_topic['subject']);
+
+// Setup breadcrumbs
+$pun_page['crumbs'] = array(
+	array($pun_config['o_board_title'], pun_link($pun_url['index'])),
+	array($cur_topic['forum_name'], pun_link($pun_url['forum'], array($cur_topic['forum_id'], sef_friendly($cur_topic['forum_name'])))),
+	array($cur_topic['subject'], pun_link($pun_url['topic'], array($id, sef_friendly($cur_topic['subject'])))),
+);
+
+($hook = get_hook('vt_pre_header_load')) ? eval($hook) : null;
+
+define('PUN_ALLOW_INDEX', 1);
+define('PUN_PAGE', 'viewtopic');
+require PUN_ROOT.'header.php';
+
+?>
+<div id="pun-main" class="main paged">
+
+	<h1><span><a class="permalink" href="<?php echo pun_link($pun_url['topic'], array($id, sef_friendly($cur_topic['subject']))) ?>" rel="bookmark" title="<?php echo $lang_topic['Permalink topic'] ?>"><?php echo htmlspecialchars($cur_topic['subject']) ?></a></span></h1>
+
+	<div class="paged-head">
+		<?php echo implode("\n\t\t", $pun_page['page_post'])."\n" ?>
+	</div>
+
+	<div class="main-head">
+		<p class="main-options"><?php echo implode(' ', $pun_page['main_head_options']) ?></p>
+		<h2><span><?php echo $pun_page['main_info'] ?></span></h2>
+	</div>
+
+	<div id="forum<?php echo $cur_topic['forum_id'] ?>" class="main-content topic">
+<?php
+
+require PUN_ROOT.'include/parser.php';
+
+$pun_page['item_count'] = 0;	// Keep track of post numbers
+
+// Retrieve the posts (and their respective poster/online status)
+$query = array(
+	'SELECT'	=> 'u.email, u.title, u.url, u.location, u.signature, u.email_setting, u.num_posts, u.registered, u.admin_note, p.id, p.poster AS username, p.poster_id, p.poster_ip, p.poster_email, p.message, p.hide_smilies, p.posted, p.edited, p.edited_by, g.g_id, g.g_user_title, o.user_id AS is_online',
+	'FROM'		=> 'posts AS p',
+	'JOINS'		=> array(
+		array(
+			'INNER JOIN'	=> 'users AS u',
+			'ON'			=> 'u.id=p.poster_id'
+		),
+		array(
+			'INNER JOIN'	=> 'groups AS g',
+			'ON'			=> 'g.g_id=u.group_id'
+		),
+		array(
+			'LEFT JOIN'		=> 'online AS o',
+			'ON'			=> '(o.user_id=u.id AND o.user_id!=1 AND o.idle=0)'
+		),
+	),
+	'WHERE'		=> 'p.topic_id='.$id,
+	'ORDER BY'	=> 'p.id',
+	'LIMIT'		=> $pun_page['start_from'].','.$pun_user['disp_posts']
+);
+
+($hook = get_hook('vt_qr_get_posts')) ? eval($hook) : null;
+$result = $pun_db->query_build($query, true) or error(__FILE__, __LINE__);
+while ($cur_post = $pun_db->fetch_assoc($result))
+{
+	($hook = get_hook('vt_post_loop_start')) ? eval($hook) : null;
+
+	++$pun_page['item_count'];
+
+	$signature = '';
+	$pun_page['user_ident'] = array();
+	$pun_page['user_info'] = array();
+	$pun_page['post_options'] = array();
+	$pun_page['message'] = array();
+
+	// Generate the post heading
+	$pun_page['item_ident'] = array(
+		'num'	=> '<strong>'.($pun_page['start_from'] + $pun_page['item_count']).'</strong>',
+		'user'	=> '<cite>'.($cur_topic['posted'] == $cur_post['posted'] ? sprintf($lang_topic['Topic by'], htmlspecialchars($cur_post['username'])) : sprintf($lang_topic['Reply by'], htmlspecialchars($cur_post['username']))).'</cite>',
+		'date'	=> '<span>'.format_time($cur_post['posted']).'</span>'
+	);
+
+	$pun_page['item_head'] = '<a class="permalink" rel="bookmark" title="'.$lang_topic['Permalink post'].'" href="'.pun_link($pun_url['post'], $cur_post['id']).'">'.implode(' ', $pun_page['item_ident']).'</a>';
+
+	// Generate author identification
+	if ($cur_post['poster_id'] > 1 && $pun_config['o_avatars'] == '1' && $pun_user['show_avatars'] != '0')
+	{
+		if (file_exists($pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.gif') && $img_size = @getimagesize($pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.gif'))
+			$pun_page['user_ident'][] = '<img src="'.$base_url.'/'.$pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.gif" '.$img_size[3].' alt="" />';
+		else if (file_exists($pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.jpg') && $img_size = @getimagesize($pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.jpg'))
+			$pun_page['user_ident'][] = '<img src="'.$base_url.'/'.$pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.jpg" '.$img_size[3].' alt="" />';
+		else if (file_exists($pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.png') && $img_size = @getimagesize($pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.png'))
+			$pun_page['user_ident'][] = '<img src="'.$base_url.'/'.$pun_config['o_avatars_dir'].'/'.$cur_post['poster_id'].'.png" '.$img_size[3].' alt="" />';
+	}
+
+	if ($cur_post['poster_id'] > 1)
+	{
+		$pun_page['user_ident'][] = '<strong class="username"><a title="'.sprintf($lang_topic['Go to profile'], htmlspecialchars($cur_post['username'])).'" href="'.pun_link($pun_url['user'], $cur_post['poster_id']).'">'.htmlspecialchars($cur_post['username']).'</a></strong>';
+		$pun_page['user_info'][] = '<li class="title"><span><strong>'.$lang_topic['Title'].'</strong> '.get_title($cur_post).'</span></li>';
+
+		if ($cur_post['is_online'] == $cur_post['poster_id'])
+			$pun_page['user_info'][] = '<li class="status"><span><strong>'.$lang_topic['Status'].'</strong> '.$lang_topic['Online'].'</span></li>';
+		else
+			$pun_page['user_info'][] = '<li class="status"><span><strong>'.$lang_topic['Status'].'</strong> '.$lang_topic['Offline'].'</span></li>';
+	}
+	else
+	{
+		$pun_page['user_ident'][] = '<strong class="username">'.htmlspecialchars($cur_post['username']).'</strong>';
+		$pun_page['user_info'][] = '<li class="title"><span><strong>'.$lang_topic['Title'].'</strong> '.get_title($cur_post).'</span></li>';
+	}
+
+	// Generate author information
+	if ($cur_post['poster_id'] > 1 && $pun_config['o_show_user_info'] == '1')
+	{
+
+		$pun_page['user_info'][] = '<li><span><strong>'.$lang_topic['Registered'].'</strong> '.format_time($cur_post['registered'], true).'</span></li>';
+
+		if ($cur_post['location'] != '')
+		{
+			if ($pun_config['o_censoring'] == '1')
+				$cur_post['location'] = censor_words($cur_post['location']);
+
+			$pun_page['user_info'][] = '<li><span><strong>'.$lang_topic['From'].'</strong> '.htmlspecialchars($cur_post['location']).'</span></li>';
+		}
+
+		if ($pun_config['o_show_post_count'] == '1' || $pun_user['is_admmod'])
+			$pun_page['user_info'][] = '<li><span><strong>'.$lang_topic['Posts'].'</strong> '.$cur_post['num_posts'].'</span></li>';
+
+		if ($pun_user['is_admmod'])
+		{
+			$pun_page['user_info'][] = '<li><span><strong>'.$lang_topic['IP'].'</strong> <a href="'.pun_link($pun_url['get_host'], $cur_post['id']).'">'.$cur_post['poster_ip'].'</a></span></li>';
+
+			if ($cur_post['admin_note'] != '')
+				$pun_page['user_info'][] = '<li><span><strong>'.$lang_topic['Note'].'</strong> '.htmlspecialchars($cur_post['admin_note']).'</span></li>';
+		}
+	}
+
+	// Generate author contact details
+	if ($pun_config['o_show_user_info'] == '1')
+	{
+		if ($cur_post['poster_id'] > 1)
+		{
+			if ($cur_post['url'] != '')
+				$pun_page['post_options'][] = '<a class="contact external" href="'.htmlspecialchars($cur_post['url']).'"><span>'.sprintf($lang_topic['Visit website'], htmlspecialchars($cur_post['username'])).'</span></a>';
+			if (($cur_post['email_setting'] == '0' && !$pun_user['is_guest']) || $pun_user['is_admmod'])
+				$pun_page['post_options'][] = '<a class="contact" href="mailto:'.$cur_post['email'].'"><span>'.$lang_common['E-mail'].'<span>&#160;'.htmlspecialchars($cur_post['username']).'</span></span></a>';
+			else if ($cur_post['email_setting'] == '1' && !$pun_user['is_guest'])
+				$pun_page['post_options'][] = '<a class="contact" href="'.pun_link($pun_url['email'], $cur_post['poster_id']).'"><span>'.$lang_common['E-mail'].'<span>&#160;'.htmlspecialchars($cur_post['username']).'</span></span></a>';
+		}
+		else
+		{
+			if ($cur_post['poster_email'] != '' && !$pun_user['is_guest'])
+				$pun_page['post_options'][] = '<a class="contact" href="mailto:'.$cur_post['poster_email'].'"><span>'.$lang_common['E-mail'].'<span>&#160;'.htmlspecialchars($cur_post['username']).'</span></span></a>';
+		}
+	}
+
+	// Generate the post options links
+	if (!$pun_user['is_guest'])
+	{
+		$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['report'], $cur_post['id']).'"><span>'.$lang_topic['Report'].'<span>&#160;'.$lang_topic['Post'].' '.($pun_page['start_from'] + $pun_page['item_count']).'</span></span></a>';
+
+		if (!$pun_user['is_admmod'])
+		{
+			if ($cur_topic['closed'] == '0')
+			{
+				if ($cur_post['poster_id'] == $pun_user['id'])
+				{
+					if (($pun_page['start_from'] + $pun_page['item_count']) == 1 && $pun_user['g_delete_topics'] == '1')
+						$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['delete'], $cur_topic['first_post_id']).'"><span>'.$lang_topic['Delete topic'].'</span></a>';
+					if (($pun_page['start_from'] + $pun_page['item_count']) > 1 && $pun_user['g_delete_posts'] == '1')
+						$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['delete'], $cur_post['id']).'"><span>'.$lang_topic['Delete'].'<span>&#160;'.$lang_topic['Post'].' '.($pun_page['start_from'] + $pun_page['item_count']).'</span></span></a>';
+					if ($pun_user['g_edit_posts'] == '1')
+						$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['edit'], $cur_post['id']).'"><span>'.$lang_topic['Edit'].'<span>&#160;'.$lang_topic['Post'].' '.($pun_page['start_from'] + $pun_page['item_count']).'</span></span></a>';
+				}
+
+				if (($cur_topic['post_replies'] == '' && $pun_user['g_post_replies'] == '1') || $cur_topic['post_replies'] == '1')
+					$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['quote'], array($id, $cur_post['id'])).'"><span>'.$lang_topic['Quote'].'<span>&#160;'.$lang_topic['Post'].' '.($pun_page['start_from'] + $pun_page['item_count']).'</span></span></a>';
+			}
+		}
+		else
+		{
+			if (($pun_page['start_from'] + $pun_page['item_count']) == 1)
+				$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['delete'], $cur_topic['first_post_id']).'">'.$lang_topic['Delete topic'].'</a>';
+			else
+				$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['delete'], $cur_post['id']).'"><span>'.$lang_topic['Delete'].'<span>&#160;'.$lang_topic['Post'].' '.($pun_page['start_from'] + $pun_page['item_count']).'</span></span></a>';
+
+			$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['edit'], $cur_post['id']).'"><span>'.$lang_topic['Edit'].'<span>&#160;'.$lang_topic['Post'].' '.($pun_page['start_from'] + $pun_page['item_count']).'</span></span></a>';
+			$pun_page['post_options'][] = '<a href="'.pun_link($pun_url['quote'], array($id, $cur_post['id'])).'"><span>'.$lang_topic['Quote'].'<span>&#160;'.$lang_topic['Post'].' '.($pun_page['start_from'] + $pun_page['item_count']).'</span></span></a>';
+		}
+	}
+
+	// Give the post some class
+	$pun_page['item_status'] = array(
+		'post',
+		($pun_page['item_count'] % 2 == 0) ? 'odd' : 'even'
+	);
+
+	if ($pun_page['item_count'] == 1)
+		$pun_page['item_status'][] = 'firstpost';
+
+	if (($pun_page['start_from'] + $pun_page['item_count']) == $pun_page['finish_at'])
+		$pun_page['item_status'][] = 'lastpost';
+
+	if ($cur_post['id'] == $cur_topic['first_post_id'])
+		$pun_page['item_status'][] = 'topicpost';
+	else
+		$pun_page['item_status'][] = 'replypost';
+
+
+	// Generate the post title
+	if ($cur_post['id'] == $cur_topic['first_post_id'])
+		$pun_page['item_subject'] = $lang_common['Topic'].': '.$cur_topic['subject'];
+	else
+		$pun_page['item_subject'] = $lang_common['Re'].' '.$cur_topic['subject'];
+
+	// Perform the main parsing of the message (BBCode, smilies, censor words etc)
+	$pun_page['message'][] = parse_message($cur_post['message'], $cur_post['hide_smilies']);
+
+	if ($cur_post['edited'] != '')
+		$pun_page['message'][] = '<p class="lastedit"><em>'.sprintf($lang_topic['Last edited'], htmlspecialchars($cur_post['edited_by']), format_time($cur_post['edited'])).'</em></p>';
+
+	// Do signature parsing/caching
+	if ($cur_post['signature'] != '' && $pun_user['show_sig'] != '0' && $pun_config['o_signatures'] == '1')
+	{
+		if (!isset($signature_cache[$cur_post['poster_id']]))
+			$signature_cache[$cur_post['poster_id']] = parse_signature($cur_post['signature']);
+
+		$pun_page['message'][] = '<div class="sig-content">'."\n\t\t\t\t\t\t\t\t".'<span class="sig-line"><!-- --></span>'."\n\t\t\t\t\t\t\t\t".$signature_cache[$cur_post['poster_id']]."\n\t\t\t\t\t\t\t".'</div>';
+	}
+
+	($hook = get_hook('vt_row_pre_display')) ? eval($hook) : null;
+
+?>
+		<div class="<?php echo implode(' ', $pun_page['item_status']) ?>">
+			<div class="postmain">
+				<div id="p<?php echo $cur_post['id'] ?>" class="posthead">
+					<h3><?php echo $pun_page['item_head'] ?></h3>
+				</div>
+				<div class="postbody">
+					<div class="user<?php if ($cur_post['is_online'] == $cur_post['poster_id']) echo ' online' ?>">
+						<h4 class="user-ident"><?php echo implode(' ', $pun_page['user_ident']) ?></h4>
+						<ul class="user-info">
+							<?php echo implode("\n\t\t\t\t\t\t\t", $pun_page['user_info'])."\n" ?>
+						</ul>
+					</div>
+					<div class="post-entry">
+						<h4 class="entry-title"><?php echo $pun_page['item_subject'] ?></h4>
+						<div class="entry-content">
+							<?php echo implode("\n\t\t\t\t\t\t\t", $pun_page['message'])."\n" ?>
+						</div>
+					</div>
+				</div>
+<?php if (!empty($pun_page['post_options'])): ?>				<div class="postfoot">
+					<div class="post-options">
+						<?php echo implode(' ', $pun_page['post_options'])."\n" ?>
+					</div>
+				</div>
+<?php endif; ?>			</div>
+		</div>
+<?php
+
+}
+
+?>
+	</div>
+
+	<div class="main-foot">
+		<p class="h2"><strong><?php echo $pun_page['main_info'] ?></strong></p>
+<?php if (!empty($pun_page['main_foot_options'])): ?>		<p class="main-options"><?php echo implode(' ', $pun_page['main_foot_options']) ?></p>
+<?php endif; ?>	</div>
+
+	<div class="paged-foot">
+		<?php echo implode("\n\t\t", array_reverse($pun_page['page_post']))."\n" ?>
+	</div>
+
+</div>
+
+<div id="pun-crumbs-foot">
+	<p class="crumbs"><?php echo generate_crumbs(false) ?></p>
+</div>
+<?php
+
+
+// Display quick post if enabled
+if ($pun_config['o_quickpost'] == '1' &&
+	!$pun_user['is_guest'] &&
+	($cur_topic['post_replies'] == '1' || ($cur_topic['post_replies'] == '' && $pun_user['g_post_replies'] == '1')) &&
+	($cur_topic['closed'] == '0' || $pun_user['is_admmod']))
+{
+
+// Setup form
+$pun_page['form_action'] = pun_link($pun_url['new_reply'], $id);
+
+$pun_page['hidden_fields'] = array(
+	'<input type="hidden" name="form_sent" value="1" />',
+	'<input type="hidden" name="form_user" value="'.((!$pun_user['is_guest']) ? htmlspecialchars($pun_user['username']) : 'Guest').'" />'
+);
+
+if ($pun_user['is_admmod'])
+	$pun_page['hidden_fields'][] = '<input type="hidden" name="csrf_token" value="'.generate_form_token($pun_page['form_action']).'" />';
+
+if (!$pun_user['is_guest'] && $pun_config['o_subscriptions'] == '1' && ($pun_user['auto_notify'] == '1' || $cur_topic['is_subscribed']))
+	$pun_page['hidden_fields'][] = '<input type="hidden" name="subscribe" value="1" />';
+
+// Setup help
+$pun_page['main_head_options'] = array();
+if ($pun_config['p_message_bbcode'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'bbcode').'" title="'.sprintf($lang_common['Help page'], $lang_common['BBCode']).'">'.$lang_common['BBCode'].'</a>';
+if ($pun_config['p_message_img_tag'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'img').'" title="'.sprintf($lang_common['Help page'], $lang_common['Images']).'">'.$lang_common['Images'].'</a>';
+if ($pun_config['o_smilies'] == '1')
+	$pun_page['main_head_options'][] = '<a class="exthelp" href="'.pun_link($pun_url['help'], 'smilies').'" title="'.sprintf($lang_common['Help page'], $lang_common['Smilies']).'">'.$lang_common['Smilies'].'</a>';
+
+($hook = get_hook('vt_quickpost_pre_display')) ? eval($hook) : null;
+
+?>
+<div id="pun-qpost" class="main">
+
+	<div class="main-head">
+		<h2><span><?php echo $lang_topic['Quick post'] ?></span></h2>
+<?php if (!empty($pun_page['main_head_options'])): ?>		<p class="main-options"><?php printf($lang_common['You may use'], implode(' ', $pun_page['main_head_options'])) ?></p>
+<?php endif; ?>	</div>
+
+	<div class="main-content frm">
+		<div id="req-msg" class="frm-warn">
+			<p class="important"><?php printf($lang_common['Required warn'], '<em class="req-text">'.$lang_common['Required'].'</em>') ?></p>
+		</div>
+		<form class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $pun_page['form_action'] ?>">
+			<div class="hidden">
+				<?php echo implode("\n\t\t\t\t", $pun_page['hidden_fields'])."\n" ?>
+			</div>
+<?php ($hook = get_hook('vt_quickpost_pre_fieldset')) ? eval($hook) : null; ?>
+			<fieldset class="frm-set set1">
+				<legend class="frm-legend"><strong><?php echo $lang_common['Write message legend'] ?></strong></legend>
+<?php ($hook = get_hook('vt_quickpost_fieldset_start')) ? eval($hook) : null; ?>
+				<div class="frm-fld text textarea required">
+					<label for="fld1">
+						<span class="fld-label"><?php echo $lang_common['Write message'] ?></span><br />
+						<span class="fld-input"><textarea id="fld1" name="req_message" rows="7" cols="95"></textarea></span>
+						<em class="req-text"><?php echo $lang_common['Required'] ?></em>
+					</label>
+				</div>
+			</fieldset>
+<?php ($hook = get_hook('vt_quickpost_post_fieldset')) ? eval($hook) : null; ?>
+			<div class="frm-buttons">
+				<span class="submit"><input type="submit" name="submit" value="<?php echo $lang_common['Submit'] ?>" accesskey="s" title="<?php echo $lang_common['Submit title'] ?>" /></span>
+				<span class="submit"><input type="submit" name="preview" value="<?php echo $lang_common['Preview'] ?>" accesskey="p" title="<?php echo $lang_common['Preview title'] ?>" /></span>
+			</div>
+		</form>
+	</div>
+
+</div>
+<?php
+
+}
+
+// Increment "num_views" for topic
+if ($pun_config['o_topic_views'] == '1')
+{
+	$query = array(
+		'UPDATE'	=> 'topics',
+		'SET'		=> 'num_views=num_views+1',
+		'WHERE'		=> 'id='.$id,
+		'PARAMS'	=> array(
+			'LOW_PRIORITY'	=> 1	// MySQL only
+		)
+	);
+
+	($hook = get_hook('vt_qr_increment_num_views')) ? eval($hook) : null;
+	$pun_db->query_build($query) or error(__FILE__, __LINE__);
+}
+
+$forum_id = $cur_topic['forum_id'];
+
+($hook = get_hook('vt_end')) ? eval($hook) : null;
+
+require PUN_ROOT.'footer.php';