Final commit for initial branch
authordan@scribus.fuhry.local.fuhry.local
Wed, 13 Jun 2007 16:59:00 -0400
changeset 3 2b2084ca1e60
parent 2 0931d60f5bdb
child 4 0b3a0aedfd53
Final commit for initial branch
includes/clientside/css/enano-shared.css~
includes/clientside/static/faders.js~
includes/clientside/static/misc.js~
includes/common.php
includes/common.php~
includes/functions.php~
includes/pageprocess.php~
includes/pageutils.php~
includes/paths.php~
includes/render.php~
includes/sessions.php~
includes/template.php~
plugins/#Untitled-1#
plugins/SpecialAdmin.php~
plugins/SpecialUpdownload.php~
plugins/SpecialUserFuncs.php~
--- a/includes/clientside/css/enano-shared.css~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,401 +0,0 @@
-/*
- * Shared stuff that all Enano themes (should) use
- */
-
-/* Information, warning, question, error, and wait boxes */
-div.error-box                     { background-image: url(../../../images/error.png);    background-repeat: no-repeat; background-color: #FFF4F4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
-div.info-box                      { background-image: url(../../../images/info.png);     background-repeat: no-repeat; background-color: #F4F4FF; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
-div.warning-box                   { background-image: url(../../../images/warning.png);  background-repeat: no-repeat; background-color: #FFFFF4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
-div.question-box                  { background-image: url(../../../images/question.png); background-repeat: no-repeat; background-color: #F4FFF4; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
-div.wait-box                      { background-image: url(../../../images/wait.png);     background-repeat: no-repeat; background-color: #FFF4FF; border: 1px dashed #406080; padding: 10px 10px 10px 50px; margin: 1em 0 0 0; min-height: 25px; }
-
-/* toolbar */
-div.toolbar {
-  border-bottom: 1px solid #909090;
-  background-color: #D0D0D0;
-  padding: 2px 0;
-  height: 22px;
-  font-family: arial, sans-serif;
-  font-size: 8pt;
-}
-div.toolbar ul {
-  margin: 0;
-  padding: 0;
-}
-div.toolbar ul li {
-  list-style: none;
-  margin: 0;
-  float: left;
-}
-div.toolbar a img {
-  opacity: 0.6;
-  /*filter: alpha(opacity=60);*/
-}
-div.toolbar a:hover img {
-  opacity: 1;
-  /*filter: alpha(opacity=100);*/
-}
-div.toolbar a {
-  display: block;
-  padding: 2px;
-  border: 1px solid transparent;
-  cursor: default;
-  width: auto;
-  color: #000000;
-  margin: 0 2px;
-  max-height: 16px;
-  text-decoration: none;
-}
-div.toolbar a:hover {
-  border: 1px solid #202090;
-  background-color: #ceceed;
-  color: #000000;
-  text-decoration: none;
-}
-div.toolbar a:active {
-  border: 1px solid #A0A0A0;
-  background-color: #E0E0E0;
-}
-div.toolbar img {
-  margin: 0;
-  padding: 0;
-  display: inline;
-  border-width: 0px;
-}
-div.toolbar a span {
-  position: relative;
-  top: -4px;
-}
-div.toolbar li span {
-  padding-left: 2px;
-  padding-right: 5px;
-}
-
-/* vertical toolbar */
-div.toolbar_vert {
-  border: 1px solid #909090;
-  background-color: #D0D0D0;
-  padding: 2px 0;
-}
-div.toolbar_vert ul {
-  margin: 0;
-  padding: 0;
-}
-div.toolbar_vert ul li {
-  list-style: none;
-  margin: 0;
-}
-div.toolbar_vert a img {
-  opacity: 0.6;
-  /*filter: alpha(opacity=60);*/
-}
-div.toolbar_vert a:hover img {
-  opacity: 1;
-  /*filter: alpha(opacity=100);*/
-}
-div.toolbar_vert a {
-  display: block;
-  padding: 2px;
-  border: 1px solid transparent;
-  cursor: default;
-  width: auto;
-  color: #000000;
-  margin: 0 2px;
-  max-height: 16px;
-  text-decoration: none;
-}
-div.toolbar_vert a:hover {
-  border: 1px solid #202090;
-  background-color: #ceceed;
-  color: #000000;
-  text-decoration: none;
-}
-div.toolbar_vert a:active {
-  border: 1px solid #A0A0A0;
-  background-color: #E0E0E0;
-}
-div.toolbar_vert img {
-  margin: 0;
-  padding: 0;
-  display: inline;
-  border-width: 0px;
-}
-div.toolbar_vert a span {
-  position: relative;
-  top: -4px;
-}
-div.toolbar_vert li span {
-  padding-left: 2px;
-  padding-right: 5px;
-}
-
-/* Tables */
-.tblholder                        { margin: 10px 0 0 0; padding: 0; border: 1px solid #AAAAAA; background-color: #E8E8E8; }
-
-/* The beautiful tables inside what may not obviously be mdg-comment divs */
-div.tblholder td.row1             { padding: 4px; background-color: #E0E0E0; }
-div.tblholder td.row2             { padding: 4px; background-color: #F0F0F0; }
-div.tblholder td.row3             { padding: 4px; background-color: #E8E8E8; }
-div.tblholder th                  { padding: 4px; background-color: #7080A0; font-weight: bold; text-align: center; color: #FFFFFF; }
-div.tblholder th.subhead          { padding: 4px; background-color: #90A0B0; font-weight: bold; text-align: center; color: #FFFFFF; }
-div.tblholder table               { background-color: #FFFFFF; width: 100%; }
-
-/* Well, not Midget and not comments (usually), but that's what the class is called ;-). Basically an informational window or used as a wrapper for tables. */
-.mdg-comment, .mdg-infobox        { margin-left: 1em; padding: 7px; border: 1px solid #AAAAAA; background-color: #E8E8E8; }
-
-/* JWS window theming */
-div.jswindow                      { border: 2px solid #7090B0; border-top: 5px solid #7090B0; padding: 0px; font-family: Trebuchet MS, tahoma, verdana, arial, sans-serif; font-size: 9pt; display: none; position: absolute; background-color: #FFFFFF; }
-div.titlebar                      { background-color: #7090B0; color: #FFFFFF; font-family: Trebuchet MS, tahoma, verdana, arial, sans-serif; font-size: 9pt; padding-bottom: 4px; cursor: default; }
-div.titlebar div.closebtn         { width: 16px; height: 16px; border: 1px solid #B0D0F0; background-color: #90B0D0; display: block; }
-div.titlebar div.closebtn:hover   { width: 16px; height: 16px; border: 1px solid #FFFFFF; background-color: #B0D0F0; display: block; }
-div.titlebar table, div.titlebar td { margin: 0; padding: 0; }
-div.jswindow div.content          { padding: 10px; margin: 0; background-color: #FFFFFF; }
-
-/* Search results */
-div.search-result h3   { font-size: 14pt; margin: 10px 0 0 0; }
-div.search-result h3 a { color: blue !important; font-weight: normal; padding-bottom: 0; }
-div.search-result p    { margin: 10px 0 0 0 !important; font-family: arial, helvetica, sans-serif; font-size: 10pt; }
-div.search-result span.search-result-info { color: green; }
-div.search-result span.search-term, div.search-result span.title-search-term { background-color: #FFFFC0; font-weight: bold; }
-
-/*
- * Search box
- */
- 
-input.js-search-box {
-  font-size: 13px;
-  margin: 0;
-  padding: 1px !important;
-  background-image: url(../../../images/search-box-normal.gif);
-  height: 15px;
-  background-repeat: repeat-x;
-  border-width: 1px;
-  border-style: solid;
-  border-color: #6c6c6c;
-  color: #C0C0C0;
-}
-
-input.js-search-box:focus {
-  background-image: url(../../../images/search-box-hilite.gif);
-  color: #666;
-}
-
-div.js-search-submit {
-  display: block;
-  position: absolute;
-  width: 24px;
-  height: 19px;
-  font-size: 1px;
-  line-height: 19px;
-  clip: rect(0px, 24px, 19px, 0px);
-  overflow: hidden;
-  margin: 0;
-  padding: 0;
-  background: transparent url(../../../images/search-btn-normal.png) no-repeat !important;
-  background-repeat: no-repeat;
-  cursor: pointer;
-}
-
-div.js-search-submit:hover {
-  background-image: url(../../../images/search-btn-hilite.png);
-}
-
-input[type ^="text"].username, input[type ^="password"].password {
-  padding: 2px 2px 2px 27px;
-  width: 96px;
-  height: 15px;
-  border: 0px none #000;
-  font-size: 11px;
-}
-input[type ^="text"].username {
-  background-image: url(../../../images/login-username.png);
-}
-input[type ^="password"].password {
-  background-image: url(../../../images/login-password.png);
-}
-
-/*
- * jBox menu system
- */
-
-div.menu, div.menu_nojs {
-  background-color: #D0D0D0;
-  border: 1px solid #A0A0A0;
-  font-size: 9pt;
-}
-div.menu a, div.menu div.label {
-  padding: 2pt 5px;
-  text-decoration: none;
-  display: block;
-  float: left;
-  color: #404040;
-}
-div.menu_nojs a, div.menu_nojs div.label {
-  padding: 2pt 5px;
-  text-decoration: none;
-  display: block;
-  color: #404040;
-}
-div.menu div.label, div.menu_nojs div.label {
-  color: #101010;
-}
-div.menu span.sep, div.menu_nojs span.sep {
-  display: block;
-  float: left;
-  width: 5px;
-}
-div.menu div.multopts, div.menu_nojs div.multopts {
-  line-height: 17pt;
-}
-div.menu div.multopts a, div.menu div.multopts div.label, div.menu_nojs div.multopts a, div.menu_nojs div.multopts div.label {
-  float: none;
-  display: inline;
-}
-div.menu a:hover, div.menu_nojs a:hover {
-  color: #FFFFFF;
-  background-color: #808080;
-}
-div.menu input[type ^="text"], div.menu input[type ^="password"], div.menu_nojs input[type ^="text"], div.menu_nojs input[type ^="password"] {
-  border-width: 0;
-  font-size: 9pt;
-  padding: 4px 5px;
-  max-width: 70px;
-  background-color: #E0E0E0;
-}
-div.menu input[type ^="text"]:hover, div.menu input[type ^="password"]:hover, div.menu_nojs input[type ^="text"]:hover, div.menu_nojs input[type ^="password"]:hover {
-  background-color: #E8E8E8;
-}
-div.menu input[type ^="text"]:focus, div.menu input[type ^="password"]:focus, div.menu_nojs input[type ^="text"]:focus, div.menu_nojs input[type ^="password"]:focus {
-  background-color: #F0F0F0;
-}
-div.menu input[type ^="button"], div.menu input[type ^="submit"], div.menu_nojs input[type ^="button"], div.menu_nojs input[type ^="submit"] {
-  border-width: 0;
-  font-size: 9pt;
-  padding: 3px 5px;
-  max-width: 70px;
-}
-div.menu a.current, div.menu a.current:hover, div.menu_nojs a.current, div.menu_nojs a.current:hover {
-  color: #FFFFFF;
-  background-color: #505050;
-}
-div.menu ul {
-  display: none;
-  position: absolute;
-  padding: 0;
-  margin: 0;
-  background-color: #D0D0D0;
-  border: 1px solid #A0A0A0;
-  min-width: 120px;
-}
-div.menu_nojs ul {
-  display: block;
-  clear: both;
-}
-div.menu ul li, div.menu_nojs ul li {
-  list-style: none;
-}
-div.menu ul a, div.menu_nojs ul a {
-  float: none;
-  margin: 0;
-}
-span.menuclear {
-  font-size: 1px;
-  height: 0px;
-  width: 0px;
-  clear: left;
-  line-height: 0px;
-  display: block;
-}
-
-/*
- * Docking Boxes code (for the sidebar editor)
- */
- 
-/* group container(s) */
-#sbedit {
-  margin: 0;
-  padding: 0;
-  /* position:relative; /* additional outer containers must also have position:relative */
-}
-/* keyboard navigation tooltip */
-.dbx-tooltip {
-  display:block;
-  position:absolute;
-  margin:36px 0 0 125px;
-  width:185px;
-  border:1px solid #000;
-  background:#ffd;
-  color:#000;
-  font:normal normal normal 0.85em tahoma, arial, sans-serif;
-  padding:2px 4px 3px 5px;
-  text-align:left;
-  }
-* html .dbx-tooltip { width:195px; }
-
-/* use CSS2 system colors in CSS2 browsers 
-   but not safari, which doesn't support them */
-*[class="dbx-tooltip"]:lang(en) {
-  border-color:InfoText;
-  background:InfoBackground;
-  color:InfoText;
-  font:small-caption;
-  font-weight:normal;
-  }
-/* additional clone styles */
-.dbx-clone {
-  opacity: 0.8;
-}
-.dbx-content ul {
-  margin: 0; padding: 0;
-  list-style: none;
-}
-.dbx-content li a, .dbx-content li a:hover {
-  text-decoration: none; color: #666;
-}
-.dbx-content2 {
-  margin: 0px 1px 0px 1px;
-}
-
-/* Progress bars */
-div.progressbar {
-  padding: 2px;
-  background-color: #90A0B0;
-  width: 308px;
-}
-div.progressbar_inner {
-  min-width: 30px;
-  color: white;
-  background-color: #7080A0;
-  padding: 4px;
-}
-/* User notification - courtest of wikipedia.org (not sure if this is included with MediaWiki) */
-/* user notification thing */
-
-.usermessage {
-	background-color: #ffce7b;
-	border: 1px solid #ffa500;
-	color: black;
-	margin: 10px 0 1em;
-	padding: .5em 1em;
-	vertical-align: middle;
-}
-.usermessage a:link, .usermessage a:active, .usermessage a:visited {
-  color: #CA7520;
-}
-.usermessage a:hover {
-  color: #AA5500 !important;
-}
-div.thumbnail {
-  display: table;
-  border: 1px solid #AAAAAA;
-  background-color: #F0F0F0;
-  padding: 4px;
-  margin-bottom: 10px;
-  padding-bottom: 0;
-}
-div.thumbnail-inner {
-  background-image: url(../../../images/thumbnail.png);
-  background-position: top right;
-  background-repeat: no-repeat;
-}
-
--- a/includes/clientside/static/faders.js~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,393 +0,0 @@
-// Message box system
-
-function darken(nofade)
-{
-  if(IE)
-    nofade = true;
-  if(document.getElementById('specialLayer_darkener'))
-  {
-    document.getElementById('specialLayer_darkener').style.display = 'block';
-    if(nofade)
-    {
-      document.getElementById('specialLayer_darkener').style.opacity = '0.7';
-      document.getElementById('specialLayer_darkener').style.filter = 'alpha(opacity=70)';
-    }
-    else
-    {
-      opacity('specialLayer_darkener', 0, 70, 1000);
-    }
-  } else {
-    w = getWidth();
-    h = getHeight();
-    var thediv = document.createElement('div');
-    if(IE)
-      thediv.style.position = 'absolute';
-    else
-      thediv.style.position = 'fixed';
-    thediv.style.top = '0px';
-    thediv.style.left = '0px';
-    thediv.style.opacity = '0';
-    thediv.style.filter = 'alpha(opacity=0)';
-    thediv.style.backgroundColor = '#000000';
-    thediv.style.width =  '100%';
-    thediv.style.height = '100%';
-    thediv.zIndex = getHighestZ() + 5;
-    thediv.id = 'specialLayer_darkener';
-    if(nofade)
-    {
-      thediv.style.opacity = '0.7';
-      thediv.style.filter = 'alpha(opacity=70)';
-      body = document.getElementsByTagName('body');
-      body = body[0];
-      body.appendChild(thediv);
-    } else {
-      body = document.getElementsByTagName('body');
-      body = body[0];
-      body.appendChild(thediv);
-      opacity('specialLayer_darkener', 0, 70, 1000);
-    }
-  }
-}
-
-function enlighten(nofade)
-{
-  if(IE)
-    nofade = true;
-  if(document.getElementById('specialLayer_darkener'))
-  {
-    if(nofade)
-    {
-      document.getElementById('specialLayer_darkener').style.display = 'none';
-    }
-    opacity('specialLayer_darkener', 70, 0, 1000);
-    setTimeout("document.getElementById('specialLayer_darkener').style.display = 'none';", 1000);
-  }
-}
-
-/**
- * The ultimate message box framework for Javascript
- * Syntax is (almost) identical to the MessageBox command in NSIS
- * @param int type - a bitfield consisting of the MB_* constants
- * @param string title - the blue text at the top of the window
- * @param string text - HTML for the body of the message box
- * Properties:
- *   onclick - an array of functions to be called on button click events
- *             NOTE: key names are to be strings, and they must be the value of the input, CaSe-SeNsItIvE
- *   onbeforeclick - same as onclick but called before the messagebox div is destroyed
- * Example:
- *   var my_message = new messagebox(MB_OK|MB_ICONSTOP, 'Error logging in', 'The username and/or password is incorrect. Please check the username and retype your password');
- *   my_message.onclick['OK'] = function() {
- *       document.getElementById('password').value = '';
- *     };
- * Deps:
- *   Modern browser that supports DOM
- *   darken() and enlighten() (above)
- *   opacity() - required for darken() and enlighten()
- *   MB_* constants are defined in enano-lib-basic.js
- */
-
-var mb_current_obj;
-
-function messagebox(type, title, message)
-{
-  var y = getScrollOffset();
-  if(document.getElementById('messageBox')) return;
-  darken(true);
-  var master_div = document.createElement('div');
-  var mydiv = document.createElement('div');
-  mydiv.style.width = '400px';
-  mydiv.style.height = '200px';
-  w = getWidth();
-  h = getHeight();
-  //master_div.style.left = (w / 2) - 200+'px';
-  //master_div.style.top = (h / 2) + y - 120+'px';
-  master_div.style.top = '-10000px';
-  master_div.style.position = ( IE ) ? 'absolute' : 'fixed';
-  z = getHighestZ(); // document.getElementById('specialLayer_darkener').style.zIndex;
-  mydiv.style.zIndex = parseInt(z) + 1;
-  mydiv.style.backgroundColor = '#FFFFFF';
-  mydiv.style.padding = '10px';
-  mydiv.style.marginBottom = '1px';
-  mydiv.id = 'messageBox';
-  mydiv.style.overflow = 'auto';
-  
-  var buttondiv = document.createElement('div');
-  buttondiv.style.width = '400px';
-  w = getWidth();
-  h = getHeight();
-  // buttondiv.style.left = (w / 2) - 200+'px';
-  // buttondiv.style.top = (h / 2) + y + 101+'px';
-  // buttondiv.style.position = ( IE ) ? 'absolute' : 'fixed';
-  z = getHighestZ(); // document.getElementById('specialLayer_darkener').style.zIndex;
-  buttondiv.style.zIndex = parseInt(z) + 1;
-  buttondiv.style.backgroundColor = '#C0C0C0';
-  buttondiv.style.padding = '10px';
-  buttondiv.style.textAlign = 'right';
-  buttondiv.style.verticalAlign = 'middle';
-  buttondiv.id = 'messageBoxButtons';
-  
-  this.clickHandler = function() { messagebox_click(this, mb_current_obj); };
-  
-  if(type & MB_ICONINFORMATION || type & MB_ICONSTOP || type & MB_ICONQUESTION || type & MB_ICONEXCLAMATION || type & MB_ICONLOCK)
-  {
-    mydiv.style.paddingLeft = '50px';
-    mydiv.style.width = '360px';
-    mydiv.style.backgroundRepeat = 'no-repeat';
-  }
-  
-  if(type & MB_ICONINFORMATION)
-  {
-    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/info.png\')';
-  }
-  
-  if(type & MB_ICONQUESTION)
-  {
-    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/question.png\')';
-  }
-  
-  if(type & MB_ICONSTOP)
-  {
-    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/error.png\')';
-  }
-  
-  if(type & MB_ICONEXCLAMATION)
-  {
-    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/warning.png\')';
-  }
-  
-  if(type & MB_ICONLOCK)
-  {
-    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/lock.png\')';
-  }
-  
-  if(type & MB_OK)
-  {
-    btn = document.createElement('input');
-    btn.type = 'button';
-    btn.value = 'OK';
-    btn.onclick = this.clickHandler;
-    btn.style.margin = '0 3px';
-    buttondiv.appendChild(btn);
-  }
-  
-  if(type & MB_OKCANCEL)
-  {
-    btn = document.createElement('input');
-    btn.type = 'button';
-    btn.value = 'OK';
-    btn.onclick = this.clickHandler;
-    btn.style.margin = '0 3px';
-    buttondiv.appendChild(btn);
-    
-    btn = document.createElement('input');
-    btn.type = 'button';
-    btn.value = 'Cancel';
-    btn.onclick = this.clickHandler;
-    btn.style.margin = '0 3px';
-    buttondiv.appendChild(btn);
-  }
-  
-  if(type & MB_YESNO)
-  {
-    btn = document.createElement('input');
-    btn.type = 'button';
-    btn.value = 'Yes';
-    btn.onclick = this.clickHandler;
-    btn.style.margin = '0 3px';
-    buttondiv.appendChild(btn);
-    
-    btn = document.createElement('input');
-    btn.type = 'button';
-    btn.value = 'No';
-    btn.onclick = this.clickHandler;
-    btn.style.margin = '0 3px';
-    buttondiv.appendChild(btn);
-  }
-  
-  if(type & MB_YESNOCANCEL)
-  {
-    btn = document.createElement('input');
-    btn.type = 'button';
-    btn.value = 'Yes';
-    btn.onclick = this.clickHandler;
-    btn.style.margin = '0 3px';
-    buttondiv.appendChild(btn);
-    
-    btn = document.createElement('input');
-    btn.type = 'button';
-    btn.value = 'No';
-    btn.onclick = this.clickHandler;
-    btn.style.margin = '0 3px';
-    buttondiv.appendChild(btn);
-    
-    btn = document.createElement('input');
-    btn.type = 'button';
-    btn.value = 'Cancel';
-    btn.onclick = this.clickHandler;
-    btn.style.margin = '0 3px';
-    buttondiv.appendChild(btn);
-  }
-  
-  heading = document.createElement('h2');
-  heading.innerHTML = title;
-  heading.style.color = '#50A0D0';
-  heading.style.fontFamily = 'trebuchet ms, verdana, arial, helvetica, sans-serif';
-  heading.style.fontSize = '12pt';
-  heading.style.fontWeight = 'lighter';
-  heading.style.textTransform = 'lowercase';
-  heading.style.marginTop = '0';
-  mydiv.appendChild(heading);
-  
-  var text = document.createElement('div');
-  text.innerHTML = String(message);
-  this.text_area = text;
-  mydiv.appendChild(text);
-  
-  this.updateContent = function(text)
-    {
-      this.text_area.innerHTML = text;
-    };
-  
-  //domObjChangeOpac(0, mydiv);
-  //domObjChangeOpac(0, master_div);
-  
-  body = document.getElementsByTagName('body');
-  body = body[0];
-  master_div.appendChild(mydiv);
-  master_div.appendChild(buttondiv);
-  
-  body.appendChild(master_div);
-  
-  setTimeout('mb_runFlyIn();', 100);
-  
-  this.onclick = new Array();
-  this.onbeforeclick = new Array();
-  mb_current_obj = this;
-}
-
-function mb_runFlyIn()
-{
-  var mydiv = document.getElementById('messageBox');
-  var maindiv = mydiv.parentNode;
-  fly_in_top(maindiv, true, false);
-}
-
-function messagebox_click(obj, mb)
-{
-  val = obj.value;
-  if(typeof mb.onbeforeclick[val] == 'function')
-  {
-    var o = mb.onbeforeclick[val];
-    var resp = o();
-    if ( resp )
-      return false;
-    o = false;
-  }
-  
-  var mydiv = document.getElementById('messageBox');
-  var maindiv = mydiv.parentNode;
-  var to = fly_out_top(maindiv, true, false);
-  
-  setTimeout("var mbdiv = document.getElementById('messageBox'); mbdiv.parentNode.removeChild(mbdiv.nextSibling); mbdiv.parentNode.removeChild(mbdiv); enlighten(true);", to);
-  if(typeof mb.onclick[val] == 'function')
-  {
-    o = mb.onclick[val];
-    o();
-    o = false;
-  }
-}
-
-function testMessageBox()
-{
-  mb = new messagebox(MB_OKCANCEL|MB_ICONINFORMATION, 'Javascripted dynamic message boxes', 'This is soooooo coool, now if only document.createElement() worked in IE!<br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text');
-  mb.onclick['OK'] = function()
-    {
-      alert('You clicked OK!');
-    }
-  mb.onbeforeclick['Cancel'] = function()
-    {
-      alert('You clicked Cancel!');
-    }
-}
-
-// Function to fade classes info-box, warning-box, error-box, etc.
-
-function fadeInfoBoxes()
-{
-  var divs = new Array();
-  d = document.getElementsByTagName('div');
-  j = 0;
-  for(var i in d)
-  {
-    if ( !d[i].tagName )
-      continue;
-    if(d[i].className=='info-box' || d[i].className=='error-box' || d[i].className=='warning-box' || d[i].className=='question-box')
-    {
-      divs[j] = d[i];
-      j++;
-    }
-  }
-  if(divs.length < 1) return;
-  for(i in divs)
-  {
-    if(!divs[i].id) divs[i].id = 'autofade_'+Math.floor(Math.random() * 100000);
-    switch(divs[i].className)
-    {
-      case 'info-box':
-      default:
-        from = '#3333FF';
-        break;
-      case 'error-box':
-        from = '#FF3333';
-        break;
-      case 'warning-box':
-        from = '#FFFF33';
-        break;
-      case 'question-box':
-        from = '#33FF33';
-        break;
-    }
-    Fat.fade_element(divs[i].id,30,2000,from,Fat.get_bgcolor(divs[i].id));
-  }
-}
-
-// Alpha fades
-
-function opacity(id, opacStart, opacEnd, millisec) {
-    //speed for each frame
-    var speed = Math.round(millisec / 100);
-    var timer = 0;
-
-    //determine the direction for the blending, if start and end are the same nothing happens
-    if(opacStart > opacEnd) {
-        for(i = opacStart; i >= opacEnd; i--) {
-            setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
-            timer++;
-        }
-    } else if(opacStart < opacEnd) {
-        for(i = opacStart; i <= opacEnd; i++)
-            {
-            setTimeout("changeOpac(" + i + ",'" + id + "')",(timer * speed));
-            timer++;
-        }
-    }
-}
-
-//change the opacity for different browsers
-function changeOpac(opacity, id) {
-    var object = document.getElementById(id).style;
-    object.opacity = (opacity / 100);
-    object.MozOpacity = (opacity / 100);
-    object.KhtmlOpacity = (opacity / 100);
-    object.filter = "alpha(opacity=" + opacity + ")";
-}
-
-function mb_logout()
-{
-  var mb = new messagebox(MB_YESNO|MB_ICONQUESTION, 'Are you sure you want to log out?', 'If you log out, you will no longer be able to access your user preferences, certain areas of this site, and this awesome logout confirmation screen until you login again.<br /><br />OK, not funny. I\'ll remove the bad humor in Banshee.');
-  mb.onclick['Yes'] = function()
-    {
-      window.location = makeUrlNS('Special', 'Logout/' + title);
-    }
-}
-
--- a/includes/clientside/static/misc.js~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,563 +0,0 @@
-// Some additional DHTML functions
-
-function fetch_offset(obj) {
-  var left_offset = obj.offsetLeft;
-  var top_offset = obj.offsetTop;
-  while ((obj = obj.offsetParent) != null) {
-    left_offset += obj.offsetLeft;
-    top_offset += obj.offsetTop;
-  }
-  return { 'left' : left_offset, 'top' : top_offset };
-}
-
-function fetch_dimensions(o) {
-  var w = o.offsetWidth;
-  var h = o.offsetHeight;
-  return { 'w' : w, 'h' : h };
-}
-
-function findParentForm(o)
-{
-  // Not implemented - someone please let me know how to do this, what I need to do is
-  // find the first parent <form> tag above param 'o', not sure how to do it with DOM
-}
-
-function ajaxReverseDNS(o, text)
-{
-  if(text) var ipaddr = text;
-  else var ipaddr = o.innerHTML;
-  rDnsObj = o;
-  rDnsBannerObj = bannerOn('Retrieving reverse DNS info...');
-  ajaxGet(stdAjaxPrefix+'&_mode=rdns&ip='+ipaddr, function() {
-      if(ajax.readyState == 4)
-      {
-        off = fetch_offset(rDnsObj);
-        dim = fetch_dimensions(rDnsObj);
-        right = off['left'] + dim['w'];
-        top = off['top'] + dim['h'];
-        var thediv = document.createElement('div');
-        thediv.className = 'info-box';
-        thediv.style.margin = '0';
-        thediv.style.position = 'absolute';
-        thediv.style.top  = top  + 'px';
-        thediv.style.display = 'none';
-        thediv.style.zIndex = getHighestZ() + 2;
-        thediv.id = 'mdgDynamic_rDnsInfoDiv_'+Math.floor(Math.random() * 1000000);
-        thediv.innerHTML = '<b>Reverse DNS:</b><br />'+ajax.responseText+' <a href="#" onclick="elem = document.getElementById(\''+thediv.id+'\'); elem.innerHTML = \'\'; elem.style.display = \'none\';return false;">Close</a>';
-        var body = document.getElementsByTagName('body');
-        body = body[0];
-        bannerOff(rDnsBannerObj);
-        body.appendChild(thediv);
-        thediv.style.display = 'block';
-        left = fetch_dimensions(thediv);
-        thediv.style.display = 'none';
-        left = right - left['w'];
-        thediv.style.left = left + 'px';
-        thediv.style.display = 'block';
-        fadeInfoBoxes();
-      }
-    });
-}
-
-function bannerOn(text)
-{
-  darken(true);
-  var thediv = document.createElement('div');
-  thediv.className = 'mdg-comment';
-  thediv.style.padding = '0';
-  thediv.style.marginLeft = '0';
-  thediv.style.position = 'absolute';
-  thediv.style.display = 'none';
-  thediv.style.padding = '4px';
-  thediv.style.fontSize = '14pt';
-  thediv.id = 'mdgDynamic_bannerDiv_'+Math.floor(Math.random() * 1000000);
-  thediv.innerHTML = text;
-  
-  var body = document.getElementsByTagName('body');
-  body = body[0];
-  body.appendChild(thediv);
-  body.style.cursor = 'wait';
-  
-  thediv.style.display = 'block';
-  dim = fetch_dimensions(thediv);
-  thediv.style.display = 'none';
-  bdim = { 'w' : getWidth(), 'h' : getHeight() };
-  so = getScrollOffset();
-  
-  left = (bdim['w'] / 2) - ( dim['w'] / 2 );
-  top  = (bdim['h'] / 2) - ( dim['h'] / 2 ) + so;
-  
-  thediv.style.top  = top  + 'px';
-  thediv.style.left = left + 'px';
-  
-  thediv.style.display = 'block';
-  
-  return thediv.id;
-}
-
-function bannerOff(id)
-{
-  e = document.getElementById(id);
-  if(!e) return;
-  e.innerHTML = '';
-  e.style.display = 'none';
-  var body = document.getElementsByTagName('body');
-  body = body[0];
-  body.style.cursor = 'default';
-  enlighten(true);
-}
-
-function disableUnload(message)
-{
-  if(typeof message != 'string') message = 'You may want to save your changes first.';
-  var body = document.getElementsByTagName('body');
-  body = body[0];
-  body.onbeforeunload='return unescape(\''+escape(message)+'\')';
-}
-
-function enableUnload()
-{
-  var body = document.getElementsByTagName('body');
-  body = body[0];
-  body.onbeforeunload = null;
-}
-
-/**
- * Gets the highest z-index of all divs in the document
- * @return integer
- */
-function getHighestZ()
-{
-  z = 0;
-  var divs = document.getElementsByTagName('div');
-  for(var i = 0; i < divs.length; i++)
-  {
-    if(divs[i].style.zIndex > z) z = divs[i].style.zIndex;
-  }
-  return z;
-}
-
-function isKeyPressed(event)
-{
-  if (event.shiftKey==1)
-  {
-    shift = true;
-  }
-  else
-  {
-    shift = false;
-  }
-}
-
-function moveDiv(div, newparent)
-{
-  var backup = div;
-  var oldparent = div.parentNode;
-  oldparent.removeChild(div);
-  newparent.appendChild(backup);
-}
-
-function readCookie(name) {var nameEQ = name + "=";var ca = document.cookie.split(';');for(var i=0;i < ca.length;i++){var c = ca[i];while (c.charAt(0)==' ') c = c.substring(1,c.length);if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);}return null;}
-function createCookie(name,value,days){if (days){var date = new Date();date.setTime(date.getTime()+(days*24*60*60*1000));var expires = "; expires="+date.toGMTString();}else var expires = "";document.cookie = name+"="+value+expires+"; path=/";}
-function eraseCookie(name) {createCookie(name,"",-1);}
-
-var busyBannerID;
-function goBusy(msg)
-{
-  if(!msg) msg = 'Please wait...';
-  body = document.getElementsByTagName('body');
-  body = body[0];
-  body.style.cursor = 'wait';
-  busyBannerID = bannerOn(msg);
-}
-
-function unBusy()
-{
-  body = document.getElementsByTagName('body');
-  body = body[0];
-  body.style.cursor = 'default';
-  bannerOff(busyBannerID);
-}
-
-function setAjaxLoading()
-{
-  if ( document.getElementById('ajaxloadicon') )
-  {
-    document.getElementById('ajaxloadicon').src=scriptPath + '/images/loading.gif';
-  }
-}
-
-function unsetAjaxLoading()
-{
-  if ( document.getElementById('ajaxloadicon') )
-  {
-    document.getElementById('ajaxloadicon').src=scriptPath + '/images/spacer.gif';
-  }
-}
-
-/*
- * Search boxes
- */
- 
-function buildSearchBoxes()
-{
-  var divs = document.getElementsByTagName('*');
-  var boxes = new Array();
-  for ( var i = 0; i < divs.length; i++ )
-  {
-    if ( divs[i].className)
-    {
-      if ( divs[i].className.substr(0, 9) == 'searchbox' )
-      {
-        boxes.push(divs[i]);
-      }
-    }
-  }
-  for ( var i = 0; i < boxes.length; i++ )
-  {
-    if ( boxes[i].className.match(/^searchbox\[([0-9]+)px\]$/) )
-    {
-      var width = boxes[i].className.match(/^searchbox\[([0-9]+)px\]$/);
-      width = parseInt(width[1]);
-    }
-    else
-    {
-      var width = 120;
-    }
-    createSearchBox(boxes[i], width);
-  }
-}
-
-function createSearchBox(parent, width)
-{
-  if ( typeof(parent) != 'object')
-  {
-    alert('BUG: createSearchBox(): parent is not an object');
-    return false;
-  }
-  //parent.style.padding = '0px';
-  //parent.style.textAlign = 'center';
-  parent.style.width = width + 'px';
-  var submit = document.createElement('div');
-  submit.onclick = function() { searchFormSubmit(this); };
-  submit.className = 'js-search-submit';
-  var input = document.createElement('input');
-  input.className = 'js-search-box';
-  input.value = 'Search';
-  input.name = 'q';
-  input.style.width = ( width - 28 ) + 'px';
-  input.onfocus = function() { if ( this.value == 'Search' ) this.value = ''; };
-  input.onblur  = function() { if ( this.value == '' ) this.value = 'Search'; };
-  parent.appendChild(input);
-  var off = fetch_offset(input);
-  var top = off['top'] + 'px';
-  var left = ( parseInt(off['left']) + ( width - 24 ) ) + 'px';
-  submit.style.top = top;
-  submit.style.left = left;
-  parent.appendChild(submit);
-}
-
-function searchFormSubmit(obj)
-{
-  var input = obj.previousSibling;
-  if ( input.value == 'Search' || input.value == '' )
-    return false;
-  var p = obj;
-  while(true)
-  {
-    p = p.parentNode;
-    if ( !p )
-      break;
-    if ( typeof(p.tagName) != 'string' )
-      break;
-    else if ( p.tagName.toLowerCase() == 'form' )
-    {
-      p.submit();
-    }
-    else if ( p.tagName.toLowerCase() == 'body' )
-    {
-      break;
-    }
-  }
-}
-
-/*
- * AJAX login box (experimental)
- */
-
-var ajax_auth_prompt_cache = false;
-var ajax_auth_mb_cache = false;
-var ajax_auth_level_cache = false;
-
-function ajaxPromptAdminAuth(call_on_ok, level)
-{
-  if ( typeof(call_on_ok) == 'function' )
-  {
-    ajax_auth_prompt_cache = call_on_ok;
-  }
-  if ( !level )
-    level = 2;
-  ajax_auth_level_cache = level;
-  var loading_win = '<div align="center" style="text-align: center;"> \
-      <p>Fetching an encryption key...</p> \
-      <p><small>Not working? Use the <a href="'+makeUrlNS('Special', 'Login/' + title)+'">alternate login form</a>.</p> \
-      <p><img alt="Please wait..." src="'+scriptPath+'/images/loading-big.gif" /></p> \
-    </div>';
-  ajax_auth_mb_cache = new messagebox(MB_OKCANCEL|MB_ICONLOCK, 'Please enter your username and password to continue.', loading_win);
-  ajax_auth_mb_cache.onbeforeclick['OK'] = ajaxValidateLogin;
-  ajaxAuthLoginInnerSetup();
-}
-
-function ajaxAuthLoginInnerSetup()
-{
-  ajaxGet(makeUrlNS('Special', 'Login', 'act=getkey'), function() {
-      if ( ajax.readyState == 4 )
-      {
-        var response = ajax.responseText;
-        if ( response.substr(0,1) != '{' )
-        {
-          alert('Invalid JSON response from server: ' + response);
-          return false;
-        }
-        response = parseJSON(response);
-        var form_html = ' \
-          <table border="0" align="center"> \
-            <tr> \
-              <td>Username:</td><td><input tabindex="1" id="ajaxlogin_user" type="text"     size="25" /> \
-            </tr> \
-            <tr> \
-              <td>Password:</td><td><input tabindex="2" id="ajaxlogin_pass" type="password" size="25" /> \
-            </tr> \
-            <tr> \
-              <td colspan="2" style="text-align: center;"> \
-                <br /><small>Trouble logging in? Try the <a href="'+makeUrlNS('Special', 'Login/' + title)+'">full login form</a>.<br /> \
-                Did you <a href="'+makeUrlNS('Special', 'PasswordReset')+'">forget your password</a>?<br /> \
-                Maybe you need to <a href="'+makeUrlNS('Special', 'Register')+'">create an account</a>.</small> \
-              </td> \
-            </tr> \
-          </table> \
-          <input type="hidden" id="ajaxlogin_crypt_key"       value="' + response.key + '" /> \
-          <input type="hidden" id="ajaxlogin_crypt_challenge" value="' + response.challenge + '" /> \
-        </form>';
-        ajax_auth_mb_cache.updateContent(form_html);
-        $('messageBox').object.nextSibling.firstChild.tabindex = '3';
-        $('ajaxlogin_user').object.focus();
-        $('ajaxlogin_pass').object.onblur = function() { $('messageBox').object.nextSibling.firstChild.focus(); };
-      }
-    });
-}
-
-function ajaxValidateLogin()
-{
-  var username,password,auth_enabled,crypt_key,crypt_data,challenge_salt,challenge_data;
-  username = document.getElementById('ajaxlogin_user');
-  if ( !username )
-    return false;
-  username = document.getElementById('ajaxlogin_user').value;
-  password = document.getElementById('ajaxlogin_pass').value;
-  auth_enabled = false;
-  
-  disableJSONExts();
-  
-  //
-  // Encryption test
-  //
-  
-  var str = '';
-  for(i=0;i<keySizeInBits/4;i++)
-  {
-    str+='0';
-  }
-  str = hexToByteArray(str);
-  var ct  = rijndaelEncrypt(str, str, 'ECB');
-  ct      = byteArrayToHex(ct);
-  var v;
-  switch(keySizeInBits)
-  {
-    case 128:
-      v = '66e94bd4ef8a2c3b884cfa59ca342b2e';
-      break;
-    case 192:
-      v = 'aae06992acbf52a3e8f4a96ec9300bd7aae06992acbf52a3e8f4a96ec9300bd7';
-      break;
-    case 256:
-      v = 'dc95c078a2408989ad48a21492842087dc95c078a2408989ad48a21492842087';
-      break;
-  }
-  auth_enabled = ( ct == v && md5_vm_test() );
-  if ( !auth_enabled )
-  {
-    alert('Login error: encryption sanity check failed\n');
-    return true;
-  }
-  
-  crypt_key = document.getElementById('ajaxlogin_crypt_key').value;
-  challenge_salt = document.getElementById('ajaxlogin_crypt_challenge').value;
-  
-  var crypt_key_md5 = hex_md5(crypt_key);
-  
-  challenge_data = hex_md5(password + challenge_salt) + challenge_salt;
-  
-  password = stringToByteArray(password);
-  crypt_key = hexToByteArray(crypt_key);
-  
-  crypt_data = rijndaelEncrypt(password, crypt_key, 'ECB');
-  crypt_data = byteArrayToHex(crypt_data);
-  
-  var json_data = {
-    'username' : username,
-    'crypt_key' : crypt_key_md5,
-    'challenge' : challenge_data,
-    'crypt_data' : crypt_data,
-    'level' : ajax_auth_level_cache
-  };
-  
-  json_data = toJSONString(json_data);
-  json_data = ajaxEscape(json_data);
-  
-  var loading_win = '<div align="center" style="text-align: center;"> \
-      <p>Logging in...</p> \
-      <p><img alt="Please wait..." src="'+scriptPath+'/images/loading-big.gif" /></p> \
-    </div>';
-    
-  ajax_auth_mb_cache.updateContent(loading_win);
-  
-  ajaxPost(makeUrlNS('Special', 'Login', 'act=ajaxlogin'), 'params=' + json_data, function() {
-      if ( ajax.readyState == 4 )
-      {
-        var response = ajax.responseText;
-        if ( response.substr(0,1) != '{' )
-        {
-          alert('Invalid JSON response from server: ' + response);
-          ajaxAuthLoginInnerSetup();
-          return false;
-        }
-        response = parseJSON(response);
-        switch(response.result)
-        {
-          case 'success':
-            if ( typeof(ajax_auth_prompt_cache) == 'function' )
-            {
-              ajax_auth_prompt_cache(response.key);
-            }
-            break;
-          case 'error':
-            alert(response.error);
-            ajaxAuthLoginInnerSetup();
-            break;
-          default:
-            alert(ajax.responseText);
-            break;
-        }
-      }
-    });
-  
-  return true;
-  
-}
-
-// This code is in the public domain. Feel free to link back to http://jan.moesen.nu/
-function sprintf()
-{
-  if (!arguments || arguments.length < 1 || !RegExp)
-  {
-    return;
-  }
-  var str = arguments[0];
-  var re = /([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X)(.*)/;
-  var a = b = [], numSubstitutions = 0, numMatches = 0;
-  while (a = re.exec(str))
-  {
-    var leftpart = a[1], pPad = a[2], pJustify = a[3], pMinLength = a[4];
-    var pPrecision = a[5], pType = a[6], rightPart = a[7];
-    
-    //alert(a + '\n' + [a[0], leftpart, pPad, pJustify, pMinLength, pPrecision);
-
-    numMatches++;
-    if (pType == '%')
-    {
-      subst = '%';
-    }
-    else
-    {
-      numSubstitutions++;
-      if (numSubstitutions >= arguments.length)
-      {
-        alert('Error! Not enough function arguments (' + (arguments.length - 1) + ', excluding the string)\nfor the number of substitution parameters in string (' + numSubstitutions + ' so far).');
-      }
-      var param = arguments[numSubstitutions];
-      var pad = '';
-             if (pPad && pPad.substr(0,1) == "'") pad = leftpart.substr(1,1);
-        else if (pPad) pad = pPad;
-      var justifyRight = true;
-             if (pJustify && pJustify === "-") justifyRight = false;
-      var minLength = -1;
-             if (pMinLength) minLength = parseInt(pMinLength);
-      var precision = -1;
-             if (pPrecision && pType == 'f') precision = parseInt(pPrecision.substring(1));
-      var subst = param;
-             if (pType == 'b') subst = parseInt(param).toString(2);
-        else if (pType == 'c') subst = String.fromCharCode(parseInt(param));
-        else if (pType == 'd') subst = parseInt(param) ? parseInt(param) : 0;
-        else if (pType == 'u') subst = Math.abs(param);
-        else if (pType == 'f') subst = (precision > -1) ? Math.round(parseFloat(param) * Math.pow(10, precision)) / Math.pow(10, precision): parseFloat(param);
-        else if (pType == 'o') subst = parseInt(param).toString(8);
-        else if (pType == 's') subst = param;
-        else if (pType == 'x') subst = ('' + parseInt(param).toString(16)).toLowerCase();
-        else if (pType == 'X') subst = ('' + parseInt(param).toString(16)).toUpperCase();
-    }
-    str = leftpart + subst + rightPart;
-  }
-  return str;
-}
-
-function paginator_goto(parentobj, this_page, num_pages, perpage, url_string)
-{
-  var height = $(parentobj).Height();
-  var width  = $(parentobj).Width();
-  var left   = $(parentobj).Left();
-  var top    = $(parentobj).Top();
-  var left_pos = left + width ;
-  var top_pos = height + top;
-  var div = document.createElement('div');
-  div.style.position = 'absolute';
-  div.style.top = top_pos + 'px';
-  div.className = 'question-box';
-  div.style.margin = '1px 0 0 2px';
-  var vtmp = 'input_' + Math.floor(Math.random() * 1000000);
-  div.innerHTML = 'Go to page:<br /><input type="text" size="2" style="padding: 1px; font-size: 8pt;" value="'+(parseInt(this_page)+1)+'" id="'+vtmp+'" />&emsp;<a href="#" onclick="paginator_submit(this, '+num_pages+', '+perpage+', unescape(\'' + escape(url_string) + '\')); return false;" style="font-size: 14pt; text-decoration: none;">&raquo;</a>&emsp;<a href="#" onclick="fly_out_top(this.parentNode, false, true); return false;" style="font-size: 14pt; text-decoration: none;">&times;</a>';
-  
-  var body = document.getElementsByTagName('body')[0];
-  body.appendChild(div);
-  
-  document.getElementById(vtmp).onkeypress = function(e){if(e.keyCode==13)this.nextSibling.nextSibling.onclick();};
-  document.getElementById(vtmp).focus();
-  
-  // fade the div
-  /*
-  if(!div.id) div.id = 'autofade_'+Math.floor(Math.random() * 100000);
-  var from = '#33FF33';
-  Fat.fade_element(div.id,30,2000,from,Fat.get_bgcolor(div.id));
-  */
-  fly_in_bottom(div, false, true);
-  
-  var divh = $(div).Width();
-  left_pos = left_pos - divh;
-  div.style.left = left_pos + 'px';
-}
-
-function paginator_submit(obj, max, perpage, formatstring)
-{
-  var userinput = obj.previousSibling.previousSibling.value;
-  userinput = parseInt(userinput);
-  var offset = ( userinput - 1 ) * perpage;
-  if ( userinput > max || isNaN(userinput) || userinput < 1 )
-  {
-    new messagebox(MB_OK|MB_ICONSTOP, 'Invalid entry', 'Please enter a page number between 1 and ' + max + '.');
-    return false;
-  }
-  var url = sprintf(formatstring, String(offset));
-  fly_out_top(obj.parentNode, false, true);
-  window.location = url;
-}
-
--- a/includes/common.php	Wed Jun 13 16:32:27 2007 -0400
+++ b/includes/common.php	Wed Jun 13 16:59:00 2007 -0400
@@ -37,9 +37,9 @@
 error_reporting(E_ALL);
 
 // Determine directory (special case for development servers)
-if ( strpos(__FILE__, '/enano-clean/') && file_exists('.enanodev') )
+if ( strpos(__FILE__, '/repo/') && file_exists('.enanodev') )
 {
-  $filename = str_replace('/enano-clean', '', __FILE__);
+  $filename = str_replace('/repo/', '/', __FILE__);
 }
 else
 {
--- a/includes/common.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-<?php
-
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 (Banshee)
- * Copyright (C) 2006-2007 Dan Fuhry
- *
- * This program is Free Software; you can redistribute 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 details.
- */
-
-if(isset($_REQUEST['GLOBALS']))
-{
-  ?>
-  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html><head><title>Hacking Attempt</title><meta http-equiv="Content-type" content="text/html; charset=utf-8" /></head><style type="text/css">body{background-color:#000;color:#CCC;font-family:trebuchet ms,sans-serif;font-size:9pt;}a{color:#FFF;}</style><body><p>Hacking attempt using <a href="http://www.hardened-php.net/index.76.html">PHP $GLOBALS overwrite vulnerability</a> detected, reported to admin</p><p>You're worse than this guy! Unless you are this guy...</p><p id="billp"><img alt=" " src="about:blank" id="billi" /></p><script type="text/javascript">// <![CDATA[
-  window.onload=function(){counter();setInterval('counter();', 1000);};var text=false;var cnt=10;function counter(){if(!text){text=document.createElement('span');text.id='billc';text.innerHTML=cnt;text.style.fontSize='96pt';text.style.color='#FF0000';p=document.getElementById('billp');p.appendChild(text);}else{if(cnt==1){document.getElementById('billi').src='http://upload.wikimedia.org/wikipedia/commons/7/7f/Bill_Gates_2004_cr.jpg';document.getElementById('billc').innerHTML='';return;}cnt--;document.getElementById('billc').innerHTML=cnt+' ';}}
-  // ]]>
-  </script><p><span style="color:black;">Powered by Enano and valid XHTML 1.1</span></p></body></html>
-  <?php
-  exit;
-}
-
-$version = '1.0';
-
-function microtime_float()
-{
-  list($usec, $sec) = explode(" ", microtime());
-  return ((float)$usec + (float)$sec);
-}
-
-global $_starttime;
-$_starttime = microtime_float();
-
-error_reporting(E_ALL);
-
-if(!defined('ENANO_ROOT')) // ENANO_ROOT is sometimes defined by plugins like AjIM that need the constant before the Enano API is initialized
-  define('ENANO_ROOT', dirname(dirname(__FILE__)));
-
-if(defined('ENANO_DEBUG') && version_compare(PHP_VERSION, '5.0.0') < 0)
-{
-  die(__FILE__.':'.__LINE__.': The debugConsole requires PHP 5.x.x or greater. Please comment out the ENANO_DEBUG constant in your index.php.');
-}
-
-if(defined('ENANO_DEBUG'))
-{
-  require_once(ENANO_ROOT.'/includes/debugger/debugConsole.php');
-} else {
-  function dc_here($m)     { return false; }
-  function dc_dump($a, $g) { return false; }
-  function dc_watch($n)    { return false; }
-  function dc_start_timer($u) { return false; }
-  function dc_stop_timer($m) { return false; }
-}
-
-if ( file_exists( ENANO_ROOT . '/_nightly.php') )
-  require(ENANO_ROOT.'/_nightly.php');
-
-// Start including files. LOTS of files. Yeah!
-require_once(ENANO_ROOT.'/includes/constants.php');
-dc_here('Enano CMS '.$version.' (dev) - debug window<br />Powered by debugConsole');
-dc_here('common: including files');
-require_once(ENANO_ROOT.'/includes/functions.php');
-require_once(ENANO_ROOT.'/includes/dbal.php');
-require_once(ENANO_ROOT.'/includes/paths.php');
-require_once(ENANO_ROOT.'/includes/sessions.php');
-require_once(ENANO_ROOT.'/includes/template.php');
-require_once(ENANO_ROOT.'/includes/plugins.php');
-require_once(ENANO_ROOT.'/includes/comment.php');
-require_once(ENANO_ROOT.'/includes/wikiformat.php');
-require_once(ENANO_ROOT.'/includes/diff.php');
-require_once(ENANO_ROOT.'/includes/render.php');
-require_once(ENANO_ROOT.'/includes/stats.php');
-require_once(ENANO_ROOT.'/includes/pageutils.php');
-require_once(ENANO_ROOT.'/includes/js-compressor.php');
-require_once(ENANO_ROOT.'/includes/rijndael.php');
-require_once(ENANO_ROOT.'/includes/email.php');
-require_once(ENANO_ROOT.'/includes/search.php');
-require_once(ENANO_ROOT.'/includes/json.php');
-require_once(ENANO_ROOT.'/includes/wikiengine/Tables.php');
-
-strip_magic_quotes_gpc();
-
-// Enano has five parts: the database abstraction layer (DBAL), the session manager, the path/URL manager, the template engine, and the plugin manager.
-// Each part has its own class and a global var; nearly all Enano functions are handled by one of these five components.
-
-global $db, $session, $paths, $template, $plugins; // Common objects
-global $enano_config; // A global used to cache config information without making loads of queries ;-)
-                      // In addition, $enano_config is used to fetch config information if die_semicritical() is called.
-                      
-global $email;
-
-if(!isset($_SERVER['HTTP_HOST'])) grinding_halt('Cannot get hostname', '<p>Your web browser did not provide the HTTP Host: field. This site requires a modern browser that supports the HTTP 1.1 standard.</p>');
-                     
-$db = new mysql();
-dc_here('common: calling $db->connect();');
-$db->connect(); // Redirects to install.php if an installation is not detected
-
-if(strstr(contentPath, '?')) $sep = '&';
-else $sep = '?';
-define('urlSeparator', $sep);
-unset($sep); // save 10 bytes of memory...
-
-// See if any diagnostic actions have been requested
-if ( isset($_GET['do']) && $_GET['do'] == 'diag' && isset($_GET['sub']) )
-{
-  switch($_GET['sub'])
-  {
-    case 'cookie_destroy':
-      unset($_COOKIE['sid']);
-      setcookie('sid', '', time()-3600*24, scriptPath);
-      setcookie('sid', '', time()-3600*24, scriptPath.'/');
-      die('Session cookie cleared. <a href="'.$_SERVER['PHP_SELF'].'">Continue</a>');
-      break;
-  }
-}
-
-// Select and fetch the site configuration
-dc_here('common: selecting global config data');
-$e = $db->sql_query('SELECT config_name, config_value FROM '.table_prefix.'config;');
-if(!$e) $db->_die('Some critical configuration information could not be selected.');
-else define('ENANO_CONFIG_FETCHED', ''); // Used in die_semicritical to figure out whether to call getConfig() or not
-
-dc_here('common: fetching $enano_config');
-$enano_config = Array();
-while($r = $db->fetchrow())
-{
-  $enano_config[$r['config_name']] = $r['config_value'];
-}
-
-$db->free_result();
-
-if(enano_version(false, true) != $version)
-{
-  grinding_halt('Version mismatch', '<p>It seems that the Enano release we\'re trying to run ('.$version.') is different from the version specified in your database ('.enano_version().'). Perhaps you need to <a href="'.scriptPath.'/upgrade.php">upgrade</a>?</p>');
-}
-
-// Our list of tables included in Enano
-$system_table_list = Array(
-    table_prefix.'categories',
-    table_prefix.'comments',
-    table_prefix.'config',
-    table_prefix.'logs',
-    table_prefix.'page_text',
-    table_prefix.'session_keys',
-    table_prefix.'pages',
-    table_prefix.'users',
-    table_prefix.'themes',
-    table_prefix.'buddies',
-    table_prefix.'banlist',
-    table_prefix.'files',
-    table_prefix.'privmsgs',
-    table_prefix.'sidebar',
-    table_prefix.'hits',
-    table_prefix.'search_index',
-    table_prefix.'groups',
-    table_prefix.'group_members',
-    table_prefix.'acl',
-    table_prefix.'search_cache'
-  );
-
-dc_here('common: initializing base classes');
-$plugins = new pluginLoader();
-
-// So where does the majority of Enano get executed? How about the next nine lines of code :)
-dc_here('common: ok, we\'re set up, starting mainstream execution');
-
-$plugins->loadAll();
-dc_here('common: loading plugins');
-  global $plugins;
-  foreach($plugins->load_list as $f) { include_once $f; } // Can't be in object context when this is done
-
-$session = new sessionManager();
-$paths = new pathManager();
-$template = new template();
-$email = new EmailEncryptor();
-
-define('ENANO_BASE_CLASSES_INITIALIZED', '');
-
-$code = $plugins->setHook('base_classes_initted');
-foreach ( $code as $cmd )
-{
-  eval($cmd);
-}
-  
-$p = RenderMan::strToPageId($paths->get_pageid_from_url());
-if( ( $p[1] == 'Admin' || $p[1] == 'Special' ) && function_exists('page_'.$p[1].'_'.$p[0].'_preloader'))
-{
-  @call_user_func('page_'.$p[1].'_'.$p[0].'_preloader');
-}
-
-$session->start();
-$paths->init();
-
-define('ENANO_MAINSTREAM', '');
-
-// If the site is disabled, bail out, unless we're trying to log in or administer the site
-if(getConfig('site_disabled') == '1')
-{
-  if ( $paths->namespace == 'Admin' || ( $paths->namespace == 'Special' && ( $paths->cpage['urlname_nons'] == 'CSS' || $paths->cpage['urlname_nons'] == 'Administration' || $paths->cpage['urlname_nons'] == 'Login' ) ) )
-  {
-    // do nothing; allow execution to continue
-  }
-  else
-  {
-    if(!$n = getConfig('site_disabled_notice')) $n = 'The administrator has disabled the site. Please check back later.';
-    
-    $text = RenderMan::render($n) . '
-    <div class="info-box">
-      If you have an administrative account, you may <a href="'.makeUrlNS('Special', 'Login').'">log in</a> to the site or <a href="'.makeUrlNS('Special', 'Administration').'">use the administration panel</a>.
-    </div>';
-    $paths->wiki_mode = 0;
-    die_semicritical('Site disabled', $text);
-  }
-}
-
-$code = $plugins->setHook('session_started');
-foreach ( $code as $cmd )
-{
-  eval($cmd);
-}
-
-if(isset($_GET['noheaders'])) $template->no_headers = true;
-
-?>
--- a/includes/functions.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1863 +0,0 @@
-<?php
-
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 (Banshee)
- * Copyright (C) 2006-2007 Dan Fuhry
- *
- * This program is Free Software; you can redistribute 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 details.
- */
- 
-function getConfig($n) {
-  global $enano_config;
-  if(isset($enano_config[$n])) return $enano_config[$n];
-  else                         return false;
-}
-
-function setConfig($n, $v) {
-  global $enano_config, $db;
-  $enano_config[$n] = $v;
-  $v = $db->escape($v);
-  $e=$db->sql_query('DELETE FROM '.table_prefix.'config WHERE config_name=\''.$n.'\';');
-  if(!$e) $db->_die('Error during generic setConfig() call row deletion.');
-  $e=$db->sql_query('INSERT INTO '.table_prefix.'config(config_name, config_value) VALUES(\''.$n.'\', \''.$v.'\')');
-  if(!$e) $db->_die('Error during generic setConfig() call row insertion.');
-}
-
-function makeUrl($t, $query = false, $escape = false)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $flags = '';
-  $sep = urlSeparator;
-  if(isset($_GET['printable'])) { $flags .= $sep.'printable'; $sep = '&'; }
-  if(isset($_GET['theme'])) { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
-  if(isset($_GET['style'])) { $flags .= $sep.'style='.$session->style; $sep = '&'; }
-  $url = $session->append_sid(contentPath.$t.$flags);
-  if($query)
-  {
-    $sep = strstr($url, '?') ? '&' : '?';
-    $url = $url . $sep . $query;
-  }
-  return ($escape) ? htmlspecialchars($url) : $url;
-}
-
-function makeUrlNS($n, $t, $query = false, $escape = false)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $flags = '';
-  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator;
-  else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
-  if(isset($_GET['printable'])) { $flags .= $sep.'printable';              $sep = '&'; }
-  if(isset($_GET['theme']))     { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
-  if(isset($_GET['style']))     { $flags .= $sep.'style='.$session->style; $sep = '&'; }
-  
-  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
-  {
-    $url = contentPath.$paths->nslist[$n].$t.$flags;
-  }
-  else
-  {
-    $url = contentPath.$n.':'.$t.$flags;
-  }
-  
-  if($query)
-  {
-    if(strstr($url, '?')) $sep =  '&';
-    else $sep = '?';
-    $url = $url . $sep . $query . $flags;
-  }
-  
-  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
-  {
-    $url = $session->append_sid($url);
-  }
-  
-  return ($escape) ? htmlspecialchars($url) : $url;
-}
-
-function makeUrlComplete($n, $t, $query = false, $escape = false)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $flags = '';
-  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator;
-  else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
-  if(isset($_GET['printable'])) { $flags .= $sep.'printable';              $sep = '&'; }
-  if(isset($_GET['theme']))     { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
-  if(isset($_GET['style']))     { $flags .= $sep.'style='.$session->style; $sep = '&'; }
-  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $url = $session->append_sid(contentPath.$paths->nslist[$n].$t.$flags);
-  else $url = contentPath.$n.':'.$t.$flags;
-  if($query)
-  {
-    if(strstr($url, '?')) $sep =  '&';
-    else $sep = '?';
-    $url = $url . $sep . $query . $flags;
-  }
-  $baseprot = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://' . $_SERVER['HTTP_HOST'];
-  $url = $baseprot . $url;
-  return ($escape) ? htmlspecialchars($url) : $url;
-}
-
-/**
- * Redirect the user to the specified URL.
- * @param string $url The URL, either relative or absolute.
- * @param string $title The title of the message
- * @param string $message A short message to show to the user
- * @param string $timeout Timeout, in seconds, to delay the redirect. Defaults to 3.
- */
- 
-function redirect($url, $title = 'Redirecting...', $message = 'Please wait while you are redirected.', $timeout = 3)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  
-  if ( $timeout == 0 )
-  {
-    header('Location: ' . $url);
-    header('HTTP/1.1 307 Temporary Redirect');
-  }
-  
-  $template->add_header('<meta http-equiv="refresh" content="' . $timeout . '; url=' . str_replace('"', '\\"', $url) . '" />');
-  $template->add_header('<script type="text/javascript">
-      function __r() {
-        // FUNCTION AUTOMATICALLY GENERATED
-        window.location="' . str_replace('"', '\\"', $url) . '";
-      }
-      setTimeout(\'__r();\', ' . $timeout . '000);
-    </script>
-    ');
-  
-  $template->tpl_strings['PAGE_NAME'] = $title;
-  $template->header(true);
-  echo '<p>' . $message . '</p><p>If you are not redirected within ' . ( $timeout + 1 ) . ' seconds, <a href="' . str_replace('"', '\\"', $url) . '">please click here</a>.</p>';
-  $template->footer(true);
-  
-  $db->close();
-  exit(0);
-  
-}
-
-// Removed wikiFormat() from here, replaced with RenderMan::render
-
-function isPage($p) {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if(isset($paths->pages[$p])) return true;
-  $d = RenderMan::strToPageID($p);
-  if($d[1] != 'Special' && $d[1] != 'Template' && $d[1] != 'Admin') return false;
-  $a = explode('/', $p);
-  if(isset($paths->pages[$a[0]])) return true;
-  else return false;
-}
-
-function arrayItemUp($arr, $keyname) {
-  $keylist = array_keys($arr);
-  $keyflop = array_flip($keylist);
-  $idx = $keyflop[$keyname];
-  $idxm = $idx - 1;
-  $temp = $arr[$keylist[$idxm]];
-  if($arr[$keylist[0]] == $arr[$keyname]) return $arr;
-  $arr[$keylist[$idxm]] = $arr[$keylist[$idx]];
-  $arr[$keylist[$idx]] = $temp;
-  return $arr;
-}
-
-function arrayItemDown($arr, $keyname) {
-  $keylist = array_keys($arr);
-  $keyflop = array_flip($keylist);
-  $idx = $keyflop[$keyname];
-  $idxm = $idx + 1;
-  $temp = $arr[$keylist[$idxm]];
-  $sz = sizeof($arr); $sz--;
-  if($arr[$keylist[$sz]] == $arr[$keyname]) return $arr;
-  $arr[$keylist[$idxm]]  =  $arr[$keylist[$idx]];
-  $arr[$keylist[$idx]]   =  $temp;
-  return $arr;
-}
-
-function arrayItemTop($arr, $keyname) {
-  $keylist = array_keys($arr);
-  $keyflop = array_flip($keylist);
-  $idx = $keyflop[$keyname];
-  while( $orig != $arr[$keylist[0]] ) {
-    // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger
-    if($idx < 0) return $arr;
-    if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) {
-      /* echo 'Infinite loop caught in arrayItemTop(<br /><pre>';
-      print_r($arr);
-      echo '</pre><br />, '.$keyname.');<br /><br />EnanoCMS: Critical error during function call, exiting to prevent excessive server load.';
-      exit; */
-      return $arr;
-    }
-    $arr = arrayItemUp($arr, $keylist[$idx]);
-    $idx--;
-  }
-  return $arr;
-}
-
-function arrayItemBottom($arr, $keyname) {
-  $keylist = array_keys($arr);
-  $keyflop = array_flip($keylist);
-  $idx = $keyflop[$keyname];
-  $sz = sizeof($arr); $sz--;
-  while( $orig != $arr[$keylist[$sz]] ) {
-    // echo 'Keyname: '.$keylist[$idx] . '<br />'; flush(); ob_flush(); // Debugger
-    if($idx > $sz) return $arr;
-    if($keylist[$idx] == '' || $keylist[$idx] < 0 || !$keylist[$idx]) {
-      echo 'Infinite loop caught in arrayItemBottom(<br /><pre>';
-      print_r($arr);
-      echo '</pre><br />, '.$keyname.');<br /><br />EnanoCMS: Critical error during function call, exiting to prevent excessive server load.';
-      exit;
-    }
-    $arr = arrayItemDown($arr, $keylist[$idx]);
-    $idx++;
-  }
-  return $arr;
-}
-
-// Convert IP address to hex string
-// Input:  127.0.0.1  (string)
-// Output: 0x7f000001 (string)
-// Updated 12/8/06 to work with PHP4 and not use eval() (blech)
-function ip2hex($ip) {
-  if ( preg_match('/^([0-9a-f:]+)$/', $ip) )
-  {
-    // this is an ipv6 address
-    return str_replace(':', '', $ip);
-  }
-  $nums = explode('.', $ip);
-  if(sizeof($nums) != 4) return false;
-  $str = '0x';
-  foreach($nums as $n)
-  {
-    $str .= (string)dechex($n);
-  }
-  return $str;
-}
-
-// Convert DWord to IP address
-// Input:  0x7f000001
-// Output: 127.0.0.1
-// Updated 12/8/06 to work with PHP4 and not use eval() (blech)
-function hex2ip($in) {
-  if(substr($in, 0, 2) == '0x') $ip = substr($in, 2, 8);
-  else $ip = substr($in, 0, 8);
-  $octets = enano_str_split($ip, 2);
-  $str = '';
-  $newoct = Array();
-  foreach($octets as $o)
-  {
-    $o = (int)hexdec($o);
-    $newoct[] = $o;
-  }
-  return implode('.', $newoct);
-}
-
-// Function strip_php moved to RenderMan class
-
-function die_semicritical($t, $p)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $db->close();
-  
-  if ( ob_get_status() )
-    ob_end_clean();
-  
-  dc_here('functions: <span style="color: red">calling die_semicritical</span>');
-  
-  $tpl = new template_nodb();
-  $tpl->load_theme('oxygen', 'bleu');
-  $tpl->tpl_strings['SITE_NAME'] = getConfig('site_name');
-  $tpl->tpl_strings['SITE_DESC'] = getConfig('site_desc');
-  $tpl->tpl_strings['COPYRIGHT'] = getConfig('copyright_notice');
-  $tpl->tpl_strings['PAGE_NAME'] = $t;
-  $tpl->header();
-  echo $p;
-  $tpl->footer();
-  
-  exit;
-}
-
-function die_friendly($t, $p)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  
-  if ( ob_get_status() )
-    ob_end_clean();
-  
-  dc_here('functions: <span style="color: red">calling die_friendly</span>');
-  $paths->cpage['name'] = $t;
-  $template->tpl_strings['PAGE_NAME'] = $t;
-  $template->header();
-  echo $p;
-  $template->footer();
-  $db->close();
-  
-  exit;
-}
-
-function grinding_halt($t, $p)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  
-  $db->close();
-  
-  if ( ob_get_status() )
-    ob_end_clean();
-  
-  dc_here('functions: <span style="color: red">calling grinding_halt</span>');
-  $tpl = new template_nodb();
-  $tpl->load_theme('oxygen', 'bleu');
-  $tpl->tpl_strings['SITE_NAME'] = 'Critical error';
-  $tpl->tpl_strings['SITE_DESC'] = 'This website is experiencing a serious error and cannot load.';
-  $tpl->tpl_strings['COPYRIGHT'] = 'Unable to retrieve copyright information';
-  $tpl->tpl_strings['PAGE_NAME'] = $t;
-  $tpl->header();
-  echo $p;
-  $tpl->footer();
-  exit;
-}
-
-function show_category_info() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  dc_here('functions: showing category info');
-  if($template->no_headers && !strpos($_SERVER['REQUEST_URI'], 'ajax.php')) return '';
-  if($paths->namespace=='Category')
-  {
-    $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'categories WHERE category_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\'Category\' ORDER BY page_id;');
-    if(!$q) $db->_die('The category information could not be selected.');
-    $ticker = -1;
-    echo '<h3>Subcategories</h3>';
-    if($db->numrows() < 1) echo '<p>There are no subcategories in this category.</p>';
-    echo '<table border="0" cellspacing="1" cellpadding="4">';
-    while($row = $db->fetchrow())
-    {
-      $ticker++;if($ticker==3) $ticker=0;
-      if($ticker==0) echo '<tr>';
-      echo '<td style="width: 200px;"><a href="'.makeUrlNS($row['namespace'], $row['page_id']).'">'.$paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'].'</a></td>';
-      if($ticker==2) echo '</tr>';
-    }
-    $db->free_result();
-    if($ticker) echo '</tr>';
-    echo '</table>';
-    
-    $q = $db->sql_query('SELECT page_id,namespace FROM '.table_prefix.'categories WHERE category_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace!=\'Category\' ORDER BY page_id;');
-    if(!$q) $db->_die('The category information could not be selected.');
-    $ticker = -1;
-    echo '<h3>Pages</h3>';
-    if($db->numrows() < 1) echo '<p>There are no pages in this category.</p>';
-    echo '<table border="0" cellspacing="1" cellpadding="4">';
-    while($row = $db->fetchrow())
-    {
-      $ticker++;if($ticker==3) $ticker=0;
-      if($ticker==0) echo '<tr>';
-      echo '<td style="width: 200px;"><a href="'.makeUrlNS($row['namespace'], $row['page_id']).'">'.$paths->pages[$paths->nslist[$row['namespace']].$row['page_id']]['name'].'</a></td>';
-      if($ticker==2) echo '</tr>';
-    }
-    $db->free_result();
-    if($ticker) echo '</tr>';
-    echo '</table><br /><br />';
-  }
-  $q = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\'');
-  if(!$q) $db->_die('The error seems to have occurred during selection of category data.');
-  if($db->numrows() > 0) {
-    echo '<div class="mdg-comment" style="margin-left: 0;">Categories: ';
-    $i=0;
-    while($r = $db->fetchrow())
-    {
-      if($i>0) echo ', ';
-      $i++;
-      echo '<a href="'.makeUrlNS('Category', $r['category_id']).'">'.$paths->pages[$paths->nslist['Category'].$r['category_id']]['name'].'</a>';
-    }
-    if( ( $paths->wiki_mode && !$paths->page_protected ) || ( $session->get_permissions('edit_cat') && $session->get_permissions('even_when_protected') ) ) echo ' [ <a href="'.makeUrl($paths->page, 'do=catedit', true).'" onclick="ajaxCatEdit(); return false;">edit categorization</a> ]</div>';
-  } else {
-    echo '<div class="mdg-comment" style="margin-left: 0;">Categories: ';
-    echo '(Uncategorized)';
-    if( ( $paths->wiki_mode && !$paths->page_protected ) || ( $session->get_permissions('edit_cat') && $session->get_permissions('even_when_protected') ) ) echo ' [ <a href="'.makeUrl($paths->page, 'do=catedit', true).'" onclick="ajaxCatEdit(); return false;">edit categorization</a> ]</div>';
-    else echo '</div>';
-  }
-  $db->free_result();
-}
-
-function show_file_info()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if($paths->namespace != 'File') return null; // Prevent unnecessary work
-  $selfn = $paths->cpage['urlname_nons']; // substr($paths->page, strlen($paths->nslist['File']), strlen($paths->cpage));
-  if(substr($paths->cpage['name'], 0, strlen($paths->nslist['File']))==$paths->nslist['File']) $selfn = substr($paths->cpage['urlname_nons'], strlen($paths->nslist['File']), strlen($paths->cpage['urlname_nons']));
-  $q = $db->sql_query('SELECT mimetype,time_id,size FROM '.table_prefix.'files WHERE page_id=\''.$selfn.'\' ORDER BY time_id DESC;');
-  if(!$q) $db->_die('The file type could not be fetched.');
-  if($db->numrows() < 1) { echo '<div class="mdg-comment" style="margin-left: 0;"><h3>Uploaded file</h3><p>There are no files uploaded with this name yet. <a href="'.makeUrlNS('Special', 'UploadFile/'.$paths->cpage['urlname_nons']).'">Upload a file...</a></p></div><br />'; return; }
-  $r = $db->fetchrow();
-  $mimetype = $r['mimetype'];
-  $datestring = date('F d, Y h:i a', (int)$r['time_id']);
-  echo '<div class="mdg-comment" style="margin-left: 0;"><p><h3>Uploaded file</h3></p><p>Type: '.$r['mimetype'].'<br />Size: ';
-  $fs = $r['size'];
-  echo $fs.' bytes';
-  $fs = (int)$fs;
-  if($fs >= 1048576)
-  {
-    $fs = round($fs / 1048576, 1);
-    echo ' ('.$fs.' MB)';
-  } elseif($fs >= 1024) {
-    $fs = round($fs / 1024, 1);
-    echo ' ('.$fs.' KB)';
-  }
-  echo '<br />Uploaded: '.$datestring.'</p>';
-  if(substr($mimetype, 0, 6)!='image/' && ( substr($mimetype, 0, 5) != 'text/' || $mimetype == 'text/html' || $mimetype == 'text/javascript' ))
-  {
-    echo '<div class="warning-box">This file type may contain viruses or other code that could harm your computer. You should exercise caution if you download it.</div>';
-  }
-  if(substr($mimetype, 0, 6)=='image/')
-  {
-    echo '<p><a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn).'"><img style="border: 0;" alt="'.$paths->page.'" src="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.htmlspecialchars(urlSeparator).'preview').'" /></a></p>';
-  }
-  echo '<p><a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.'/'.$r['time_id'].htmlspecialchars(urlSeparator).'download').'">Download this file</a>';
-  if(!$paths->page_protected && ( $paths->wiki_mode || $session->get_permissions('upload_new_version') ))
-  {
-    echo '  |  <a href="'.makeUrlNS('Special', 'UploadFile'.'/'.$selfn).'">Upload new version</a>';
-  }
-  echo '</p>';
-  if($db->numrows() > 1)
-  {
-    echo '<h3>File history</h3><p>';
-    while($r = $db->fetchrow())
-    {
-      echo '(<a href="'.makeUrlNS('Special', 'DownloadFile'.'/'.$selfn.'/'.$r['time_id'].htmlspecialchars(urlSeparator).'download').'">this ver</a>) ';
-      if($session->get_permissions('history_rollback'))
-        echo ' (<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">revert</a>) ';
-      $mimetype = $r['mimetype'];
-      $datestring = date('F d, Y h:i a', (int)$r['time_id']);
-      echo $datestring.': '.$r['mimetype'].', ';
-      $fs = $r['size'];
-      $fs = (int)$fs;
-      if($fs >= 1048576)
-      {
-        $fs = round($fs / 1048576, 1);
-        echo ' '.$fs.' MB';
-      } elseif($fs >= 1024) {
-        $fs = round($fs / 1024, 1);
-        echo ' '.$fs.' KB';
-      } else {
-        echo ' '.$fs.' bytes';
-      }
-      echo '<br />';
-    }
-    echo '</p>';
-  }
-  $db->free_result();
-  echo '</div><br />';
-}
-
-function display_page_headers()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if($session->get_permissions('vote_reset') && $paths->cpage['delvotes'] > 0)
-  {
-    $hr = implode(', ', explode('|', $paths->cpage['delvote_ips']));
-    $is = 'is';
-    $s = '';
-    $s2 = 's';
-    if ( $paths->cpage['delvotes'] > 1)
-    {
-      $is = 'are';
-      $s = 's';
-      $s2 = '';
-    }
-    echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;" id="mdgDeleteVoteNoticeBox">
-            <b>Notice:</b> There '.$is.' '.$paths->cpage['delvotes'].' user'.$s.' that think'.$s2.' this page should be deleted.<br />
-            <b>Users that voted:</b> ' . $hr . '<br />
-            <a href="'.makeUrl($paths->page, 'do=deletepage').'" onclick="ajaxDeletePage(); return false;">Delete page</a>  |  <a href="'.makeUrl($paths->page, 'do=resetvotes').'" onclick="ajaxResetDelVotes(); return false;">Reset votes</a>
-          </div>';
-  }
-}
-
-function display_page_footers()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if(isset($_GET['nofooters'])) return;
-  $code = $plugins->setHook('send_page_footers');
-  foreach ( $code as $cmd )
-  {
-    eval($cmd);
-  }
-  show_file_info();
-  show_category_info();
-}
-
-function password_prompt($id = false)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if(!$id) $id = $paths->page;
-  if(isset($paths->pages[$id]['password']) && strlen($paths->pages[$id]['password']) == 40 && !isset($_REQUEST['pagepass']))
-  {
-    die_friendly('Password required', '<p>You must supply a password to access this page.</p><form action="'.makeUrl($paths->pages[$id]['urlname']).'" method="post"><p>Password: <input name="pagepass" type="password" /></p><p><input type="submit" value="Submit" /></p>');
-  } elseif(isset($_REQUEST['pagepass'])) {
-    $p = (preg_match('#^([a-f0-9]*){40}$#', $_REQUEST['pagepass'])) ? $_REQUEST['pagepass'] : sha1($_REQUEST['pagepass']);
-    if($p != $paths->pages[$id]['password']) die_friendly('Password required', '<p style="color: red;">The password you entered is incorrect.</p><form action="'.makeUrl($paths->page).'" method="post"><p>Password: <input name="pagepass" type="password" /></p><p><input type="submit" value="Submit" /></p>');
-  }
-}
-
-function str_hex($string){
-    $hex='';
-    for ($i=0; $i < strlen($string); $i++){
-        $hex .= ' '.dechex(ord($string[$i]));
-    }
-    return substr($hex, 1, strlen($hex));
-}
-
-// Function pulled from phpBB's smtp.php
-function smtp_get_response($socket, $response, $line = __LINE__) 
-{
-	$server_response = '';
-	while (substr($server_response, 3, 1) != ' ') 
-	{
-		if (!($server_response = fgets($socket, 256))) 
-		{
-      die_friendly('SMTP Error', "<p>Couldn't get mail server response codes</p>");
-		}
-	} 
-
-	if (!(substr($server_response, 0, 3) == $response)) 
-	{ 
-    die_friendly('SMTP Error', "<p>Ran into problems sending mail. Response: $server_response</p>");
-	} 
-}
-
-function smtp_send_email($to, $subject, $message, $from)
-{
-  return smtp_send_email_core($to, $subject, $message, "From: <$from>\n");
-}
-
-// Replacement or substitute for PHP's mail command
-// Ported from phpBB - copyright (C) phpBB group, GPL.
-function smtp_send_email_core($mail_to, $subject, $message, $headers = '')
-{
-	global $board_config;
-
-	// Fix any bare linefeeds in the message to make it RFC821 Compliant.
-	$message = preg_replace("#(?<!\r)\n#si", "\r\n", $message);
-
-	if ($headers != '')
-	{
-		if (is_array($headers))
-		{
-			if (sizeof($headers) > 1)
-			{
-				$headers = join("\n", $headers);
-			}
-			else
-			{
-				$headers = $headers[0];
-			}
-		}
-		$headers = chop($headers);
-
-		// Make sure there are no bare linefeeds in the headers
-		$headers = preg_replace('#(?<!\r)\n#si', "\r\n", $headers);
-
-		// Ok this is rather confusing all things considered,
-		// but we have to grab bcc and cc headers and treat them differently
-		// Something we really didn't take into consideration originally
-		$header_array = explode("\r\n", $headers);
-		@reset($header_array);
-
-		$headers = '';
-		while(list(, $header) = each($header_array))
-		{
-			if (preg_match('#^cc:#si', $header))
-			{
-				$cc = preg_replace('#^cc:(.*)#si', '\1', $header);
-			}
-			else if (preg_match('#^bcc:#si', $header))
-			{
-				$bcc = preg_replace('#^bcc:(.*)#si', '\1', $header);
-				$header = '';
-			}
-			$headers .= ($header != '') ? $header . "\r\n" : '';
-		}
-
-		$headers = chop($headers);
-		$cc = explode(', ', $cc);
-		$bcc = explode(', ', $bcc);
-	}
-
-	if (trim($subject) == '')
-	{
-		die_friendly(GENERAL_ERROR, "No email Subject specified");
-	}
-
-	if (trim($message) == '')
-	{
-		die_friendly(GENERAL_ERROR, "Email message was blank");
-	}
-  
-  // setup SMTP
-  $host = getConfig('smtp_server');
-  if ( empty($host) )
-    return 'No smtp_host in config';
-  if ( strstr($host, ':' ) )
-  {
-    $n = explode(':', $host);
-    $smtp_host = $n[0];
-    $port = intval($n[1]);
-  }
-  else
-  {
-    $smtp_host = $host;
-    $port = 25;
-  }
-  
-  $smtp_user = getConfig('smtp_user');
-  $smtp_pass = getConfig('smtp_password');
-  
-	// Ok we have error checked as much as we can to this point let's get on
-	// it already.
-	if( !$socket = @fsockopen($smtp_host, $port, $errno, $errstr, 20) )
-	{
-		die_friendly(GENERAL_ERROR, "Could not connect to smtp host : $errno : $errstr");
-	}
-
-	// Wait for reply
-	smtp_get_response($socket, "220", __LINE__);
-
-	// Do we want to use AUTH?, send RFC2554 EHLO, else send RFC821 HELO
-	// This improved as provided by SirSir to accomodate
-	if( !empty($smtp_user) && !empty($smtp_pass) )
-	{ 
-		enano_fputs($socket, "EHLO " . $smtp_host . "\r\n");
-		smtp_get_response($socket, "250", __LINE__);
-
-		enano_fputs($socket, "AUTH LOGIN\r\n");
-		smtp_get_response($socket, "334", __LINE__);
-
-		enano_fputs($socket, base64_encode($smtp_user) . "\r\n");
-		smtp_get_response($socket, "334", __LINE__);
-
-		enano_fputs($socket, base64_encode($smtp_pass) . "\r\n");
-		smtp_get_response($socket, "235", __LINE__);
-	}
-	else
-	{
-		enano_fputs($socket, "HELO " . $smtp_host . "\r\n");
-		smtp_get_response($socket, "250", __LINE__);
-	}
-
-	// From this point onward most server response codes should be 250
-	// Specify who the mail is from....
-	enano_fputs($socket, "MAIL FROM: <" . getConfig('contact_email') . ">\r\n");
-	smtp_get_response($socket, "250", __LINE__);
-
-	// Specify each user to send to and build to header.
-	$to_header = '';
-
-	// Add an additional bit of error checking to the To field.
-	$mail_to = (trim($mail_to) == '') ? 'Undisclosed-recipients:;' : trim($mail_to);
-	if (preg_match('#[^ ]+\@[^ ]+#', $mail_to))
-	{
-		enano_fputs($socket, "RCPT TO: <$mail_to>\r\n");
-		smtp_get_response($socket, "250", __LINE__);
-	}
-
-	// Ok now do the CC and BCC fields...
-	@reset($bcc);
-	while(list(, $bcc_address) = each($bcc))
-	{
-		// Add an additional bit of error checking to bcc header...
-		$bcc_address = trim($bcc_address);
-		if (preg_match('#[^ ]+\@[^ ]+#', $bcc_address))
-		{
-			enano_fputs($socket, "RCPT TO: <$bcc_address>\r\n");
-			smtp_get_response($socket, "250", __LINE__);
-		}
-	}
-
-	@reset($cc);
-	while(list(, $cc_address) = each($cc))
-	{
-		// Add an additional bit of error checking to cc header
-		$cc_address = trim($cc_address);
-		if (preg_match('#[^ ]+\@[^ ]+#', $cc_address))
-		{
-			enano_fputs($socket, "RCPT TO: <$cc_address>\r\n");
-			smtp_get_response($socket, "250", __LINE__);
-		}
-	}
-
-	// Ok now we tell the server we are ready to start sending data
-	enano_fputs($socket, "DATA\r\n");
-
-	// This is the last response code we look for until the end of the message.
-	smtp_get_response($socket, "354", __LINE__);
-
-	// Send the Subject Line...
-	enano_fputs($socket, "Subject: $subject\r\n");
-
-	// Now the To Header.
-	enano_fputs($socket, "To: $mail_to\r\n");
-
-	// Now any custom headers....
-	enano_fputs($socket, "$headers\r\n\r\n");
-
-	// Ok now we are ready for the message...
-	enano_fputs($socket, "$message\r\n");
-
-	// Ok the all the ingredients are mixed in let's cook this puppy...
-	enano_fputs($socket, ".\r\n");
-	smtp_get_response($socket, "250", __LINE__);
-
-	// Now tell the server we are done and close the socket...
-	enano_fputs($socket, "QUIT\r\n");
-	fclose($socket);
-
-	return TRUE;
-}
-
-/**
- * Tell which version of Enano we're running.
- * @param bool $long if true, uses English version names (e.g. alpha, beta, release candidate). If false (default) uses abbreviations (1.0a1, 1.0b3, 1.0RC2, etc.)
- * @return string
- */
-
-function enano_version($long = false, $no_nightly = false)
-{
-  $r = getConfig('enano_version');
-  $rc = ( $long ) ? ' release candidate ' : 'RC';
-  $b = ( $long ) ? ' beta ' : 'b';
-  $a = ( $long ) ? ' alpha ' : 'a';
-  if($v = getConfig('enano_rc_version')) $r .= $rc.$v;
-  if($v = getConfig('enano_beta_version')) $r .= $b.$v;
-  if($v = getConfig('enano_alpha_version')) $r .= $a.$v;
-  if ( defined('ENANO_NIGHTLY') && !$no_nightly )
-  {
-    $nightlytag  = ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR;
-    $nightlylong = ' nightly; build date: ' . ENANO_NIGHTLY_MONTH . '-' . ENANO_NIGHTLY_DAY . '-' . ENANO_NIGHTLY_YEAR;
-    $r = ( $long ) ? $r . $nightlylong : $r . '-nightly-' . $nightlytag;
-  }
-  return $r;
-}
-
-function _dualurlenc($t) {
-  return rawurlencode(rawurlencode($t));
-}
-  
-function _die($t) {
-  $_ob = 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\'' . rawurlencode('' . $t . '') . '\')';
-  die($_ob);
-}
-
-function jsdie($text) {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $text = rawurlencode($text . "\n\nSQL Backtrace:\n" . $db->sql_backtrace());
-  echo 'document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.$text.'\');';
-}
-
-// HTML sanitizing function - written by Kallahar
-// Original function at: http://quickwired.com/kallahar/smallprojects/php_xss_filter_function.php
-
-// UNUSED - todo: remove this in gold or put it to use
-
-function RemoveXSS($val) {
-  // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
-  // this prevents some character re-spacing such as <java\0script>
-  // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
-  $val = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $val);
-  
-  // straight replacements, the user should never need these since they're normal characters
-  // this prevents like <IMG SRC=&#X40&#X61&#X76&#X61&#X73&#X63&#X72&#X69&#X70&#X74&#X3A&#X61&#X6C&#X65&#X72&#X74&#X28&#X27&#X58&#X53&#X53&#X27&#X29>
-  $search  = 'abcdefghijklmnopqrstuvwxyz';
-  $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
-  $search .= '1234567890!@#$%^&*()';
-  $search .= '~`";:?+/={}[]-_|\'\\';
-  for ($i = 0; $i < strlen($search); $i++) {
-    // ;? matches the ;, which is optional
-    // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars
-  
-    // &#x0040 @ search for the hex values
-    $val = preg_replace('/(&#[x|X]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ;
-    // &#00064 @ 0{0,7} matches '0' zero to seven times
-    $val = preg_replace('/(&#0{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ;
-  }
-  
-  // now the only remaining whitespace attacks are \t, \n, and \r
-  $ra1 = Array('javascript', 'vbscript', 'expression', 'applet', 'meta', 'xml', 'blink', 'link', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'title', 'base');
-  $ra2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload');
-  $ra = array_merge($ra1, $ra2);
-  
-  $found = true; // keep replacing as long as the previous round replaced something
-  while ($found == true) {
-    $val_before = $val;
-    for ($i = 0; $i < sizeof($ra); $i++) {
-      $pattern = '/';
-      for ($j = 0; $j < strlen($ra[$i]); $j++) {
-        if ($j > 0) {
-          $pattern .= '(';
-          $pattern .= '(&#[x|X]0{0,8}([9][a][b]);?)?';
-          $pattern .= '|(&#0{0,8}([9][10][13]);?)?';
-          $pattern .= ')?';
-        }
-        $pattern .= $ra[$i][$j];
-      }
-      $pattern .= '/i';
-      $replacement = substr($ra[$i], 0, 2).'<b></b>'.substr($ra[$i], 2); // add in <> to nerf the tag
-      $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
-      if ($val_before == $val) {
-        // no replacements were made, so exit the loop
-        $found = false;
-      }
-    }
-  }
-  return $val;
-}
-
-/**
- * Capitalizes the first letter of a string
- * @param $text string the text to be transformed
- * @return string
- */
- 
-function capitalize_first_letter($text)
-{
-  return strtoupper(substr($text, 0, 1)) . substr($text, 1);
-}
-
-/**
- * Checks if a value in a bitfield is on or off
- * @param $bitfield int the bit-field value
- * @param $value int the value to switch off
- * @return bool
- */
- 
-function is_bit($bitfield, $value)
-{
-  return ( $bitfield & $value ) ? true : false;
-}
-
-/**
- * Trims spaces/newlines from the beginning and end of a string
- * @param $text the text to process
- * @return string
- */
- 
-function trim_spaces($text)
-{
-  $d = true;
-  while($d)
-  {
-    $c = substr($text, 0, 1);
-    $a = substr($text, strlen($text)-1, strlen($text));
-    if($c == "\n" || $c == "\r" || $c == "\t" || $c == ' ') $text = substr($text, 1, strlen($text));
-    elseif($a == "\n" || $a == "\r" || $a == "\t" || $a == ' ') $text = substr($text, 0, strlen($text)-1);
-    else $d = false;
-  }
-  return $text;
-}
-
-/**
- * Enano-ese equivalent of str_split() which is only found in PHP5
- * @param $text string the text to split
- * @param $inc int size of each block
- * @return array
- */
- 
-function enano_str_split($text, $inc = 1)
-{
-  if($inc < 1) return false;
-  if($inc >= strlen($text)) return Array($text);
-  $len = ceil(strlen($text) / $inc);
-  $ret = Array();
-  for($i=0;$i<strlen($text);$i=$i+$inc)
-  {
-    $ret[] = substr($text, $i, $inc);
-  }
-  return $ret;
-}
-
-/**
- * Converts a hexadecimal number to a binary string.
- * @param text string hexadecimal number
- * @return string
- */
-function hex2bin($text)
-{
-  $arr = enano_str_split($text, 2);
-  $ret = '';
-  for ($i=0; $i<sizeof($arr); $i++)
-  {
-    $ret .= chr(hexdec($arr[$i]));
-  }
-  return $ret;
-}
-
-/**
- * Generates and/or prints a human-readable backtrace
- * @param bool $return - if true, this function returns a string, otherwise returns null
- * @return mixed
- */
- 
-function enano_debug_print_backtrace($return = false)
-{
-  ob_start();
-  echo '<pre>';
-  debug_print_backtrace();
-  echo '</pre>';
-  $c = ob_get_contents();
-  ob_end_clean();
-  if($return) return $c;
-  else echo $c;
-  return null;
-}
-
-/**
- * Like rawurlencode(), but encodes all characters
- * @param string $text the text to encode
- * @param optional string $prefix text before each hex character
- * @param optional string $suffix text after each hex character
- * @return string
- */
- 
-function hexencode($text, $prefix = '%', $suffix = '')
-{
-  $arr = enano_str_split($text);
-  $r = '';
-  foreach($arr as $a)
-  {
-    $nibble = (string)dechex(ord($a));
-    if(strlen($nibble) == 1) $nibble = '0' . $nibble;
-    $r .= $prefix . $nibble . $suffix;
-  }
-  return $r;
-}
-
-/**
- * Enano-ese equivalent of get_magic_quotes_gpc()
- * @return bool
- */
- 
-function enano_get_magic_quotes_gpc()
-{
-  if(function_exists('get_magic_quotes_gpc'))
-  {
-    return ( get_magic_quotes_gpc() == 1 );
-  }
-  else
-  {
-    return ( strtolower(@ini_get('magic_quotes_gpc')) == '1' );
-  }
-}
-
-/**
- * Recursive stripslashes()
- * @param array
- * @return array
- */
- 
-function stripslashes_recurse($arr)
-{
-  foreach($arr as $k => $xxxx)
-  {
-    $val =& $arr[$k];
-    if(is_string($val))
-      $val = stripslashes($val);
-    elseif(is_array($val))
-      $val = stripslashes_recurse($val);
-  }
-  return $arr;
-}
-
-/**
- * If magic_quotes_gpc is on, calls stripslashes() on everything in $_GET/$_POST/$_COOKIE
- * @ignore - this doesn't work
- * @todo port version from the PHP manual
- * @return void
- */
-function strip_magic_quotes_gpc()
-{
-  if(enano_get_magic_quotes_gpc())
-  {
-    $_POST   = stripslashes_recurse($_POST);
-    $_GET    = stripslashes_recurse($_GET);
-    $_COOKIE = stripslashes_recurse($_COOKIE);
-  }
-}
-
-/**
- * A very basic single-character compression algorithm for binary strings/bitfields
- * @param string $bits the text to compress
- * @return string
- */
- 
-function compress_bitfield($bits)
-{
-  $crc32 = crc32($bits);
-  $bits .= '0';
-  $start_pos = 0;
-  $current = substr($bits, 1, 1);
-  $last    = substr($bits, 0, 1);
-  $chunk_size = 1;
-  $len = strlen($bits);
-  $crc = $len;
-  $crcval = 0;
-  for ( $i = 1; $i < $len; $i++ )
-  {
-    $current = substr($bits, $i, 1);
-    $last    = substr($bits, $i - 1, 1);
-    $next    = substr($bits, $i + 1, 1);
-    // Are we on the last character?
-    if($current == $last && $i+1 < $len)
-      $chunk_size++;
-    else
-    {
-      if($i+1 == $len && $current == $next)
-      {
-        // This character completes a chunk
-        $chunk_size++;
-        $i++;
-        $chunk = substr($bits, $start_pos, $chunk_size);
-        $chunklen = strlen($chunk);
-        $newchunk = $last . '[' . $chunklen . ']';
-        $newlen   = strlen($newchunk);
-        $bits = substr($bits, 0, $start_pos) . $newchunk . substr($bits, $i, $len);
-        $chunk_size = 1;
-        $i = $start_pos + $newlen;
-        $start_pos = $i;
-        $len = strlen($bits);
-        $crcval = $crcval + $chunklen;
-      }
-      else
-      {
-        // Last character completed a chunk
-        $chunk = substr($bits, $start_pos, $chunk_size);
-        $chunklen = strlen($chunk);
-        $newchunk = $last . '[' . $chunklen . '],';
-        $newlen   = strlen($newchunk);
-        $bits = substr($bits, 0, $start_pos) . $newchunk . substr($bits, $i, $len);
-        $chunk_size = 1;
-        $i = $start_pos + $newlen;
-        $start_pos = $i;
-        $len = strlen($bits);
-        $crcval = $crcval + $chunklen;
-      }
-    }
-  }
-  if($crc != $crcval)
-  {
-    echo __FUNCTION__.'(): ERROR: length check failed, this is a bug in the algorithm<br />Debug info: aiming for a CRC val of '.$crc.', got '.$crcval;
-    return false;
-  }
-  $compressed = 'cbf:len='.$crc.';crc='.dechex($crc32).';data='.$bits.'|end';
-  return $compressed;
-}
-
-/**
- * Uncompresses a bitfield compressed with compress_bitfield()
- * @param string $bits the compressed bitfield
- * @return string the uncompressed, original (we hope) bitfield OR bool false on error
- */
- 
-function uncompress_bitfield($bits)
-{
-  if(substr($bits, 0, 4) != 'cbf:')
-  {
-    echo __FUNCTION__.'(): ERROR: Invalid stream';
-    return false;
-  }
-  $len = intval(substr($bits, strpos($bits, 'len=')+4, strpos($bits, ';')-strpos($bits, 'len=')-4));
-  $crc = substr($bits, strpos($bits, 'crc=')+4, 8);
-  $data = substr($bits, strpos($bits, 'data=')+5, strpos($bits, '|end')-strpos($bits, 'data=')-5);
-  $data = explode(',', $data);
-  foreach($data as $a => $b)
-  {
-    $d =& $data[$a];
-    $char = substr($d, 0, 1);
-    $dlen = intval(substr($d, 2, strlen($d)-1));
-    $s = '';
-    for($i=0;$i<$dlen;$i++,$s.=$char);
-    $d = $s;
-    unset($s, $dlen, $char);
-  }
-  $decompressed = implode('', $data);
-  $decompressed = substr($decompressed, 0, -1);
-  $dcrc = (string)dechex(crc32($decompressed));
-  if($dcrc != $crc)
-  {
-    echo __FUNCTION__.'(): ERROR: CRC check failed<br />debug info:<br />original crc: '.$crc.'<br />decomp\'ed crc: '.$dcrc.'<br />';
-    return false;
-  }
-  return $decompressed;
-}
-
-/**
- * Exports a MySQL table into a SQL string.
- * @param string $table The name of the table to export
- * @param bool $structure If true, include a CREATE TABLE command
- * @param bool $data If true, include the contents of the table
- * @param bool $compact If true, omits newlines between parts of SQL statements, use in Enano database exporter
- * @return string
- */
-
-function export_table($table, $structure = true, $data = true, $compact = false)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $struct_keys = '';
-  $divider   = (!$compact) ? "\n" : "\n";
-  $spacer1   = (!$compact) ? "\n" : " ";
-  $spacer2   = (!$compact) ? "  " : " ";
-  $rowspacer = (!$compact) ? "\n  " : " ";
-  $index_list = Array();
-  $cols = $db->sql_query('SHOW COLUMNS IN '.$table.';');
-  if(!$cols)
-  {
-    echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />';
-    return false;
-  }
-  $col = Array();
-  $sqlcol = Array();
-  $collist = Array();
-  $pri_keys = Array();
-  // Using fetchrow_num() here to compensate for MySQL l10n
-  while( $row = $db->fetchrow_num() )
-  {
-    $field =& $row[0];
-    $type  =& $row[1];
-    $null  =& $row[2];
-    $key   =& $row[3];
-    $def   =& $row[4];
-    $extra =& $row[5];
-    $col[] = Array(
-      'name'=>$field,
-      'type'=>$type,
-      'null'=>$null,
-      'key'=>$key,
-      'default'=>$def,
-      'extra'=>$extra,
-      );
-    $collist[] = $field;
-  }
-  
-  if ( $structure )
-  {
-    $db->sql_query('SET SQL_QUOTE_SHOW_CREATE = 0;');
-    $struct = $db->sql_query('SHOW CREATE TABLE '.$table.';');
-    if ( !$struct )
-      $db->_die();
-    $row = $db->fetchrow_num();
-    $db->free_result();
-    $struct = $row[1];
-    $struct = preg_replace("/\n\) ENGINE=(.+)$/", "\n);", $struct);
-    unset($row);
-    if ( $compact )
-    {
-      $struct_arr = explode("\n", $struct);
-      foreach ( $struct_arr as $i => $leg )
-      {
-        if ( $i == 0 )
-          continue;
-        $test = trim($leg);
-        if ( empty($test) )
-        {
-          unset($struct_arr[$i]);
-          continue;
-        }
-        $struct_arr[$i] = preg_replace('/^([\s]*)/', ' ', $leg);
-      }
-      $struct = implode("", $struct_arr);
-    }
-  }
-  
-  // Structuring complete
-  if($data)
-  {
-    $datq = $db->sql_query('SELECT * FROM '.$table.';');
-    if(!$datq)
-    {
-      echo 'export_table(): Error getting column list: '.$db->get_error_text().'<br />';
-      return false;
-    }
-    if($db->numrows() < 1)
-    {
-      if($structure) return $struct;
-      else return '';
-    }
-    $rowdata = Array();
-    $dataqs = Array();
-    $insert_strings = Array();
-    $z = false;
-    while($row = $db->fetchrow_num())
-    {
-      $z = false;
-      foreach($row as $i => $cell)
-      {
-        $str = mysql_encode_column($cell, $col[$i]['type']);
-        $rowdata[] = $str;
-      }
-      $dataqs2 = implode(",$rowspacer", $dataqs) . ",$rowspacer" . '( ' . implode(', ', $rowdata) . ' )';
-      $ins = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . $dataqs2 . ";";
-      if ( strlen( $ins ) > MYSQL_MAX_PACKET_SIZE )
-      {
-        // We've exceeded the maximum allowed packet size for MySQL - separate this into a different query
-        $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";;
-        $dataqs = Array('( ' . implode(', ', $rowdata) . ' )');
-        $z = true;
-      }
-      else
-      {
-        $dataqs[] = '( ' . implode(', ', $rowdata) . ' )';
-      }
-      $rowdata = Array();
-    }
-    if ( !$z )
-    {
-      $insert_strings[] = 'INSERT INTO '.$table.'( '.implode(',', $collist).' ) VALUES' . implode(",$rowspacer", $dataqs) . ";";;
-      $dataqs = Array();
-    }
-    $datstring = implode($divider, $insert_strings);
-  }
-  if($structure && !$data) return $struct;
-  elseif(!$structure && $data) return $datstring;
-  elseif($structure && $data) return $struct . $divider . $datstring;
-  elseif(!$structure && !$data) return '';
-}
-
-/**
- * Encodes a string value for use in an INSERT statement for given column type $type.
- * @access private
- */
- 
-function mysql_encode_column($input, $type)
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  // Decide whether to quote the string or not
-  if(substr($type, 0, 7) == 'varchar' || $type == 'datetime' || $type == 'text' || $type == 'tinytext' || $type == 'smalltext' || $type == 'longtext' || substr($type, 0, 4) == 'char')
-  {
-    $str = "'" . $db->escape($input) . "'";
-  }
-  elseif(in_array($type, Array('blob', 'longblob', 'mediumblob', 'smallblob')) || substr($type, 0, 6) == 'binary' || substr($type, 0, 9) == 'varbinary')
-  {
-    $str = '0x' . hexencode($input, '', '');
-  }
-  elseif(is_null($input))
-  {
-    $str = 'NULL';
-  }
-  else
-  {
-    $str = (string)$input;
-  }
-  return $str;
-}
-
-/**
- * Creates an associative array defining which file extensions are allowed and which ones aren't
- * @return array keyname will be a file extension, value will be true or false
- */
-
-function fetch_allowed_extensions()
-{
-  global $mime_types;
-  $bits = getConfig('allowed_mime_types');
-  if(!$bits) return Array(false);
-  $bits = uncompress_bitfield($bits);
-  if(!$bits) return Array(false);
-  $bits = enano_str_split($bits, 1);
-  $ret = Array();
-  $mt = array_keys($mime_types);
-  foreach($bits as $i => $b)
-  {
-    $ret[$mt[$i]] = ( $b == '1' ) ? true : false;
-  }
-  return $ret;
-}
-
-/**
- * Generates a random key suitable for encryption
- * @param int $len the length of the key
- * @return string a BINARY key
- */
-
-function randkey($len = 32)
-{
-  $key = '';
-  for($i=0;$i<$len;$i++)
-  {
-    $key .= chr(mt_rand(0, 255));
-  }
-  return $key;
-}
-
-/**
- * Decodes a hex string.
- * @param string $hex The hex code to decode
- * @return string
- */
-
-function hexdecode($hex)
-{
-  $hex = enano_str_split($hex, 2);
-  $bin_key = '';
-  foreach($hex as $nibble)
-  {
-    $byte = chr(hexdec($nibble));
-    $bin_key .= $byte;
-  }
-  return $bin_key;
-}
-
-/**
- * Enano's own (almost) bulletproof HTML sanitizer.
- * @param string $html The input HTML
- * @return string cleaned HTML
- */
-
-function sanitize_html($html, $filter_php = true)
-{
-  
-  $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>(.*?)</\\1>#is', '&lt;\\1\\2\\3javascript:\\59&gt;\\60&lt;/\\1&gt;', $html);
-  $html = preg_replace('#<([a-z]+)([\s]+)([^>]+?)'.htmlalternatives('javascript:').'(.+?)>#is', '&lt;\\1\\2\\3javascript:\\59&gt;', $html);
-  
-  if($filter_php)
-    $html = str_replace(
-      Array('<?php',    '<?',    '<%',    '?>',    '%>'),
-      Array('&lt;?php', '&lt;?', '&lt;%', '?&gt;', '%&gt;'),
-      $html);
-  
-  $tag_whitelist = array_keys ( setupAttributeWhitelist() );
-  if ( !$filter_php )
-    $tag_whitelist[] = '?php';
-  $len = strlen($html);
-  $in_quote = false;
-  $quote_char = '';
-  $tag_start = 0;
-  $tag_name = '';
-  $in_tag = false;
-  $trk_name = false;
-  for ( $i = 0; $i < $len; $i++ )
-  {
-    $chr = $html{$i};
-    $prev = ( $i == 0 ) ? '' : $html{ $i - 1 };
-    $next = ( ( $i + 1 ) == $len ) ? '' : $html { $i + 1 };
-    if ( $in_quote && $in_tag )
-    {
-      if ( $quote_char == $chr && $prev != '\\' )
-        $in_quote = false;
-    }
-    elseif ( ( $chr == '"' || $chr == "'" ) && $prev != '\\' && $in_tag )
-    {
-      $in_quote = true;
-      $quote_char = $chr;
-    }
-    if ( $chr == '<' && !$in_tag && $next != '/' )
-    {                                          
-      // start of a tag
-      $tag_start = $i;
-      $in_tag = true;
-      $trk_name = true;
-    }
-    elseif ( !$in_quote && $in_tag && $chr == '>' )
-    {
-      $full_tag = substr($html, $tag_start, ( $i - $tag_start ) + 1 );
-      $l = strlen($tag_name) + 2;
-      $attribs_only = trim( substr($full_tag, $l, ( strlen($full_tag) - $l - 1 ) ) );
-      
-      // Debugging message
-      // echo htmlspecialchars($full_tag) . '<br />';
-      
-      if ( !in_array($tag_name, $tag_whitelist) )
-      {
-        // Illegal tag
-        //echo $tag_name . ' ';
-        
-        $s = ( empty($attribs_only) ) ? '' : ' ';
-        
-        $sanitized = '&lt;' . $tag_name . $s . $attribs_only . '&gt;';
-        
-        $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1);
-        $html = str_replace('</' . $tag_name . '>', '&lt;/' . $tag_name . '&gt;', $html);
-        $new_i = $tag_start + strlen($sanitized);
-        
-        $len = strlen($html);
-        $i = $new_i;
-        
-        $in_tag = false;
-        $tag_name = '';
-        continue;
-      }
-      else
-      {
-        if ( $tag_name == '?php' && !$filter_php )
-          continue;
-        $f = fixTagAttributes( $attribs_only, $tag_name );
-        $s = ( empty($f) ) ? '' : ' ';
-        
-        $sanitized = '<' . $tag_name . $f . '>';
-        $new_i = $tag_start + strlen($sanitized);
-        
-        $html = substr($html, 0, $tag_start) . $sanitized . substr($html, $i + 1);
-        $len = strlen($html);
-        $i = $new_i;
-        
-        $in_tag = false;
-        $tag_name = '';
-        continue;
-      }
-    }
-    elseif ( $in_tag && $trk_name )
-    {
-      $is_alphabetical = ( strtolower($chr) != strtoupper($chr) || in_array($chr, array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) || $chr == '?' );
-      if ( $is_alphabetical )
-        $tag_name .= $chr;
-      else
-      {
-        $trk_name = false;
-      }
-    }
-    
-  }
-  
-  return $html;
-  
-}
-
-function htmlalternatives($string)
-{
-  $ret = '';
-  for ( $i = 0; $i < strlen($string); $i++ )
-  {
-    $chr = $string{$i};
-    $ch1 = ord($chr);
-    $ch2 = dechex($ch1);
-    $byte = '(&\\#([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch1 . ';|\\\\([0]*){0,7}' . $ch2 . ';|&\\#x([0]*){0,7}' . $ch2 . ';|%([0]*){0,7}' . $ch2 . '|' . preg_quote($chr) . ')';
-    $ret .= $byte;
-    $ret .= '([\s]){0,2}';
-  }
-  return $ret;
-}
-
-/**
- * Paginates (breaks into multiple pages) a MySQL result resource, which is treated as unbuffered.
- * @param resource The MySQL result resource. This should preferably be an unbuffered query.
- * @param string A template, with variables being named after the column name
- * @param int The number of total results. This should be determined by a second query.
- * @param string sprintf-style formatting string for URLs for result pages. First parameter will be start offset.
- * @param int Optional. Start offset in individual results. Defaults to 0.
- * @param int Optional. The number of results per page. Defualts to 10.
- * @param int Optional. An associative array of functions to call, with key names being column names, and values being function names. Values can also be an array with key 0 being either an object or a string(class name) and key 1 being a [static] method.
- * @param string Optional. The text to be sent before the result list, only if there are any results. Possibly the start of a table.
- * @param string Optional. The text to be sent after the result list, only if there are any results. Possibly the end of a table.
- * @return string
- */
-
-function paginate($q, $tpl_text, $num_results, $result_url, $start = 0, $perpage = 10, $callers = Array(), $header = '', $footer = '')
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $parser = $template->makeParserText($tpl_text);
-  $num_pages = ceil ( $num_results / $perpage );
-  $out = '';
-  $i = 0;
-  $this_page = ceil ( $start / $perpage );
-  
-  // Build paginator
-  $begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;">
-    <table border="0" cellspacing="1" cellpadding="4">
-      <tr><th>Page:</th>';
-  $block = '<td class="row1" style="text-align: center;">{LINK}</td>';
-  $end = '</tr></table></div>';
-  $blk = $template->makeParserText($block);
-  $inner = '';
-  $cls = 'row2';
-  if ( $num_pages < 5 )
-  {
-    for ( $i = 0; $i < $num_pages; $i++ )
-    {
-      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      $offset = strval($i * $perpage);
-      $url = sprintf($result_url, $offset);
-      $j = $i + 1;
-      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
-      $blk->assign_vars(array(
-        'CLASS'=>$cls,
-        'LINK'=>$link
-        ));
-      $inner .= $blk->run();
-    }
-  }
-  else
-  {
-    if ( $this_page + 5 > $num_pages )
-    {
-      $list = Array();
-      $tp = $this_page;
-      if ( $this_page + 0 == $num_pages ) $tp = $tp - 3;
-      if ( $this_page + 1 == $num_pages ) $tp = $tp - 2;
-      if ( $this_page + 2 == $num_pages ) $tp = $tp - 1;
-      for ( $i = $tp - 1; $i <= $tp + 1; $i++ )
-      {
-        $list[] = $i;
-      }
-    }
-    else
-    {
-      $list = Array();
-      $current = $this_page;
-      $lower = ( $current < 3 ) ? 1 : $current - 1;
-      for ( $i = 0; $i < 3; $i++ )
-      {
-        $list[] = $lower + $i;
-      }
-    }
-    $url = sprintf($result_url, '0');
-    $link = ( 0 == $start ) ? "<b>First</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; First</a>";
-    $blk->assign_vars(array(
-      'CLASS'=>$cls,
-      'LINK'=>$link
-      ));
-    $inner .= $blk->run();
-    
-    // if ( !in_array(1, $list) )
-    // {
-    //   $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-    //   $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
-    //   $inner .= $blk->run();
-    // }
-    
-    foreach ( $list as $i )
-    {
-      if ( $i == $num_pages )
-        break;
-      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      $offset = strval($i * $perpage);
-      $url = sprintf($result_url, $offset);
-      $j = $i + 1;
-      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
-      $blk->assign_vars(array(
-        'CLASS'=>$cls,
-        'LINK'=>$link
-        ));
-      $inner .= $blk->run();
-    }
-    
-    $total = $num_pages * $perpage - $perpage;
-    
-    if ( $this_page < $num_pages )
-    {
-      // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
-      // $inner .= $blk->run();
-    
-      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      $offset = strval($total);
-      $url = sprintf($result_url, $offset);
-      $j = $i + 1;
-      $link = ( $offset == strval($start) ) ? "<b>Last</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Last &raquo;</a>";
-      $blk->assign_vars(array(
-        'CLASS'=>$cls,
-        'LINK'=>$link
-        ));
-      $inner .= $blk->run();
-    }
-    
-  }
-  
-  $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$this_page.', '.$num_pages.', '.$perpage.', unescape(\'' . rawurlencode($result_url) . '\'));">&darr;</td>';
-  
-  $paginator = "\n$begin$inner$end\n";
-  $out .= $paginator;
-  
-  $cls = 'row2';
-  
-  if ( $row = $db->fetchrow($q) )
-  {
-    $i = 0;
-    $out .= $header;
-    do {
-      $i++;
-      if ( $i <= $start )
-      {
-        continue;
-      }
-      if ( ( $i - $start ) > $perpage )
-      {
-        break;
-      }
-      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      foreach ( $row as $j => $val )
-      {
-        if ( isset($callers[$j]) )
-        {
-          $tmp = ( is_callable($callers[$j]) ) ? @call_user_func($callers[$j], $val, $row) : $v;
-          
-          if ( $tmp )
-          {
-            $row[$j] = $tmp;
-          }
-        }
-      }
-      $parser->assign_vars($row);
-      $parser->assign_vars(array('_css_class' => $cls));
-      $out .= $parser->run();
-    } while ( $row = $db->fetchrow($q) );
-    $out .= $footer;
-  }
-  
-  $out .= $paginator;
-  
-  return $out;
-}
-
-/**
- * This is the same as paginate(), but it processes an array instead of a MySQL result resource.
- * @param array The results. Each value is simply echoed.
- * @param int The number of total results. This should be determined by a second query.
- * @param string sprintf-style formatting string for URLs for result pages. First parameter will be start offset.
- * @param int Optional. Start offset in individual results. Defaults to 0.
- * @param int Optional. The number of results per page. Defualts to 10.
- * @param string Optional. The text to be sent before the result list, only if there are any results. Possibly the start of a table.
- * @param string Optional. The text to be sent after the result list, only if there are any results. Possibly the end of a table.
- * @return string
- */
-
-function paginate_array($q, $num_results, $result_url, $start = 0, $perpage = 10, $header = '', $footer = '')
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $parser = $template->makeParserText($tpl_text);
-  $num_pages = ceil ( $num_results / $perpage );
-  $out = '';
-  $i = 0;
-  $this_page = ceil ( $start / $perpage );
-  
-  // Build paginator
-  $begin = '<div class="tblholder" style="display: table; margin: 10px 0 0 auto;">
-    <table border="0" cellspacing="1" cellpadding="4">
-      <tr><th>Page:</th>';
-  $block = '<td class="row1" style="text-align: center;">{LINK}</td>';
-  $end = '</tr></table></div>';
-  $blk = $template->makeParserText($block);
-  $inner = '';
-  $cls = 'row2';
-  if ( $start > 0 )
-  {
-    $url = sprintf($result_url, abs($start - $perpage));
-    $link = "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; Prev</a>";
-    $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-    $blk->assign_vars(array(
-      'CLASS'=>$cls,
-      'LINK'=>$link
-      ));
-    $inner .= $blk->run();
-  }
-  if ( $num_pages < 5 )
-  {
-    for ( $i = 0; $i < $num_pages; $i++ )
-    {
-      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      $offset = strval($i * $perpage);
-      $url = sprintf($result_url, $offset);
-      $j = $i + 1;
-      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
-      $blk->assign_vars(array(
-        'CLASS'=>$cls,
-        'LINK'=>$link
-        ));
-      $inner .= $blk->run();
-    }
-  }
-  else
-  {
-    if ( $this_page + 5 > $num_pages )
-    {
-      $list = Array();
-      $tp = $this_page;
-      if ( $this_page + 0 == $num_pages ) $tp = $tp - 3;
-      if ( $this_page + 1 == $num_pages ) $tp = $tp - 2;
-      if ( $this_page + 2 == $num_pages ) $tp = $tp - 1;
-      for ( $i = $tp - 1; $i <= $tp + 1; $i++ )
-      {
-        $list[] = $i;
-      }
-    }
-    else
-    {
-      $list = Array();
-      $current = $this_page;
-      $lower = ( $current < 3 ) ? 1 : $current - 1;
-      for ( $i = 0; $i < 3; $i++ )
-      {
-        $list[] = $lower + $i;
-      }
-    }
-    $url = sprintf($result_url, '0');
-    $link = ( 0 == $start ) ? "<b>First</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>&laquo; First</a>";
-    $blk->assign_vars(array(
-      'CLASS'=>$cls,
-      'LINK'=>$link
-      ));
-    $inner .= $blk->run();
-    
-    // if ( !in_array(1, $list) )
-    // {
-    //   $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-    //   $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
-    //   $inner .= $blk->run();
-    // }
-    
-    foreach ( $list as $i )
-    {
-      if ( $i == $num_pages )
-        break;
-      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      $offset = strval($i * $perpage);
-      $url = sprintf($result_url, $offset);
-      $j = $i + 1;
-      $link = ( $offset == strval($start) ) ? "<b>$j</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>$j</a>";
-      $blk->assign_vars(array(
-        'CLASS'=>$cls,
-        'LINK'=>$link
-        ));
-      $inner .= $blk->run();
-    }
-    
-    $total = $num_pages * $perpage - $perpage;
-    
-    if ( $this_page < $num_pages )
-    {
-      // $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      // $blk->assign_vars(array('CLASS'=>$cls,'LINK'=>'...'));
-      // $inner .= $blk->run();
-    
-      $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-      $offset = strval($total);
-      $url = sprintf($result_url, $offset);
-      $j = $i + 1;
-      $link = ( $offset == strval($start) ) ? "<b>Last</b>" : "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Last &raquo;</a>";
-      $blk->assign_vars(array(
-        'CLASS'=>$cls,
-        'LINK'=>$link
-        ));
-      $inner .= $blk->run();
-    }
-    
-  }
-  
-  if ( $start < $total )
-  {
-    $url = sprintf($result_url, abs($start + $perpage));
-    $link = "<a href=".'"'."$url".'"'." style='text-decoration: none;'>Next &raquo;</a>";
-    $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-    $blk->assign_vars(array(
-      'CLASS'=>$cls,
-      'LINK'=>$link
-      ));
-    $inner .= $blk->run();
-  }
-  
-  $inner .= '<td class="row2" style="cursor: pointer;" onclick="paginator_goto(this, '.$this_page.', '.$num_pages.', '.$perpage.', unescape(\'' . rawurlencode($result_url) . '\'));">&darr;</td>';
-  
-  $paginator = "\n$begin$inner$end\n";
-  if ( $total > 1 )
-    $out .= $paginator;
-  
-  $cls = 'row2';
-  
-  if ( sizeof($q) > 0 )
-  {
-    $i = 0;
-    $out .= $header;
-    foreach ( $q as $val ) {
-      $i++;
-      if ( $i <= $start )
-      {
-        continue;
-      }
-      if ( ( $i - $start ) > $perpage )
-      {
-        break;
-      }
-      $out .= $val;
-    }
-    $out .= $footer;
-  }
-  
-  if ( $total > 1 )
-    $out .= $paginator;
-  
-  return $out;
-}
-
-/** 
- * Enano version of fputs for debugging
- */
-
-function enano_fputs($socket, $data)
-{
-  // echo '<pre>' . htmlspecialchars($data) . '</pre>';
-  // flush();
-  // ob_flush();
-  // ob_end_flush();
-  return fputs($socket, $data);
-}
-
-/**
- * Sanitizes a page URL string so that it can safely be stored in the database.
- * @param string Page ID to sanitize
- * @return string Cleaned text
- */
-
-function sanitize_page_id($page_id)
-{
-  
-  // First, replace spaces with underscores  
-  $page_id = str_replace(' ', '_', $page_id);
-  
-  preg_match_all('/\.[A-Fa-f0-9][A-Fa-f0-9]/', $page_id, $matches);
-  
-  foreach ( $matches[0] as $id => $char )
-  {
-    $char = substr($char, 1);
-    $char = strtolower($char);
-    $char = intval(hexdec($char));
-    $char = chr($char);
-    $page_id = str_replace($matches[0][$id], $char, $page_id);
-  }
-  
-  $pid_clean = preg_replace('/[\w\/:;\(\)@\[\]_-]/', 'X', $page_id);
-  $pid_dirty = enano_str_split($pid_clean, 1);
-  
-  foreach ( $pid_dirty as $id => $char )
-  {
-    if ( $char == 'X' )
-      continue;
-    $cid = ord($char);
-    $cid = dechex($cid);
-    $cid = strval($cid);
-    if ( strlen($cid) < 2 )
-    {
-      $cid = strtoupper("0$cid");
-    }
-    $pid_dirty[$id] = ".$cid";
-  }
-  
-  $pid_chars = enano_str_split($page_id, 1);
-  $page_id_cleaned = '';
-  
-  foreach ( $pid_chars as $id => $char )
-  {
-    if ( $pid_dirty[$id] == 'X' )
-      $page_id_cleaned .= $char;
-    else
-      $page_id_cleaned .= $pid_dirty[$id];
-  }
-  
-  global $mime_types;
-          
-  $exts = array_keys($mime_types);
-  $exts = '(' . implode('|', $exts) . ')';
-  
-  $page_id_cleaned = preg_replace('/\.2e' . $exts . '$/', '.\\1', $page_id_cleaned);
-  
-  return $page_id_cleaned;
-}
-
-//die('<pre>Original:  01010101010100101010100101010101011010'."\nProcessed: ".uncompress_bitfield(compress_bitfield('01010101010100101010100101010101011010')).'</pre>');
-
-?>
--- a/includes/pageprocess.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,455 +0,0 @@
-<?php
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 (Banshee)
- * pageprocess.php - intelligent retrieval of pages
- * Copyright (C) 2006-2007 Dan Fuhry
- *
- * This program is Free Software; you can redistribute 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 details.
- */
-
-/**
- * Class to handle fetching page text (possibly from a cache) and formatting it.
- * @package Enano
- * @subpackage UI
- * @copyright 2007 Dan Fuhry
- * @license GNU General Public License <http://www.gnu.org/licenses/gpl.html>
- */
-
-class PageProcessor
-{
-  
-  /**
-   * Page ID and namespace of the page handled by this instance
-   * @var string
-   */
-  
-  var $page_id;
-  var $namespace;
-  
-  /**
-   * Tracks if the page we're loading exists in the database or not.
-   * @var bool
-   */
-  
-  var $page_exists = false;
-  
-  /**
-   * Permissions!
-   * @var object
-   */
-  
-  var $perms = null;
-  
-  /**
-   * Switch to track if redirects are allowed. Defaults to true.
-   * @var bool
-   */
-  
-  var $allow_redir = true;
-  
-  /**
-   * If this is set to true, this will call the header and footer funcs on $template when render() is called.
-   * @var bool
-   */
-  
-  var $send_headers = false;
-  
-  /**
-   * Cache the fetched text so we don't fetch it from the DB twice.
-   * @var string
-   */
-  
-  var $text_cache = '';
-  
-  /**
-   * Debugging information to track errors. You can set enable to false to disable sending debug information.
-   * @var array
-   */
-  
-  var $debug = array(
-      'enable' => true,
-      'works'  => false
-    );
-  
-  /**
-   * Constructor.
-   * @param string The page ID (urlname) of the page
-   * @param string The namespace of the page
-   */
-  
-  function __construct( $page_id, $namespace )
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    // See if we can get some debug info
-    if ( function_exists('debug_backtrace') && $this->debug['enable'] )
-    {
-      $this->debug['works'] = true;
-      $this->debug['backtrace'] = enano_debug_print_backtrace(true);
-    }
-    
-    // First things first - check page existence and permissions
-    
-    if ( !isset($paths->nslist[$namespace]) )
-    {
-      $this->send_error('The namespace "' . htmlspecialchars($namespace) . '" does not exist.');
-    }
-    
-    $this->_setup( $page_id, $namespace );
-    
-  }
-  
-  /**
-   * The main method to send the page content. Also responsible for checking permissions.
-   */
-  
-  function send()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if ( !$this->perms->get_permissions('read') )
-    {
-      $this->err_access_denied();
-      return false;
-    }
-    if ( $this->namespace == 'Special' || $this->namespace == 'Admin' )
-    {
-      if ( !$this->page_exists )
-      {
-        redirect( makeUrl(getConfig('main_page')), 'Can\'t find special page', 'The special or administration page you requested does not exist. You will now be transferred to the main page.', 2 );
-      }
-      $func_name = "page_{$this->namespace}_{$this->page_id}";
-      if ( function_exists($func_name) )
-      {
-        return @call_user_func($func_name);
-      }
-      else
-      {
-        $title = 'Page backend not found';
-        $message = "The administration page you are looking for was properly registered using the page API, but the backend function
-                    (<tt>$fname</tt>) was not found. If this is a plugin page, then this is almost certainly a bug with the plugin.";
-                    
-        if ( $this->send_headers )
-        {
-          $template->tpl_strings['PAGE_NAME'] = $title;
-          $template->header();
-          echo "<p>$message</p>";
-          $template->footer();
-        }
-        else
-        {
-          echo "<h2>$title</h2>
-                <p>$message</p>";
-        }
-        return false;
-      }
-    }
-    else if ( in_array($this->namespace, array('Article', 'User', 'Project', 'Help', 'File', 'Category')) && $this->page_exists )
-    {
-      // Send as regular page
-      $text = $this->fetch_text();
-      if ( $text == 'err_no_text_rows' )
-      {
-        $this->err_no_rows();
-        return false;
-      }
-      else
-      {
-        $this->render();
-      }
-    }
-    else if ( ( $this->namespace == 'Template' || $this->namespace == 'System' ) && $this->page_exists )
-    {
-      $this->header();
-      
-      $text = $this->fetch_text();
-      $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $text);
-      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
-      
-      $text = RenderMan::render( $text );
-      
-      echo $text;
-      
-      $this->footer();
-      
-    }
-    else if ( !$this->page_exists )
-    {
-      // Perhaps this is hooked?
-      ob_start();
-      
-      $code = $plugins->setHook('page_not_found');
-      foreach ( $code as $cmd )
-      {
-        eval($cmd);
-      }
-      
-      $ob = ob_get_contents();
-      
-      if ( empty($ob) )
-      {
-        $this->err_page_not_existent();
-      }
-      
-    }
-    
-  }
-  
-  /**
-   * Sets internal variables.
-   * @access private
-   */
-  
-  function _setup($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $page_id_cleaned = sanitize_page_id($page_id);
-    
-    $this->page_id = $page_id_cleaned;
-    $this->namespace = $namespace;
-    
-    $this->perms = $session->fetch_page_acl( $page_id, $namespace );
-    
-    // Exception for Admin: pages
-    if ( $this->namespace == 'Admin' )
-    {
-      $fname = "page_Admin_{$this->page_id}";
-    }
-    
-    // Does the page "exist"?
-    if ( $paths->cpage['urlname_nons'] == $page_id && $paths->namespace == $namespace && !$paths->page_exists && ( $this->namespace == 'Admin' && !function_exists($fname) ) )
-    {
-      $this->page_exists = false;
-    }
-    else if ( !isset( $paths->pages[ $paths->nslist[$namespace] . $page_id ] ) && ( $this->namespace == 'Admin' && !function_exists($fname) ) )
-    {
-      $this->page_exists = false;
-    }
-    else
-    {
-      $this->page_exists = true;
-    }
-  }
-  
-  /**
-   * Renders it all in one go, and echoes it out. This assumes that the text is in the DB.
-   * @access private
-   */
-  
-  function render()
-  {
-    $text = $this->fetch_text();
-    
-    $this->header();
-    echo RenderMan::render($text);
-    $this->footer();
-  }
-  
-  /**
-   * Sends the page header, dependent on, of course, whether we're supposed to.
-   */
-  
-  function header()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if ( $this->send_headers )
-      $template->header();
-  }
-  
-  /**
-   * Sends the page footer, dependent on, of course, whether we're supposed to.
-   */
-  
-  function footer()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if ( $this->send_headers )
-      $template->footer();
-  }
-  
-  /**
-   * Fetches the raw, unfiltered page text.
-   * @access public
-   */
-  
-  function fetch_text()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    if ( !empty($this->text_cache) )
-    {
-      return $this->text_cache;
-    }
-    
-    $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\';');
-    if ( !$q )
-    {
-      $this->send_error('Error during SQL query.', true);
-    }
-    if ( $db->numrows() < 1 )
-    {
-      $this->page_exists = false;
-      return 'err_no_text_rows';
-    }
-    
-    $row = $db->fetchrow();
-    $db->free_result();
-    
-    if ( !empty($row['char_tag']) )
-    {
-      // This page text entry uses the old text-escaping format
-      $from = array(
-          "{APOS:{$row['char_tag']}}",
-          "{QUOT:{$row['char_tag']}}",
-          "{SLASH:{$row['char_tag']}}"
-        );
-      $to = array("'", '"',  '\\');
-      $row['page_text'] = str_replace($from, $to, $row['page_text']);
-    }
-    
-    $this->text_cache = $row['page_text'];
-    
-    return $row['page_text'];
-    
-  }
-  
-  /**
-   * Send the error message to the user that the access to this page is denied.
-   * @access private
-   */
-  
-  function err_access_denied()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $ob = '';
-    $template->tpl_strings['PAGE_NAME'] = 'Access denied';
-      
-    if ( $this->send_headers )
-    {
-      $ob .= $template->getHeader();
-    }
-    
-    $ob .= '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
-    
-    if ( $this->send_headers )
-    {
-      $ob .= $template->getFooter();
-    }
-    echo $ob;
-  }
-  
-  /**
-   * Send the error message to the user complaining that there weren't any rows.
-   * @access private
-   */
-  
-  function err_no_rows()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $title = 'No text rows';
-    $message = 'While the page\'s existence was verified, there were no rows in the database that matched the query for the text. This may indicate a bug with the software; ask the webmaster for more information.';
-    if ( $this->send_headers )
-    {
-      $template->tpl_strings['PAGE_NAME'] = $title;
-      $template->header();
-      echo "<p>$message</p>";
-      $template->footer();
-    }
-    else
-    {
-      echo "<h2>$title</h2>
-            <p>$message</p>";
-    }
-  }
-  
-  /**
-   * Tell the user the page doesn't exist, and present them with their options.
-   * @access private
-   */
-   
-  function err_page_not_existent()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $this->header();
-    header('HTTP/1.1 404 Not Found');
-    echo '<h3>There is no page with this title yet.</h3>
-           <p>You have requested a page that doesn\'t exist yet.';
-    if ( $session->get_permissions('create_page') )
-    {
-      echo ' You can <a href="'.makeUrlNS($this->namespace, $this->page_id, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
-    }
-    else
-    {
-      echo ' Return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.</p>';
-    }
-    if ( $session->get_permissions('history_rollback') )
-    {
-      $e = $db->sql_query('SELECT * FROM ' . table_prefix . 'logs WHERE action=\'delete\' AND page_id=\'' . $this->page_id . '\' AND namespace=\'' . $this->namespace . '\' ORDER BY time_id DESC;');
-      if ( !$e )
-      {
-        $db->_die('The deletion log could not be selected.');
-      }
-      if ( $db->numrows() > 0 )
-      {
-        $r = $db->fetchrow();
-        echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on ' . $r['date_string'] . '. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">roll back</a> the deletion.</p>';
-      }
-      $db->free_result();
-    }
-    echo '<p>
-            HTTP Error: 404 Not Found
-          </p>';
-    $this->footer();
-  }
-  
-  /**
-   * PHP 4 constructor.
-   * @see PageProcessor::__construct()
-   */
-  
-  function PageProcessor( $page_id, $namespace )
-  {
-    $this->__construct($page_id, $namespace);
-  }
-  
-  /**
-   * Send an error message and die
-   * @var string Error message
-   * @var bool If true, send DBAL's debugging information as well
-   */
-   
-  function send_error($message, $sql = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $content = "<p>$message</p>";
-    $template->tpl_strings['PAGE_NAME'] = 'General error in page fetcher';
-    
-    if ( $this->debug['works'] )
-    {
-      $content .= $this->debug['backtrace'];
-    }
-    
-    header('HTTP/1.1 500 Internal Server Error');
-    
-    $template->header();
-    echo $content;
-    $template->footer();
-    
-    $db->close();
-    
-    exit;
-    
-  }
-  
-} // class PageProcessor
-
-?>
--- a/includes/pageutils.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2059 +0,0 @@
-<?php
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 (Banshee)
- * Copyright (C) 2006-2007 Dan Fuhry
- * pageutils.php - a class that handles raw page manipulations, used mostly by AJAX requests or their old-fashioned form-based counterparts
- *
- * This program is Free Software; you can redistribute 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 details.
- */
- 
-class PageUtils {
-  
-  /**
-   * List possible username completions
-   * @param $name the name to check for
-   * @return array
-   */
-  
-  function checkusername($name)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $q = $db->sql_query('SELECT username FROM '.table_prefix.'users WHERE username=\''.$db->escape(rawurldecode($name)).'\'');
-    if(!$q) die(mysql_error());
-    if($db->numrows() < 1) { $db->free_result(); return('good'); }
-    else { $db->free_result(); return('bad'); }
-  }
-  
-  /**
-   * Get the wiki formatting source for a page
-   * @param $page the full page id (Namespace:Pagename)
-   * @return string
-   * @todo (DONE) Make it require a password (just for security purposes)
-   */
-   
-  function getsource($page, $password = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!isset($paths->pages[$page]))
-    {
-      return '';
-    }
-    
-    if(strlen($paths->pages[$page]['password']) == 40)
-    {
-      if(!$password || ( $password != $paths->pages[$page]['password']))
-      {
-        return 'invalid_password';
-      }
-    }
-    
-    if(!$session->get_permissions('view_source')) // Dependencies handle this for us - this also checks for read privileges
-      return 'access_denied';
-    $pid = RenderMan::strToPageID($page);
-    if($pid[1] == 'Special' || $pid[1] == 'Admin')
-    {
-      die('This type of page ('.$paths->nslist[$pid[1]].') cannot be edited because the page source code is not stored in the database.');
-    }
-    
-    $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$pid[0].'\' AND namespace=\''.$pid[1].'\'');
-    if ( !$e )
-    {
-      $db->_die('The page text could not be selected.');
-    }
-    if( $db->numrows() < 1 )
-    {
-      return ''; //$db->_die('There were no rows in the text table that matched the page text query.');
-    }
-    
-    $r = $db->fetchrow();
-    $db->free_result();
-    $message = $r['page_text'];
-    
-    return htmlspecialchars($message);
-  }
-  
-  /**
-   * Basically a frontend to RenderMan::getPage(), with the ability to send valid data for nonexistent pages
-   * @param $page the full page id (Namespace:Pagename)
-   * @param $send_headers true if the theme headers should be sent (still dependent on current page settings), false otherwise
-   * @return string
-   */
-  
-  function getpage($page, $send_headers = false, $hist_id = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    ob_start();
-    $pid = RenderMan::strToPageID($page);
-    //die('<pre>'.print_r($pid, true).'</pre>');
-    if(isset($paths->pages[$page]['password']) && strlen($paths->pages[$page]['password']) == 40)
-    {
-      password_prompt($page);
-    }
-    if(isset($paths->pages[$page]))
-    {
-      doStats($pid[0], $pid[1]);
-    }
-    if($paths->custom_page || $pid[1] == 'Special')
-    {
-      // If we don't have access to the page, get out and quick!
-      if(!$session->get_permissions('read') && $pid[0] != 'Login' && $pid[0] != 'Register')
-      {
-        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
-        
-        if ( $send_headers )
-        {
-          $template->header();
-        }
-        
-        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
-        
-        if ( $send_headers )
-        {
-          $template->footer();
-        }
-        
-        $r = ob_get_contents();
-        ob_end_clean();
-        return $r;
-      }
-      
-      $fname = 'page_'.$pid[1].'_'.$paths->pages[$page]['urlname_nons'];
-      @call_user_func($fname);
-      
-    }
-    else if ( $pid[1] == 'Admin' )
-    {
-      // If we don't have access to the page, get out and quick!
-      if(!$session->get_permissions('read'))
-      {
-        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
-        if ( $send_headers )
-        {
-          $template->header();
-        }
-        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
-        if ( $send_headers )
-        {
-          $template->footer();
-        }
-        $r = ob_get_contents();
-        ob_end_clean();
-        return $r;
-      }
-      
-      $fname = 'page_'.$pid[1].'_'.$pid[0];
-      if ( !function_exists($fname) )
-      {
-        $title = 'Page backend not found';
-        $message = "The administration page you are looking for was properly registered using the page API, but the backend function
-                    (<tt>$fname</tt>) was not found. If this is a plugin page, then this is almost certainly a bug with the plugin.";
-        if ( $send_headers )
-        {
-          die_friendly($title, "<p>$message</p>");
-        }
-        else
-        {
-          echo "<h2>$title</h2>\n<p>$message</p>";
-        }
-      }
-      @call_user_func($fname);
-    }
-    else if ( !isset( $paths->pages[$page] ) )
-    {
-      ob_start();
-      $code = $plugins->setHook('page_not_found');
-      foreach ( $code as $cmd )
-      {
-        eval($cmd);
-      }
-      $text = ob_get_contents();
-      if ( $text != '' )
-      {
-        ob_end_clean();
-        return $text;
-      }
-      $template->header();
-      if($m = $paths->sysmsg('Page_not_found'))
-      {
-        eval('?>'.RenderMan::render($m));
-      }
-      else
-      {
-        header('HTTP/1.1 404 Not Found');
-        echo '<h3>There is no page with this title yet.</h3>
-               <p>You have requested a page that doesn\'t exist yet.';
-        if($session->get_permissions('create_page')) echo ' You can <a href="'.makeUrl($paths->page, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
-        else echo ' Return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.</p>';
-        if($session->get_permissions('history_rollback')) {
-          $e = $db->sql_query('SELECT * FROM '.table_prefix.'logs WHERE action=\'delete\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' ORDER BY time_id DESC;');
-          if(!$e) $db->_die('The deletion log could not be selected.');
-          if($db->numrows() > 0) {
-            $r = $db->fetchrow();
-            echo '<p>This page also appears to have some log entries in the database - it seems that it was deleted on '.$r['date_string'].'. You can probably <a href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">roll back</a> the deletion.</p>';
-          }
-          $db->free_result();
-        }
-        echo '<p>
-                HTTP Error: 404 Not Found
-              </p>';
-      }
-      $template->footer();
-    }
-    else
-    {
-      
-      // If we don't have access to the page, get out and quick!
-      if(!$session->get_permissions('read'))
-      {
-        $template->tpl_strings['PAGE_NAME'] = 'Access denied';
-        if($send_headers) $template->header();
-        echo '<div class="error-box"><b>Access to this page is denied.</b><br />This may be because you are not logged in or you have not met certain criteria for viewing this page.</div>';
-        if($send_headers) $template->footer();
-        $r = ob_get_contents();
-        ob_end_clean();
-        return $r;
-      }
-      
-      ob_start();
-      $code = $plugins->setHook('page_custom_handler');
-      foreach ( $code as $cmd )
-      {
-        eval($cmd);
-      }
-      $text = ob_get_contents();
-      if ( $text != '' )
-      {
-        ob_end_clean();
-        return $text;
-      }
-      
-      if($hist_id) {
-        $e = $db->sql_query('SELECT page_text,date_string,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$paths->pages[$page]['urlname_nons'].'\' AND namespace=\''.$pid[1].'\' AND log_type=\'page\' AND action=\'edit\' AND time_id='.$db->escape($hist_id).'');
-        if($db->numrows() < 1)
-        {
-          $db->_die('There were no rows in the text table that matched the page text query.');
-        }
-        $r = $db->fetchrow();
-        $db->free_result();
-        $message = '<div class="info-box" style="margin-left: 0; margin-top: 5px;"><b>Notice:</b><br />The page you are viewing was archived on '.$r['date_string'].'.<br /><a href="'.makeUrl($page).'" onclick="ajaxReset(); return false;">View current version</a>  |  <a href="'.makeUrl($page, 'do=rollback&amp;id='.$hist_id).'" onclick="ajaxRollback(\''.$hist_id.'\')">Restore this version</a></div><br />'.RenderMan::render($r['page_text']);
-        
-        if( !$paths->pages[$page]['special'] )
-        {
-          if($send_headers)
-          {
-            $template->header(); 
-          }
-          display_page_headers();
-        }
-        
-        eval('?>'.$message);
-        
-        if( !$paths->pages[$page]['special'] )
-        {
-          display_page_footers();
-          if($send_headers)
-          {
-            $template->footer();
-          }
-        }
-        
-      } else {
-        if(!$paths->pages[$page]['special'])
-        {
-          $message = RenderMan::getPage($paths->pages[$page]['urlname_nons'], $pid[1]);
-        }
-        else
-        {
-          $message = RenderMan::getPage($paths->pages[$page]['urlname_nons'], $pid[1], 0, false, false, false, false);
-        }
-        // This line is used to debug wikiformatted code
-        // die('<pre>'.htmlspecialchars($message).'</pre>');
-        
-        if( !$paths->pages[$page]['special'] )
-        {
-          if($send_headers)
-          {
-            $template->header(); 
-          }
-          display_page_headers();
-        }
-
-        // This is it, this is what all of Enano has been working up to...
-        
-        eval('?>'.$message);
-        
-        if( !$paths->pages[$page]['special'] )
-        {
-          display_page_footers();
-          if($send_headers)
-          {
-            $template->footer();
-          }
-        }
-      }
-    }
-    $ret = ob_get_contents();
-    ob_end_clean();
-    return $ret;
-  }
-  
-  /**
-   * Writes page data to the database, after verifying permissions and running the XSS filter
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $message the text to save
-   * @return string
-   */
-   
-  function savepage($page_id, $namespace, $message, $summary = 'No edit summary given', $minor = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $uid = sha1(microtime());
-    $pname = $paths->nslist[$namespace] . $page_id;
-    
-    if(!$session->get_permissions('edit_page'))
-      return 'Access to edit pages is denied.';
-    
-    if(!isset($paths->pages[$pname]))
-    {
-      if(!PageUtils::createPage($page_id, $namespace))
-        return 'The page did not exist, and I was not able to create it. Permissions problem?';
-    }
-    
-    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
-    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
-    if(($prot || !$wiki) && $session->user_level < USER_LEVEL_ADMIN ) return('You are not authorized to edit this page.');
-    
-    // Strip potentially harmful tags and PHP from the message, if we are in wiki mode and the user is not an administrator
-    $message = RenderMan::preprocess_text($message, false, false);
-    
-    $msg=$db->escape($message);
-    
-    $minor = $minor ? 'true' : 'false';
-    $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$msg.'\', \''.$uid.'\', \''.$session->username.'\', \''.$db->escape(htmlspecialchars($summary)).'\', '.$minor.');';
-    if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
-    
-    $q = 'UPDATE '.table_prefix.'page_text SET page_text=\''.$msg.'\',char_tag=\''.$uid.'\' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';';
-    $e = $db->sql_query($q);
-    if(!$e) $db->_die('Enano was unable to save the page contents. Your changes have been lost <tt>:\'(</tt>.');
-      
-    $paths->rebuild_page_index($page_id, $namespace);
-      
-    return 'good';
-  }
-  
-  /**
-   * Creates a page, both in memory and in the database.
-   * @param string $page_id
-   * @param string $namespace
-   * @return bool true on success, false on failure
-   */
-  
-  function createPage($page_id, $namespace, $name = false, $visible = 1)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(in_array($namespace, Array('Special', 'Admin')))
-    {
-      // echo '<b>Notice:</b> PageUtils::createPage: You can\'t create a special page in the database<br />';
-      return false; // Can't create a special page
-    }
-    
-    if(!isset($paths->nslist[$namespace]))
-    {
-      // echo '<b>Notice:</b> PageUtils::createPage: Couldn\'t look up the namespace<br />';
-      return false; // Couldn't look up namespace
-    }
-    
-    $pname = $paths->nslist[$namespace] . $page_id;
-    if(isset($paths->pages[$pname]))
-    {
-      // echo '<b>Notice:</b> PageUtils::createPage: Page already exists<br />';
-      return false; // Page already exists
-    }
-    
-    if(!$session->get_permissions('create_page'))
-    {
-      // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create pages<br />';
-      return false; // Access denied
-    }
-    
-    if($session->user_level < USER_LEVEL_ADMIN && $namespace == 'System')
-    {
-      // echo '<b>Notice:</b> PageUtils::createPage: Not authorized to create system messages<br />';
-      return false; // Not authorized to create system messages
-    }
-    
-    if ( !$name )
-      $name = str_replace('_', ' ', $page_id);
-    $page = str_replace(' ', '_', $page_id);
-    $regex = '#^([A-z0-9 _\-\.\/\!\@\(\)]*)$#is';
-    if(!preg_match($regex, $page))
-    {
-      //echo '<b>Notice:</b> PageUtils::createPage: Name contains invalid characters<br />';
-      return false; // Name contains invalid characters
-    }
-    
-    $prot = ( $namespace == 'System' ) ? 1 : 0;
-    
-    $paths->add_page(Array(
-      'name'=>$name,
-      'urlname'=>$page,
-      'namespace'=>$namespace,
-      'special'=>0,'visible'=>1,'comments_on'=>0,'protected'=>$prot,'delvotes'=>0,'delvote_ips'=>'','wiki_mode'=>2,
-    ));
-    
-    $qa = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace,visible,protected) VALUES(\''.$db->escape($name).'\', \''.$db->escape($page).'\', \''.$namespace.'\', '. ( $visible ? '1' : '0' ) .', '.$prot.');');
-    $qb = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace) VALUES(\''.$db->escape($page).'\', \''.$namespace.'\');');
-    $qc = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'create\', \''.$session->username.'\', \''.$db->escape($page).'\', \''.$namespace.'\');');
-    
-    if($qa && $qb && $qc)
-      return true;
-    else
-    {
-      echo $db->get_error();
-      return false;
-    }
-  }
-  
-  /**
-   * Sets the protection level on a page.
-   * @param $page_id string the page ID
-   * @param $namespace string the namespace
-   * @param $level int level of protection - 0 is off, 1 is full, 2 is semi
-   * @param $reason string why the page is being (un)protected
-   * @return string - "good" on success, in all other cases, an error string (on query failure, calls $db->_die() )
-   */
-  function protect($page_id, $namespace, $level, $reason)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $pname = $paths->nslist[$namespace] . $page_id;
-    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
-    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
-    
-    if(!$session->get_permissions('protect')) return('Insufficient access rights');
-    if(!$wiki) return('Page protection only has an effect when Wiki Mode is enabled.');
-    if(!preg_match('#^([0-9]+){1}$#', (string)$level)) return('Invalid $level parameter.');
-    
-    if($reason!='NO_REASON') {
-      switch($level)
-      {
-        case 0:
-          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'unprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
-          break;
-        case 1:
-          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'prot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
-          break;
-        case 2:
-          $q = 'INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'semiprot\', \''.$session->username.'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape(htmlspecialchars($reason)).'\');';
-          break;
-        default:
-          return 'PageUtils::protect(): Invalid value for $level';
-          break;
-      }
-      if(!$db->sql_query($q)) $db->_die('The log entry for the page protection could not be inserted.');
-    }
-    
-    $q = $db->sql_query('UPDATE '.table_prefix.'pages SET protected='.$_POST['level'].' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-    if(!$q) $db->_die('The pages table was not updated.');
-    
-    return('good');
-  }
-  
-  /**
-   * Generates an HTML table with history information in it.
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @return string
-   */
-  
-  function histlist($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    if(!$session->get_permissions('history_view'))
-      return 'Access denied';
-    
-    ob_start();
-    
-    $pname = $paths->nslist[$namespace] . $page_id;
-    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
-    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
-    
-    $q = 'SELECT time_id,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' ORDER BY time_id DESC;';
-    if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
-    echo 'History of edits and actions<h3>Edits:</h3>';
-    $numrows = $db->numrows();
-    if($numrows < 1) echo 'No history entries in this category.';
-    else
-    {
-      
-      echo '<form action="'.makeUrlNS($namespace, $page_id, 'do=diff').'" onsubmit="ajaxHistDiff(); return false;" method="get">
-            <input type="submit" value="Compare selected revisions" />
-            <br /><span>&nbsp;</span>
-            <div class="tblholder">
-            <table border="0" width="100%" cellspacing="1" cellpadding="4">
-            <tr>
-              <th colspan="2">Diff</th>
-              <th>Date/time</th>
-              <th>User</th>
-              <th>Edit summary</th>
-              <th>Minor</th>
-              <th colspan="3">Actions</th>
-            </tr>'."\n"."\n";
-      $cls = 'row2';
-      $ticker = 0;
-      
-      while($r = $db->fetchrow()) {
-        
-        $ticker++;
-        
-        if($cls == 'row2') $cls = 'row1';
-        else $cls = 'row2';
-        
-        echo '<tr>'."\n";
-        
-        // Diff selection
-        if($ticker == 1)
-        {
-          $s1 = '';
-          $s2 = 'checked="checked" ';
-        }
-        elseif($ticker == 2)
-        {
-          $s1 = 'checked="checked" ';
-          $s2 = '';
-        }
-        else
-        {
-          $s1 = '';
-          $s2 = '';
-        }
-        if($ticker > 1)        echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s1.'name="diff1" type="radio" value="'.$r['time_id'].'" id="diff1_'.$r['time_id'].'" class="clsDiff1Radio" onclick="selectDiff1Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
-        if($ticker < $numrows) echo '<td class="'.$cls.'" style="padding: 0;"><input '.$s2.'name="diff2" type="radio" value="'.$r['time_id'].'" id="diff2_'.$r['time_id'].'" class="clsDiff2Radio" onclick="selectDiff2Button(this);" /></td>'."\n"; else echo '<td class="'.$cls.'"></td>';
-        
-        // Date and time
-        echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">'."\n";
-        
-        // User
-        if($session->get_permissions('mod_misc') && preg_match('#^([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}\.([0-9]*){1,3}$#', $r['author'])) $rc = ' style="cursor: pointer;" title="Click cell background for reverse DNS info" onclick="ajaxReverseDNS(this, \''.$r['author'].'\');"';
-        else $rc = '';
-        echo '<td class="'.$cls.'"'.$rc.'><a href="'.makeUrlNS('User', $r['author']).'" ';
-        if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
-        echo '>'.$r['author'].'</a></td class="'.$cls.'">'."\n";
-        
-        // Edit summary
-        echo '<td class="'.$cls.'">'.$r['edit_summary'].'</td>'."\n";
-        
-        // Minor edit
-        echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>'."\n";
-        
-        // Actions!
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'oldid='.$r['time_id']).'" onclick="ajaxHistView(\''.$r['time_id'].'\'); return false;">View revision</a></td>'."\n";
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>'."\n";
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert to this revision</a></td>'."\n";
-        
-        echo '</tr>'."\n"."\n";
-        
-      }
-      echo '</table>
-            </div>
-            <br />
-            <input type="hidden" name="do" value="diff" />
-            <input type="submit" value="Compare selected revisions" />
-            </form>
-            <script type="text/javascript">buildDiffList();</script>';
-    }
-    $db->free_result();
-    echo '<h3>Other changes:</h3>';
-    $q = 'SELECT time_id,action,date_string,page_id,namespace,author,edit_summary,minor_edit FROM '.table_prefix.'logs WHERE log_type=\'page\' AND action!=\'edit\' AND page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\' ORDER BY time_id DESC;';
-    if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
-    if($db->numrows() < 1) echo 'No history entries in this category.';
-    else {
-      
-      echo '<div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4"><tr><th>Date/time</th><th>User</th><th>Minor</th><th>Action taken</th><th>Extra info</th><th colspan="2"></th></tr>';
-      $cls = 'row2';
-      while($r = $db->fetchrow()) {
-        
-        if($cls == 'row2') $cls = 'row1';
-        else $cls = 'row2';
-        
-        echo '<tr>';
-        
-        // Date and time
-        echo '<td class="'.$cls.'">'.$r['date_string'].'</td class="'.$cls.'">';
-        
-        // User
-        echo '<td class="'.$cls.'"><a href="'.makeUrlNS('User', $r['author']).'" ';
-        if(!isPage($paths->nslist['User'] . $r['author'])) echo 'class="wikilink-nonexistent"';
-        echo '>'.$r['author'].'</a></td class="'.$cls.'">';
-        
-        
-        // Minor edit
-        echo '<td class="'.$cls.'" style="text-align: center;">'. (( $r['minor_edit'] ) ? 'M' : '' ) .'</td>';
-        
-        // Action taken
-        echo '<td class="'.$cls.'">';
-        if    ($r['action']=='prot')     echo 'Protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
-        elseif($r['action']=='unprot')   echo 'Unprotected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
-        elseif($r['action']=='semiprot') echo 'Semi-protected page</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
-        elseif($r['action']=='rename')   echo 'Renamed page</td><td class="'.$cls.'">Old title: '.$r['edit_summary'];
-        elseif($r['action']=='create')   echo 'Created page</td><td class="'.$cls.'">';
-        elseif($r['action']=='delete')   echo 'Deleted page</td><td class="'.$cls.'">';
-        elseif($r['action']=='reupload') echo 'Uploaded new file version</td><td class="'.$cls.'">Reason: '.$r['edit_summary'];
-        echo '</td>';
-        
-        // Actions!
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">View user contribs</a></td>';
-        echo '<td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS($namespace, $page_id, 'do=rollback&amp;id='.$r['time_id']).'" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">Revert action</a></td>';
-        
-        //echo '(<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">rollback</a>) <i>'.$r['date_string'].'</i> '.$r['author'].' (<a href="'.makeUrl($paths->nslist['User'].$r['author']).'">Userpage</a>, <a href="'.makeUrl($paths->nslist['Special'].'Contributions/'.$r['author']).'">Contrib</a>): ';
-        
-        if($r['minor_edit']) echo '<b> - minor edit</b>';
-        echo '<br />';
-        
-        echo '</tr>';
-      }
-      echo '</table></div>';
-    }
-    $db->free_result();
-    $ret = ob_get_contents();
-    ob_end_clean();
-    return $ret;
-  }
-  
-  /**
-   * Rolls back a logged action
-   * @param $id the time ID, a.k.a. the primary key in the logs table
-   * @return string
-   */
-   
-  function rollback($id)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('history_rollback')) return('You are not authorized to perform rollbacks.');
-    if(!preg_match('#^([0-9]+)$#', (string)$id)) return('The value "id" on the query string must be an integer.');
-    $e = $db->sql_query('SELECT log_type,action,date_string,page_id,namespace,page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id.';');
-    if(!$e) $db->_die('The rollback data could not be selected.');
-    $rb = $db->fetchrow();
-    $db->free_result();
-    switch($rb['log_type']) {
-      case "page":
-        switch($rb['action']) {
-          case "edit":
-            $t = $db->escape($rb['page_text']);
-            $e = $db->sql_query('UPDATE '.table_prefix.'page_text SET page_text=\''.$t.'\',char_tag=\''.$rb['char_tag'].'\' WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the state it was in on '.$rb['date_string'].'.');
-            break;
-          case "rename":
-            $t = $db->escape($rb['edit_summary']);
-            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$t.'\' WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been rolled back to the name it had ("'.$rb['edit_summary'].'") before '.$rb['date_string'].'.');
-            break;
-          case "prot":
-            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
-            break;
-          case "semiprot":
-            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=0 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been unprotected according to the log created at '.$rb['date_string'].'.');
-            break;
-          case "unprot":
-            $e = $db->sql_query('UPDATE '.table_prefix.'pages SET protected=1 WHERE urlname=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\'');
-            if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            else return('The page "'.$paths->pages[$paths->nslist[$rb['namespace']].$rb['page_id']]['name'].'" has been protected according to the log created at '.$rb['date_string'].'.');
-            break;
-          case "delete":
-            if(!$session->get_permissions('history_rollback_extra')) return('Administrative privileges are required for page undeletion.');
-            if(isset($paths->pages[$paths->cpage['urlname']])) return('You cannot raise a dead page that is alive.');
-            $name = str_replace('_', ' ', $rb['page_id']);
-            $e = $db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace) VALUES( \''.$name.'\', \''.$rb['page_id'].'\',\''.$rb['namespace'].'\' )');if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'logs WHERE page_id=\''.$rb['page_id'].'\' AND namespace=\''.$rb['namespace'].'\' AND log_type=\'page\' AND action=\'edit\' ORDER BY time_id DESC;'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            $r = $db->fetchrow();
-            $e = $db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace,page_text,char_tag) VALUES(\''.$rb['page_id'].'\',\''.$rb['namespace'].'\',\''.$db->escape($r['page_text']).'\',\''.$r['char_tag'].'\')'); if(!$e) return("An error occurred during the rollback operation.\nMySQL said: ".mysql_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
-            return('The page "'.$name.'" has been undeleted according to the log created at '.$rb['date_string'].'.');
-            break;
-          case "reupload":
-            if(!$session->get_permissions('history_rollbacks_extra')) return('Administrative privileges are required for file rollbacks.');
-            $newtime = time();
-            $newdate = date('d M Y h:i a');
-            if(!$db->sql_query('UPDATE '.table_prefix.'logs SET time_id='.$newtime.',date_string=\''.$newdate.'\' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
-            if(!$db->sql_query('UPDATE '.table_prefix.'files SET time_id='.$newtime.' WHERE time_id='.$id)) return('Error during query: '.mysql_error());
-            return('The file has been rolled back to the version uploaded on '.date('d M Y h:i a', (int)$id).'.');
-            break;
-          default:
-            return('Rollback of the action "'.$rb['action'].'" is not yet supported.');
-            break;
-        }
-        break;
-      case "security":
-      case "login":
-        return('A '.$rb['log_type'].'-related log entry cannot be rolled back.');
-        break;
-      default:
-        return('Unknown log entry type: "'.$rb['log_type'].'"');
-    }
-  }
-  
-  /**
-   * Posts a comment.
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $name the name of the person posting, defaults to current username/IP
-   * @param $subject the subject line of the comment
-   * @param $text the comment text
-   * @return string javascript code
-   */
-   
-  function addcomment($page_id, $namespace, $name, $subject, $text, $captcha_code = false, $captcha_id = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $_ob = '';
-    if(!$session->get_permissions('post_comments'))
-      return 'Access denied';
-    if(getConfig('comments_need_login') == '2' && !$session->user_logged_in) _die('Access denied to post comments: you need to be logged in first.');
-    if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
-    {
-      if(!$captcha_code || !$captcha_id) _die('BUG: PageUtils::addcomment: no CAPTCHA data passed to method');
-      $result = $session->get_captcha($captcha_id);
-      if($captcha_code != $result) _die('The confirmation code you entered was incorrect.');
-    }
-    $text = RenderMan::preprocess_text($text);
-    $name = $session->user_logged_in ? RenderMan::preprocess_text($session->username) : RenderMan::preprocess_text($name);
-    $subj = RenderMan::preprocess_text($subject);
-    if(getConfig('approve_comments')=='1') $appr = '0'; else $appr = '1';
-    $q = 'INSERT INTO '.table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\''.$page_id.'\',\''.$namespace.'\',\''.$subj.'\',\''.$text.'\',\''.$name.'\','.$session->user_id.','.$appr.','.time().')';
-    $e = $db->sql_query($q);
-    if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.mysql_error().'\n\nQuery:\n'.$q).'\'))');
-    else $_ob .= '<div class="info-box">Your comment has been posted.</div>';
-    return PageUtils::comments($page_id, $namespace, false, Array(), $_ob);
-  }
-  
-  /**
-   * Generates partly-compiled HTML/Javascript code to be eval'ed by the user's browser to display comments
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $action administrative action to perform, default is false
-   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
-   * @param $_ob text to prepend to output, used by PageUtils::addcomment
-   * @return array
-   * @access private
-   */
-   
-  function comments_raw($page_id, $namespace, $action = false, $flags = Array(), $_ob = '')
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $pname = $paths->nslist[$namespace] . $page_id;
-    
-    ob_start();
-    
-    if($action && $session->get_permissions('mod_comments')) // Nip hacking attempts in the bud
-    {
-      switch($action) {
-      case "delete":
-        if(isset($flags['id']))
-        {
-          $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.intval($flags['id']).' LIMIT 1;';
-        } else {
-          $n = $db->escape($flags['name']);
-          $s = $db->escape($flags['subj']);
-          $t = $db->escape($flags['text']);
-          $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
-        }
-        $e=$db->sql_query($q);
-        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
-        break;
-      case "approve":
-        if(isset($flags['id']))
-        {
-          $where = 'comment_id='.intval($flags['id']);
-        } else {
-          $n = $db->escape($flags['name']);
-          $s = $db->escape($flags['subj']);
-          $t = $db->escape($flags['text']);
-          $where = 'name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\'';
-        }
-        $q = 'SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.' LIMIT 1;';
-        $e = $db->sql_query($q);
-        if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
-        $r = $db->fetchrow();
-        $db->free_result();
-        $a = ( $r['approved'] ) ? '0' : '1';
-        $q = 'UPDATE '.table_prefix.'comments SET approved='.$a.' WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND '.$where.';';
-        $e=$db->sql_query($q);
-        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
-        if($a=='1') $v = 'Unapprove';
-        else $v = 'Approve';
-        echo 'document.getElementById("mdgApproveLink'.$_GET['id'].'").innerHTML="'.$v.'";';
-        break;
-      }
-    }
-    
-    if(!defined('ENANO_TEMPLATE_LOADED'))
-    {
-      $template->load_theme($session->theme, $session->style);
-    }
-    
-    $tpl = $template->makeParser('comment.tpl');
-    
-    $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=0;');
-    if(!$e) $db->_die('The comment text data could not be selected.');
-    $num_unapp = $db->numrows();
-    $db->free_result();
-    $e = $db->sql_query('SELECT * FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND approved=1;');
-    if(!$e) $db->_die('The comment text data could not be selected.');
-    $num_app = $db->numrows();
-    $db->free_result();
-    $lq = $db->sql_query('SELECT c.comment_id,c.subject,c.name,c.comment_data,c.approved,c.time,c.user_id,u.user_level,u.signature
-                  FROM '.table_prefix.'comments AS c
-                  LEFT JOIN '.table_prefix.'users AS u
-                    ON c.user_id=u.user_id
-                  WHERE page_id=\''.$page_id.'\'
-                  AND namespace=\''.$namespace.'\' ORDER BY c.time ASC;');
-    if(!$lq) _die('The comment text data could not be selected. '.mysql_error());
-    $_ob .= '<h3>Article Comments</h3>';
-    $n = ( $session->get_permissions('mod_comments')) ? $db->numrows() : $num_app;
-    if($n==1) $s = 'is '.$n.' comment'; else $s = 'are '.$n.' comments';
-    if($n < 1)
-    {
-      $_ob .= '<p>There are currently no comments on this '.strtolower($namespace).'';
-      if($namespace != 'Article') $_ob .= ' page';
-      $_ob .= '.</p>';
-    } else $_ob .= '<p>There '.$s.' on this article.</p>';
-    if($session->get_permissions('mod_comments') && $num_unapp > 0) $_ob .= ' <span style="color: #D84308">'.$num_unapp.' of those are unapproved.</span>';
-    elseif(!$session->get_permissions('mod_comments') && $num_unapp > 0) { $u = ($num_unapp == 1) ? "is $num_unapp comment" : "are $num_unapp comments"; $_ob .= ' However, there ' . $u . ' awating approval.'; }
-    $list = 'list = { ';
-    // _die(htmlspecialchars($ttext));
-    $i = -1;
-    while($row = $db->fetchrow($lq))
-    {
-      $i++;
-      $strings = Array();
-      $bool = Array();
-      if($session->get_permissions('mod_comments') || $row['approved']) {
-        $list .= $i . ' : { \'comment\' : unescape(\''.rawurlencode($row['comment_data']).'\'), \'name\' : unescape(\''.rawurlencode($row['name']).'\'), \'subject\' : unescape(\''.rawurlencode($row['subject']).'\'), }, ';
-        
-        // Comment ID (used in the Javascript apps)
-        $strings['ID'] = (string)$i;
-        
-        // Determine the name, and whether to link to the user page or not
-        $name = '';
-        if($row['user_id'] > 0) $name .= '<a href="'.makeUrlNS('User', str_replace(' ', '_', $row['name'])).'">';
-        $name .= $row['name'];
-        if($row['user_id'] > 0) $name .= '</a>';
-        $strings['NAME'] = $name; unset($name);
-        
-        // Subject
-        $s = $row['subject'];
-        if(!$row['approved']) $s .= ' <span style="color: #D84308">(Unapproved)</span>';
-        $strings['SUBJECT'] = $s;
-        
-        // Date and time
-        $strings['DATETIME'] = date('F d, Y h:i a', $row['time']);
-        
-        // User level
-        switch($row['user_level'])
-        {
-          default:
-          case USER_LEVEL_GUEST:
-            $l = 'Guest';
-            break;
-          case USER_LEVEL_MEMBER:
-            $l = 'Member';
-            break;
-          case USER_LEVEL_MOD:
-            $l = 'Moderator';
-            break;
-          case USER_LEVEL_ADMIN:
-            $l = 'Administrator';
-            break;
-        }
-        $strings['USER_LEVEL'] = $l; unset($l);
-        
-        // The actual comment data
-        $strings['DATA'] = RenderMan::render($row['comment_data']);
-        
-        if($session->get_permissions('edit_comments'))
-        {
-          // Edit link
-          $strings['EDIT_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=editcomment&amp;id='.$row['comment_id']).'" onclick="editComment(\''.$i.'\'); return false;" id="editbtn_'.$i.'">edit</a>';
-        
-          // Delete link
-          $strings['DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=deletecomment&amp;id='.$row['comment_id']).'" onclick="ajaxDeleteComment(\''.$i.'\'); return false;">delete</a>';
-        }
-        else
-        {
-          // Edit link
-          $strings['EDIT_LINK'] = '';
-        
-          // Delete link
-          $strings['DELETE_LINK'] = '';
-        }
-        
-        // Send PM link
-        $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/Compose/To/'.$row['name']).'">Send private message</a><br />' : '';
-        
-        // Add Buddy link
-        $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $row['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/FriendList/Add/'.$row['name']).'">Add to buddy list</a>' : '';
-        
-        // Mod links
-        $applink = '';
-        $applink .= '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=approve&amp;id='.$row['comment_id']).'" onclick="ajaxCommentAdmin(\'approve\', \''.$i.'\'); return false;" id="mdgApproveLink'.$i.'">';
-        if($row['approved']) $applink .= 'Unapprove';
-        else $applink .= 'Approve';
-        $applink .= '</a>';
-        $strings['MOD_APPROVE_LINK'] = $applink; unset($applink);
-        $strings['MOD_DELETE_LINK'] = '<a href="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=admin&amp;action=delete&amp;id='.$row['comment_id']).'" onclick="ajaxCommentAdmin(\'delete\', \''.$i.'\'); return false;">Delete</a>';
-        
-        // Signature
-        $strings['SIGNATURE'] = '';
-        if($row['signature'] != '') $strings['SIGNATURE'] = RenderMan::render($row['signature']);
-        
-        $bool['auth_mod'] = ($session->get_permissions('mod_comments')) ? true : false;
-        $bool['can_edit'] = ( ( $session->user_logged_in && $row['name'] == $session->username && $session->get_permissions('edit_comments') ) || $session->get_permissions('mod_comments') ) ? true : false;
-        $bool['signature'] = ( $strings['SIGNATURE'] == '' ) ? false : true;
-        
-        // Done processing and compiling, now let's cook it into HTML
-        $tpl->assign_vars($strings);
-        $tpl->assign_bool($bool);
-        $_ob .= $tpl->run();
-      }
-    }
-    if(getConfig('comments_need_login') != '2' || $session->user_logged_in)
-    {
-      if(!$session->get_permissions('post_comments'))
-      {
-        $_ob .= '<h3>Got something to say?</h3><p>Access to post comments on this page is denied.</p>';
-      }
-      else
-      {
-        $_ob .= '<h3>Got something to say?</h3>If you have comments or suggestions on this article, you can shout it out here.';
-        if(getConfig('approve_comments')=='1') $_ob .= '  Before your comment will be visible to the public, a moderator will have to approve it.';
-        if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) $_ob .= ' Because you are not logged in, you will need to enter a visual confirmation before your comment will be posted.';
-        $sn = $session->user_logged_in ? $session->username . '<input name="name" id="mdgScreenName" type="hidden" value="'.$session->username.'" />' : '<input name="name" id="mdgScreenName" type="text" size="35" />';
-        $_ob .= '  <a href="#" id="mdgCommentFormLink" style="display: none;" onclick="document.getElementById(\'mdgCommentForm\').style.display=\'block\';this.style.display=\'none\';return false;">Leave a comment...</a>
-        <div id="mdgCommentForm">
-        <h3>Comment form</h3>
-        <form action="'.makeUrlNS($namespace, $page_id, 'do=comments&amp;sub=postcomment').'" method="post" style="margin-left: 1em">
-        <table border="0">
-        <tr><td>Your name or screen name:</td><td>'.$sn.'</td></tr>
-        <tr><td>Comment subject:</td><td><input name="subj" id="mdgSubject" type="text" size="35" /></td></tr>';
-        if(getConfig('comments_need_login') == '1' && !$session->user_logged_in)
-        {
-          $session->kill_captcha();
-          $captcha = $session->make_captcha();
-          $_ob .= '<tr><td>Visual confirmation:<br /><small>Please enter the code you see on the right.</small></td><td><img src="'.makeUrlNS('Special', 'Captcha/'.$captcha).'" alt="Visual confirmation" style="cursor: pointer;" onclick="this.src = \''.makeUrlNS("Special", "Captcha/".$captcha).'/\'+Math.floor(Math.random() * 100000);" /><input name="captcha_id" id="mdgCaptchaID" type="hidden" value="'.$captcha.'" /><br />Code: <input name="captcha_input" id="mdgCaptchaInput" type="text" size="10" /><br /><small><script type="text/javascript">document.write("If you can\'t read the code, click on the image to generate a new one.");</script><noscript>If you can\'t read the code, please refresh this page to generate a new one.</noscript></small></td></tr>';
-        }
-        $_ob .= '
-        <tr><td valign="top">Comment text:<br />(most HTML will be stripped)</td><td><textarea name="text" id="mdgCommentArea" rows="10" cols="40"></textarea></td></tr>
-        <tr><td colspan="2" style="text-align: center;"><input type="submit" value="Submit Comment" /></td></tr>
-        </table>
-        </form>
-        </div>';
-      }
-    } else {
-      $_ob .= '<h3>Got something to say?</h3><p>You need to be logged in to post comments. <a href="'.makeUrlNS('Special', 'Login/'.$pname.'%2523comments').'">Log in</a></p>';
-    }
-    $list .= '};';
-    echo 'document.getElementById(\'ajaxEditContainer\').innerHTML = unescape(\''. rawurlencode($_ob) .'\');
-    ' . $list;
-    echo 'Fat.fade_all(); document.getElementById(\'mdgCommentForm\').style.display = \'none\'; document.getElementById(\'mdgCommentFormLink\').style.display="inline";';
-    
-    $ret = ob_get_contents();
-    ob_end_clean();
-    return Array($ret, $_ob);
-    
-  }
-  
-  /**
-   * Generates ready-to-execute Javascript code to be eval'ed by the user's browser to display comments
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $action administrative action to perform, default is false
-   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
-   * @param $_ob text to prepend to output, used by PageUtils::addcomment
-   * @return string
-   */
-   
-  function comments($page_id, $namespace, $action = false, $id = -1, $_ob = '')
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob);
-    return $r[0];
-  }
-  
-  /**
-   * Generates HTML code for comments - used in browser compatibility mode
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $action administrative action to perform, default is false
-   * @param $flags additional info for $action, shouldn't be used except when deleting/approving comments, etc.
-   * @param $_ob text to prepend to output, used by PageUtils::addcomment
-   * @return string
-   */
-  
-  function comments_html($page_id, $namespace, $action = false, $id = -1, $_ob = '')
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $r = PageUtils::comments_raw($page_id, $namespace, $action, $id, $_ob);
-    return $r[1];
-  }
-  
-  /**
-   * Updates comment data.
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $subject new subject
-   * @param $text new text
-   * @param $old_subject the old subject, unprocessed and identical to the value in the DB
-   * @param $old_text the old text, unprocessed and identical to the value in the DB
-   * @param $id the javascript list ID, used internally by the client-side app
-   * @return string
-   */
-  
-  function savecomment($page_id, $namespace, $subject, $text, $old_subject, $old_text, $id = -1)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('edit_comments'))
-      return 'result="BAD";error="Access denied"';
-    // Avoid SQL injection
-    $old_text    = $db->escape($old_text);
-    $old_subject = $db->escape($old_subject);
-    // Safety check - username/login
-    if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
-    {
-      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
-      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
-      $s = $db->sql_query($q);
-      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
-      $r = $db->fetchrow($s);
-      $db->free_result();
-      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
-    }
-    $s = RenderMan::preprocess_text($subject);
-    $t = RenderMan::preprocess_text($text);
-    $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_data=\''.$old_text.'\' AND subject=\''.$old_subject.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
-    $result = $db->sql_query($sql);
-    if($result)
-    {
-      return 'result="GOOD";
-                      list['.$id.'][\'subject\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $s))))).'\');
-                      list['.$id.'][\'comment\'] = unescape(\''.str_replace('%5Cn', '%0A', rawurlencode(str_replace('{{EnAnO:Newline}}', '\\n', stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t))))).'\'); id = '.$id.';
-      s = unescape(\''.rawurlencode($s).'\');
-      t = unescape(\''.str_replace('%5Cn', '<br \\/>', rawurlencode(RenderMan::render(str_replace('{{EnAnO:Newline}}', "\n", stripslashes(str_replace('\\n', '{{EnAnO:Newline}}', $t)))))).'\');';
-    }
-    else
-    {
-      return 'result="BAD"; error=unescape("'.rawurlencode('Enano encountered a problem whilst saving the comment.
-      Performed SQL:
-      '.$sql.'
-    
-      Error returned by MySQL: '.mysql_error()).'");';
-    }
-  }
-  
-  /**
-   * Updates comment data using the comment_id column instead of the old, messy way
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $subject new subject
-   * @param $text new text
-   * @param $id the comment ID (primary key in enano_comments table)
-   * @return string
-   */
-  
-  function savecomment_neater($page_id, $namespace, $subject, $text, $id)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!is_int($id)) die('PageUtils::savecomment: $id is not an integer, aborting for safety');
-    if(!$session->get_permissions('edit_comments'))
-      return 'Access denied';
-    // Safety check - username/login
-    if(!$session->get_permissions('mod_comments')) // allow mods to edit comments
-    {
-      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
-      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
-      $s = $db->sql_query($q);
-      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
-      $r = $db->fetchrow($s);
-      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
-      $db->free_result();
-    }
-    $s = RenderMan::preprocess_text($subject);
-    $t = RenderMan::preprocess_text($text);
-    $sql  = 'UPDATE '.table_prefix.'comments SET subject=\''.$s.'\',comment_data=\''.$t.'\' WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
-    $result = $db->sql_query($sql);
-    if($result)
-    return 'good';
-    else return 'Enano encountered a problem whilst saving the comment.
-    Performed SQL:
-    '.$sql.'
-    
-    Error returned by MySQL: '.mysql_error();
-  }
-  
-  /**
-   * Deletes a comment.
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $name the name the user posted under
-   * @param $subj the subject of the comment to be deleted
-   * @param $text the text of the comment to be deleted
-   * @param $id the javascript list ID, used internally by the client-side app
-   * @return string
-   */
-  
-  function deletecomment($page_id, $namespace, $name, $subj, $text, $id)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    if(!$session->get_permissions('edit_comments'))
-      return 'alert("Access to delete/edit comments is denied");';
-    
-    if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.');
-    $n = $db->escape($name);
-    $s = $db->escape($subj);
-    $t = $db->escape($text);
-    
-    // Safety check - username/login
-    if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
-    {
-      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
-      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_data=\''.$t.'\' AND subject=\''.$s.'\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
-      $s = $db->sql_query($q);
-      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
-      $r = $db->fetchrow($s);
-      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
-      $db->free_result();
-    }
-    $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND name=\''.$n.'\' AND subject=\''.$s.'\' AND comment_data=\''.$t.'\' LIMIT 1;';
-    $e=$db->sql_query($q);
-    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
-    return('good');
-  }
-  
-  /**
-   * Deletes a comment in a cleaner fashion.
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $id the comment ID (primary key)
-   * @return string
-   */
-  
-  function deletecomment_neater($page_id, $namespace, $id)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    if(!preg_match('#^([0-9]+)$#', (string)$id)) die('$_GET[id] is improperly formed.');
-    
-    if(!$session->get_permissions('edit_comments'))
-      return 'alert("Access to delete/edit comments is denied");';
-    
-    // Safety check - username/login
-    if(!$session->get_permissions('mod_comments')) // allows mods to delete comments
-    {
-      if(!$session->user_logged_in) _die('AJAX comment save safety check failed because you are not logged in. Sometimes this can happen because you are using a browser that does not send cookies as part of AJAX requests.<br /><br />Please log in and try again.');
-      $q = 'SELECT c.name FROM '.table_prefix.'comments c, '.table_prefix.'users u WHERE comment_id='.$id.' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND u.user_id=c.user_id;';
-      $s = $db->sql_query($q);
-      if(!$s) _die('SQL error during safety check: '.mysql_error().'<br /><br />Attempted SQL:<br /><pre>'.htmlspecialchars($q).'</pre>');
-      $r = $db->fetchrow($s);
-      if($db->numrows() < 1 || $r['name'] != $session->username) _die('Safety check failed, probably due to a hacking attempt.');
-      $db->free_result();
-    }
-    $q = 'DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\' AND comment_id='.$id.' LIMIT 1;';
-    $e=$db->sql_query($q);
-    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.mysql_error().'\n\nQuery:\n'.$q).'\'));');
-    return('good');
-  }
-  
-  /**
-   * Renames a page.
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $name the new name for the page
-   * @return string error string or success message
-   */
-   
-  function rename($page_id, $namespace, $name)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $pname = $paths->nslist[$namespace] . $page_id;
-    
-    $prot = ( ( $paths->pages[$pname]['protected'] == 2 && $session->user_logged_in && $session->reg_time + 60*60*24*4 < time() ) || $paths->pages[$pname]['protected'] == 1) ? true : false;
-    $wiki = ( ( $paths->pages[$pname]['wiki_mode'] == 2 && getConfig('wiki_mode') == '1') || $paths->pages[$pname]['wiki_mode'] == 1) ? true : false;
-    
-    if( empty($name)) die('Name is too short');
-    if( ( $session->get_permissions('rename') && ( ( $prot && $session->get_permissions('even_when_protected') ) || !$prot ) ) && ( $paths->namespace != 'Special' && $paths->namespace != 'Admin' )) {
-      $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'rename\', \''.$paths->cpage['urlname_nons'].'\', \''.$paths->namespace.'\', \''.$session->username.'\', \''.$paths->cpage['name'].'\')');
-      if(!$e) $db->_die('The page title could not be updated.');
-      $e = $db->sql_query('UPDATE '.table_prefix.'pages SET name=\''.$db->escape($name).'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-      if(!$e) $db->_die('The page title could not be updated.');
-      else return('The page "'.$paths->pages[$pname]['name'].'" has been renamed to "'.$name.'". You are encouraged to leave a comment explaining your action.
-
-You will see the change take effect the next time you reload this page.');
-    } else {
-      return('Access is denied.');
-    }
-  }
-  
-  /**
-   * Flushes (clears) the action logs for a given page
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @return string error/success string
-   */
-   
-  function flushlogs($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('clear_logs')) die('Administrative privileges are required to flush logs, you loser.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-    if(!$e) $db->_die('The log entries could not be deleted.');
-    $e = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-    if(!$e) $db->_die('The current page text could not be selected; as a result, creating the backup of the page failed. Please make a backup copy of the page by clicking Edit this page and then clicking Save Changes.');
-    $row = $db->fetchrow();
-    $db->free_result();
-    $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \''.$page_id.'\', \''.$namespace.'\', \''.$db->escape($row['page_text']).'\', \''.$row['char_tag'].'\', \''.$session->username.'\', \''."Automatic backup created when logs were purged".'\', '.'false'.');';
-    if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
-    return('The logs for this page have been cleared. A backup of this page has been added to the logs table so that this page can be restored in case of vandalism or spam later.');
-  }
-  
-  /**
-   * Deletes a page.
-   * @param $page_id the condemned page ID
-   * @param $namespace the condemned namespace
-   * @return string
-   */
-   
-  function deletepage($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $perms = $session->fetch_page_acl($page_id, $namespace);
-    if(!$perms->get_permissions('delete_page')) die('Administrative privileges are required to delete pages, you loser.');
-    $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'delete\', \''.$page_id.'\', \''.$namespace.'\', \''.$session->username.'\')');
-    if(!$e) $db->_die('The page log entry could not be inserted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
-    if(!$e) $db->_die('The page categorization entries could not be deleted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'comments WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
-    if(!$e) $db->_die('The page comments could not be deleted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'page_text WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
-    if(!$e) $db->_die('The page text entry could not be deleted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'pages WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'');
-    if(!$e) $db->_die('The page entry could not be deleted.');
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'files WHERE page_id=\''.$page_id.'\'');
-    if(!$e) $db->_die('The file entry could not be deleted.');
-    return('This page has been deleted. Note that there is still a log of edits and actions in the database, and anyone with admin rights can raise this page from the dead unless the log is cleared. If the deleted file is an image, there may still be cached thumbnails of it in the cache/ directory, which is inaccessible to users.');
-  }
-  
-  /**
-   * Increments the deletion votes for a page by 1, and adds the current username/IP to the list of users that have voted for the page to prevent dual-voting
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @return string
-   */
-   
-  function delvote($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('vote_delete'))
-      return 'Access denied';
-    $pname = $paths->nslist[$namespace] . $page_id;
-    $cv = $paths->pages[$pname]['delvotes'];
-    $ips = $paths->pages[$pname]['delvote_ips'];
-    $ips = explode('|', $ips);
-    if(in_array($_SERVER['REMOTE_ADDR'], $ips)) return('It appears that you have already voted to have this page deleted.');
-    if($session->user_logged_in)
-      if(in_array($session->username, $ips))
-        return('It appears that you have already voted to have this page deleted.');
-    $ips[] = $_SERVER['REMOTE_ADDR'];
-    if($session->user_logged_in) $ips[] = $session->username;
-    $ips = implode('|', $ips);
-    $ips = substr($ips, 1, strlen($ips));
-    $cv++;
-    $q = 'UPDATE '.table_prefix.'pages SET delvotes='.$cv.',delvote_ips=\''.$ips.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
-    $w = $db->sql_query($q);
-    if(!$w) return("Error updating pages table: ".mysql_error()."\n\nAttemped SQL:\n".$q);
-    return('Your vote to have this page deleted has been cast.'."\nYou are encouraged to leave a comment explaining the reason for your vote.");
-  }
-  
-  /**
-   * Resets the number of votes against a page to 0.
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @return string
-   */
-  
-  function resetdelvotes($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('vote_reset')) die('You need moderator rights in order to do this, stinkin\' hacker.');
-    $q = 'UPDATE '.table_prefix.'pages SET delvotes=0,delvote_ips=\'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\'';
-    $e = $db->sql_query($q);
-    if(!$e) $db->_die('The number of delete votes was not reset.');
-    else return('The number of votes for having this page deleted has been reset to zero.');
-  }
-  
-  /**
-   * Gets a list of styles for a given theme name.
-   * @param $id the name of the directory for the theme
-   * @return string Javascript code
-   */
-   
-  function getstyles()
-  {
-    $dir = './themes/'.$_GET['id'].'/css/';
-    $list = Array();
-    // Open a known directory, and proceed to read its contents
-    if (is_dir($dir)) {
-      if ($dh = opendir($dir)) {
-        while (($file = readdir($dh)) !== false) {
-          if(preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css') { // _printable.css should be included with every theme
-                                                                                    // it should be a copy of the original style, but
-                                                                                    // mostly black and white
-                                                                                    // Note to self: document this
-            $list[] = substr($file, 0, strlen($file)-4);
-          }
-        }
-        closedir($dh);
-      }
-    } else return($dir.' is not a dir');
-    $l = 'var list = new Array();';
-    $i = -1;
-    foreach($list as $li) {
-      $i++;
-      $l .= "list[$i] = '$li';";
-    }
-    return $l;
-  }
-  
-  /**
-   * Assembles a Javascript app with category information
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @return string Javascript code
-   */
-   
-  function catedit($page_id, $namespace)
-  {
-    $d = PageUtils::catedit_raw($page_id, $namespace);
-    return $d[0] . ' /* BEGIN CONTENT */ document.getElementById("ajaxEditContainer").innerHTML = unescape(\''.rawurlencode($d[1]).'\');';
-  }
-  
-  /**
-   * Does the actual HTML/javascript generation for cat editing, but returns an array
-   * @access private
-   */
-   
-  function catedit_raw($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    ob_start();
-    $_ob = '';
-    $e = $db->sql_query('SELECT category_id FROM '.table_prefix.'categories WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\'');
-    if(!$e) jsdie('Error selecting category information for current page: '.mysql_error());
-    $cat_current = Array();
-    while($r = $db->fetchrow())
-    {
-      $cat_current[] = $r;
-    }
-    $db->free_result();
-    $cat_all = Array();
-    for($i=0;$i<sizeof($paths->pages)/2;$i++)
-    {
-      if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i];
-    }
-    
-    // Make $cat_all an associative array, like $paths->pages
-    $sz = sizeof($cat_all);
-    for($i=0;$i<$sz;$i++)
-    {
-      $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i];
-    }
-    // Now, the "zipper" function - join the list of categories with the list of cats that this page is a part of
-    $cat_info = $cat_all;
-    for($i=0;$i<sizeof($cat_current);$i++)
-    {
-      $un = $cat_current[$i]['category_id'];
-      $cat_info[$un]['member'] = true;
-    }
-    // Now copy the information we just set into the numerically named keys
-    for($i=0;$i<sizeof($cat_info)/2;$i++)
-    {
-      $un = $cat_info[$i]['urlname_nons'];
-      $cat_info[$i] = $cat_info[$un];
-    }
-    
-    echo 'catlist = new Array();'; // Initialize the client-side category list
-    $_ob .= '<h3>Select which categories this page should be included in.</h3>
-             <form name="mdgCatForm" action="'.makeUrlNS($namespace, $page_id, 'do=catedit').'" method="post">';
-    if ( sizeof($cat_info) < 1 )
-    {
-      $_ob .= '<p>There are no categories on this site yet.</p>';
-    }
-    for ( $i = 0; $i < sizeof($cat_info) / 2; $i++ )
-    {
-      // Protection code added 1/3/07
-      // Updated 3/4/07
-      $is_prot = false;
-      $perms = $session->fetch_page_acl($cat_info[$i]['urlname_nons'], 'Category');
-      if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') ||
-         ( $cat_info[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) )
-         $is_prot = true;
-      $prot = ( $is_prot ) ? ' disabled="disabled" ' : '';
-      $prottext = ( $is_prot ) ? ' <img alt="(protected)" width="16" height="16" src="'.scriptPath.'/images/lock16.png" />' : '';
-      echo 'catlist['.$i.'] = \''.$cat_info[$i]['urlname_nons'].'\';';
-      $_ob .= '<span class="catCheck"><input '.$prot.' name="'.$cat_info[$i]['urlname_nons'].'" id="mdgCat_'.$cat_info[$i]['urlname_nons'].'" type="checkbox"';
-      if(isset($cat_info[$i]['member'])) $_ob .= ' checked="checked"';
-      $_ob .= '/>  <label for="mdgCat_'.$cat_info[$i]['urlname_nons'].'">'.$cat_info[$i]['name'].$prottext.'</label></span><br />';
-    }
-    
-    $disabled = ( sizeof($cat_info) < 1 ) ? 'disabled="disabled"' : '';
-      
-    $_ob .= '<div style="border-top: 1px solid #CCC; padding-top: 5px; margin-top: 10px;"><input name="__enanoSaveButton" ' . $disabled . ' style="font-weight: bold;" type="submit" onclick="ajaxCatSave(); return false;" value="Save changes" /> <input name="__enanoCatCancel" type="submit" onclick="ajaxReset(); return false;" value="Cancel" /></div></form>';
-    
-    $cont = ob_get_contents();
-    ob_end_clean();
-    return Array($cont, $_ob);
-  }
-  
-  /**
-   * Saves category information
-   * WARNING: If $which_cats is empty, all the category information for the selected page will be nuked!
-   * @param $page_id string the page ID
-   * @param $namespace string the namespace
-   * @param $which_cats array associative array of categories to put the page in
-   * @return string "GOOD" on success, error string on failure
-   */
-  
-  function catsave($page_id, $namespace, $which_cats)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('edit_cat')) return('Insufficient privileges to change category information');
-    
-    $page_perms = $session->fetch_page_acl($page_id, $namespace);
-    $page_data =& $paths->pages[$paths->nslist[$namespace].$page_id];
-    
-    $cat_all = Array();
-    for($i=0;$i<sizeof($paths->pages)/2;$i++)
-    {
-      if($paths->pages[$i]['namespace']=='Category') $cat_all[] = $paths->pages[$i];
-    }
-    
-    // Make $cat_all an associative array, like $paths->pages
-    $sz = sizeof($cat_all);
-    for($i=0;$i<$sz;$i++)
-    {
-      $cat_all[$cat_all[$i]['urlname_nons']] = $cat_all[$i];
-    }
-    
-    $rowlist = Array();
-    
-    for($i=0;$i<sizeof($cat_all)/2;$i++)
-    {
-      $auth = true;
-      $perms = $session->fetch_page_acl($cat_all[$i]['urlname_nons'], 'Category');
-      if ( !$session->get_permissions('edit_cat') || !$perms->get_permissions('edit_cat') ||
-         ( $cat_all[$i]['really_protected'] && !$perms->get_permissions('even_when_protected') ) ||
-         ( !$page_perms->get_permissions('even_when_protected') && $page_data['protected'] == '1' ) )
-         $auth = false;
-      if(!$auth)
-      {
-        // Find out if the page is currently in the category
-        $q = $db->sql_query('SELECT * FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-        if(!$q)
-          return 'MySQL error: '.$db->get_error();
-        if($db->numrows() > 0)
-        {
-          $auth = true;
-          $which_cats[$cat_all[$i]['urlname_nons']] = true; // Force the category to stay in its current state
-        }
-        $db->free_result();
-      }
-      if(isset($which_cats[$cat_all[$i]['urlname_nons']]) && $which_cats[$cat_all[$i]['urlname_nons']] == true /* for clarity ;-) */ && $auth ) $rowlist[] = '(\''.$page_id.'\', \''.$namespace.'\', \''.$cat_all[$i]['urlname_nons'].'\')';
-    }
-    if(sizeof($rowlist) > 0)
-    {
-      $val = implode(',', $rowlist);
-      $q = 'INSERT INTO '.table_prefix.'categories(page_id,namespace,category_id) VALUES' . $val . ';';
-      $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-      if(!$e) $db->_die('The old category data could not be deleted.');
-      $e = $db->sql_query($q);
-      if(!$e) $db->_die('The new category data could not be inserted.');
-      return('GOOD');
-    }
-    else
-    {
-      $e = $db->sql_query('DELETE FROM '.table_prefix.'categories WHERE page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-      if(!$e) $db->_die('The old category data could not be deleted.');
-      return('GOOD');
-    }
-  }
-  
-  /**
-   * Sets the wiki mode level for a page.
-   * @param $page_id string the page ID
-   * @param $namespace string the namespace
-   * @param $level int 0 for off, 1 for on, 2 for use global setting
-   * @return string "GOOD" on success, error string on failure
-   */
-  
-  function setwikimode($page_id, $namespace, $level)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('set_wiki_mode')) return('Insufficient access rights');
-    if(!isset($level) || (isset($level) && !preg_match('#^([0-2]){1}$#', (string)$level))) return('Invalid mode string');
-    $q = $db->sql_query('UPDATE '.table_prefix.'pages SET wiki_mode='.$level.' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-    if(!$q) return('Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
-    return('GOOD');
-  }
-  
-  /**
-   * Sets the access password for a page.
-   * @param $page_id string the page ID
-   * @param $namespace string the namespace
-   * @param $pass string the SHA1 hash of the password - if the password doesn't match the regex ^([0-9a-f]*){40,40}$ it will be sha1'ed
-   * @return string
-   */
-  
-  function setpass($page_id, $namespace, $pass)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    // Determine permissions
-    if($paths->pages[$paths->nslist[$namespace].$page_id]['password'] != '')
-      $a = $session->get_permissions('password_reset');
-    else
-      $a = $session->get_permissions('password_set');
-    if(!$a)
-      return 'Access is denied';
-    if(!isset($pass)) return('Password was not set on URL');
-    $p = $pass;
-    if(!preg_match('#([0-9a-f]){40,40}#', $p)) $p = sha1($p);
-    if($p=='da39a3ee5e6b4b0d3255bfef95601890afd80709') $p = '';
-    $e = $db->sql_query('UPDATE '.table_prefix.'pages SET password=\''.$p.'\' WHERE urlname=\''.$page_id.'\' AND namespace=\''.$namespace.'\';');
-    if(!$e) die('PageUtils::setpass(): Error during update query: '.mysql_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
-    if($p=='') return('The password for this page has been disabled.');
-    else return('The password for this page has been set.');
-  }
-  
-  /**
-   * Generates some preview HTML
-   * @param $text string the wikitext to use
-   * @return string
-   */
-   
-  function genPreview($text)
-  {
-    return '<div class="info-box"><b>Reminder:</b> This is only a preview - your changes to this page have not yet been saved.</div><div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: 250px; overflow: auto; margin: 1em 0 1em 1em;">'.RenderMan::render(RenderMan::preprocess_text($text, false, false)).'</div>';
-  }
-  
-  /**
-   * Makes a scrollable box
-   * @param string $text the inner HTML
-   * @param int $height Optional - the maximum height. Defaults to 250.
-   * @return string
-   */
-   
-  function scrollBox($text, $height = 250)
-  {
-    return '<div style="background-color: #F8F8F8; padding: 10px; border: 1px dashed #406080; max-height: '.(string)intval($height).'px; overflow: auto; margin: 1em 0 1em 1em;">'.$text.'</div>';
-  }
-  
-  /**
-   * Generates a diff summary between two page revisions.
-   * @param $page_id the page ID
-   * @param $namespace the namespace
-   * @param $id1 the time ID of the first revision
-   * @param $id2 the time ID of the second revision
-   * @return string XHTML-formatted diff
-   */
-   
-  function pagediff($page_id, $namespace, $id1, $id2)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('history_view'))
-      return 'Access denied';
-    if(!preg_match('#^([0-9]+)$#', (string)$id1) ||
-       !preg_match('#^([0-9]+)$#', (string)$id2  )) return 'SQL injection attempt';
-    // OK we made it through security
-    // Safest way to make sure we don't end up with the revisions in wrong columns is to make 2 queries
-    if(!$q1 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id1.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
-    if(!$q2 = $db->sql_query('SELECT page_text,char_tag,author,edit_summary FROM '.table_prefix.'logs WHERE time_id='.$id2.' AND log_type=\'page\' AND action=\'edit\' AND page_id=\''.$page_id.'\' AND namespace=\''.$namespace.'\';')) return 'MySQL error: '.mysql_error();
-    $row1 = $db->fetchrow($q1);
-    $db->free_result($q1);
-    $row2 = $db->fetchrow($q2);
-    $db->free_result($q2);
-    if(sizeof($row1) < 1 || sizeof($row2) < 2) return 'Couldn\'t find any rows that matched the query. The time ID probably doesn\'t exist in the logs table.';
-    $text1 = $row1['page_text'];
-    $text2 = $row2['page_text'];
-    $time1 = date('F d, Y h:i a', $id1);
-    $time2 = date('F d, Y h:i a', $id2);
-    $_ob = "
-    <p>Comparing revisions: {$time1} &rarr; {$time2}</p>
-    ";
-    // Free some memory
-    unset($row1, $row2, $q1, $q2);
-    
-    $_ob .= RenderMan::diff($text1, $text2);
-    return $_ob;
-  }
-  
-  /**
-   * Gets ACL information about the selected page for target type X and target ID Y.
-   * @param string $page_id The page ID
-   * @param string $namespace The namespace
-   * @param array $parms What to select. This is an array purely for JSON compatibility. It should be an associative array with keys target_type and target_id.
-   * @return array
-   */
-   
-  function acl_editor($parms = Array())
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$session->get_permissions('edit_acl') && $session->user_level < USER_LEVEL_ADMIN)
-      return 'Access is denied.';
-    $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false;
-    $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false;
-    $page_id =& $parms['page_id'];
-    $namespace =& $parms['namespace'];
-    $page_where_clause      = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\''.$db->escape($page_id).'\' AND a.namespace=\''.$db->escape($namespace).'\'';
-    $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\'';
-    //die(print_r($page_id,true));
-    $template->load_theme();
-    // $perms_obj = $session->fetch_page_acl($page_id, $namespace);
-    $perms_obj =& $session;
-    $return = Array();
-    if ( !file_exists(ENANO_ROOT . '/themes/' . $session->theme . '/acledit.tpl') )
-    {
-      return Array(
-        'mode' => 'error',
-        'error' => 'It seems that (a) the file acledit.tpl is missing from these theme, and (b) the JSON response is working.',
-      );
-    }
-    $return['template'] = $template->extract_vars('acledit.tpl');
-    $return['page_id'] = $page_id;
-    $return['namespace'] = $namespace;
-    if(isset($parms['mode']))
-    {
-      switch($parms['mode'])
-      {
-        case 'listgroups':
-          $return['groups'] = Array();
-          $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups ORDER BY group_name ASC;');
-          while($row = $db->fetchrow())
-          {
-            $return['groups'][] = Array(
-              'id' => $row['group_id'],
-              'name' => $row['group_name'],
-              );
-          }
-          $db->free_result();
-          break;
-        case 'seltarget':
-          $return['mode'] = 'seltarget';
-          $return['acl_types'] = $perms_obj->acl_types;
-          $return['acl_deps'] = $perms_obj->acl_deps;
-          $return['acl_descs'] = $perms_obj->acl_descs;
-          $return['target_type'] = $parms['target_type'];
-          $return['target_id'] = $parms['target_id'];
-          switch($parms['target_type'])
-          {
-            case ACL_TYPE_USER:
-              $q = $db->sql_query('SELECT a.rules,u.user_id FROM '.table_prefix.'users AS u
-                  LEFT JOIN '.table_prefix.'acl AS a
-                    ON a.target_id=u.user_id
-                  WHERE a.target_type='.ACL_TYPE_USER.'
-                    AND u.username=\''.$db->escape($parms['target_id']).'\'
-                    '.$page_where_clause.';');
-              if(!$q)
-                return(Array('mode'=>'error','error'=>mysql_error()));
-              if($db->numrows() < 1)
-              {
-                $return['type'] = 'new';
-                $q = $db->sql_query('SELECT user_id FROM '.table_prefix.'users WHERE username=\''.$db->escape($parms['target_id']).'\';');
-                if(!$q)
-                  return(Array('mode'=>'error','error'=>mysql_error()));
-                if($db->numrows() < 1)
-                  return Array('mode'=>'error','error'=>'The username you entered was not found.');
-                $row = $db->fetchrow();
-                $return['target_name'] = $return['target_id'];
-                $return['target_id'] = intval($row['user_id']);
-                $return['current_perms'] = $session->acl_types;
-              }
-              else
-              {
-                $return['type'] = 'edit';
-                $row = $db->fetchrow();
-                $return['target_name'] = $return['target_id'];
-                $return['target_id'] = intval($row['user_id']);
-                $return['current_perms'] = $session->acl_merge($perms_obj->acl_types, $session->string_to_perm($row['rules']));
-              }
-              $db->free_result();
-              // Eliminate types that don't apply to this namespace
-              if ( $namespace )
-              {
-                foreach ( $return['current_perms'] AS $i => $perm )
-                {
-                  if ( ( $page_id != null && $namespace != null ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) )
-                  {
-                    // echo "// SCOPE CONTROL: eliminating: $i\n";
-                    unset($return['current_perms'][$i]);
-                    unset($return['acl_types'][$i]);
-                    unset($return['acl_descs'][$i]);
-                    unset($return['acl_deps'][$i]);
-                  }
-                }
-              }
-              break;
-            case ACL_TYPE_GROUP:
-              $q = $db->sql_query('SELECT a.rules,g.group_name,g.group_id FROM '.table_prefix.'groups AS g
-                  LEFT JOIN '.table_prefix.'acl AS a
-                    ON a.target_id=g.group_id
-                  WHERE a.target_type='.ACL_TYPE_GROUP.'
-                    AND g.group_id=\''.intval($parms['target_id']).'\'
-                    '.$page_where_clause.';');
-              if(!$q)
-                return(Array('mode'=>'error','error'=>mysql_error()));
-              if($db->numrows() < 1)
-              {
-                $return['type'] = 'new';
-                $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups WHERE group_id=\''.intval($parms['target_id']).'\';');
-                if(!$q)
-                  return(Array('mode'=>'error','error'=>mysql_error()));
-                if($db->numrows() < 1)
-                  return Array('mode'=>'error','error'=>'The group ID you submitted is not valid.');
-                $row = $db->fetchrow();
-                $return['target_name'] = $row['group_name'];
-                $return['target_id'] = intval($row['group_id']);
-                $return['current_perms'] = $session->acl_types;
-              }
-              else
-              {
-                $return['type'] = 'edit';
-                $row = $db->fetchrow();
-                $return['target_name'] = $row['group_name'];
-                $return['target_id'] = intval($row['group_id']);
-                $return['current_perms'] = $session->acl_merge($session->acl_types, $session->string_to_perm($row['rules']));
-              }
-              $db->free_result();
-              // Eliminate types that don't apply to this namespace
-              if ( $namespace )
-              {
-                foreach ( $return['current_perms'] AS $i => $perm )
-                {
-                  if ( ( $page_id != false && $namespace != false ) && ( !in_array ( $namespace, $session->acl_scope[$i] ) && !in_array('All', $session->acl_scope[$i]) ) )
-                  {
-                    // echo "// SCOPE CONTROL: eliminating: $i\n"; //; ".print_r($namespace,true).":".print_r($page_id,true)."\n";
-                    unset($return['current_perms'][$i]);
-                    unset($return['acl_types'][$i]);
-                    unset($return['acl_descs'][$i]);
-                    unset($return['acl_deps'][$i]);
-                  }
-                }
-              }
-              //return Array('mode'=>'debug','text'=>print_r($return, true));
-              break;
-            default:
-              return Array('mode'=>'error','error','Invalid ACL type ID');
-              break;
-          }
-          return $return;
-          break;
-        case 'save_new':
-        case 'save_edit':
-          $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
-            '.$page_where_clause_lite.';');
-          if(!$q)
-            return Array('mode'=>'error','error'=>mysql_error());
-          $rules = $session->perm_to_string($parms['perms']);
-          if ( sizeof ( $rules ) < 1 )
-          {
-            return array(
-                'mode' => 'error', 
-                'error' => 'Supplied rule list has a length of zero'
-              );
-          }
-          $q = ($page_id && $namespace) ? 'INSERT INTO '.table_prefix.'acl ( target_type, target_id, page_id, namespace, rules )
-                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($page_id).'\', \''.$db->escape($namespace).'\', \''.$db->escape($rules).'\' )' :
-                                          'INSERT INTO '.table_prefix.'acl ( target_type, target_id, rules )
-                                             VALUES( '.intval($parms['target_type']).', '.intval($parms['target_id']).', \''.$db->escape($rules).'\' )';
-          if(!$db->sql_query($q)) return Array('mode'=>'error','error'=>mysql_error());
-          return Array(
-              'mode' => 'success',
-              'target_type' => $parms['target_type'],
-              'target_id' => $parms['target_id'],
-              'target_name' => $parms['target_name'],
-              'page_id' => $page_id,
-              'namespace' => $namespace,
-            );
-          break;
-        case 'delete':
-          $q = $db->sql_query('DELETE FROM '.table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).'
-            '.$page_where_clause_lite.';');
-          if(!$q)
-            return Array('mode'=>'error','error'=>mysql_error());
-          return Array(
-              'mode' => 'delete',
-              'target_type' => $parms['target_type'],
-              'target_id' => $parms['target_id'],
-              'target_name' => $parms['target_name'],
-              'page_id' => $page_id,
-              'namespace' => $namespace,
-            );
-          break;
-        default:
-          return Array('mode'=>'error','error'=>'Hacking attempt');
-          break;
-      }
-    }
-    return $return;
-  }
-  
-  /**
-   * Same as PageUtils::acl_editor(), but the parms are a JSON string instead of an array. This also returns a JSON string.
-   * @param string $parms Same as PageUtils::acl_editor/$parms, but should be a valid JSON string.
-   * @return string
-   */
-   
-  function acl_json($parms = '{ }')
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
-    $parms = $json->decode($parms);
-    $ret = PageUtils::acl_editor($parms);
-    $ret = $json->encode($ret);
-    return $ret;
-  }
-  
-  /**
-   * A non-Javascript frontend for the ACL API.
-   * @param array The request data, if any, this should be in the format required by PageUtils::acl_editor()
-   */
-   
-  function aclmanager($parms)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    ob_start();
-    // Convenience
-    $formstart = '<form 
-                    action="' . makeUrl($paths->page, 'do=aclmanager', true) . '"
-                    method="post" enctype="multipart/form-data"
-                    onsubmit="if(!submitAuthorized) return false;"
-                    >';
-    $formend   = '</form>';
-    $parms    = PageUtils::acl_preprocess($parms);
-    $response = PageUtils::acl_editor($parms);
-    $response = PageUtils::acl_postprocess($response);
-    
-    //die('<pre>' . htmlspecialchars(print_r($response, true)) . '</pre>');
-    
-    switch($response['mode'])
-    {
-      case 'debug':
-        echo '<pre>' . htmlspecialchars($response['text']) . '</pre>';
-        break;
-      case 'stage1':
-        echo '<h3>Manage page access</h3>
-              <p>Please select who should be affected by this access rule.</p>';
-        echo $formstart;
-        echo '<p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_GROUP . '" checked="checked" /> A usergroup</label></p>
-              <p><select name="data[target_id_grp]">';
-        foreach ( $response['groups'] as $group )
-        {
-          echo '<option value="' . $group['id'] . '">' . $group['name'] . '</option>';
-        }
-        echo '</select></p>
-              <p><label><input type="radio" name="data[target_type]" value="' . ACL_TYPE_USER . '" /> A specific user</label></p>
-              <p>' . $template->username_field('data[target_id_user]') . '</p>
-              <p>What should this access rule control?</p>
-              <p><label><input name="data[scope]" value="only_this" type="radio" checked="checked" /> Only this page</p>
-              <p><label><input name="data[scope]" value="entire_site" type="radio" /> The entire site</p>
-              <div style="margin: 0 auto 0 0; text-align: right;">
-                <input name="data[mode]" value="seltarget" type="hidden" />
-                <input type="hidden" name="data[page_id]" value="' . $paths->cpage['urlname_nons'] . '" />
-                <input type="hidden" name="data[namespace]" value="' . $paths->namespace . '" />
-                <input type="submit" value="Next &gt;" />
-              </div>';
-        echo $formend;
-        break;
-      case 'success':
-        echo '<div class="info-box">
-                <b>Permissions updated</b><br />
-                The permissions for ' . $response['target_name'] . ' on this page have been updated successfully.<br />
-                ' . $formstart . '
-                <input type="hidden" name="data[mode]" value="seltarget" />
-                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
-                <input type="hidden" name="data[target_id_user]" value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
-                <input type="hidden" name="data[target_id_grp]"  value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
-                <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
-                <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
-                <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
-                <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
-                ' . $formend . '
-              </div>';
-        break;
-      case 'delete':
-        echo '<div class="info-box">
-                <b>Rule deleted</b><br />
-                The selected access rule has been successfully deleted.<br />
-                ' . $formstart . '
-                <input type="hidden" name="data[mode]" value="seltarget" />
-                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
-                <input type="hidden" name="data[target_id_user]" value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
-                <input type="hidden" name="data[target_id_grp]"  value="' . ( ( intval($response['target_type']) == ACL_TYPE_USER ) ? $response['target_name'] : $response['target_id'] ) .'" />
-                <input type="hidden" name="data[scope]" value="' . ( ( $response['page_id'] ) ? 'only_this' : 'entire_site' ) . '" />
-                <input type="hidden" name="data[page_id]" value="' . ( ( $response['page_id'] ) ? $response['page_id'] : 'false' ) . '" />
-                <input type="hidden" name="data[namespace]" value="' . ( ( $response['namespace'] ) ? $response['namespace'] : 'false' ) . '" />
-                <input type="submit" value="Return to ACL editor" /> <input type="submit" name="data[act_go_stage1]" value="Return to user/scope selection" />
-                ' . $formend . '
-              </div>';
-        break;
-      case 'seltarget':
-        if ( $response['type'] == 'edit' )
-        {
-          echo '<h3>Editing permissions</h3>';
-        }
-        else
-        {
-          echo '<h3>Create new rule</h3>';
-        }
-        $type  = ( $response['target_type'] == ACL_TYPE_GROUP ) ? 'group' : 'user';
-        $scope = ( $response['page_id'] ) ? 'this page' : 'this entire site';
-        echo 'This panel allows you to edit what the '.$type.' "'.$response['target_name'].'" can do on <b>'.$scope.'</b>. Unless you set a permission to "Deny", these permissions may be overridden by other rules.';
-        echo $formstart;
-        $parser = $template->makeParserText( $response['template']['acl_field_begin'] );
-        echo $parser->run();
-        $parser = $template->makeParserText( $response['template']['acl_field_item'] );
-        $cls = 'row2';
-        foreach ( $response['acl_types'] as $acl_type => $value )
-        {
-          $vars = Array(
-              'FIELD_DENY_CHECKED' => '',
-              'FIELD_DISALLOW_CHECKED' => '',
-              'FIELD_WIKIMODE_CHECKED' => '',
-              'FIELD_ALLOW_CHECKED' => '',
-            );
-          $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-          $vars['ROW_CLASS'] = $cls;
-          
-          switch ( $response['current_perms'][$acl_type] )
-          {
-            case AUTH_ALLOW:
-              $vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"';
-              break;
-            case AUTH_WIKIMODE:
-              $vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"';
-              break;
-            case AUTH_DISALLOW:
-            default:
-              $vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"';
-              break;
-             case AUTH_DENY:
-              $vars['FIELD_DENY_CHECKED'] = 'checked="checked"';
-              break;
-          }
-          $vars['FIELD_NAME'] = 'data[perms][' . $acl_type . ']';
-          $vars['FIELD_DESC'] = $response['acl_descs'][$acl_type];
-          $parser->assign_vars($vars);
-          echo $parser->run();
-        }
-        $parser = $template->makeParserText( $response['template']['acl_field_end'] );
-        echo $parser->run();
-        echo '<div style="margin: 10px auto 0 0; text-align: right;">
-                <input name="data[mode]" value="save_' . $response['type'] . '" type="hidden" />
-                <input type="hidden" name="data[page_id]" value="'   . (( $response['page_id']   ) ? $response['page_id']   : 'false') . '" />
-                <input type="hidden" name="data[namespace]" value="' . (( $response['namespace'] ) ? $response['namespace'] : 'false') . '" />
-                <input type="hidden" name="data[target_type]" value="' . $response['target_type'] . '" />
-                <input type="hidden" name="data[target_id]" value="' . $response['target_id'] . '" />
-                <input type="hidden" name="data[target_name]" value="' . $response['target_name'] . '" />
-                <input type="submit" value="Save changes" />&nbsp;&nbsp;<input type="submit" name="data[act_delete_rule]" value="Delete rule" style="color: #AA0000;" onclick="return confirm(\'Do you really want to delete this ACL rule?\');" />
-              </div>';
-        echo $formend;
-        break;
-      case 'error':
-        ob_end_clean();
-        die_friendly('Error occurred', '<p>Error returned by permissions API:</p><pre>' . htmlspecialchars($response['error']) . '</pre>');
-        break;
-    }
-    $ret = ob_get_contents();
-    ob_end_clean();
-    echo
-      $template->getHeader() .
-      $ret .
-      $template->getFooter();
-  }
-  
-  /**
-   * Preprocessor to turn the form-submitted data from the ACL editor into something the backend can handle
-   * @param array The posted data
-   * @return array
-   * @access private
-   */
-   
-  function acl_preprocess($parms)
-  {
-    if ( !isset($parms['mode']) )
-      // Nothing to do
-      return $parms;
-    switch ( $parms['mode'] )
-    {
-      case 'seltarget':
-        
-        // Who's affected?
-        $parms['target_type'] = intval( $parms['target_type'] );
-        $parms['target_id'] = ( $parms['target_type'] == ACL_TYPE_GROUP ) ? $parms['target_id_grp'] : $parms['target_id_user'];
-        
-      case 'save_edit':
-      case 'save_new':
-        if ( isset($parms['act_delete_rule']) )
-        {
-          $parms['mode'] = 'delete';
-        }
-        
-        // Scope (just this page or entire site?)
-        if ( $parms['scope'] == 'entire_site' || ( $parms['page_id'] == 'false' && $parms['namespace'] == 'false' ) )
-        {
-          $parms['page_id']   = false;
-          $parms['namespace'] = false;
-        }
-        
-        break;
-    }
-    
-    if ( isset($parms['act_go_stage1']) )
-    {
-      $parms = array(
-          'mode' => 'listgroups'
-        );
-    }
-    
-    return $parms;
-  }
-  
-  function acl_postprocess($response)
-  {
-    if(!isset($response['mode']))
-    {
-      if ( isset($response['groups']) )
-        $response['mode'] = 'stage1';
-      else
-        $response = Array(
-            'mode' => 'error',
-            'error' => 'Invalid action passed by API backend.',
-          );
-    }
-    return $response;
-  }
-   
-}
-
-?>
--- a/includes/paths.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,808 +0,0 @@
-<?php
-
-/**
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 (Banshee)
- * Copyright (C) 2006-2007 Dan Fuhry
- * paths.php - The part of Enano that actually manages content. Everything related to page handling and namespaces is in here.
- *
- * This program is Free Software; you can redistribute 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 details.
- *
- * @package Enano
- * @subpackage PathManager
- * @see http://enano.homelinux.org/Help:API_Documentation
- */
- 
-class pathManager {
-  var $pages, $custom_page, $cpage, $page, $fullpage, $page_exists, $namespace, $nslist, $admin_tree, $wiki_mode, $page_protected, $template_cache;
-  function __construct()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $GLOBALS['paths'] =& $this;
-    $this->pages = Array();
-    
-    dc_here('paths: setting up namespaces, admin nodes');
-    
-    // DEFINE NAMESPACES HERE
-    // The key names should NOT EVER be changed, or Enano will be very broken
-    $this->nslist = Array(
-      'Article' =>'',
-      'User'    =>'User:',
-      'File'    =>'File:',
-      'Help'    =>'Help:',
-      'Admin'   =>'Admin:',
-      'Special' =>'Special:',
-      'System'  =>'Enano:',
-      'Template'=>'Template:',
-      'Category'=>'Category:',
-      'Project' =>str_replace(' ', '_', getConfig('site_name')).':',
-      );
-    
-    // ACL types
-    // Note: you can set any of these to AUTH_DENY to universally and unconditionally deny access to the selected action.
-    // These can also be added from within plugins
-    
-    $session->register_acl_type('read',                   AUTH_ALLOW,    'Read page(s)');
-    $session->register_acl_type('post_comments',          AUTH_ALLOW,    'Post comments',                                                                                            Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('edit_comments',          AUTH_ALLOW,    'Edit own comments',                                                                                        Array('post_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('edit_page',              AUTH_WIKIMODE, 'Edit page',                                                                                                Array('view_source'),                                     'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('view_source',            AUTH_WIKIMODE, 'View source',                                                                                              Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category'); // Only used if the page is protected
-    $session->register_acl_type('mod_comments',           AUTH_DISALLOW, 'Moderate comments',                                                                                        Array('edit_comments'),                                   'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('history_view',           AUTH_WIKIMODE, 'View history/diffs',                                                                                       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('history_rollback',       AUTH_DISALLOW, 'Rollback history',                                                                                         Array('history_view'),                                    'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('history_rollback_extra', AUTH_DISALLOW, 'Undelete page(s)',                                                                                         Array('history_rollback'),                                'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('protect',                AUTH_DISALLOW, 'Protect page(s)',                                                                                          Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('rename',                 AUTH_WIKIMODE, 'Rename page(s)',                                                                                           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('clear_logs',             AUTH_DISALLOW, 'Clear page logs (dangerous)',                                                                              Array('read', 'protect', 'even_when_protected'),          'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('vote_delete',            AUTH_ALLOW,    'Vote to delete',                                                                                           Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('vote_reset',             AUTH_DISALLOW, 'Reset delete votes',                                                                                       Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('delete_page',            AUTH_DISALLOW, 'Delete page(s)',                                                                                           Array(),                                                  'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('set_wiki_mode',          AUTH_DISALLOW, 'Set per-page wiki mode',                                                                                   Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('password_set',           AUTH_DISALLOW, 'Set password',                                                                                             Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('password_reset',         AUTH_DISALLOW, 'Disable/reset password',                                                                                   Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('mod_misc',               AUTH_DISALLOW, 'Super moderator (generate SQL backtraces, view IP addresses, and send large numbers of private messages)', Array(),                                                  'All');
-    $session->register_acl_type('edit_cat',               AUTH_WIKIMODE, 'Edit categorization',                                                                                      Array('read'),                                            'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('even_when_protected',    AUTH_DISALLOW, 'Allow editing, renaming, and categorization even when protected',                                          Array('edit_page', 'rename', 'mod_comments', 'edit_cat'), 'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('upload_files',           AUTH_DISALLOW, 'Upload files',                                                                                             Array('create_page'),                                     'Article|User|Project|Template|File|Help|System|Category|Special');
-    $session->register_acl_type('upload_new_version',     AUTH_WIKIMODE, 'Upload new versions of files',                                                                             Array('upload_files'),                                    'Article|User|Project|Template|File|Help|System|Category|Special');
-    $session->register_acl_type('create_page',            AUTH_WIKIMODE, 'Create pages',                                                                                             Array(),                                                  'Article|User|Project|Template|File|Help|System|Category|Special');
-    $session->register_acl_type('php_in_pages',           AUTH_DISALLOW, 'Embed PHP code in pages',                                                                                  Array('edit_page'),                                       'Article|User|Project|Template|File|Help|System|Category');
-    $session->register_acl_type('edit_acl',               AUTH_DISALLOW, 'Edit access control lists', Array('read', 'post_comments', 'edit_comments', 'edit_page', 'view_source', 'mod_comments', 'history_view', 'history_rollback', 'history_rollback_extra', 'protect', 'rename', 'clear_logs', 'vote_delete', 'vote_reset', 'delete_page', 'set_wiki_mode', 'password_set', 'password_reset', 'mod_misc', 'edit_cat', 'even_when_protected', 'upload_files', 'upload_new_version', 'create_page', 'php_in_pages'));
-    
-    // DO NOT add new admin pages here! Use a plugin to call $paths->addAdminNode();
-    $this->addAdminNode('General', 'General Configuration', 'GeneralConfig');
-    $this->addAdminNode('General', 'File uploads', 'UploadConfig');
-    $this->addAdminNode('General', 'Allowed file types', 'UploadAllowedMimeTypes');
-    $this->addAdminNode('General', 'Manage Plugins', 'PluginManager');
-    $this->addAdminNode('General', 'Backup database', 'DBBackup');
-    $this->addAdminNode('Content', 'Manage Pages', 'PageManager');
-    $this->addAdminNode('Content', 'Edit page content', 'PageEditor');
-    $this->addAdminNode('Appearance', 'Manage themes', 'ThemeManager');
-    $this->addAdminNode('Users', 'Manage users', 'UserManager');
-    $this->addAdminNode('Users', 'Edit groups', 'GroupManager');
-    $this->addAdminNode('Users', 'Ban control', 'BanControl');
-    $this->addAdminNode('Users', 'Mass e-mail', 'MassEmail');
-    
-    $code = $plugins->setHook('acl_rule_init');
-    foreach ( $code as $cmd )
-    {
-      eval($cmd);
-    }
-    
-    $this->wiki_mode = (int)getConfig('wiki_mode')=='1';
-    $this->template_cache = Array();
-  }
-  function pathManager()
-  {
-    $this->__construct();
-  }
-  function init()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    dc_here('paths: selecting master page data');
-    
-    $code = $plugins->setHook('paths_init_before');
-    foreach ( $code as $cmd )
-    {
-      eval($cmd);
-    }
-    
-    $e = $db->sql_query('SELECT name,urlname,namespace,special,visible,comments_on,protected,delvotes,delvote_ips,wiki_mode,password FROM '.table_prefix.'pages ORDER BY name;');
-    if( !$e )
-    {
-      $db->_die('The error seems to have occured while selecting the page information. File: includes/paths.php; line: '.__LINE__);
-    }
-    while($r = $db->fetchrow())
-    {
-      
-      $r['urlname_nons'] = $r['urlname'];
-      $r['urlname'] = $this->nslist[$r['namespace']] . $r['urlname']; // Applies the User:/File:/etc prefixes to the URL names
-      
-      if ( $r['delvotes'] == null)
-      {
-        $r['delvotes'] = 0;
-      }
-      if ( $r['protected'] == 0 || $r['protected'] == 1 )
-      {
-        $r['really_protected'] = (int)$r['protected'];
-      }
-      else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '1')
-      {
-        $r['really_protected'] = 1;
-      }
-      else if ( $r['protected'] == 2 && getConfig('wiki_mode') == '0' )
-      {
-        $r['really_protected'] = 0;
-      }
-      
-      $this->pages[$r['urlname']] = $r;
-      $this->pages[] =& $this->pages[$r['urlname']];
-      
-    }
-    $db->free_result();
-    dc_here('paths: determining page ID');
-    if( isset($_GET['title']) )
-    {
-      if ( $_GET['title'] == '' && getConfig('main_page') != '' )
-      {
-        $this->main_page();
-      }
-      if(strstr($_GET['title'], ' '))
-      {
-        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
-        $loc = str_replace(' ', '_', $loc);
-        $loc = str_replace('+', '_', $loc);
-        $loc = str_replace('%20', '_', $loc);
-        redirect($loc, 'Redirecting...', 'Space detected in the URL, please wait whilst you are redirected', 0);
-        exit;
-      }
-      $url_namespace_special = substr($_GET['title'], 0, strlen($this->nslist['Special']) );
-      $url_namespace_template = substr($_GET['title'], 0, strlen($this->nslist['Template']) );
-      if($url_namespace_special == $this->nslist['Special'] || $url_namespace_template == $this->nslist['Template'] )
-      {
-        $ex = explode('/', $_GET['title']);
-        $this->page = $ex[0];
-      }
-      else
-      {
-        $this->page = $_GET['title'];
-      }
-      $this->fullpage = $_GET['title'];
-    }
-    elseif( isset($_SERVER['PATH_INFO']) )
-    {
-      $pi = explode('/', $_SERVER['PATH_INFO']);
-      
-      if( !isset($pi[1]) || (isset($pi[1]) && $pi[1] == '' && getConfig('main_page') != '') )
-      {
-        $this->main_page();
-      }
-      if( strstr($pi[1], ' ') )
-      {
-        $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
-        $loc = str_replace('+', '_', $loc);
-        $loc = str_replace('%20', '_', $loc);
-        redirect($loc, 'Redirecting...', 'Please wait whilst you are redirected', 3);
-        exit;
-      }
-      unset($pi[0]);
-      if( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] || substr($pi[1], 0, strlen($this->nslist['Template'])) == $this->nslist['Template'] )
-      {
-        $pi2 = $pi[1];
-      }
-      else
-      {
-        $pi2 = implode('/', $pi);
-      }
-      $this->page = $pi2;
-      $this->fullpage = implode('/', $pi);
-    }
-    else
-    {
-      $k = array_keys($_GET);
-      foreach($k as $c)
-      {
-        if(substr($c, 0, 1) == '/')
-        {
-          $this->page = substr($c, 1, strlen($c));
-          
-          // Bugfix for apache somehow passing dots as underscores
-          global $mime_types;
-          $exts = array_keys($mime_types);
-          $exts = '(' . implode('|', $exts) . ')';
-          if ( preg_match( '#_'.$exts.'#i', $this->page ) )
-            $this->page = preg_replace( '#_'.$exts.'#i', '.\\1', $this->page );
-          
-          $this->fullpage = $this->page;
-          
-          if(substr($this->page, 0, strlen($this->nslist['Special']))==$this->nslist['Special'] || substr($this->page, 0, strlen($this->nslist['Template']))==$this->nslist['Template'])
-          {
-            $ex = explode('/', $this->page);
-            $this->page = $ex[0];
-          }
-          if(strstr($this->page, ' '))
-          {
-            $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
-            $loc = str_replace('+', '_', $loc);
-            $loc = str_replace('%20', '_', $loc);
-            redirect($loc, 'Redirecting...', 'Space in the URL detected, please wait whilst you are redirected', 0);
-            exit;
-          }
-          break;
-        }
-      }
-      if(!$this->page && !($this->page == '' && getConfig('main_page') == ''))
-      {
-        $this->main_page();
-      }
-    }
-    
-    dc_here('paths: setting $paths->cpage');
-    
-    if(isset($this->pages[$this->page]))
-    {
-      dc_here('paths: page existence verified, our page ID is: '.$this->page);
-      $this->page_exists = true;
-      $this->cpage = $this->pages[$this->page];
-      $this->namespace = $this->cpage['namespace'];
-      if(!isset($this->cpage['wiki_mode'])) $this->cpage['wiki_mode'] = 2;
-      
-      // Determine the wiki mode for this page, now that we have this->cpage established
-      if($this->cpage['wiki_mode'] == 2)
-      {
-        $this->wiki_mode = (int)getConfig('wiki_mode');
-      }
-      else
-      {
-        $this->wiki_mode = $this->cpage['wiki_mode'];
-      }
-      // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
-      if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username))
-      {
-        $this->wiki_mode = true;
-      }
-      // And above all, if the site requires wiki mode to be off for non-logged-in users, disable it now
-      if(getConfig('wiki_mode_require_login')=='1' && !$session->user_logged_in)
-      {
-        $this->wiki_mode = false;
-      }
-      if($this->cpage['protected'] == 2)
-      {
-        // The page is semi-protected, determine permissions
-        if($session->user_logged_in && $session->reg_time + 60*60*24*4 < time()) 
-        {
-          $this->page_protected = 0;
-        }
-        else
-        {
-          $this->page_protected = 1;
-        }
-      }
-      else
-      {
-        $this->page_protected = $this->cpage['protected'];
-      }
-    }
-    else
-    {
-      dc_here('paths: page doesn\'t exist, creating new page in memory<br />our page ID is: '.$this->page);
-      $this->page_exists = false;
-      $this->cpage = Array(
-        'name'=>str_replace('_', ' ', $this->page),
-        'urlname'=>$this->page,
-        'namespace'=>'Article',
-        'special'=>0,
-        'visible'=>0,
-        'comments_on'=>1,
-        'protected'=>0,
-        'delvotes'=>0,
-        'delvote_ips'=>'',
-        'wiki_mode'=>2,
-        );
-      // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
-      $k = array_keys($this->nslist);
-      for($i=0;$i<sizeof($this->nslist);$i++)
-      {
-        $ln = strlen($this->nslist[$k[$i]]);
-        if( substr($this->page, 0, $ln) == $this->nslist[$k[$i]] )
-        {
-          $this->cpage['namespace'] = $k[$i];
-          $this->cpage['urlname_nons'] = substr($this->page, strlen($this->nslist[$this->cpage['namespace']]), strlen($this->page));
-          if(!isset($this->cpage['wiki_mode'])) 
-          {
-            $this->cpage['wiki_mode'] = 2;
-          }
-        }
-      }
-      $this->namespace = $this->cpage['namespace'];
-      
-      if($this->namespace=='System') 
-      {
-        $this->cpage['protected'] = 1;
-      }
-      if($this->namespace=='Special')
-      {
-        // Can't load nonexistent pages
-        $this->main_page();
-      }
-      // Allow the user to create/modify his user page uncondtionally (admins can still protect the page)
-      if($this->page == $this->nslist['User'].str_replace(' ', '_', $session->username)) 
-      {
-        $this->wiki_mode = true;
-      }
-    }
-    // This is used in the admin panel to keep track of form submission targets
-    $this->cpage['module'] = $this->cpage['urlname'];
-    
-    // Page is set up, call any hooks
-    $code = $plugins->setHook('page_set');
-    foreach ( $code as $cmd )
-    {
-      eval($cmd);
-    }
-    
-    $session->init_permissions();
-  }
-  
-  function add_page($flags)
-  {
-    //dc_dump($flags, 'paths: page added by plugin:');
-    $flags['urlname_nons'] = $flags['urlname'];
-    $flags['urlname'] = $this->nslist[$flags['namespace']] . $flags['urlname']; // Applies the User:/File:/etc prefixes to the URL names
-    $pages_len = sizeof($this->pages)/2;
-    $this->pages[$pages_len] = $flags;
-    $this->pages[$flags['urlname']] =& $this->pages[$pages_len];
-  }
-  
-  function main_page()
-  {
-    if( is_string(getConfig('main_page')) )
-    {
-      header('Location: '.makeUrl(getConfig('main_page')));
-      die('If you aren\'t redirected, <a href="' . makeUrl(getConfig('main_page')) . '">click here</a>.');
-    }
-    else
-    {
-      header('Location: '.makeUrl($this->pages[0]['urlname']));
-      die('If you aren\'t redirected, <a href="' . makeUrl($this->pages[0]['urlname']) . '">click here</a>.');
-    }
-    exit;
-  }
-  
-  function sysmsg($n)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    dc_here('paths: system message requested: '.$n);
-    $q = $db->sql_query('SELECT page_text, char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape($n).'\' AND namespace=\'System\'');
-    if( !$q )
-    {
-      $db->_die('Error during generic selection of system page data.');
-    }
-    if($db->numrows() < 1)
-    {
-      return false;
-      //$db->_die('Error during generic selection of system page data: there were no rows in the text table that matched the page text query.');
-    }
-    $r = $db->fetchrow();
-    $db->free_result();
-    $message = $r['page_text'];
-    
-    $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $message);
-    
-    return $message;
-  }
-  function get_pageid_from_url()
-  {
-    if(isset($_GET['title']))
-    {
-      if( $_GET['title'] == '' && getConfig('main_page') != '' )
-      {
-        $this->main_page();
-      }
-      if(strstr($_GET['title'], ' '))
-      {
-        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
-        $loc = str_replace(' ', '_', $loc);
-        $loc = str_replace('+', '_', $loc);
-        header('Location: '.$loc);
-        exit;
-      }
-      $ret = $_GET['title'];
-    }
-    elseif(isset($_SERVER['PATH_INFO']))
-    {
-      $pi = explode('/', $_SERVER['PATH_INFO']);
-      
-      if(!isset($pi[1]) || (isset($pi[1]) && $pi[1] == ''))
-      {
-        return false;
-      }
-      
-      if(strstr($pi[1], ' '))
-      {
-        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
-        $loc = str_replace(' ', '_', $loc);
-        $loc = str_replace('+', '_', $loc);
-        header('Location: '.$loc);
-        exit;
-      }
-      if( !( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ) )
-      {
-        unset($pi[0]);
-        $pi[1] = implode('/', $pi);
-      }
-      $ret = $pi[1];
-    }
-    else
-    {
-      $k = array_keys($_GET);
-      foreach($k as $c)
-      {
-        if(substr($c, 0, 1) == '/')
-        {
-          $ret = substr($c, 1, strlen($c));
-          if(substr($ret, 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ||
-             substr($ret, 0, strlen($this->nslist['Admin'])) == $this->nslist['Admin'])
-          {
-            $ret = explode('/', $ret);
-            $ret = $ret[0];
-          }
-          break;
-        }
-      }
-    }
-    
-    return ( isset($ret) ) ? $ret : false;
-  }
-  // Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
-  function parseAdminTree() 
-  {
-    $k = array_keys($this->admin_tree);
-    $i = 0;
-    $ret = '';
-    $ret .= "var TREE_ITEMS = [\n  ['Administration panel home', 'javascript:ajaxPage(\'".$this->nslist['Admin']."Home\');',\n    ";
-    foreach($k as $key)
-    {
-      $i++;
-      $ret .= "['".$key."', 'javascript:trees[0].toggle($i)', \n";
-      foreach($this->admin_tree[$key] as $c)
-      {
-        $i++;
-        $ret .= "        ['".$c['name']."', 'javascript:ajaxPage(\\'".$this->nslist['Admin'].$c['pageid']."\\');'],\n";
-      }
-      $ret .= "      ],\n";
-    }
-    $ret .= "    ['Log out of admin panel', 'javascript:ajaxPage(\\'".$this->nslist['Admin']."AdminLogout\\');'],\n";
-    // I used this while I painstakingly wrote the Runt code that auto-expands certain nodes based on the value of a bitfield stored in a cookie. *shudders*
-    // $ret .= "    ['(debug) Clear menu bitfield', 'javascript:createCookie(\\'admin_menu_state\\', \\'1\\', 365);'],\n";
-    $ret .= "]\n];";
-    return $ret;
-  }
-  function addAdminNode($section, $page_title, $url)
-  {
-    if(!isset($this->admin_tree[$section]))
-    {
-      $this->admin_tree[$section] = Array();
-    }
-    $this->admin_tree[$section][] = Array(
-        'name'=>$page_title,
-        'pageid'=>$url
-      );
-  }
-  function getParam($id = 0)
-  {
-    if(isset($_SERVER['PATH_INFO']))
-    {
-      $pi = explode('/', $_SERVER['PATH_INFO']);
-      $id = $id + 2;
-      return isset($pi[$id]) ? $pi[$id] : false;
-    }
-    else if( isset($_GET['title']) )
-    {
-      $pi = explode('/', $_GET['title']);
-      $id = $id + 1;
-      return isset($pi[$id]) ? $pi[$id] : false;
-    }
-    else
-    {
-      $k = array_keys($_GET);
-      foreach($k as $c)
-      {
-        if(substr($c, 0, 1) == '/')
-        {
-          
-          // Bugfix for apache somehow passing dots as underscores
-          global $mime_types;
-          $exts = array_keys($mime_types);
-          $exts = '(' . implode('|', $exts) . ')';
-          if ( preg_match( '#_'.$exts.'#i', $c ) )
-            $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
-          
-          $pi = explode('/', $c);
-          $id = $id + 2;
-          return isset($pi[$id]) ? $pi[$id] : false;
-        }
-      }
-      return false;
-    }
-  }
-  
-  function getAllParams()
-  {
-    if(isset($_SERVER['PATH_INFO']))
-    {
-      $pi = explode('/', $_SERVER['PATH_INFO']);
-      unset($pi[0], $pi[1]);
-      return implode('/', $pi);
-    }
-    else if( isset($_GET['title']) )
-    {
-      $pi = explode('/', $_GET['title']);
-      unset($pi[0]);
-      return implode('/', $pi);
-    }
-    else
-    {
-      $k = array_keys($_GET);
-      foreach($k as $c)
-      {
-        if(substr($c, 0, 1) == '/')
-        {
-          // Bugfix for apache somehow passing dots as underscores
-          global $mime_types;
-          $exts = array_keys($mime_types);
-          $exts = '(' . implode('|', $exts) . ')';
-          if ( preg_match( '#_'.$exts.'#i', $c ) )
-            $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
-          
-          $pi = explode('/', $c);
-          unset($pi[0], $pi[1]);
-          return implode('/', $pi);
-        }
-      }
-      return false;
-    }
-  }
-  
-  /**
-   * Creates a new namespace in memory
-   * @param string $id the namespace ID
-   * @param string $prefix the URL prefix, must not be blank or already used
-   * @return bool true on success false on failure
-   */
-  
-  function create_namespace($id, $prefix)
-  {
-    if(in_array($prefix, $this->nslist))
-    {
-      // echo '<b>Warning:</b> pathManager::create_namespace: Prefix "'.$prefix.'" is already taken<br />';
-      return false;
-    }
-    if( isset($this->nslist[$id]) )
-    {
-      // echo '<b>Warning:</b> pathManager::create_namespace: Namespace ID "'.$prefix.'" is already taken<br />';
-      return false;
-    }
-    $this->nslist[$id] = $prefix;
-  }
-  
-  /**
-   * Fetches the page texts for searching
-   */
-   
-  function fetch_page_search_texts()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $texts = Array();
-    $q = $db->sql_query('SELECT t.page_id,t.namespace,t.page_text,t.char_tag FROM '.table_prefix.'page_text AS t
-                           LEFT JOIN '.table_prefix.'pages AS p
-                             ON t.page_id=p.urlname
-                           WHERE p.namespace=t.namespace
-                             AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
-                             AND p.visible=1;'); // Only indexes "visible" pages
-    
-    if( !$q )
-    {
-      return false;
-    }
-    while($row = $db->fetchrow())
-    {
-      $pid = $this->nslist[$row['namespace']] . $row['page_id'];
-      $texts[$pid] = $row['page_text'];
-    }
-    $db->free_result();
-    
-    return $texts;
-  }
-  
-  /**
-   * Fetches a MySQL search query to use for Searcher::searchMySQL()
-   */
-   
-  function fetch_page_search_resource()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    // sha1('') returns "da39a3ee5e6b4b0d3255bfef95601890afd80709"
-    $texts = 'SELECT t.page_text,CONCAT(\'ns=\',t.namespace,\';pid=\',t.page_id) FROM '.table_prefix.'page_text AS t
-                           LEFT JOIN '.table_prefix.'pages AS p
-                             ON ( t.page_id=p.urlname AND t.namespace=p.namespace )
-                           WHERE p.namespace=t.namespace
-                             AND ( p.password=\'\' OR p.password=\'da39a3ee5e6b4b0d3255bfef95601890afd80709\' )
-                             AND p.visible=1;'; // Only indexes "visible" pages
-    return $texts;
-  }
-  
-  /**
-   * Rebuilds the search index
-   */
-   
-  function rebuild_search_index()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $search = new Searcher();
-    $texts = Array();
-    $textq = $db->sql_unbuffered_query($this->fetch_page_search_resource());
-    if(!$textq) $db->_die('');
-    while($row = $db->fetchrow_num())
-    {
-      $texts[(string)$row[1]] = $row[0];
-    }
-    $search->buildIndex($texts);
-    // echo '<pre>'.print_r($search->index, true).'</pre>';
-    // return;
-    $q = $db->sql_query('DELETE FROM '.table_prefix.'search_index');
-    if(!$q) return false;
-    $secs = Array();
-    $q = 'INSERT INTO '.table_prefix.'search_index(word,page_names) VALUES';
-    foreach($search->index as $word => $pages)
-    {
-      $secs[] = '(\''.$db->escape($word).'\', \''.$db->escape($pages).'\')';
-    }
-    $q .= implode(',', $secs);
-    unset($secs);
-    $q .= ';';
-    $result = $db->sql_query($q);
-    $db->free_result();
-    if($result)
-      return true;
-    else
-      $db->_die('The search index was trying to rebuild itself when the error occured.');
-  }
-  
-  /**
-   * Partially rebuilds the search index, removing/inserting entries only for the current page
-   * @param string $page_id
-   * @param string $namespace
-   */
-  
-  function rebuild_page_index($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$db->sql_query('SELECT page_text FROM '.table_prefix.'page_text
-      WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';'))
-    {
-      return $db->get_error();
-    }
-    $row = $db->fetchrow();
-    $db->free_result();
-    $search = new Searcher();
-    $search->buildIndex(Array("ns={$namespace};pid={$page_id}"=>$row['page_text']));
-    $new_index = $search->index;
-    
-    $keys = array_keys($search->index);
-    foreach($keys as $i => $k)
-    {
-      $c =& $keys[$i];
-      $c = hexencode($c, '', '');
-    }
-    $keys = "word=0x" . implode ( " OR word=0x", $keys ) . "";
-    
-    // Zap the cache
-    $cache = array_keys($search->index);
-    if ( count($cache) < 1 )
-    {
-      return false;
-    }
-    $cache = "query LIKE '%" . implode ( "%' OR query LIKE '%", $cache ) . "%'";
-    $db->sql_query('DELETE FROM '.table_prefix.'search_cache WHERE '.$cache);
-    
-    $query = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index WHERE '.$keys.';');
-    
-    while($row = $db->fetchrow())
-    {
-      $row['word'] = rtrim($row['word'], "\0");
-      $new_index[ $row['word'] ] = $row['page_names'] . ',' . $search->index[ $row['word'] ];
-    }
-    $db->free_result();
-    
-    $db->sql_query('DELETE FROM '.table_prefix.'search_index WHERE '.$keys.';');
-    
-    $secs = Array();
-    $q = 'INSERT INTO '.table_prefix.'search_index(word,page_names) VALUES';
-    foreach($new_index as $word => $pages)
-    {
-      $secs[] = '(\''.$db->escape($word).'\', \''.$db->escape($pages).'\')';
-    }
-    $q .= implode(',', $secs);
-    unset($secs);
-    $q .= ';';
-    if(!$db->check_query($q))
-    {
-      die('BUG: PathManager::rebuild_page_index: Query rejected by SQL parser:<pre>'.$q.'</pre>');
-    }
-    $result = $db->sql_query($q);
-    if($result)
-      return true;
-    else
-      $db->_die('The search index was trying to rebuild itself when the error occured.');
-    
-  }
-  
-  /**
-   * Creates an instance of the Searcher class, including index info
-   * @return object
-   */
-   
-  function makeSearcher($match_case = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $search = new Searcher();
-    $q = $db->sql_query('SELECT word,page_names FROM '.table_prefix.'search_index;');
-    if(!$q)
-    {
-      echo $db->get_error();
-      return false;
-    }
-    $idx = Array();
-    while($row = $db->fetchrow($q))
-    {
-      $row['word'] = rtrim($row['word'], "\0");
-      $idx[$row['word']] = $row['page_names'];
-    }
-    $db->free_result();
-    $search->index = $idx;
-    if($match_case)
-      $search->match_case = true;
-    return $search;
-  }
-  
-  /**
-   * Creates an associative array filled with the values of all the page titles
-   * @return array
-   */
-   
-  function get_page_titles()
-  {
-    $texts = Array();
-    for ( $i = 0; $i < sizeof($this->pages) / 2; $i++ )
-    {
-      $texts[$this->pages[$i]['urlname']] = $this->pages[$i]['name'];
-    }
-    return $texts;
-  }
-  
-  /**
-   * Creates an instance of the Searcher class, including index info for page titles
-   * @return object
-   */
-   
-  function makeTitleSearcher($match_case = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $search = new Searcher();
-    $texts = $this->get_page_titles();
-    $search->buildIndex($texts);
-    if($match_case)
-      $search->match_case = true;
-    return $search;
-  }
-  
-}
-  
-?>
--- a/includes/render.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,792 +0,0 @@
-<?php
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 (Banshee)
- * render.php - handles fetching pages and parsing them into HTML
- * Copyright (C) 2006-2007 Dan Fuhry
- *
- * This program is Free Software; you can redistribute 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 details.
- */
- 
-class RenderMan {
-  
-  function strToPageID($string)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $k = array_keys($paths->nslist);
-    for($i=0;$i<sizeof($paths->nslist);$i++)
-    {
-      $ln = strlen($paths->nslist[$k[$i]]);
-      if(substr($string, 0, $ln) == $paths->nslist[$k[$i]])
-      {
-        $ns = $k[$i];
-        $pg = substr($string, strlen($paths->nslist[$ns]), strlen($string));
-      }
-    }
-    return Array($pg, $ns);
-  }
-  
-  function getPage($page_id, $namespace, $wiki = 1, $smilies = true, $filter_links = true, $redir = true, $render = true)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    dc_here('render: page requested<br />ID/namespace: '."$page_id, $namespace<br />Wiki mode: $wiki<br />Smilies: ".(string)$smilies."<br />Allow redirects: ".(string)$redir);
-    
-    $perms =& $session;
-    
-    if ( $page_id != $paths->cpage['urlname_nons'] || $namespace != $paths->namespace )
-    {
-      unset($perms);
-      unset($perms); // PHP <5.1.5 Zend bug
-      $perms = $session->fetch_page_acl($page_id, $namespace);
-    }
-    
-    if(!$perms->get_permissions('read'))
-      return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
-    
-    if($wiki == 0 || $render == false)
-    {
-      if(!$perms->get_permissions('view_source'))
-      {
-        return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
-      }
-    }
-    
-    $q = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';');
-    if ( !$q )
-    {
-      $db->_die('Method called was: RenderMan::getPage(\''.$page_id.'\', \''.$namespace.'\');.');
-    }
-    if ( $db->numrows() < 1 )
-    {
-      return false;
-    }
-    $row = $db->fetchrow();
-    $db->free_result();
-    
-    $message = $row['page_text'];
-    $chartag = $row['char_tag'];
-    unset($row); // Free some memory
-    
-    if ( preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && $redir && !isset($_GET['redirect']) || ( isset($_GET['redirect']) && $_GET['redirect'] != 'no' ) )
-    {
-      dc_here('render: looks like a redirect page to me...');
-      $old = $paths->cpage;
-      $a = RenderMan::strToPageID($m[1]);
-      $a[0] = str_replace(' ', '_', $a[0]);
-      
-      $pageid = str_replace(' ', '_', $paths->nslist[$a[1]] . $a[0]);
-      $paths->page = $pageid;
-      $paths->cpage = $paths->pages[$pageid];
-      //die('<pre>'.print_r($paths->cpage,true).'</pre>');
-      
-      dc_here('render: wreckin\' $template, and reloading the theme vars to match the new page<br />This might get messy!');
-      
-      unset($template);
-      unset($GLOBALS['template']);
-      
-      $GLOBALS['template'] = new template();
-      global $template;
-      
-      $template->template(); // Tear down and rebuild the template parser
-      $template->load_theme($session->theme, $session->style);
-      
-      $data = '<div><small>(Redirected from <a href="'.makeUrlNS($old['namespace'], $old['urlname_nons'], 'redirect=no', true).'">'.$old['name'].'</a>)</small></div>'.RenderMan::getPage($a[0], $a[1], $wiki, $smilies, $filter_links, false /* Enforces a maximum of one redirect */);
-      
-      return $data;
-    }
-    else if(preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && isset($_GET['redirect']) && $_GET['redirect'] == 'no')
-    {
-      dc_here('render: looks like a redirect page to me...');
-      dc_here('render: skipping redirect as requested on URI');
-      preg_match('#^\#redirect \[\[(.+)\]\]#', $message, $m);
-      $m[1] = str_replace(' ', '_', $m[1]);
-      $message = preg_replace('#\#redirect \[\[(.+)\]\]#', '<nowiki><div class="mdg-infobox"><table border="0" width="100%" cellspacing="0" cellpadding="0"><tr><td valign="top"><img alt="Cute wet-floor icon" src="'.scriptPath.'/images/redirector.png" /></td><td valign="top" style="padding-left: 10px;"><b>This page is a <i>redirector</i>.</b><br />This means that this page will not show its own content by default. Instead it will display the contents of the page it redirects to.<br /><br />To create a redirect page, make the <i>first characters</i> in the page content <tt>#redirect [[Page_ID]]</tt>. For more information, see the Enano <a href="http://enanocms.org/Help:Wiki_formatting">Wiki formatting guide</a>.<br /><br />This page redirects to <a href="'.makeUrl($m[1]).'">'.$paths->pages[$m[1]]['name'].'</a>.</td></tr></table></div><br /><hr style="margin-left: 1em; width: 200px;" /></nowiki>', $message);
-    }
-    $session->disallow_password_grab();
-    dc_here('render: alright, got the text, formatting...');
-    return ($render) ? RenderMan::render($message, $wiki, $smilies, $filter_links) : $message;
-  }
-  
-  function getTemplate($id, $parms)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    dc_here('render: template requested: '.$id);
-    if(!isset($paths->pages[$paths->nslist['Template'].$id])) 
-    {
-      return '[['.$paths->nslist['Template'].$id.']]';
-    }
-    if(isset($paths->template_cache[$id]))
-    {
-      $text = $paths->template_cache[$id];
-    }
-    else
-    {
-      $text = RenderMan::getPage($id, 'Template', 0, true, true, 0);
-      $paths->template_cache[$id] = $text;
-    }
-    
-    $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
-    $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
-    
-    preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
-    
-    foreach($matchlist[1] as $m)
-    {
-      if(isset($parms[((int)$m)+1])) 
-      {
-        $p = $parms[((int)$m)+1];
-      }
-      else
-      {
-        $p = '<b>Notice:</b> RenderMan::getTemplate(): Parameter '.$m.' is not set';
-      }
-      $text = str_replace('(_'.$m.'_)', $p, $text);
-    }
-    $text = RenderMan::include_templates($text);
-    return $text;
-  }
-  
-  function fetch_template_text($id)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    dc_here('render: template raw data requested: '.$id);
-    if(!isset($paths->pages[$paths->nslist['Template'].$id])) 
-    {
-      return '[['.$paths->nslist['Template'].$id.']]';
-    }
-    if(isset($paths->template_cache[$id]))
-    {
-      $text = $paths->template_cache[$id];
-    }
-    else
-    {
-      $text = RenderMan::getPage($id, 'Template', 0, false, false, false, false);
-      $paths->template_cache[$id] = $text;
-    }
-    
-    if ( is_string($text) )
-    {
-      $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
-      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
-    }
-    
-    return $text;
-  }
-  
-  function render($text, $wiki = 1, $smilies = true, $filter_links = true)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if($smilies)
-    {
-      $text = RenderMan::smilieyize($text);
-    }
-    if($wiki == 1)
-    {
-      $text = RenderMan::next_gen_wiki_format($text);
-    }
-    elseif($wiki == 2)
-    {
-      $text = $template->tplWikiFormat($text);
-    }
-    return $text;
-  }
-  
-  function PlainTextRender($text, $wiki = 1, $smilies = false, $filter_links = true)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if($smilies)
-    {
-      $text = RenderMan::smilieyize($text);
-    }
-    if($wiki == 1)
-    {
-      $text = RenderMan::next_gen_wiki_format($text, true);
-    }
-    elseif($wiki == 2)
-    {
-      $text = $template->tplWikiFormat($text);
-    }
-    return $text;
-  }
-  
-  function next_gen_wiki_format($text, $plaintext = false, $filter_links = true, $do_params = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $random_id = md5( time() . mt_rand() );
-    
-    // Strip out <nowiki> sections and PHP code
-    
-    $php = preg_match_all('#<\?php(.*?)\?>#is', $text, $phpsec);
-    
-    for($i=0;$i<sizeof($phpsec[1]);$i++)
-    {
-      $text = str_replace('<?php'.$phpsec[1][$i].'?>', '{PHP:'.$random_id.':'.$i.'}', $text);
-    }
-    
-    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
-    
-    for($i=0;$i<sizeof($nowiki[1]);$i++)
-    {
-      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
-    }
-    
-    $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $text);
-    if ( $paths->namespace == 'Template' )
-    {
-      $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
-    }
-    
-    if ( !$plaintext )
-    {
-      // Process images
-      
-      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\|([0-9]+)\|([0-9]+)\]\]#is', $text, $matchlist);
-      $matches = Array();
-      $matches['images']  =& $matchlist[1];
-      $matches['widths']  =& $matchlist[2];
-      $matches['heights'] =& $matchlist[3];
-      for($i=0;$i<sizeof($matchlist[1]);$i++)
-      {
-        if(isPage($paths->nslist['File'].$matches['images'][$i])) $text = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].'|'.$matches['widths'][$i].'|'.$matches['heights'][$i].']]',
-          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i], 'preview&amp;width='.$matches['widths'][$i].'&amp;height='.$matches['heights'][$i]).'" /></a></nowiki>',
-          $text);
-      }
-      
-      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $text, $matchlist);
-      $matches = Array();
-      $matches['images'] = $matchlist[1];
-      for($i=0;$i<sizeof($matchlist[1]);$i++)
-      {
-        if(isPage($paths->nslist['File'].$matches['images'][$i])) $text = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
-          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" /></a></nowiki>',
-          $text);
-      }
-      
-    }
-    
-    if($do_params)
-    {
-      preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
-      foreach($matchlist[1] as $m)
-      {
-        $text = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $text);
-      }
-    }
-    
-    $text = RenderMan::include_templates($text);
-    
-    $text = process_tables($text);
-    
-    $wiki =& Text_Wiki::singleton('Mediawiki');
-    if($plaintext)
-    {
-      $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
-      $result = $wiki->transform($text, 'Plain');
-    }
-    else
-    {
-      $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
-      $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
-      $result = $wiki->transform($text, 'Xhtml');
-    }
-    
-    // Reinsert <nowiki> sections
-    for($i=0;$i<$nw;$i++)
-    {
-      $result = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', $nowiki[1][$i], $result);
-    }
-    
-    // Reinsert PHP
-    for($i=0;$i<$php;$i++)
-    {
-      $result = str_replace('{PHP:'.$random_id.':'.$i.'}', '<?php'.$phpsec[1][$i].'?>', $result);
-    }
-    
-    return $result;
-    
-  }
-  
-  function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false) {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
-    
-    $random_id = md5( time() . mt_rand() );
-    
-    // Strip out <nowiki> sections
-    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $message, $nowiki);
-    
-    if(!$plaintext)
-    {
-    
-      //return '<pre>'.print_r($nowiki,true).'</pre>';
-      
-      for($i=0;$i<sizeof($nowiki[1]);$i++)
-      {
-        $message = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $message);
-      }
-      
-      $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $message);
-      
-      //return '<pre>'.htmlspecialchars($message).'</pre>';
-      
-      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\|([0-9]+)\|([0-9]+)\]\]#is', $message, $matchlist);
-      $matches = Array();
-      $matches['images'] = $matchlist[1];
-      $matches['widths'] = $matchlist[2];
-      $matches['heights'] = $matchlist[3];
-      for($i=0;$i<sizeof($matchlist[1]);$i++)
-      {
-        if(isPage($paths->nslist['File'].$matches['images'][$i])) $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].'|'.$matches['widths'][$i].'|'.$matches['heights'][$i].']]',
-          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i], 'preview&amp;width='.$matches['widths'][$i].'&amp;height='.$matches['heights'][$i]).'" /></a></nowiki>',
-          $message);
-      }
-      
-      $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $message, $matchlist);
-      $matches = Array();
-      $matches['images'] = $matchlist[1];
-      for($i=0;$i<sizeof($matchlist[1]);$i++)
-      {
-        if(isPage($paths->nslist['File'].$matches['images'][$i])) $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
-          '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" /></a></nowiki>',
-          $message);
-      }
-    
-    }
-    
-    if($do_params)
-    {
-      preg_match_all('#\(_([0-9]+)_\)#', $message, $matchlist);
-      foreach($matchlist[1] as $m)
-      {
-        $message = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $message);
-      }
-    }
-    
-    $message = RenderMan::include_templates($message);
-    
-    // Reinsert <nowiki> sections
-    for($i=0;$i<$nw;$i++)
-    {
-      $message = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $message);
-    }
-    
-    $message = process_tables($message);
-    //if($message2 != $message) return '<pre>'.htmlspecialchars($message2).'</pre>';
-    //$message = str_replace(array('<table>', '</table>'), array('<nowiki><table>', '</table></nowiki>'), $message);
-    
-    $wiki =& Text_Wiki::singleton('Mediawiki');
-    if($plaintext)
-    {
-      $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
-      $result = $wiki->transform($message, 'Plain');
-    } else {
-      $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
-      $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
-      $result = $wiki->transform($message, 'Xhtml');
-    }
-    
-    // HTML fixes
-    $result = preg_replace('#<tr>([\s]*?)<\/tr>#is', '', $result);
-    $result = preg_replace('#<p>([\s]*?)<\/p>#is', '', $result);
-    $result = preg_replace('#<br />([\s]*?)<table#is', '<table', $result);
-    $result = str_replace("<pre><code>\n", "<pre><code>", $result);
-    $result = preg_replace("/<p><table([^>]*?)><\/p>/", "<table\\1>", $result);
-    $result = str_replace("<br />\n</td>", "\n</td>", $result);
-    $result = str_replace("<p><tr>", "<tr>", $result);
-    $result = str_replace("<tr><br />", "<tr>", $result);
-    $result = str_replace("</tr><br />", "</tr>", $result);
-    $result = str_replace("</table></p>", "</table>", $result);
-    $result = str_replace("</table><br />", "</table>", $result);
-    $result = preg_replace('/<\/table>$/', "</table><br /><br />", $result);
-    
-    $result = str_replace('<nowiki>',  '&lt;nowiki&gt;',  $result);
-    $result = str_replace('</nowiki>', '&lt;/nowiki&gt;', $result);
-    
-    return $result;
-  }
-  
-  function destroy_javascript($message, $_php = false)
-  {
-    $message = preg_replace('#<(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;\\1\\2&gt;', $message);
-    $message = preg_replace('#</(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;/\\1\\2&gt;', $message);
-    $message = preg_replace('#(javascript|script|activex|chrome|about|applet):#is', '\\1&#058;', $message);
-    if ( $_php )
-    {
-      // Left in only for compatibility
-      $message = preg_replace('#&lt;(.*?)>#is', '<\\1>', $message);
-      $message = preg_replace('#<(.*?)&gt;#is', '<\\1>', $message);
-      $message = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $message);
-      // strip <a href="foo" onclick="bar();">-type attacks
-      $message = preg_replace('#<([a-zA-Z:\-]+) (.*?)on([A-Za-z]*)=(.*?)>#is', '&lt;\\1\\2on\\3=\\4&gt;', $message);
-    }
-    return $message;
-  }
-  
-  function strip_php($message)
-  {
-    return RenderMan::destroy_javascript($message, true);
-  }
-  
-  function sanitize_html($text)
-  {
-    $text = htmlspecialchars($text);
-    $allowed_tags = Array('b', 'i', 'u', 'pre', 'code', 'tt', 'br', 'p', 'nowiki', '!--([^.]+)--');
-    foreach($allowed_tags as $t)
-    {
-      $text = preg_replace('#&lt;'.$t.'&gt;(.*?)&lt;/'.$t.'&gt;#is', '<'.$t.'>\\1</'.$t.'>', $text);
-      $text = preg_replace('#&lt;'.$t.' /&gt;#is', '<'.$t.' />', $text);
-      $text = preg_replace('#&lt;'.$t.'&gt;#is', '<'.$t.'>', $text);
-    }
-    return $text;
-  }
-  
-  /* *
-   * Replaces template inclusions with the templates
-   * @param string $message The text to format
-   * @return string
-   * /
-   
-  function old_include_templates($message)
-  {
-    $random_id = md5( time() . mt_rand() );
-    preg_match_all('#\{\{(.+?)\}\}#s', $message, $matchlist);
-    foreach($matchlist[1] as $m)
-    {
-      $mn = $m;
-      // Strip out wikilinks and re-add them after the explosion (because of the "|")
-      preg_match_all('#\[\[(.+?)\]\]#i', $m, $linklist);
-      //echo '<pre>'.print_r($linklist, true).'</pre>';
-      for($i=0;$i<sizeof($linklist[1]);$i++)
-      {
-        $mn = str_replace('[['.$linklist[1][$i].']]', '{WIKILINK:'.$random_id.':'.$i.'}', $mn);
-      }
-      
-      $ar = explode('|', $mn);
-      
-      for($j=0;$j<sizeof($ar);$j++)
-      {
-        for($i=0;$i<sizeof($linklist[1]);$i++)
-        {
-          $ar[$j] = str_replace('{WIKILINK:'.$random_id.':'.$i.'}', '[['.$linklist[1][$i].']]', $ar[$j]);
-        }
-      }
-      
-      $tp = $ar[0];
-      unset($ar[0]);
-      $tp = str_replace(' ', '_', $tp);
-      $message = str_replace('{{'.$m.'}}', RenderMan::getTemplate($tp, $ar), $message);
-    }
-    return $message;
-  }
-  */
-  
-  /**
-   * Parses a partial template tag in wikitext, and return an array with the parameters.
-   * @param string The portion of the template tag that contains the parameters. Example:
-   * <code>
-   * foo = lorem ipsum
-   * bar = dolor sit amet
-   * </code>
-   * @return array Example:
-   * [foo] => lorem ipsum
-   * [bar] => dolor sit amet
-   */
-  
-  function parse_template_vars($input)
-  {
-    $input = explode("\n", trim( $input ));
-    $parms = Array();
-    $current_line = '';
-    $current_parm = '';
-    foreach ( $input as $num => $line )
-    {
-      if ( preg_match('/^([ ]*?)([A-z0-9_]+?)([ ]*?)=([ ]*?)(.+?)$/i', $line, $matches) )
-      {
-        $parm =& $matches[2];
-        $text =& $matches[5];
-        if ( $parm == $current_parm )
-        {
-          $current_line .= $text;
-        }
-        else
-        {
-          // New parameter
-          if ( $current_parm != '' )
-            $parms[$current_parm] = $current_line;
-          $current_line = $text;
-          $current_parm = $parm;
-        }
-      }
-      else if ( $num == 0 )
-      {
-        // Syntax error
-        return false;
-      }
-      else
-      {
-        $current_line .= "\n$line";
-      }
-    }
-    if ( !empty($current_parm) && !empty($current_line) )
-    {
-      $parms[$current_parm] = $current_line;
-    }
-    return $parms;
-  }
-  
-  /**
-   * Processes all template tags within a block of wikitext.
-   * @param string The text to process
-   * @return string Formatted text
-   * @example
-   * <code>
-   $text = '{{Template
-     parm1 = Foo
-     parm2 = Bar
-     }}';
-   $text = include_templates($text);
-   * </code>
-   */
-  
-  function include_templates($text)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $template_regex = "/\{\{([A-z0-9_-]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
-    if ( $count = preg_match_all($template_regex, $text, $matches) )
-    {
-      for ( $i = 0; $i < $count; $i++ )
-      {
-        $parmsection = trim($matches[2][$i]);
-        if ( !empty($parmsection) )
-        {
-          $parms = parse_template_vars($parmsection);
-          foreach ( $parms as $j => $parm )
-          {
-            $parms[$j] = $parm;
-          }
-        }
-        else
-        {
-          $parms = Array();
-        }
-        if ( $tpl_code = RenderMan::fetch_template_text($matches[1][$i]) )
-        {
-          $parser = $template->makeParserText($tpl_code);
-          $parser->assign_vars($parms);
-          $text = str_replace($matches[0][$i], $parser->run(), $text);
-        }
-      }
-    }
-    return $text;
-  }
-  
-  /**
-   * Preprocesses an HTML text string prior to being sent to MySQL.
-   * @param string $text
-   * @param bool $strip_all_php - if true, strips all PHP regardless of user permissions. Else, strips PHP only if user level < USER_LEVEL_ADMIN.
-   */
-  function preprocess_text($text, $strip_all_php = true, $sqlescape = true)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $random_id = md5( time() . mt_rand() );
-    
-    $can_do_php = ( $session->get_permissions('php_in_pages') && !$strip_all_php );
-    
-    $text = sanitize_html($text, ( !$can_do_php ));
-    
-    if ( !$can_do_php )
-    {
-      // If we can't do PHP, we can't do Javascript either.
-      $text = RenderMan::destroy_javascript($text);
-    }
-    
-    // Strip out <nowiki> sections and PHP code
-    
-    $php = preg_match_all('#(<|&lt;)\?php(.*?)\?(>|&gt;)#is', $text, $phpsec);
-    
-    //die('<pre>'.htmlspecialchars(print_r($phpsec, true))."\n".htmlspecialchars(print_r($text, true)).'</pre>');
-    
-    for($i=0;$i<sizeof($phpsec[1]);$i++)
-    {
-      $text = str_replace($phpsec[0][$i], '{PHP:'.$random_id.':'.$i.'}', $text);
-    }
-    
-    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
-    
-    for($i=0;$i<sizeof($nowiki[1]);$i++)
-    {
-      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
-    }
-    
-    $text = str_replace('~~~~~', date('G:i, j F Y (T)'), $text);
-    $text = str_replace('~~~~', "[[User:$session->username|$session->username]] ".date('G:i, j F Y (T)'), $text);
-    $text = str_replace('~~~', "[[User:$session->username|$session->username]] ", $text);
-    
-    // Reinsert <nowiki> sections
-    for($i=0;$i<$nw;$i++)
-    {
-      $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
-    }
-    // Reinsert PHP
-    for($i=0;$i<$php;$i++)
-    {
-      $phsec = ''.$phpsec[1][$i].'?php'.$phpsec[2][$i].'?'.$phpsec[3][$i].'';
-      if ( $strip_all_php )
-        $phsec = htmlspecialchars($phsec);
-      $text = str_replace('{PHP:'.$random_id.':'.$i.'}', $phsec, $text);
-    }
-    
-    $text = ( $sqlescape ) ? $db->escape($text) : $text;
-    
-    return $text;
-  }
-  
-  function smilieyize($text, $complete_urls = false)
-  {
-    
-    $random_id = md5( time() . mt_rand() );
-    
-    // Smileys array - eventually this will be fetched from the database by
-    // RenderMan::initSmileys during initialization, but it will all be hardcoded for beta 2
-    
-    $smileys = Array(
-      'O:-)'    => 'face-angel.png',
-      'O:)'     => 'face-angel.png',
-      'O=)'     => 'face-angel.png',
-      ':-)'     => 'face-smile.png',
-      ':)'      => 'face-smile.png',
-      '=)'      => 'face-smile-big.png',
-      ':-('     => 'face-sad.png',
-      ':('      => 'face-sad.png',
-      ';('      => 'face-sad.png',
-      ':-O'     => 'face-surprise.png',
-      ';-)'     => 'face-wink.png',
-      ';)'      => 'face-wink.png',
-      '8-)'     => 'face-glasses.png',
-      '8)'      => 'face-glasses.png',
-      ':-D'     => 'face-grin.png',
-      ':D'      => 'face-grin.png',
-      '=D'      => 'face-grin.png',
-      ':-*'     => 'face-kiss.png',
-      ':*'      => 'face-kiss.png',
-      '=*'      => 'face-kiss.png',
-      ':\'('    => 'face-crying.png',
-      ':-|'     => 'face-plain.png',
-      ':-\\'    => 'face-plain.png',
-      ':-/'     => 'face-plain.png',
-      ':joke:'  => 'face-plain.png',
-      ']:-&gt;' => 'face-devil-grin.png',
-      ':kiss:'  => 'face-kiss.png',
-      ':-P'     => 'face-tongue-out.png',
-      ':P'      => 'face-tongue-out.png',
-      ':-p'     => 'face-tongue-out.png',
-      ':p'      => 'face-tongue-out.png',
-      ':-X'     => 'face-sick.png',
-      ':X'      => 'face-sick.png',
-      ':sick:'  => 'face-sick.png',
-      ':-]'     => 'face-oops.png',
-      ':]'      => 'face-oops.png',
-      ':oops:'  => 'face-oops.png',
-      ':-['     => 'face-embarassed.png',
-      ':['      => 'face-embarassed.png'
-      );
-    /*
-    $keys = array_keys($smileys);
-    foreach($keys as $k)
-    {
-      $regex1 = '#([\W]+)'.preg_quote($k).'([\s\n\r\.]+)#s';
-      $regex2 = '\\1<img alt="'.$k.'" title="'.$k.'" src="'.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" />\\2';
-      $text = preg_replace($regex1, $regex2, $text);
-    }                                                                      
-    */
-    
-    // Strip out <nowiki> sections
-    //return '<pre>'.htmlspecialchars($text).'</pre>';
-    $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
-    
-    for($i=0;$i<sizeof($nowiki[1]);$i++)
-    {
-      $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
-    }
-    
-    $keys = array_keys($smileys);
-    foreach($keys as $k)
-    {
-      $t = str_hex($k);
-      $t = explode(' ', $t);
-      $s = '';
-      foreach($t as $b)
-      {
-        $s.='&#x'.$b.';';
-      }
-      $pfx = ( $complete_urls ) ? 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] : '';
-      $text = str_replace(' '.$k, ' <nowiki><img title="'.$s.'" alt="'.$s.'" src="'.$pfx.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" /></nowiki>', $text);
-    }
-    //*/
-    
-    // Reinsert <nowiki> sections
-    for($i=0;$i<$nw;$i++)
-    {
-      $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
-    }
-    
-    return $text;
-  }
-  
-  /*
-   * **** DEPRECATED ****
-   * Replaces some critical characters in a string with MySQL-safe equivalents
-   * @param $text string the text to escape
-   * @return array key 0 is the escaped text, key 1 is the character tag
-   * /
-   
-  function escape_page_text($text)
-  {
-    $char_tag = md5(microtime() . mt_rand());
-    $text = str_replace("'",  "{APOS:$char_tag}",  $text);
-    $text = str_replace('"',  "{QUOT:$char_tag}",  $text);
-    $text = str_replace("\\", "{SLASH:$char_tag}", $text);
-    return Array($text, $char_tag);
-  }
-  */
-  
-  /* **** DEPRECATED ****
-   * Reverses the result of RenderMan::escape_page_text().
-   * @param $text string the text to unescape
-   * @param $char_tag string the character tag
-   * @return string
-   * /
-   
-  function unescape_page_text($text, $char_tag)
-  {
-    $text = str_replace("{APOS:$char_tag}",  "'",  $text);
-    $text = str_replace("{QUOT:$char_tag}",  '"',  $text);
-    $text = str_replace("{SLASH:$char_tag}", "\\", $text);
-    return $text;
-  }
-  */
-  
-  /**
-   * Generates a summary of the differences between two texts, and formats it as XHTML.
-   * @param $str1 string the first block of text
-   * @param $str2 string the second block of text
-   * @return string
-   */
-  function diff($str1, $str2)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $str1 = explode("\n", $str1);
-    $str2 = explode("\n", $str2);
-    $diff = new Diff($str1, $str2);
-    $renderer = new TableDiffFormatter();
-    return '<table class="diff">'.$renderer->format($diff).'</table>';
-  }
-  
-}
- 
-?>
--- a/includes/sessions.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2425 +0,0 @@
-<?php
-
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 (Banshee)
- * Copyright (C) 2006-2007 Dan Fuhry
- * sessions.php - everything related to security and user management
- *
- * This program is Free Software; you can redistribute 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 details.
- */
- 
-// Prepare a string for insertion into a MySQL database
-function filter($str) { return $db->escape($str); }
-
-/**
- * Anything and everything related to security and user management. This includes AES encryption, which is illegal in some countries.
- * Documenting the API was not easy - I hope you folks enjoy it.
- * @package Enano
- * @subpackage Session manager
- * @category security, user management, logins, etc.
- */
-
-class sessionManager {
-  
-  # Variables
-  
-  /**
-   * Whether we're logged in or not
-   * @var bool
-   */
-   
-  var $user_logged_in = false;
-  
-  /**
-   * Our current low-privilege session key
-   * @var string
-   */
-  
-  var $sid;
-  
-  /**
-   * Username of currently logged-in user, or IP address if not logged in
-   * @var string
-   */
-  
-  var $username;
-  
-  /**
-   * User ID of currently logged-in user, or -1 if not logged in
-   * @var int
-   */
-  
-  var $user_id;
-  
-  /**
-   * Real name of currently logged-in user, or blank if not logged in
-   * @var string
-   */
-  
-  var $real_name;
-  
-  /**
-   * E-mail address of currently logged-in user, or blank if not logged in
-   * @var string
-   */
-  
-  var $email;
-  
-  /**
-   * User level of current user
-   * USER_LEVEL_GUEST: guest
-   * USER_LEVEL_MEMBER: regular user
-   * USER_LEVEL_CHPREF: default - pseudo-level that allows changing password and e-mail address (requires re-authentication)
-   * USER_LEVEL_MOD: moderator
-   * USER_LEVEL_ADMIN: administrator
-   * @var int
-   */
-  
-  var $user_level;
-  
-  /**
-   * High-privilege session key
-   * @var string or false if not running on high-level authentication
-   */
-  
-  var $sid_super;
-  
-  /**
-   * The user's theme preference, defaults to $template->default_theme
-   * @var string
-   */
-  
-  var $theme;
-  
-  /**
-   * The user's style preference, or style auto-detected based on theme if not logged in
-   * @var string
-   */
-  
-  var $style;
-  
-  /**
-   * Signature of current user - appended to comments, etc.
-   * @var string
-   */
-  
-  var $signature;
-  
-  /**
-   * UNIX timestamp of when we were registered, or 0 if not logged in
-   * @var int
-   */
-  
-  var $reg_time;
-  
-  /**
-   * MD5 hash of the current user's password, if applicable
-   * @var string OR bool false
-   */
-   
-  var $password_hash;
-  
-  /**
-   * The number of unread private messages this user has.
-   * @var int
-   */
-  
-  var $unread_pms = 0;
-  
-  /**
-   * AES key used to encrypt passwords and session key info - irreversibly destroyed when disallow_password_grab() is called
-   * @var string
-   */
-   
-  var $private_key;
-  
-  /**
-   * Regex that defines a valid username, minus the ^ and $, these are added later
-   * @var string
-   */
-   
-   var $valid_username = '([A-Za-z0-9 \!\@\(\)-]+)';
-   
-  /**
-   * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
-   * @var string
-   */
-   
-  var $auth_level = -1;
-  
-  /**
-   * State variable to track if a session timed out
-   * @var bool
-   */
-  
-  var $sw_timed_out = false;
-  
-  /**
-   * Switch to track if we're started or not.
-   * @access private
-   * @var bool
-   */
-   
-  var $started = false;
-  
-  /**
-   * Switch to control compatibility mode (for older Enano websites being upgraded)
-   * @access private
-   * @var bool
-   */
-   
-  var $compat = false;
-  
-  /**
-   * Our list of permission types.
-   * @access private
-   * @var array
-   */
-   
-  var $acl_types = Array();
-  
-  /**
-   * The list of descriptions for the permission types
-   * @var array
-   */
-   
-  var $acl_descs = Array();
-  
-  /**
-   * A list of dependencies for ACL types.
-   * @var array
-   */
-   
-  var $acl_deps = Array();
-  
-  /**
-   * Our tell-all list of permissions.
-   * @access private - or, preferably, protected
-   * @var array
-   */
-   
-  var $perms = Array();
-  
-  /**
-   * A cache variable - saved after sitewide permissions are checked but before page-specific permissions.
-   * @var array
-   * @access private
-   */
-  
-  var $acl_base_cache = Array();
-  
-  /**
-   * Stores the scope information for ACL types.
-   * @var array
-   * @access private
-   */
-   
-  var $acl_scope = Array();
-  
-  /**
-   * Array to track which default permissions are being used
-   * @var array
-   * @access private
-   */
-   
-  var $acl_defaults_used = Array();
-  
-  /**
-   * Array to track group membership.
-   * @var array
-   */
-   
-  var $groups = Array();
-  
-  /**
-   * Associative array to track group modship.
-   * @var array
-   */
-   
-  var $group_mod = Array();
-  
-  # Basic functions
-   
-  /**
-   * Constructor.
-   */
-   
-  function __construct()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    include(ENANO_ROOT.'/config.php');
-    unset($dbhost, $dbname, $dbuser, $dbpasswd);
-    if(isset($crypto_key))
-    {
-      $this->private_key = $crypto_key;
-      $this->private_key = hexdecode($this->private_key);
-    }
-    else
-    {
-      if(is_writable(ENANO_ROOT.'/config.php'))
-      {
-        // Generate and stash a private key
-        // This should only happen during an automated silent gradual migration to the new encryption platform.
-        $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-        $this->private_key = $aes->gen_readymade_key();
-        
-        $config = file_get_contents(ENANO_ROOT.'/config.php');
-        if(!$config)
-        {
-          die('$session->__construct(): can\'t get the contents of config.php');
-        }
-        
-        $config = str_replace("?>", "\$crypto_key = '{$this->private_key}';\n?>", $config);
-        // And while we're at it...
-        $config = str_replace('MIDGET_INSTALLED', 'ENANO_INSTALLED', $config);
-        $fh = @fopen(ENANO_ROOT.'/config.php', 'w');
-        if ( !$fh ) 
-        {
-          die('$session->__construct(): Couldn\'t open config file for writing to store the private key, I tried to avoid something like this...');
-        }
-        
-        fwrite($fh, $config);
-        fclose($fh);
-      }
-      else
-      {
-        die_semicritical('Crypto error', '<p>No private key was found in the config file, and we can\'t generate one because we don\'t have write access to the config file. Please CHMOD config.php to 666 or 777 and reload this page.</p>');
-      }
-    }
-    // Check for compatibility mode
-    if(defined('IN_ENANO_INSTALL'))
-    {
-      $q = $db->sql_query('SELECT old_encryption FROM '.table_prefix.'users LIMIT 1;');
-      if(!$q)
-      {
-        $error = mysql_error();
-        if(strstr($error, "Unknown column 'old_encryption'"))
-          $this->compat = true;
-        else
-          $db->_die('This should never happen and is a bug - the only error that was supposed to happen here didn\'t happen. (sessions.php in constructor, during compat mode check)');
-      }
-      $db->free_result();
-    }
-  }
-  
-  /**
-   * PHP 4 compatible constructor.
-   */
-   
-  function sessionManager()
-  {
-    $this->__construct();
-  }
-  
-  /**
-   * Wrapper function to sanitize strings for MySQL and HTML
-   * @param string $text The text to sanitize
-   * @return string
-   */
-  
-  function prepare_text($text)
-  {
-    global $db;
-    return $db->escape(htmlspecialchars($text));
-  }
-  
-  /**
-   * Makes a SQL query and handles error checking
-   * @param string $query The SQL query to make
-   * @return resource
-   */
-  
-  function sql($query)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $result = $db->sql_query($query);
-    if(!$result)
-    {
-      $db->_die('The error seems to have occurred somewhere in the session management code.');
-    }
-    return $result;
-  }
-  
-  # Session restoration and permissions
-  
-  /**
-   * Initializes the basic state of things, including most user prefs, login data, cookie stuff
-   */
-  
-  function start()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if($this->started) return;
-    $this->started = true;
-    $user = false;
-    if(isset($_COOKIE['sid']))
-    {
-      if($this->compat)
-      {
-        $userdata = $this->compat_validate_session($_COOKIE['sid']);
-      }
-      else
-      {
-        $userdata = $this->validate_session($_COOKIE['sid']);
-      }
-      if(is_array($userdata))
-      {
-        $data = RenderMan::strToPageID($paths->get_pageid_from_url());
-        
-        if(!$this->compat && $userdata['account_active'] != 1 && $data[1] != 'Special' && $data[1] != 'Admin')
-        {
-          $this->logout();
-          $a = getConfig('account_activation');
-          switch($a)
-          {
-            case 'none':
-            default:
-              $solution = 'Your account was most likely deactivated by an administrator. Please contact the site administration for further assistance.';
-              break;
-            case 'user':
-              $solution = 'Please check your e-mail; you should have been sent a message with instructions on how to activate your account. If you do not receive an e-mail from this site within 24 hours, please contact the site administration for further assistance.';
-              break;
-            case 'admin':
-              $solution = 'This website has been configured so that all user accounts must be activated by the administrator before they can be used, so your account will most likely be activated the next time the one of the administrators visits the site.';
-              break;
-          }
-          die_semicritical('Account error', '<p>It appears that your user account has not yet been activated. '.$solution.'</p>');
-        }
-        
-        $this->sid = $_COOKIE['sid'];
-        $this->user_logged_in = true;
-        $this->user_id =       intval($userdata['user_id']);
-        $this->username =      $userdata['username'];
-        $this->password_hash = $userdata['password'];
-        $this->user_level =    intval($userdata['user_level']);
-        $this->real_name =     $userdata['real_name'];
-        $this->email =         $userdata['email'];
-        $this->unread_pms =    $userdata['num_pms'];
-        if(!$this->compat)
-        {
-          $this->theme =         $userdata['theme'];
-          $this->style =         $userdata['style'];
-          $this->signature =     $userdata['signature'];
-          $this->reg_time =      $userdata['reg_time'];
-        }
-        // Small security risk here - it allows someone who has already authenticated as an administrator to store the "super" key in
-        // the cookie. Change this to USER_LEVEL_MEMBER to override that. The same 15-minute restriction applies to this "exploit".
-        $this->auth_level =    $userdata['auth_level'];
-        if(!isset($template->named_theme_list[$this->theme]))
-        {
-          if($this->compat || !is_object($template))
-          {
-            $this->theme = 'oxygen';
-            $this->style = 'bleu';
-          }
-          else
-          {
-            $this->theme = $template->default_theme;
-            $this->style = $template->default_style;
-          }
-        }
-        $user = true;
-        
-        if(isset($_REQUEST['auth']) && !$this->sid_super)
-        {
-          // Now he thinks he's a moderator. Or maybe even an administrator. Let's find out if he's telling the truth.
-          if($this->compat)
-          {
-            $key = $_REQUEST['auth'];
-            $super = $this->compat_validate_session($key);
-          }
-          else
-          {
-            $key = strrev($_REQUEST['auth']);
-            $super = $this->validate_session($key);
-          }
-          if(is_array($super))
-          {
-            $this->auth_level = intval($super['auth_level']);
-            $this->sid_super = $_REQUEST['auth'];
-          }
-        }
-      }
-    }
-    if(!$user)
-    {
-      //exit;
-      $this->register_guest_session();
-    }
-    if(!$this->compat)
-    {
-      // init groups
-      $q = $this->sql('SELECT g.group_name,g.group_id,m.is_mod FROM '.table_prefix.'groups AS g
-          LEFT JOIN '.table_prefix.'group_members AS m
-            ON g.group_id=m.group_id
-          WHERE ( m.user_id='.$this->user_id.' 
-            OR g.group_name=\'Everyone\')
-            ' . ( enano_version() == '1.0RC1' ? '' : 'AND ( m.pending != 1 OR m.pending IS NULL )' ) . '
-          ORDER BY group_id ASC;'); // Make sure "Everyone" comes first so the permissions can be overridden
-      if($row = $db->fetchrow())
-      {
-        do {
-          $this->groups[$row['group_id']] = $row['group_name'];
-          $this->group_mod[$row['group_id']] = ( intval($row['is_mod']) == 1 );
-        } while($row = $db->fetchrow());
-      }
-      else
-      {
-        die('No group info');
-      }
-    }
-    $this->check_banlist();
-    
-    if ( isset ( $_GET['printable'] ) )
-    {
-      $this->theme = 'printable';
-      $this->style = 'default';
-    }
-    
-  }
-  
-  # Logins
-  
-  /**
-   * Attempts to perform a login using crypto functions
-   * @param string $username The username
-   * @param string $aes_data The encrypted password, hex-encoded
-   * @param string $aes_key The MD5 hash of the encryption key, hex-encoded
-   * @param string $challenge The 256-bit MD5 challenge string - first 128 bits should be the hash, the last 128 should be the challenge salt
-   * @param int $level The privilege level we're authenticating for, defaults to 0
-   * @return string 'success' on success, or error string on failure
-   */
-   
-  function login_with_crypto($username, $aes_data, $aes_key, $challenge, $level = USER_LEVEL_MEMBER)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $privcache = $this->private_key;
-    
-    // Instanciate the Rijndael encryption object
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-    
-    // Fetch our decryption key
-    
-    $aes_key = $this->fetch_public_key($aes_key);
-    if(!$aes_key)
-      return 'Couldn\'t look up public key "'.$aes_key.'" for decryption';
-    
-    // Convert the key to a binary string
-    $bin_key = hexdecode($aes_key);
-    
-    if(strlen($bin_key) != AES_BITS / 8)
-      return 'The decryption key is the wrong length';
-    
-    // Decrypt our password
-    $password = $aes->decrypt($aes_data, $bin_key, ENC_HEX);
-    
-    // Initialize our success switch
-    $success = false;
-    
-    // Select the user data from the table, and decrypt that so we can verify the password
-    $this->sql('SELECT password,old_encryption,user_id,user_level,theme,style,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$this->prepare_text(strtolower($username)).'\';');
-    if($db->numrows() < 1)
-      return 'The username and/or password is incorrect.';
-    $row = $db->fetchrow();
-    
-    // Check to see if we're logging in using a temporary password
-    
-    if((intval($row['temp_password_time']) + 3600*24) > time() )
-    {
-      $temp_pass = $aes->decrypt( $row['temp_password'], $this->private_key, ENC_HEX );
-      if( $temp_pass == $password )
-      {
-        $url = makeUrlComplete('Special', 'PasswordReset/stage2/' . $row['user_id'] . '/' . $row['temp_password']);
-        redirect($url, 'Login sucessful', 'Please wait while you are transferred to the Password Reset form.');
-        exit;
-      }
-    }
-    
-    if($row['old_encryption'] == 1)
-    {
-      // The user's password is stored using the obsolete and insecure MD5 algorithm, so we'll update the field with the new password
-      if(md5($password) == $row['password'])
-      {
-        $pass_stashed = $aes->encrypt($password, $this->private_key, ENC_HEX);
-        $this->sql('UPDATE '.table_prefix.'users SET password=\''.$pass_stashed.'\',old_encryption=0 WHERE user_id='.$row['user_id'].';');
-        $success = true;
-      }
-    }
-    else
-    {
-      // Our password field is up-to-date with the >=1.0RC1 encryption standards, so decrypt the password in the table and see if we have a match; if so then do challenge authentication
-      $real_pass = $aes->decrypt(hexdecode($row['password']), $this->private_key, ENC_BINARY);
-      if($password == $real_pass)
-      {
-        // Yay! We passed AES authentication, now do an MD5 challenge check to make sure we weren't spoofed
-        $chal = substr($challenge, 0, 32);
-        $salt = substr($challenge, 32, 32);
-        $correct_challenge = md5( $real_pass . $salt );
-        if($chal == $correct_challenge)
-          $success = true;
-      }
-    }
-    if($success)
-    {
-      if($level > $row['user_level'])
-        return 'You are not authorized for this level of access.';
-      
-      $sess = $this->register_session(intval($row['user_id']), $username, $password, $level);
-      if($sess)
-      {
-        $this->username = $username;
-        $this->user_id = intval($row['user_id']);
-        $this->theme = $row['theme'];
-        $this->style = $row['style'];
-        
-        if($level > USER_LEVEL_MEMBER)
-          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
-        else
-          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
-        
-        $code = $plugins->setHook('login_success');
-        foreach ( $code as $cmd )
-        {
-          eval($cmd);
-        }
-        return 'success';
-      }
-      else
-        return 'Your login credentials were correct, but an internal error occurred while registering the session key in the database.';
-    }
-    else
-    {
-      if($level > USER_LEVEL_MEMBER)
-        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
-      else
-        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
-        
-      return 'The username and/or password is incorrect.';
-    }
-  }
-  
-  /**
-   * Attempts to login without using crypto stuff, mainly for use when the other side doesn't like Javascript
-   * This method of authentication is inherently insecure, there's really nothing we can do about it except hope and pray that everyone moves to Firefox
-   * Technically it still uses crypto, but it only decrypts the password already stored, which is (obviously) required for authentication
-   * @param string $username The username
-   * @param string $password The password -OR- the MD5 hash of the password if $already_md5ed is true
-   * @param bool $already_md5ed This should be set to true if $password is an MD5 hash, and should be false if it's plaintext. Defaults to false.
-   * @param int $level The privilege level we're authenticating for, defaults to 0
-   */
-  
-  function login_without_crypto($username, $password, $already_md5ed = false, $level = USER_LEVEL_MEMBER)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $pass_hashed = ( $already_md5ed ) ? $password : md5($password);
-    
-    // Perhaps we're upgrading Enano?
-    if($this->compat)
-    {
-      return $this->login_compat($username, $pass_hashed, $level);
-    }
-    
-    // Instanciate the Rijndael encryption object
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-    
-    // Initialize our success switch
-    $success = false;
-    
-    // Retrieve the real password from the database
-    $this->sql('SELECT password,old_encryption,user_id,user_level,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$this->prepare_text(strtolower($username)).'\';');
-    if($db->numrows() < 1)
-      return 'The username and/or password is incorrect.';
-    $row = $db->fetchrow();
-    
-    // Check to see if we're logging in using a temporary password
-    
-    if((intval($row['temp_password_time']) + 3600*24) > time() )
-    {
-      $temp_pass = $aes->decrypt( $row['temp_password'], $this->private_key, ENC_HEX );
-      if( md5($temp_pass) == $pass_hashed )
-      {
-        header('Location: ' . makeUrlComplete('Special', 'PasswordReset/stage2/' . $row['user_id'] . '/' . $row['temp_password']) );
-        exit;
-      }
-    }
-    
-    if($row['old_encryption'] == 1)
-    {
-      // The user's password is stored using the obsolete and insecure MD5 algorithm - we'll update the field with the new password
-      if($pass_hashed == $row['password'] && !$already_md5ed)
-      {
-        $pass_stashed = $aes->encrypt($password, $this->private_key, ENC_HEX);
-        $this->sql('UPDATE '.table_prefix.'users SET password=\''.$pass_stashed.'\',old_encryption=0 WHERE user_id='.$row['user_id'].';');
-        $success = true;
-      }
-      elseif($pass_hashed == $row['password'] && $already_md5ed)
-      {
-        // We don't have the real password so don't bother with encrypting it, just call it success and get out of here
-        $success = true;
-      }
-    }
-    else
-    {
-      // Our password field is up-to-date with the >=1.0RC1 encryption standards, so decrypt the password in the table and see if we have a match
-      $real_pass = $aes->decrypt($row['password'], $this->private_key);
-      if($pass_hashed == md5($real_pass))
-      {
-        $success = true;
-      }
-    }
-    if($success)
-    {
-      if((int)$level > (int)$row['user_level'])
-        return 'You are not authorized for this level of access.';
-      $sess = $this->register_session(intval($row['user_id']), $username, $real_pass, $level);
-      if($sess)
-      {
-        if($level > USER_LEVEL_MEMBER)
-          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
-        else
-          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
-        
-        $code = $plugins->setHook('login_success');
-        foreach ( $code as $cmd )
-        {
-          eval($cmd);
-        }
-        return 'success';
-      }
-      else
-        return 'Your login credentials were correct, but an internal error occured while registering the session key in the database.';
-    }
-    else
-    {
-      if($level > USER_LEVEL_MEMBER)
-        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
-      else
-        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
-        
-      return 'The username and/or password is incorrect.';
-    }
-  }
-  
-  /**
-   * Attempts to log in using the old table structure and algorithm.
-   * @param string $username
-   * @param string $password This should be an MD5 hash
-   * @return string 'success' if successful, or error message on failure
-   */
-  
-  function login_compat($username, $password, $level = 0)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $pass_hashed =& $password;
-    $this->sql('SELECT password,user_id,user_level FROM '.table_prefix.'users WHERE username=\''.$this->prepare_text($username).'\';');
-    if($db->numrows() < 1)
-      return 'The username and/or password is incorrect.';
-    $row = $db->fetchrow();
-    if($row['password'] == $password)
-    {
-      if((int)$level > (int)$row['user_level'])
-        return 'You are not authorized for this level of access.';
-      $sess = $this->register_session_compat(intval($row['user_id']), $username, $password, $level);
-      if($sess)
-        return 'success';
-      else
-        return 'Your login credentials were correct, but an internal error occured while registering the session key in the database.';
-    }
-    else
-    {
-      return 'The username and/or password is incorrect.';
-    }
-  }
-  
-  /**
-   * Registers a session key in the database. This function *ASSUMES* that the username and password have already been validated!
-   * Basically the session key is a base64-encoded cookie (encrypted with the site's private key) that says "u=[username];p=[sha1 of password]"
-   * @param int $user_id
-   * @param string $username
-   * @param string $password
-   * @param int $level The level of access to grant, defaults to USER_LEVEL_MEMBER
-   * @return bool
-   */
-   
-  function register_session($user_id, $username, $password, $level = USER_LEVEL_MEMBER)
-  {
-    $salt = md5(microtime() . mt_rand());
-    $passha1 = sha1($password);
-    $session_key = "u=$username;p=$passha1;s=$salt";
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-    $session_key = $aes->encrypt($session_key, $this->private_key, ENC_HEX);
-    if($level > USER_LEVEL_MEMBER)
-    {
-      $hexkey = strrev($session_key);
-      $this->sid_super = $hexkey;
-      $_GET['auth'] = $hexkey;
-    }
-    else
-    {
-      setcookie( 'sid', $session_key, time()+315360000, scriptPath.'/' );
-      $_COOKIE['sid'] = $session_key;
-    }
-    $keyhash = md5($session_key);
-    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
-    if(!$ip)
-      die('$session->register_session: Remote-Addr was spoofed');
-    $time = time();
-    if(!is_int($user_id))
-      die('Somehow an SQL injection attempt crawled into our session registrar! (1)');
-    if(!is_int($level))
-      die('Somehow an SQL injection attempt crawled into our session registrar! (2)');
-    
-    $query = $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key, salt, user_id, auth_level, source_ip, time) VALUES(\''.$keyhash.'\', \''.$salt.'\', '.$user_id.', '.$level.', \''.$ip.'\', '.$time.');');
-    return true;
-  }
-  
-  /**
-   * Identical to register_session in nature, but uses the old login/table structure. DO NOT use this.
-   * @see sessionManager::register_session()
-   * @access private
-   */
-  
-  function register_session_compat($user_id, $username, $password, $level = 0)
-  {
-    $salt = md5(microtime() . mt_rand());
-    $thekey = md5($password . $salt);
-    if($level > 0)
-    {
-      $this->sid_super = $thekey;
-    }
-    else
-    {
-      setcookie( 'sid', $thekey, time()+315360000, scriptPath.'/' );
-      $_COOKIE['sid'] = $thekey;
-    }
-    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
-    if(!$ip)
-      die('$session->register_session: Remote-Addr was spoofed');
-    $time = time();
-    if(!is_int($user_id))
-      die('Somehow an SQL injection attempt crawled into our session registrar! (1)');
-    if(!is_int($level))
-      die('Somehow an SQL injection attempt crawled into our session registrar! (2)');
-    $query = $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key, salt, user_id, auth_level, source_ip, time) VALUES(\''.$thekey.'\', \''.$salt.'\', '.$user_id.', '.$level.', \''.$ip.'\', '.$time.');');
-    return true;
-  }
-  
-  /**
-   * Creates/restores a guest session
-   * @todo implement real session management for guests
-   */
-   
-  function register_guest_session()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $this->username = $_SERVER['REMOTE_ADDR'];
-    $this->user_level = USER_LEVEL_GUEST;
-    if($this->compat || defined('IN_ENANO_INSTALL'))
-    {
-      $this->theme = 'oxygen';
-      $this->style = 'bleu';
-    }
-    else
-    {
-      $this->theme = ( isset($_GET['theme']) && isset($template->named_theme_list[$_GET['theme']])) ? $_GET['theme'] : $template->default_theme;
-      $this->style = ( isset($_GET['style']) && file_exists(ENANO_ROOT.'/themes/'.$this->theme . '/css/'.$_GET['style'].'.css' )) ? $_GET['style'] : substr($template->named_theme_list[$this->theme]['default_style'], 0, strlen($template->named_theme_list[$this->theme]['default_style'])-4);
-    }
-    $this->user_id = 1;
-  }
-  
-  /**
-   * Validates a session key, and returns the userdata associated with the key or false
-   * @param string $key The session key to validate
-   * @return array Keys are 'user_id', 'username', 'email', 'real_name', 'user_level', 'theme', 'style', 'signature', 'reg_time', 'account_active', 'activation_key', and 'auth_level' or bool false if validation failed. The key 'auth_level' is the maximum authorization level that this key provides.
-   */
-   
-  function validate_session($key)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE, true);
-    $decrypted_key = $aes->decrypt($key, $this->private_key, ENC_HEX);
-    
-    if ( !$decrypted_key )
-    {
-      die_semicritical('AES encryption error', '<p>Something went wrong during the AES decryption process.</p><pre>'.print_r($decrypted_key, true).'</pre>');
-    }
-    
-    $n = preg_match('/^u='.$this->valid_username.';p=([A-Fa-f0-9]+?);s=([A-Fa-f0-9]+?)$/', $decrypted_key, $keydata);
-    if($n < 1)
-    {
-      // echo '(debug) $session->validate_session: Key does not match regex<br />Decrypted key: '.$decrypted_key;
-      return false;
-    }
-    $keyhash = md5($key);
-    $salt = $db->escape($keydata[3]);
-    $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,x.* FROM '.table_prefix.'session_keys AS k
-                           LEFT JOIN '.table_prefix.'users AS u
-                             ON ( u.user_id=k.user_id )
-                           LEFT JOIN '.table_prefix.'users_extra AS x
-                             ON ( u.user_id=x.user_id OR x.user_id IS NULL )
-                           LEFT JOIN '.table_prefix.'privmsgs AS p
-                             ON ( p.message_to=u.username AND p.message_read=0 )
-                           WHERE k.session_key=\''.$keyhash.'\'
-                             AND k.salt=\''.$salt.'\'
-                           GROUP BY u.user_id;');
-    if($db->numrows() < 1)
-    {
-      // echo '(debug) $session->validate_session: Key was not found in database<br />';
-      return false;
-    }
-    $row = $db->fetchrow();
-    $row['user_id'] =& $row['uid'];
-    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
-    if($row['auth_level'] > $row['user_level'])
-    {
-      // Failed authorization check
-      // echo '(debug) $session->validate_session: access to this auth level denied<br />';
-      return false;
-    }
-    if($ip != $row['source_ip'])
-    {
-      // Failed IP address check
-      // echo '(debug) $session->validate_session: IP address mismatch<br />';
-      return false;
-    }
-    
-    // Do the password validation
-    $real_pass = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
-    
-    //die('<pre>'.print_r($keydata, true).'</pre>');
-    if(sha1($real_pass) != $keydata[2])
-    {
-      // Failed password check
-      // echo '(debug) $session->validate_session: encrypted password is wrong<br />Real password: '.$real_pass.'<br />Real hash: '.sha1($real_pass).'<br />User hash: '.$keydata[2];
-      return false;
-    }
-    
-    $time_now = time();
-    $time_key = $row['time'] + 900;
-    if($time_now > $time_key && $row['auth_level'] > USER_LEVEL_MEMBER)
-    {
-      // Session timed out
-      // echo '(debug) $session->validate_session: super session timed out<br />';
-      $this->sw_timed_out = true;
-      return false;
-    }
-    
-    // If this is an elevated-access session key, update the time
-    if( $row['auth_level'] > USER_LEVEL_MEMBER )
-    {
-      $this->sql('UPDATE '.table_prefix.'session_keys SET time='.time().' WHERE session_key=\''.$keyhash.'\';');
-    }
-    
-    $row['password'] = md5($real_pass);
-    return $row;
-  }
-  
-  /**
-   * Validates a session key, and returns the userdata associated with the key or false. Optimized for compatibility with the old MD5-based auth system.
-   * @param string $key The session key to validate
-   * @return array Keys are 'user_id', 'username', 'email', 'real_name', 'user_level', 'theme', 'style', 'signature', 'reg_time', 'account_active', 'activation_key', and 'auth_level' or bool false if validation failed. The key 'auth_level' is the maximum authorization level that this key provides.
-   */
-   
-  function compat_validate_session($key)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $key = $db->escape($key);
-    
-    $query = $this->sql('SELECT u.user_id,u.username,u.password,u.email,u.real_name,u.user_level,k.source_ip,k.salt,k.time,k.auth_level FROM '.table_prefix.'session_keys AS k
-                           LEFT JOIN '.table_prefix.'users AS u
-                             ON u.user_id=k.user_id
-                           WHERE k.session_key=\''.$key.'\';');
-    if($db->numrows() < 1)
-    {
-      // echo '(debug) $session->validate_session: Key '.$key.' was not found in database<br />';
-      return false;
-    }
-    $row = $db->fetchrow();
-    $ip = ip2hex($_SERVER['REMOTE_ADDR']);
-    if($row['auth_level'] > $row['user_level'])
-    {
-      // Failed authorization check
-      // echo '(debug) $session->validate_session: user not authorized for this access level';
-      return false;
-    }
-    if($ip != $row['source_ip'])
-    {
-      // Failed IP address check
-      // echo '(debug) $session->validate_session: IP address mismatch; IP in table: '.$row['source_ip'].'; reported IP: '.$ip.'';
-      return false;
-    }
-    
-    // Do the password validation
-    $real_key = md5($row['password'] . $row['salt']);
-    
-    //die('<pre>'.print_r($keydata, true).'</pre>');
-    if($real_key != $key)
-    {
-      // Failed password check
-      // echo '(debug) $session->validate_session: supplied password is wrong<br />Real key: '.$real_key.'<br />User key: '.$key;
-      return false;
-    }
-    
-    $time_now = time();
-    $time_key = $row['time'] + 900;
-    if($time_now > $time_key && $row['auth_level'] >= 1)
-    {
-      $this->sw_timed_out = true;
-      // Session timed out
-      // echo '(debug) $session->validate_session: super session timed out<br />';
-      return false;
-    }
-    
-    return $row;
-  }
-   
-  /**
-   * Demotes us to one less than the specified auth level. AKA destroys elevated authentication and/or logs out the user, depending on $level
-   * @param int $level How low we should go - USER_LEVEL_MEMBER means demote to USER_LEVEL_GUEST, and anything more powerful than USER_LEVEL_MEMBER means demote to USER_LEVEL_MEMBER
-   * @return string 'success' if successful, or error on failure
-   */
-   
-  function logout($level = USER_LEVEL_MEMBER)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $ou = $this->username;
-    $oid = $this->user_id;
-    if($level > USER_LEVEL_CHPREF)
-    {
-      $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-      if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD) return 'success';
-      // Destroy elevated privileges
-      $keyhash = md5(strrev($this->sid_super));
-      $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.$keyhash.'\' AND user_id=\'' . $this->user_id . '\';');
-      $this->sid_super = false;
-      $this->auth_level = USER_LEVEL_MEMBER;
-    }
-    else
-    {
-      if($this->user_logged_in)
-      {
-        // Completely destroy our session
-        if($this->auth_level > USER_LEVEL_CHPREF)
-        {
-          $this->logout(USER_LEVEL_ADMIN);
-        }
-        $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.md5($this->sid).'\';');
-        setcookie( 'sid', '', time()-(3600*24), scriptPath.'/' );
-      }
-    }
-    $code = $plugins->setHook('logout_success'); // , Array('level'=>$level,'old_username'=>$ou,'old_user_id'=>$oid));
-    foreach ( $code as $cmd )
-    {
-      eval($cmd);
-    }
-    return 'success';
-  }
-  
-  # Miscellaneous stuff
-  
-  /**
-   * Appends the high-privilege session key to the URL if we are authorized to do high-privilege stuff
-   * @param string $url The URL to add session data to
-   * @return string
-   */
-  
-  function append_sid($url)
-  {
-    $sep = ( strstr($url, '?') ) ? '&' : '?';
-    if ( $this->sid_super )
-    {
-      $url = $url . $sep . 'auth=' . urlencode($this->sid_super);
-      // echo($this->sid_super.'<br/>');
-    }
-    return $url;
-  }
-  
-  /**
-   * Grabs the user's password MD5
-   * @return string, or bool false if access denied
-   */
-   
-  function grab_password_hash()
-  {
-    if(!$this->password_hash) return false;
-    return $this->password_hash;
-  }
-  
-  /**
-   * Destroys the user's password MD5 in memory
-   */
-  
-  function disallow_password_grab()
-  {
-    $this->password_hash = false;
-    return false;
-  }
-  
-  /**
-   * Generates an AES key and stashes it in the database
-   * @return string Hex-encoded AES key
-   */
-   
-  function rijndael_genkey()
-  {
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-    $key = $aes->gen_readymade_key();
-    $keys = getConfig('login_key_cache');
-    if(is_string($keys))
-      $keys .= $key;
-    else
-      $keys = $key;
-    setConfig('login_key_cache', $keys);
-    return $key;
-  }
-  
-  /**
-   * Generate a totally random 128-bit value for MD5 challenges
-   * @return string
-   */
-   
-  function dss_rand()
-  {
-    $aes = new AESCrypt();
-    $random = $aes->randkey(128);
-    unset($aes);
-    return md5(microtime() . $random);
-  }
-  
-  /**
-   * Fetch a cached login public key using the MD5sum as an identifier. Each key can only be fetched once before it is destroyed.
-   * @param string $md5 The MD5 sum of the key
-   * @return string, or bool false on failure
-   */
-   
-  function fetch_public_key($md5)
-  {
-    $keys = getConfig('login_key_cache');
-    $keys = enano_str_split($keys, AES_BITS / 4);
-    
-    foreach($keys as $i => $k)
-    {
-      if(md5($k) == $md5)
-      {
-        unset($keys[$i]);
-        if(count($keys) > 0)
-        {
-          if ( strlen(getConfig('login_key_cache') ) > 64000 )
-          {
-            // This should only need to be done once every month or so for an average-size site
-            setConfig('login_key_cache', '');
-          }
-          else
-          {
-            $keys = implode('', array_values($keys));
-            setConfig('login_key_cache', $keys);
-          }
-        }
-        else
-        {
-          setConfig('login_key_cache', '');
-        }
-        return $k;
-      }
-    }
-    // Couldn't find the key...
-    return false;
-  }
-  
-  /**
-   * Adds a user to a group.
-   * @param int User ID
-   * @param int Group ID
-   * @param bool Group moderator - defaults to false
-   * @return bool True on success, false on failure
-   */
-  
-  function add_user_to_group($user_id, $group_id, $is_mod = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    // Validation
-    if ( !is_int($user_id) || !is_int($group_id) || !is_bool($is_mod) )
-      return false;
-    if ( $user_id < 1 || $group_id < 1 )
-      return false;
-    
-    $mod_switch = ( $is_mod ) ? '1' : '0';
-    $q = $this->sql('SELECT member_id,is_mod FROM '.table_prefix.'group_members WHERE user_id=' . $user_id . ' AND group_id=' . $group_id . ';');
-    if ( !$q )
-      $db->_die();
-    if ( $db->numrows() < 1 )
-    {
-      // User is not in group
-      $this->sql('INSERT INTO '.table_prefix.'group_members(user_id,group_id,is_mod) VALUES(' . $user_id . ', ' . $group_id . ', ' . $mod_switch . ');');
-      return true;
-    }
-    else
-    {
-      $row = $db->fetchrow();
-      // Update modship status
-      if ( strval($row['is_mod']) == $mod_switch )
-      {
-        // Modship unchanged
-        return true;
-      }
-      else
-      {
-        // Modship changed
-        $this->sql('UPDATE '.table_prefix.'group_members SET is_mod=' . $mod_switch . ' WHERE member_id=' . $row['member_id'] . ';');
-        return true;
-      }
-    }
-    return false;
-  }
-  
-  /**
-   * Removes a user from a group.
-   * @param int User ID
-   * @param int Group ID
-   * @return bool True on success, false on failure
-   * @todo put a little more error checking in...
-   */
-  
-  function remove_user_from_group($user_id, $group_id)
-  {
-    if ( !is_int($user_id) || !is_int($group_id) )
-      return false;
-    $this->sql('DELETE FROM '.table_prefix."group_members WHERE user_id=$user_id AND group_id=$group_id;");
-    return true;
-  }
-  
-  /**
-   * Checks the banlist to ensure that we're an allowed user. Doesn't return anything because it dies if the user is banned.
-   */
-   
-  function check_banlist()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if($this->compat)
-      $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex FROM '.table_prefix.'banlist ORDER BY ban_type;');
-    else
-      $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex,reason FROM '.table_prefix.'banlist ORDER BY ban_type;');
-    if(!$q) $db->_die('The banlist data could not be selected.');
-    $banned = false;
-    while($row = $db->fetchrow())
-    {
-      if($this->compat)
-        $row['reason'] = 'None available - session manager is in compatibility mode';
-      switch($row['ban_type'])
-      {
-      case BAN_IP:
-        if(intval($row['is_regex'])==1) {
-          if(preg_match('#'.$row['ban_value'].'#i', $_SERVER['REMOTE_ADDR']))
-          {
-            $banned = true;
-            $reason = $row['reason'];
-          }
-        }
-        else {
-          if($row['ban_value']==$_SERVER['REMOTE_ADDR']) { $banned = true; $reason = $row['reason']; }
-        }
-        break;
-      case BAN_USER:
-        if(intval($row['is_regex'])==1) {
-          if(preg_match('#'.$row['ban_value'].'#i', $this->username))
-          {
-            $banned = true;
-            $reason = $row['reason'];
-          }
-        }
-        else {
-          if($row['ban_value']==$this->username) { $banned = true; $reason = $row['reason']; }
-        }
-        break;
-      case BAN_EMAIL:
-        if(intval($row['is_regex'])==1) {
-          if(preg_match('#'.$row['ban_value'].'#i', $this->email))
-          {
-            $banned = true;
-            $reason = $row['reason'];
-          }
-        }
-        else {
-          if($row['ban_value']==$this->email) { $banned = true; $reason = $row['reason']; }
-        }
-        break;
-      default:
-        die('Ban error: rule "'.$row['ban_value'].'" has an invalid type ('.$row['ban_type'].')');
-      }
-    }
-    if($banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS')
-    {
-      // This guy is banned - kill the session, kill the database connection, bail out, and be pretty about it
-      die_semicritical('Ban notice', '<div class="error-box">You have been banned from this website. Please contact the site administrator for more information.<br /><br />Reason:<br />'.$reason.'</div>');
-      exit;
-    }
-  }
-  
-  # Registration
-  
-  /**
-   * Registers a user. This does not perform any type of login.
-   * @param string $username
-   * @param string $password This should be unencrypted.
-   * @param string $email
-   * @param string $real_name Optional, defaults to ''.
-   */
-   
-  function create_user($username, $password, $email, $real_name = '') {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    // Initialize AES
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-    
-    if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.';
-    $username = $this->prepare_text($username);
-    $email = $this->prepare_text($email);
-    $real_name = $this->prepare_text($real_name);
-    $password = $aes->encrypt($password, $this->private_key, ENC_HEX);
-    
-    $nameclause = ( $real_name != '' ) ? ' OR real_name=\''.$real_name.'\'' : '';
-    $q = $this->sql('SELECT * FROM '.table_prefix.'users WHERE lcase(username)=\''.strtolower($username).'\' OR email=\''.$email.'\''.$nameclause.';');
-    if($db->numrows() > 0) {
-      $r = 'The ';
-      $i=0;
-      $row = $db->fetchrow();
-      // Wow! An error checker that actually speaks English with the properest grammar! :-P
-      if($row['username'] == $username) { $r .= 'username'; $i++; }
-      if($row['email'] == $email) { if($i) $r.=', '; $r .= 'e-mail address'; $i++; }
-      if($row['real_name'] == $real_name && $real_name != '') { if($i) $r.=', and '; $r .= 'real name'; $i++; }
-      $r .= ' that you entered ';
-      $r .= ( $i == 1 ) ? 'is' : 'are';
-      $r .= ' already in use by another user.';
-      return $r;
-    }
-    
-    // Require the account to be activated?
-    switch(getConfig('account_activation'))
-    {
-      case 'none':
-      default:
-        $active = '1';
-        break;
-      case 'user':
-        $active = '0';
-        break;
-      case 'admin':
-        $active = '0';
-        break;
-    }
-    
-    // Generate a totally random activation key
-    $actkey = sha1 ( microtime() . mt_rand() );
-
-    // We good, create the user    
-    $this->sql('INSERT INTO '.table_prefix.'users ( username, password, email, real_name, theme, style, reg_time, account_active, activation_key, user_level ) VALUES ( \''.$username.'\', \''.$password.'\', \''.$email.'\', \''.$real_name.'\', \''.$template->default_theme.'\', \''.$template->default_style.'\', '.time().', '.$active.', \''.$actkey.'\', '.USER_LEVEL_CHPREF.' )');
-    
-    // Require the account to be activated?
-    switch(getConfig('account_activation'))
-    {
-      case 'none':
-      default:
-        break;
-      case 'user':
-        $a = $this->send_activation_mail($username);
-        if(!$a)
-        {
-          $this->admin_activation_request($username);
-          return 'The activation e-mail could not be sent due to an internal error. This could possibly be due to an incorrect SMTP configuration. A request has been sent to the administrator to activate your account for you. ' . $a;
-        }
-        break;
-      case 'admin':
-        $this->admin_activation_request($username);
-        break;
-    }
-    
-    // Leave some data behind for the hook
-    $code = $plugins->setHook('user_registered'); // , Array('username'=>$username));
-    foreach ( $code as $cmd )
-    {
-      eval($cmd);
-    }
-    
-    // $this->register_session($username, $password);
-    return 'success';
-  }
-  
-  /**
-   * Attempts to send an e-mail to the specified user with activation instructions.
-   * @param string $u The usernamd of the user requesting activation
-   * @return bool true on success, false on failure
-   */
-   
-  function send_activation_mail($u, $actkey = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $q = $this->sql('SELECT username,email FROM '.table_prefix.'users WHERE user_id=1 OR user_level=' . USER_LEVEL_ADMIN . ' ORDER BY user_id ASC;');
-    $un = $db->fetchrow();
-    $admin_user = $un['username'];
-    $q = $this->sql('SELECT username,activation_key,account_active,email FROM '.table_prefix.'users WHERE username=\''.$db->escape($u).'\';');
-    $r = $db->fetchrow();
-    if ( empty($r['email']) )
-      $db->_die('BUG: $session->send_activation_mail(): no e-mail address in row');
-    $message = 'Dear '.$u.',
-Thank you for registering on '.getConfig('site_name').'. Your account creation is almost complete. To complete the registration process, please click the following link or paste it into your web browser:
-    
-';
-    if(isset($_SERVER['HTTPS'])) $prot = 'https';
-    else $prot = 'http';                                                                           
-    if($_SERVER['SERVER_PORT'] == '80') $p = '';
-    else $p = ':'.$_SERVER['SERVER_PORT'];
-    $sidbak = false;
-    if($this->sid_super)
-      $sidbak = $this->sid_super;
-    $this->sid_super = false;
-    $aklink = makeUrlNS('Special', 'ActivateAccount/'.str_replace(' ', '_', $u).'/'. ( ( is_string($actkey) ) ? $actkey : $r['activation_key'] ) );
-    if($sidbak)
-      $this->sid_super = $sidbak;
-    unset($sidbak);
-    $message .= "$prot://".$_SERVER['HTTP_HOST'].$p.$aklink;
-      $message .= "\n\nSincerely yours, \n$admin_user and the ".$_SERVER['HTTP_HOST']." administration team";
-    error_reporting(E_ALL);
-    dc_dump($r, 'session: about to send activation e-mail to '.$r['email']);
-    if(getConfig('smtp_enabled') == '1')
-    {
-      $result = smtp_send_email($r['email'], getConfig('site_name').' website account activation', preg_replace("#(?<!\r)\n#s", "\n", $message), getConfig('contact_email'));
-      if($result == 'success') $result = true;
-      else { echo $result; $result = false; }
-    } else {
-      $result = mail($r['email'], getConfig('site_name').' website account activation', preg_replace("#(?<!\r)\n#s", "\n", $message), 'From: '.getConfig('contact_email'));
-    }
-    return $result;
-  }
-  
-  /**
-   * Sends an e-mail to a user so they can reset their password.
-   * @param int $user The user ID, or username if it's a string
-   * @return bool true on success, false on failure
-   */
-   
-  function mail_password_reset($user)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(is_int($user))
-    {
-      $q = $this->sql('SELECT user_id,username,email FROM '.table_prefix.'users WHERE user_id='.$user.';'); // This is SAFE! This is only called if $user is an integer
-    }
-    elseif(is_string($user))
-    {
-      $q = $this->sql('SELECT user_id,username,email FROM '.table_prefix.'users WHERE username=\''.$db->escape($user).'\';');
-    }
-    else
-    {
-      return false;
-    }
-    
-    $row = $db->fetchrow();
-    $temp_pass = $this->random_pass();
-    
-    $this->register_temp_password($row['user_id'], $temp_pass);
-    
-    $site_name = getConfig('site_name');
-    
-    $message = "Dear {$row['username']},
-    
-Someone (hopefully you) on the {$site_name} website requested that a new password be created.
-
-The request was sent from the IP address {$_SERVER['REMOTE_ADDR']}.
-
-If you did not request the new password, then you do not need to do anything; the password will be invalidated after 24 hours.
-
-If you did request this password, then please log in using the password shown below:
-
-  Password: {$temp_pass}
-  
-After you log in using this password, you will be able to reset your real password. You can only log in using this temporary password once.
-
-Sincerely yours,
-The {$site_name} administration team
-";
-    
-    if(getConfig('smtp_enabled') == '1')
-    {
-      $result = smtp_send_email($row['email'], getConfig('site_name').' password reset', preg_replace("#(?<!\r)\n#s", "\n", $message), getConfig('contact_email'));
-      if($result == 'success')
-      {
-        $result = true;
-      }
-      else
-      {
-        echo '<p>'.$result.'</p>';
-        $result = false;
-      }
-    } else {
-      $result = mail($row['email'], getConfig('site_name').' password reset', preg_replace("#(?<!\r)\n#s", "\n", $message), 'From: '.getConfig('contact_email'));
-    }
-    return $result;
-  }
-  
-  /**
-   * Sets the temporary password for the specified user to whatever is specified.
-   * @param int $user_id
-   * @param string $password
-   * @return bool
-   */
-   
-  function register_temp_password($user_id, $password)
-  {
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-    $temp_pass = $aes->encrypt($password, $this->private_key, ENC_HEX);
-    $this->sql('UPDATE '.table_prefix.'users SET temp_password=\'' . $temp_pass . '\',temp_password_time='.time().' WHERE user_id='.intval($user_id).';');
-  }
-  
-  /**
-   * Sends a request to the admin panel to have the username $u activated.
-   * @param string $u The username of the user requesting activation
-   */
-  
-  function admin_activation_request($u)
-  {
-    global $db;
-    $this->sql('INSERT INTO '.table_prefix.'logs(log_type, action, time_id, date_string, author, edit_summary) VALUES(\'admin\', \'activ_req\', '.time().', \''.date('d M Y h:i a').'\', \''.$this->username.'\', \''.$db->escape($u).'\');');
-  }
-  
-  /**
-   * Activates a user account. If the action fails, a report is sent to the admin.
-   * @param string $user The username of the user requesting activation
-   * @param string $key The activation key
-   */
-  
-  function activate_account($user, $key)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $this->sql('UPDATE '.table_prefix.'users SET account_active=1 WHERE username=\''.$db->escape($user).'\' AND activation_key=\''.$db->escape($key).'\';');
-    $r = mysql_affected_rows();
-    if ( $r > 0 )
-    {
-      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
-    }
-    else
-    {
-      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
-    }
-    return $r;
-  }
-  
-  /**
-   * For a given user level identifier (USER_LEVEL_*), returns a string describing that user level.
-   * @param int User level
-   * @return string
-   */
-  
-  function userlevel_to_string($user_level)
-  {
-    switch ( $user_level )
-    {
-      case USER_LEVEL_GUEST:
-        return 'Low - guest privileges';
-      case USER_LEVEL_MEMBER:
-        return 'Standard - normal member level';
-      case USER_LEVEL_CHPREF:
-        return 'Medium - user can change his/her own e-mail address and password';
-      case USER_LEVEL_MOD:
-        return 'High - moderator privileges';
-      case USER_LEVEL_ADMIN:
-        return 'Highest - administrative privileges';
-      default:
-        return "Unknown ($user_level)";
-    }
-  }
-  
-  /**
-   * Updates a user's information in the database. Note that any of the values except $user_id can be false if you want to preserve the old values.
-   * @param int $user_id The user ID of the user to update - this cannot be changed
-   * @param string $username The new username
-   * @param string $old_pass The current password - only required if sessionManager::$user_level < USER_LEVEL_ADMIN. This should usually be an UNENCRYPTED string. This can also be an array - if it is, key 0 is treated as data AES-encrypted with key 1
-   * @param string $password The new password
-   * @param string $email The new e-mail address
-   * @param string $realname The new real name
-   * @param string $signature The updated forum/comment signature
-   * @param int $user_level The updated user level
-   * @return string 'success' if successful, or array of error strings on failure
-   */
-   
-  function update_user($user_id, $username = false, $old_pass = false, $password = false, $email = false, $realname = false, $signature = false, $user_level = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    // Create some arrays
-    
-    $errors = Array(); // Used to hold error strings
-    $strs = Array();   // Sub-query statements
-    
-    // Scan the user ID for problems
-    if(intval($user_id) < 1) $errors[] = 'SQL injection attempt';
-    
-    // Instanciate the AES encryption class
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-    
-    // If all of our input vars are false, then we've effectively done our job so get out of here
-    if($username === false && $password === false && $email === false && $realname === false && $signature === false && $user_level === false)
-    {
-   // echo 'debug: $session->update_user(): success (no changes requested)';
-      return 'success';
-    }
-    
-    // Initialize our authentication check
-    $authed = false;
-    
-    // Verify the inputted password
-    if(is_string($old_pass))
-    {
-      $q = $this->sql('SELECT password FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
-      if($db->numrows() < 1)
-      {
-        $errors[] = 'The password data could not be selected for verification.';
-      }
-      else
-      {
-        $row = $db->fetchrow();
-        $real = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
-        if($real == $old_pass)
-          $authed = true;
-      }
-    }
-    
-    elseif(is_array($old_pass))
-    {
-      $old_pass = $aes->decrypt($old_pass[0], $old_pass[1]);
-      $q = $this->sql('SELECT password FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
-      if($db->numrows() < 1)
-      {
-        $errors[] = 'The password data could not be selected for verification.';
-      }
-      else
-      {
-        $row = $db->fetchrow();
-        $real = $aes->decrypt($row['password'], $this->private_key, ENC_HEX);
-        if($real == $old_pass)
-          $authed = true;
-      }
-    }
-    
-    // Initialize our query
-    $q = 'UPDATE '.table_prefix.'users SET ';
-    
-    if($this->auth_level >= USER_LEVEL_ADMIN || $authed) // Need the current password in order to update the e-mail address, change the username, or reset the password
-    {
-      // Username
-      if(is_string($username))
-      {
-        // Check the username for problems
-        if(!preg_match('#^'.$this->valid_username.'$#', $username))
-          $errors[] = 'The username you entered contains invalid characters.';
-        $strs[] = 'username=\''.$db->escape($username).'\'';
-      }
-      // Password
-      if(is_string($password) && strlen($password) >= 6)
-      {
-        // Password needs to be encrypted before being stashed
-        $encpass = $aes->encrypt($password, $this->private_key, ENC_HEX);
-        if(!$encpass)
-          $errors[] = 'The password could not be encrypted due to an internal error.';
-        $strs[] = 'password=\''.$encpass.'\'';
-      }
-      // E-mail addy
-      if(is_string($email))
-      {
-        // I didn't write this regex.
-        if(!preg_match('/^(?:[\w\d]+\.?)+@(?:(?:[\w\d]\-?)+\.)+\w{2,4}$/', $email))
-          $errors[] = 'The e-mail address you entered is invalid.';
-        $strs[] = 'email=\''.$db->escape($email).'\'';
-      }
-    }
-    // Real name
-    if(is_string($realname))
-    {
-      $strs[] = 'real_name=\''.$db->escape($realname).'\'';
-    }
-    // Forum/comment signature
-    if(is_string($signature))
-    {
-      $strs[] = 'signature=\''.$db->escape($signature).'\'';
-    }
-    // User level
-    if(is_int($user_level))
-    {
-      $strs[] = 'user_level='.$user_level;
-    }
-    
-    // Add our generated query to the query string
-    $q .= implode(',', $strs);
-    
-    // One last error check
-    if(sizeof($strs) < 1) $errors[] = 'An internal error occured building the SQL query, this is a bug';
-    if(sizeof($errors) > 0) return $errors;
-    
-    // Free our temp arrays
-    unset($strs, $errors);
-    
-    // Finalize the query and run it
-    $q .= ' WHERE user_id='.$user_id.';';
-    $this->sql($q);
-    
-    // We also need to trigger re-activation.
-    if ( is_string($email) )
-    {
-      switch(getConfig('account_activation'))
-      {
-        case 'user':
-        case 'admin':
-          
-          if ( $session->user_level >= USER_LEVEL_MOD && getConfig('account_activation') == 'admin' )
-            // Don't require re-activation by admins for admins
-            break;
-          
-          // retrieve username
-          if ( !$username )
-          {
-            $q = $this->sql('SELECT username FROM '.table_prefix.'users WHERE user_id='.$user_id.';');
-            if($db->numrows() < 1)
-            {
-              $errors[] = 'The username could not be selected.';
-            }
-            else
-            {
-              $row = $db->fetchrow();
-              $username = $row['username'];
-            }
-          }
-          if ( !$username )
-            return $errors;
-          
-          // Generate a totally random activation key
-          $actkey = sha1 ( microtime() . mt_rand() );
-          $a = $this->send_activation_mail($username, $actkey);
-          if(!$a)
-          {
-            $this->admin_activation_request($username);
-          }
-          // Deactivate the account until e-mail is confirmed
-          $q = $db->sql_query('UPDATE '.table_prefix.'users SET account_active=0,activation_key=\'' . $actkey . '\' WHERE user_id=' . $user_id . ';');
-          break;
-      }
-    }
-    
-    // Yay! We're done
-    return 'success';
-  }
-  
-  #
-  # Access Control Lists
-  #
-  
-  /**
-   * Creates a new permission field in memory. If the permissions are set in the database, they are used. Otherwise, $default_perm is used.
-   * @param string $acl_type An identifier for this field
-   * @param int $default_perm Whether permission should be granted or not if it's not specified in the ACLs.
-   * @param string $desc A human readable name for the permission type
-   * @param array $deps The list of dependencies - this should be an array of ACL types
-   * @param string $scope Which namespaces this field should apply to. This should be either a pipe-delimited list of namespace IDs or just "All".
-   */
-   
-  function register_acl_type($acl_type, $default_perm = AUTH_DISALLOW, $desc = false, $deps = Array(), $scope = 'All')
-  {
-    if(isset($this->acl_types[$acl_type]))
-      return false;
-    else
-    {
-      if(!$desc)
-      {
-        $desc = capitalize_first_letter(str_replace('_', ' ', $acl_type));
-      }
-      $this->acl_types[$acl_type] = $default_perm;
-      $this->acl_descs[$acl_type] = $desc;
-      $this->acl_deps[$acl_type] = $deps;
-      $this->acl_scope[$acl_type] = explode('|', $scope);
-    }
-    return true;
-  }
-  
-  /**
-   * Tells us whether permission $type is allowed or not based on the current rules.
-   * @param string $type The permission identifier ($acl_type passed to sessionManager::register_acl_type())
-   * @param bool $no_deps If true, disables dependency checking
-   * @return bool True if allowed, false if denied or if an error occured
-   */
-   
-  function get_permissions($type, $no_deps = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if ( isset( $this->perms[$type] ) )
-    {
-      if ( $this->perms[$type] == AUTH_DENY )
-        $ret = false;
-      else if ( $this->perms[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
-        $ret = true;
-      else if ( $this->perms[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
-        $ret = false;
-      else if ( $this->perms[$type] == AUTH_ALLOW )
-        $ret = true;
-      else if ( $this->perms[$type] == AUTH_DISALLOW )
-        $ret = false;
-    }
-    else if(isset($this->acl_types[$type]))
-    {
-      if ( $this->acl_types[$type] == AUTH_DENY )
-        $ret = false;
-      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
-        $ret = true;
-      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
-        $ret = false;
-      else if ( $this->acl_types[$type] == AUTH_ALLOW )
-        $ret = true;
-      else if ( $this->acl_types[$type] == AUTH_DISALLOW )
-        $ret = false;
-    }
-    else
-    {
-      // ACL type is undefined
-      trigger_error('Unknown access type "' . $type . '"', E_USER_WARNING);
-      return false; // Be on the safe side and deny access
-    }
-    if ( !$no_deps )
-    {
-      if ( !$this->acl_check_deps($type) )
-        return false;
-    }
-    return $ret;
-  }
-  
-  /**
-   * Fetch the permissions that apply to the current user for the page specified. The object you get will have the get_permissions method
-   * and several other abilities.
-   * @param string $page_id
-   * @param string $namespace
-   * @return object
-   */
-   
-  function fetch_page_acl($page_id, $namespace)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    if ( count ( $this->acl_base_cache ) < 1 )
-    {
-      // Permissions table not yet initialized
-      return false;
-    }
-    
-    //if ( !isset( $paths->pages[$paths->nslist[$namespace] . $page_id] ) )
-    //{
-    //  // Page does not exist
-    //  return false;
-    //}
-    
-    $object = new Session_ACLPageInfo( $page_id, $namespace, $this->acl_types, $this->acl_descs, $this->acl_deps, $this->acl_base_cache );
-    
-    return $object;
-    
-  }
-  
-  /**
-   * Read all of our permissions from the database and process/apply them. This should be called after the page is determined.
-   * @access private
-   */
-  
-  function init_permissions()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    // Initialize the permissions list with some defaults
-    $this->perms = $this->acl_types;
-    $this->acl_defaults_used = $this->perms;
-    
-    // Fetch sitewide defaults from the permissions table
-    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE page_id IS NULL AND namespace IS NULL AND ( ';
-    
-    $q = Array();
-    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
-    if(count($this->groups) > 0)
-    {
-      foreach($this->groups as $g_id => $g_name)
-      {
-        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
-      }
-    }
-    $bs .= implode(' OR ', $q) . ' ) ORDER BY target_type ASC, target_id ASC;';
-    $q = $this->sql($bs);
-    if ( $row = $db->fetchrow() )
-    {
-      do {
-        $rules = $this->string_to_perm($row['rules']);
-        $is_everyone = ( $row['target_type'] == ACL_TYPE_GROUP && $row['target_id'] == 1 );
-        $this->acl_merge_with_current($rules, $is_everyone);
-      } while ( $row = $db->fetchrow() );
-    }
-    
-    // Eliminate types that don't apply to this namespace
-    foreach ( $this->perms AS $i => $perm )
-    {
-      if ( !in_array ( $paths->namespace, $this->acl_scope[$i] ) && !in_array('All', $this->acl_scope[$i]) )
-      {
-        unset($this->perms[$i]);
-      }
-    }
-    
-    // Cache the sitewide permissions for later use
-    $this->acl_base_cache = $this->perms;
-    
-    // Build a query to grab ACL info
-    $bs = 'SELECT rules,target_type,target_id FROM '.table_prefix.'acl WHERE ( ';
-    $q = Array();
-    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$this->user_id.' )';
-    if(count($this->groups) > 0)
-    {
-      foreach($this->groups as $g_id => $g_name)
-      {
-        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
-      }
-    }
-    // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
-    // permissions to override group permissions.
-    $bs .= implode(' OR ', $q) . ' ) AND ( page_id=\''.$db->escape($paths->cpage['urlname_nons']).'\' AND namespace=\''.$db->escape($paths->namespace).'\' )     
-      ORDER BY target_type ASC, page_id ASC, namespace ASC;';
-    $q = $this->sql($bs);
-    if ( $row = $db->fetchrow() )
-    {
-      do {
-        $rules = $this->string_to_perm($row['rules']);
-        $is_everyone = ( $row['target_type'] == ACL_TYPE_GROUP && $row['target_id'] == 1 );
-        $this->acl_merge_with_current($rules, $is_everyone);
-      } while ( $row = $db->fetchrow() );
-    }
-    
-  }
-  
-  /**
-   * Extends the scope of a permission type.
-   * @param string The name of the permission type
-   * @param string The namespace(s) that should be covered. This can be either one namespace ID or a pipe-delimited list.
-   * @param object Optional - the current $paths object, in case we're doing this from the acl_rule_init hook
-   */
-   
-  function acl_extend_scope($perm_type, $namespaces, &$p_in)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $p_obj = ( is_object($p_in) ) ? $p_in : $paths;
-    $nslist = explode('|', $namespaces);
-    foreach ( $nslist as $i => $ns )
-    {
-      if ( !isset($p_obj->nslist[$ns]) )
-      {
-        unset($nslist[$i]);
-      }
-      else
-      {
-        $this->acl_scope[$perm_type][] = $ns;
-        if ( isset($this->acl_types[$perm_type]) && !isset($this->perms[$perm_type]) )
-        {
-          $this->perms[$perm_type] = $this->acl_types[$perm_type];
-        }
-      }
-    }
-  }
-  
-  /**
-   * Converts a permissions field into a string for database insertion. Similar in spirit to serialize().
-   * @param array $perms An associative array with only integers as values
-   * @return string
-   */
-   
-  function perm_to_string($perms)
-  {
-    $s = '';
-    foreach($perms as $perm => $ac)
-    {
-      $s .= "$perm=$ac;";
-    }
-    return $s;
-  }
-  
-  /**
-   * Converts a permissions string back to an array.
-   * @param string $perms The result from sessionManager::perm_to_string()
-   * @return array
-   */
-   
-  function string_to_perm($perms)
-  {
-    $ret = Array();
-    preg_match_all('#([a-z0-9_-]+)=([0-9]+);#i', $perms, $matches);
-    foreach($matches[1] as $i => $t)
-    {
-      $ret[$t] = intval($matches[2][$i]);
-    }
-    return $ret;
-  }
-  
-  /**
-   * Merges two ACL arrays. Both parameters should be permission list arrays. The second group takes precedence over the first, but AUTH_DENY always prevails.
-   * @param array $perm1 The first set of permissions
-   * @param array $perm2 The second set of permissions
-   * @return array
-   */
-   
-  function acl_merge($perm1, $perm2)
-  {
-    $ret = $perm1;
-    foreach ( $perm2 as $type => $level )
-    {
-      if ( isset( $ret[$type] ) )
-      {
-        if ( $ret[$type] != AUTH_DENY )
-          $ret[$type] = $level;
-      }
-      // else
-      // {
-      //   $ret[$type] = $level;
-      // }
-    }
-    return $ret;
-  }
-  
-  /**
-   * Merges the ACL array sent with the current permissions table, deciding precedence based on whether defaults are in effect or not.
-   * @param array The array to merge into the master ACL list
-   * @param bool If true, $perm is treated as the "new default"
-   * @param int 1 if this is a site-wide ACL, 2 if page-specific. Defaults to 2.
-   */
-  
-  function acl_merge_with_current($perm, $is_everyone = false, $scope = 2)
-  {
-    foreach ( $this->perms as $i => $p )
-    {
-      if ( isset($perm[$i]) )
-      {
-        if ( $is_everyone && !$this->acl_defaults_used[$i] )
-          continue;
-        // Decide precedence
-        if ( isset($this->acl_defaults_used[$i]) )
-        {
-          //echo "$i: default in use, overriding to: {$perm[$i]}<br />";
-          // Defaults are in use, override
-          $this->perms[$i] = $perm[$i];
-          $this->acl_defaults_used[$i] = ( $is_everyone );
-        }
-        else
-        {
-          //echo "$i: default NOT in use";
-          // Defaults are not in use, merge as normal
-          if ( $this->perms[$i] != AUTH_DENY )
-          {
-            //echo ", but overriding";
-            $this->perms[$i] = $perm[$i];
-          }
-          //echo "<br />";
-        }
-      }
-    }
-  }
-  
-  /**
-   * Merges two ACL arrays. Both parameters should be permission list arrays. The second group takes precedence
-   * over the first, without exceptions. This is used to merge the hardcoded defaults with admin-specified
-   * defaults, which take precedence.
-   * @param array $perm1 The first set of permissions
-   * @param array $perm2 The second set of permissions
-   * @return array
-   */
-   
-  function acl_merge_complete($perm1, $perm2)
-  {
-    $ret = $perm1;
-    foreach ( $perm2 as $type => $level )
-    {
-      $ret[$type] = $level;
-    }
-    return $ret;
-  }
-  
-  /**
-   * Tell us if the dependencies for a given permission are met.
-   * @param string The ACL permission ID
-   * @return bool
-   */
-   
-  function acl_check_deps($type)
-  {
-    if(!isset($this->acl_deps[$type])) // This will only happen if the permissions table is hacked or improperly accessed
-      return true;
-    if(sizeof($this->acl_deps[$type]) < 1)
-      return true;
-    $deps = $this->acl_deps[$type];
-    while(true)
-    {
-      $full_resolved = true;
-      $j = sizeof($deps);
-      for ( $i = 0; $i < $j; $i++ )
-      {
-        $b = $deps;
-        $deps = array_merge($deps, $this->acl_deps[$deps[$i]]);
-        if( $b == $deps )
-        {
-          break 2;
-        }
-        $j = sizeof($deps);
-      }
-    }
-    //die('<pre>'.print_r($deps, true).'</pre>');
-    foreach($deps as $d)
-    {
-      if ( !$this->get_permissions($d) )
-      {
-        return false;
-      }
-    }
-    return true;
-  }
-  
-  /**
-   * Makes a CAPTCHA code and caches the code in the database
-   * @param int $len The length of the code, in bytes
-   * @return string A unique identifier assigned to the code. This hash should be passed to sessionManager::getCaptcha() to retrieve the code.
-   */
-  
-  function make_captcha($len = 7)
-  {
-    $chars = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9');
-    $s = '';
-    for($i=0;$i<$len;$i++) $s .= $chars[mt_rand(0, count($chars)-1)];
-    $hash = md5(microtime() . mt_rand());
-    $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key,salt,auth_level,source_ip,user_id) VALUES(\''.$hash.'\', \''.$s.'\', -1, \''.ip2hex($_SERVER['REMOTE_ADDR']).'\', -2);');
-    return $hash;
-  }
-  
-  /**
-   * For the given code ID, returns the correct CAPTCHA code, or false on failure
-   * @param string $hash The unique ID assigned to the code
-   * @return string The correct confirmation code
-   */
-  
-  function get_captcha($hash)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $s = $this->sql('SELECT salt FROM '.table_prefix.'session_keys WHERE session_key=\''.$db->escape($hash).'\' AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
-    if($db->numrows() < 1) return false;
-    $r = $db->fetchrow();
-    return $r['salt'];
-  }
-  
-  /**
-   * Deletes all CAPTCHA codes cached in the DB for this user.
-   */
-  
-  function kill_captcha()
-  {
-    $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE user_id=-2 AND source_ip=\''.ip2hex($_SERVER['REMOTE_ADDR']).'\';');
-  }
-  
-  /**
-   * Generates a random password.
-   * @param int $length Optional - length of password
-   * @return string
-   */
-   
-  function random_pass($length = 10)
-  {
-    $valid_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_+@#%&<>';
-    $valid_chars = enano_str_split($valid_chars);
-    $ret = '';
-    for ( $i = 0; $i < $length; $i++ )
-    {
-      $ret .= $valid_chars[mt_rand(0, count($valid_chars)-1)];
-    }
-    return $ret;
-  }
-  
-  /**
-   * Generates some Javascript that calls the AES encryption library.
-   * @param string The name of the form
-   * @param string The name of the password field
-   * @param string The name of the field that switches encryption on or off
-   * @param string The name of the field that contains the encryption key
-   * @param string The name of the field that will contain the encrypted password
-   * @param string The name of the field that handles MD5 challenge data
-   * @return string
-   */
-   
-  function aes_javascript($form_name, $pw_field, $use_crypt, $crypt_key, $crypt_data, $challenge)
-  {
-    $code = '
-      <script type="text/javascript">
-        disableJSONExts();
-          str = \'\';
-          for(i=0;i<keySizeInBits/4;i++) str+=\'0\';
-          var key = hexToByteArray(str);
-          var pt = hexToByteArray(str);
-          var ct = rijndaelEncrypt(pt, key, \'ECB\');
-          var ct = byteArrayToHex(ct);
-          switch(keySizeInBits)
-          {
-            case 128:
-              v = \'66e94bd4ef8a2c3b884cfa59ca342b2e\';
-              break;
-            case 192:
-              v = \'aae06992acbf52a3e8f4a96ec9300bd7aae06992acbf52a3e8f4a96ec9300bd7\';
-              break;
-            case 256:
-              v = \'dc95c078a2408989ad48a21492842087dc95c078a2408989ad48a21492842087\';
-              break;
-          }
-          var testpassed = ' . ( ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0') ? 'false; // CRYPTO-AUTH DISABLED ON USER REQUEST // ' : '' ) . '( ct == v && md5_vm_test() );
-          var frm = document.forms.'.$form_name.';
-          if(testpassed)
-          {
-            frm.'.$use_crypt.'.value = \'yes\';
-            var cryptkey = frm.'.$crypt_key.'.value;
-            frm.'.$crypt_key.'.value = hex_md5(cryptkey);
-            cryptkey = hexToByteArray(cryptkey);
-            if(!cryptkey || ( ( typeof cryptkey == \'string\' || typeof cryptkey == \'object\' ) ) && cryptkey.length != keySizeInBits / 8 )
-            {
-              if ( frm._login ) frm._login.disabled = true;
-              len = ( typeof cryptkey == \'string\' || typeof cryptkey == \'object\' ) ? \'\\nLen: \'+cryptkey.length : \'\';
-              alert(\'The key is messed up\\nType: \'+typeof(cryptkey)+len);
-            }
-          }
-          if(frm.username) frm.username.focus();
-          function runEncryption()
-          {
-            if(testpassed)
-            {
-              pass = frm.'.$pw_field.'.value;
-              chal = frm.'.$challenge.'.value;
-              challenge = hex_md5(pass + chal) + chal;
-              frm.'.$challenge.'.value = challenge;
-              pass = stringToByteArray(pass);
-              cryptstring = rijndaelEncrypt(pass, cryptkey, \'ECB\');
-              if(!cryptstring)
-              {
-                return false;
-              }
-              cryptstring = byteArrayToHex(cryptstring);
-              frm.'.$crypt_data.'.value = cryptstring;
-              frm.'.$pw_field.'.value = \'\';
-            }
-            return false;
-          }
-        </script>
-        ';
-    return $code;
-  }
-  
-}
-
-/**
- * Class used to fetch permissions for a specific page. Used internally by SessionManager.
- * @package Enano
- * @subpackage Session manager
- * @license http://www.gnu.org/copyleft/gpl.html
- * @access private
- */
- 
-class Session_ACLPageInfo {
-  
-  /**
-   * The page ID of this ACL info package
-   * @var string
-   */
-   
-  var $page_id;
-  
-  /**
-   * The namespace of the page being checked
-   * @var string
-   */
-   
-  var $namespace;
-  
-  /**
-   * Our list of permission types.
-   * @access private
-   * @var array
-   */
-   
-  var $acl_types = Array();
-  
-  /**
-   * The list of descriptions for the permission types
-   * @var array
-   */
-   
-  var $acl_descs = Array();
-  
-  /**
-   * A list of dependencies for ACL types.
-   * @var array
-   */
-   
-  var $acl_deps = Array();
-  
-  /**
-   * Our tell-all list of permissions.
-   * @access private - or, preferably, protected...too bad this has to be PHP4 compatible
-   * @var array
-   */
-   
-  var $perms = Array();
-  
-  /**
-   * Constructor.
-   * @param string $page_id The ID of the page to check
-   * @param string $namespace The namespace of the page to check.
-   * @param array $acl_types List of ACL types
-   * @param array $acl_descs List of human-readable descriptions for permissions (associative)
-   * @param array $acl_deps List of dependencies for permissions. For example, viewing history/diffs depends on the ability to read the page.
-   * @param array $base What to start with - this is an attempt to reduce the number of SQL queries.
-   */
-   
-  function Session_ACLPageInfo($page_id, $namespace, $acl_types, $acl_descs, $acl_deps, $base)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $this->perms = $session->acl_merge_complete($acl_types, $base);
-    $this->acl_deps = $acl_deps;
-    $this->acl_types = $acl_types;
-    $this->acl_descs = $acl_descs;
-    
-    // Build a query to grab ACL info
-    $bs = 'SELECT rules FROM '.table_prefix.'acl WHERE ( ';
-    $q = Array();
-    $q[] = '( target_type='.ACL_TYPE_USER.' AND target_id='.$session->user_id.' )';
-    if(count($session->groups) > 0)
-    {
-      foreach($session->groups as $g_id => $g_name)
-      {
-        $q[] = '( target_type='.ACL_TYPE_GROUP.' AND target_id='.intval($g_id).' )';
-      }
-    }
-    // The reason we're using an ORDER BY statement here is because ACL_TYPE_GROUP is less than ACL_TYPE_USER, causing the user's individual
-    // permissions to override group permissions.
-    $bs .= implode(' OR ', $q) . ' ) AND ( page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\' )     
-      ORDER BY target_type ASC, page_id ASC, namespace ASC;';
-    $q = $session->sql($bs);
-    if ( $row = $db->fetchrow() )
-    {
-      do {
-        $rules = $session->string_to_perm($row['rules']);
-        $this->perms = $session->acl_merge($this->perms, $rules);
-      } while ( $row = $db->fetchrow() );
-    }
-    
-    $this->page_id = $page_id;
-    $this->namespace = $namespace;
-  }
-  
-  /**
-   * Tells us whether permission $type is allowed or not based on the current rules.
-   * @param string $type The permission identifier ($acl_type passed to sessionManager::register_acl_type())
-   * @param bool $no_deps If true, disables dependency checking
-   * @return bool True if allowed, false if denied or if an error occured
-   */
-   
-  function get_permissions($type, $no_deps = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if ( isset( $this->perms[$type] ) )
-    {
-      if ( $this->perms[$type] == AUTH_DENY )
-        $ret = false;
-      else if ( $this->perms[$type] == AUTH_WIKIMODE &&
-        ( isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id]) && 
-          ( $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '1' ||
-            ( $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '2'
-              && getConfig('wiki_mode') == '1'
-          ) ) ) )
-        $ret = true;
-      else if ( $this->perms[$type] == AUTH_WIKIMODE && (
-        !isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id])
-        || (
-          isset($paths->pages[$paths->nslist[$this->namespace].$this->page_id]) && (
-            $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '0'
-            || (
-              $paths->pages[$paths->nslist[$this->namespace].$this->page_id]['wiki_mode'] == '2' && getConfig('wiki_mode') != '1'
-          ) ) ) ) )
-        $ret = false;
-      else if ( $this->perms[$type] == AUTH_ALLOW )
-        $ret = true;
-      else if ( $this->perms[$type] == AUTH_DISALLOW )
-        $ret = false;
-    }
-    else if(isset($this->acl_types[$type]))
-    {
-      if ( $this->acl_types[$type] == AUTH_DENY )
-        $ret = false;
-      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && $paths->wiki_mode )
-        $ret = true;
-      else if ( $this->acl_types[$type] == AUTH_WIKIMODE && !$paths->wiki_mode )
-        $ret = false;
-      else if ( $this->acl_types[$type] == AUTH_ALLOW )
-        $ret = true;
-      else if ( $this->acl_types[$type] == AUTH_DISALLOW )
-        $ret = false;
-    }
-    else
-    {
-      // ACL type is undefined
-      trigger_error('Unknown access type "' . $type . '"', E_USER_WARNING);
-      return false; // Be on the safe side and deny access
-    }
-    if ( !$no_deps )
-    {
-      if ( !$this->acl_check_deps($type) )
-        return false;
-    }
-    return $ret;
-  }
-  
-  /**
-   * Tell us if the dependencies for a given permission are met.
-   * @param string The ACL permission ID
-   * @return bool
-   */
-   
-  function acl_check_deps($type)
-  {
-    if(!isset($this->acl_deps[$type])) // This will only happen if the permissions table is hacked or improperly accessed
-      return true;
-    if(sizeof($this->acl_deps[$type]) < 1)
-      return true;
-    $deps = $this->acl_deps[$type];
-    while(true)
-    {
-      $full_resolved = true;
-      $j = sizeof($deps);
-      for ( $i = 0; $i < $j; $i++ )
-      {
-        $b = $deps;
-        $deps = array_merge($deps, $this->acl_deps[$deps[$i]]);
-        if( $b == $deps )
-        {
-          break 2;
-        }
-        $j = sizeof($deps);
-      }
-    }
-    //die('<pre>'.print_r($deps, true).'</pre>');
-    foreach($deps as $d)
-    {
-      if ( !$this->get_permissions($d) )
-      {
-        return false;
-      }
-    }
-    return true;
-  }
-  
-}
-
-?>
--- a/includes/template.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1785 +0,0 @@
-<?php
-
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 (Banshee)
- * Copyright (C) 2006-2007 Dan Fuhry
- *
- * This program is Free Software; you can redistribute 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 details.
- */
- 
-class template {
-  var $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list, $named_theme_list, $default_theme, $default_style, $plugin_blocks, $namespace_string, $style_list, $theme_loaded;
-  function __construct()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    dc_here('template: initializing all class variables');
-    $this->tpl_bool    = Array();
-    $this->tpl_strings = Array();
-    $this->sidebar_extra = '';
-    $this->toolbar_menu = '';
-    $this->additional_headers = '';
-    $this->plugin_blocks = Array();
-    $this->theme_loaded = false;
-    
-    $this->theme_list = Array();
-    $this->named_theme_list = Array();
-    $e = $db->sql_query('SELECT theme_id,theme_name,enabled,default_style FROM '.table_prefix.'themes WHERE enabled=1 ORDER BY theme_order;');
-    if(!$e) $db->_die('The list of themes could not be selected.');
-    for($i=0;$i < $db->numrows(); $i++)
-    {
-      $this->theme_list[$i] = $db->fetchrow();
-      $this->named_theme_list[$this->theme_list[$i]['theme_id']] = $this->theme_list[$i];
-    }
-    $db->free_result();
-    $this->default_theme = $this->theme_list[0]['theme_id'];
-    $dir = ENANO_ROOT.'/themes/'.$this->default_theme.'/css/';
-    $list = Array();
-    // Open a known directory, and proceed to read its contents
-    if (is_dir($dir)) {
-      if ($dh = opendir($dir)) {
-        while (($file = readdir($dh)) !== false) {
-          if(preg_match('#^(.*?)\.css$#i', $file) && $file != '_printable.css') {
-            $list[] = substr($file, 0, strlen($file)-4);
-          }
-        }
-        closedir($dh);
-      }
-    }
-    
-    $def = ENANO_ROOT.'/themes/'.$this->default_theme.'/css/'.$this->named_theme_list[$this->default_theme]['default_style'];
-    if(file_exists($def))
-    {
-      $this->default_style = substr($this->named_theme_list[$this->default_theme]['default_style'], 0, strlen($this->named_theme_list[$this->default_theme]['default_style'])-4);
-    } else {
-      $this->default_style = $list[0];
-    }
-    
-    $this->style_list = $list;
-    
-  }
-  function template()
-  {
-    $this->__construct();
-  }
-  function sidebar_widget($t, $h)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!defined('ENANO_TEMPLATE_LOADED'))
-    {
-      $this->load_theme($session->theme, $session->style);
-    }
-    if(!$this->sidebar_widgets)
-      $this->sidebar_widgets = '';
-    $tplvars = $this->extract_vars('elements.tpl');
-    $parser = $this->makeParserText($tplvars['sidebar_section_raw']);
-    $parser->assign_vars(Array('TITLE'=>$t,'CONTENT'=>$h));
-    $this->plugin_blocks[$t] = $h;
-    $this->sidebar_widgets .= $parser->run();
-  }
-  function add_header($html)
-  {
-    $this->additional_headers .= "\n" . $html;
-  }
-  function get_css($s = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!defined('ENANO_TEMPLATE_LOADED'))
-      $this->load_theme($session->theme, $session->style);
-    $path = ( $s ) ? 'css/'.$s : 'css/'.$this->style.'.css';
-    if ( !file_exists(ENANO_ROOT . '/themes/' . $this->theme . '/' . $path) )
-    {
-      echo "/* WARNING: Falling back to default file because file $path does not exist */\n";
-      $path = 'css/' . $this->style_list[0] . '.css';
-    }
-    return $this->process_template($path);
-  }
-  function load_theme($name = false, $css = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $this->theme = ( $name ) ? $name : $session->theme;
-    $this->style = ( $css ) ? $css : $session->style;
-    if ( !$this->theme )
-    {
-      $this->theme = $this->theme_list[0]['theme_id'];
-      $this->style = substr($this->theme_list[0]['default_style'], 0, strlen($this->theme_list[0]['default_style'])-4);
-    }
-    $this->theme_loaded = true;
-  }
-  
-  function init_vars()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    global $email;
-    
-    dc_here("template: initializing all variables");
-    
-    if(!$this->theme || !$this->style)
-    {
-      $this->load_theme();
-    }
-    
-    if(defined('ENANO_TEMPLATE_LOADED'))
-    {
-      dc_here('template: access denied to call template::init_vars(), bailing out');
-      die_semicritical('Illegal call', '<p>$template->load_theme was called multiple times, this is not supposed to happen. Exiting with fatal error.</p>');
-    }
-    
-    define('ENANO_TEMPLATE_LOADED', '');
-    
-    $tplvars = $this->extract_vars('elements.tpl');
-    
-    dc_here('template: setting all template vars');
-    
-    if(isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE'))
-    {
-      $this->add_header('
-        <!--[if lt IE 7]>
-        <script language="JavaScript">
-        function correctPNG() // correctly handle PNG transparency in Win IE 5.5 & 6.
-        {
-           var arVersion = navigator.appVersion.split("MSIE")
-           var version = parseFloat(arVersion[1])
-           if (version >= 5.5 && typeof(document.body.filters) == "object")
-           {
-              for(var i=0; i<document.images.length; i++)
-              {
-                 var img = document.images[i];
-                 continue;
-                 var imgName = img.src.toUpperCase();
-                 if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
-                 {
-                    var imgID = (img.id) ? "id=\'" + img.id + "\' " : "";
-                    var imgClass = (img.className) ? "class=\'" + img.className + "\' " : "";
-                    var imgTitle = (img.title) ? "title=\'" + img.title + "\' " : "title=\'" + img.alt + "\' ";
-                    var imgStyle = "display:inline-block;" + img.style.cssText;
-                    if (img.align == "left") imgStyle = "float:left;" + imgStyle;
-                    if (img.align == "right") imgStyle = "float:right;" + imgStyle;
-                    if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle;
-                    var strNewHTML = "<span " + imgID + imgClass + imgTitle + " style=\\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";" + "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader" + "(src=\\\'" + img.src + "\\\', sizingMethod=\'scale\');\\"></span>";
-                    img.outerHTML = strNewHTML;
-                    i = i-1;
-                 }
-              }
-           }   
-        }
-        window.attachEvent("onload", correctPNG);
-        </script>
-        <![endif]-->
-        ');
-    }
-    
-    // Get the "article" button text (depends on namespace)
-    switch($paths->namespace) {
-      case "Article":
-      default:
-        $ns = 'article';
-        break;
-      case "Admin":
-        $ns = 'administration page';
-        break;
-      case "System":
-        $ns = 'system message';
-        break;
-      case "File":
-        $ns = 'uploaded file';
-        break;
-      case "Help":
-        $ns = 'documentation page';
-        break;
-      case "User":
-        $ns = 'user page';
-        break;
-      case "Special":
-        $ns = 'special page';
-        break;
-      case "Template":
-        $ns = 'template';
-        break;
-      case "Project":
-        $ns = 'project page';
-        break;
-      case "Category":
-        $ns = 'category';
-        break;
-    }
-    $this->namespace_string = $ns;
-    $code = $plugins->setHook('page_type_string_set');
-    foreach ( $code as $cmd )
-    {
-      eval($cmd);
-    }
-    $ns =& $this->namespace_string;
-    
-    // Initialize the toolbar
-    $tb = '';
-    
-    // Create "xx page" button
-    
-    $btn_selected = ( isset($tplvars['toolbar_button_selected'])) ? $tplvars['toolbar_button_selected'] : $tplvars['toolbar_button'];
-    $parser = $this->makeParserText($btn_selected);
-    
-    $parser->assign_vars(array(
-        'FLAGS' => 'onclick="void(ajaxReset()); return false;" title="View the page contents, all of the page contents, and nothing but the page contents (alt-a)" accesskey="a"',
-        'PARENTFLAGS' => 'id="mdgToolbar_article"',
-        'HREF' => makeUrl($paths->page, null, true),
-        'TEXT' => $this->namespace_string
-      ));
-    
-    $tb .= $parser->run();
-    
-    $button = $this->makeParserText($tplvars['toolbar_button']);
-    
-    // Page toolbar
-    // Comments button
-    if ( $session->get_permissions('read') && getConfig('enable_comments')=='1' && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $paths->cpage['comments_on'] == 1 )
-    {
-      
-      $e = $db->sql_query('SELECT approved FROM '.table_prefix.'comments WHERE page_id=\''.$paths->cpage['urlname_nons'].'\' AND namespace=\''.$paths->namespace.'\';');
-      if ( !$e )
-      {
-        $db->_die();
-      }
-      $nc = $db->numrows();
-      $nu = 0;
-      $na = 0;
-      
-      while ( $r = $db->fetchrow() )
-      {  
-        if ( !$r['approved'] )
-        {
-          $nu++;
-        }
-        else
-        {
-          $na++;
-        }
-      }
-      
-      $db->free_result();
-      $n = ( $session->get_permissions('mod_comments') ) ? (string)$nc : (string)$na;
-      if ( $session->get_permissions('mod_comments') && $nu > 0 )
-      {
-        $n .= ' total/'.$nu.' unapp.';
-      }
-      
-      $button->assign_vars(array(
-          'FLAGS' => 'onclick="void(ajaxComments()); return false;" title="View the comments that other users have posted about this page (alt-c)" accesskey="c"',
-          'PARENTFLAGS' => 'id="mdgToolbar_discussion"',
-          'HREF' => makeUrl($paths->page, 'do=comments', true),
-          'TEXT' => 'discussion ('.$n.')',
-        ));
-      
-      $tb .= $button->run();
-    }
-    // Edit button
-    if($session->get_permissions('read') && ($paths->namespace != 'Special' && $paths->namespace != 'Admin') && ( $session->get_permissions('edit_page') && ( ( $paths->page_protected && $session->get_permissions('even_when_protected') ) || !$paths->page_protected ) ) )
-    {
-      $button->assign_vars(array(
-        'FLAGS' => 'onclick="void(ajaxEditor()); return false;" title="Edit the contents of this page (alt-e)" accesskey="e"',
-        'PARENTFLAGS' => 'id="mdgToolbar_edit"',
-        'HREF' => makeUrl($paths->page, 'do=edit', true),
-        'TEXT' => 'edit this page'
-        ));
-      $tb .= $button->run();
-    // View source button
-    }
-    else if($session->get_permissions('view_source') && ( !$session->get_permissions('edit_page') || !$session->get_permissions('even_when_protected') && $paths->page_protected ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin') 
-    {
-      $button->assign_vars(array(
-        'FLAGS' => 'onclick="void(ajaxViewSource()); return false;" title="View the source code (wiki markup) that this page uses (alt-e)" accesskey="e"',
-        'PARENTFLAGS' => 'id="mdgToolbar_edit"',
-        'HREF' => makeUrl($paths->page, 'do=viewsource', true),
-        'TEXT' => 'view source'
-        ));
-      $tb .= $button->run();
-    }
-    // History button
-    if ( $session->get_permissions('read') /* && $paths->wiki_mode */ && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('history_view') )
-    {
-      $button->assign_vars(array(
-        'FLAGS'       => 'onclick="void(ajaxHistory()); return false;" title="View a log of actions taken on this page (alt-h)" accesskey="h"',
-        'PARENTFLAGS' => 'id="mdgToolbar_history"',
-        'HREF'        => makeUrl($paths->page, 'do=history', true),
-        'TEXT'        => 'history'
-        ));
-      $tb .= $button->run();
-    }
-    
-    $menubtn = $this->makeParserText($tplvars['toolbar_menu_button']);
-    
-    // Additional actions menu
-    // Rename button
-    if ( $session->get_permissions('read') && $paths->page_exists && ( $session->get_permissions('rename') && ( $paths->page_protected && $session->get_permissions('even_when_protected') || !$paths->page_protected ) ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
-    {
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="void(ajaxRename()); return false;" title="Change the display name of this page (alt-r)" accesskey="r"',
-          'HREF'  => makeUrl($paths->page, 'do=rename', true),
-          'TEXT'  => 'rename',
-        ));
-      $this->toolbar_menu .= $menubtn->run();
-    }
-    
-    // Vote-to-delete button
-    if ( $paths->wiki_mode && $session->get_permissions('vote_delete') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin')
-    {
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="void(ajaxDelVote()); return false;" title="Vote to have this page deleted (alt-d)" accesskey="d"',
-          'HREF'  => makeUrl($paths->page, 'do=delvote', true),
-          'TEXT'  => 'vote to delete this page',
-        ));
-      $this->toolbar_menu .= $menubtn->run();
-    }
-    
-    // Clear-votes button
-    if ( $session->get_permissions('read') && $paths->wiki_mode && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('vote_reset') && $paths->cpage['delvotes'] > 0)
-    {
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="void(ajaxResetDelVotes()); return false;" title="Vote to have this page deleted (alt-y)" accesskey="y"',
-          'HREF'  => makeUrl($paths->page, 'do=resetvotes', true),
-          'TEXT'  => 'reset deletion votes',
-        ));
-      $this->toolbar_menu .= $menubtn->run();
-    }
-    
-    // Printable page button
-    if ( $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
-    {
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'title="View a version of this page that is suitable for printing"',
-          'HREF'  => makeUrl($paths->page, 'printable=yes', true),
-          'TEXT'  => 'view printable version',
-        ));
-      $this->toolbar_menu .= $menubtn->run();
-    }
-    
-    // Protect button
-    if($session->get_permissions('read') && $paths->wiki_mode && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' && $session->get_permissions('protect'))
-    {
-      
-      $label = $this->makeParserText($tplvars['toolbar_label']);
-      $label->assign_vars(array('TEXT' => 'protection:'));
-      $t0 = $label->run();
-      
-      $ctmp = ''; 
-      if ( $paths->cpage['protected'] == 1 )
-      {
-        $ctmp=' style="text-decoration: underline;"';
-      }
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'accesskey="i" onclick="ajaxProtect(1); return false;" id="protbtn_1" title="Prevents all non-administrators from editing this page. [alt-i]"'.$ctmp,
-          'HREF'  => makeUrl($paths->page, 'do=protect&level=1', true),
-          'TEXT'  => 'on'
-        ));
-      $t1 = $menubtn->run();
-      
-      $ctmp = '';
-      if ( $paths->cpage['protected'] == 0 )
-      {
-        $ctmp=' style="text-decoration: underline;"';
-      }
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'accesskey="o" onclick="ajaxProtect(0); return false;" id="protbtn_0" title="Allows everyone to edit this page. [alt-o]"'.$ctmp,
-          'HREF'  => makeUrl($paths->page, 'do=protect&level=0', true),
-          'TEXT'  => 'off'
-        ));
-      $t2 = $menubtn->run();
-      
-      $ctmp = '';
-      if ( $paths->cpage['protected'] == 2 )
-      {
-        $ctmp = ' style="text-decoration: underline;"';
-      }
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'accesskey="p" onclick="ajaxProtect(2); return false;" id="protbtn_2" title="Allows only users who have been registered for 4 days to edit this page. [alt-p]"'.$ctmp,
-          'HREF'  => makeUrl($paths->page, 'do=protect&level=2', true),
-          'TEXT'  => 'semi'
-        ));
-      $t3 = $menubtn->run();
-      
-      $this->toolbar_menu .= '        <table border="0" cellspacing="0" cellpadding="0">
-          <tr>
-            <td>'.$t0.'</td>
-            <td>'.$t1.'</td>
-            <td>'.$t2.'</td>
-            <td>'.$t3.'</td>
-          </tr>
-        </table>';
-    }
-    
-    // Wiki mode button
-    if($session->get_permissions('read') && $paths->page_exists && $session->get_permissions('set_wiki_mode') && $paths->namespace != 'Special' && $paths->namespace != 'Admin')
-    {
-      // label at start
-      $label = $this->makeParserText($tplvars['toolbar_label']);
-      $label->assign_vars(array('TEXT' => 'page wiki mode:'));
-      $t0 = $label->run();
-      
-      // on button
-      $ctmp = '';
-      if ( $paths->cpage['wiki_mode'] == 1 )
-      {
-        $ctmp = ' style="text-decoration: underline;"';
-      }
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="ajaxSetWikiMode(1); return false;" id="wikibtn_1" title="Forces wiki functions to be allowed on this page."'.$ctmp,
-          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=1', true),
-          'TEXT' => 'on'
-        ));
-      $t1 = $menubtn->run();
-      
-      // off button
-      $ctmp = '';
-      if ( $paths->cpage['wiki_mode'] == 0 )
-      {
-        $ctmp=' style="text-decoration: underline;"';
-      }
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="ajaxSetWikiMode(0); return false;" id="wikibtn_0" title="Forces wiki functions to be disabled on this page."'.$ctmp,
-          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=0', true),
-          'TEXT' => 'off'
-        ));
-      $t2 = $menubtn->run();
-      
-      // global button
-      $ctmp = ''; 
-      if ( $paths->cpage['wiki_mode'] == 2 )
-      {
-        $ctmp=' style="text-decoration: underline;"';
-      }
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="ajaxSetWikiMode(2); return false;" id="wikibtn_2" title="Causes this page to use the global wiki mode setting (default)"'.$ctmp,
-          'HREF' => makeUrl($paths->page, 'do=setwikimode&level=2', true),
-          'TEXT' => 'global'
-        ));
-      $t3 = $menubtn->run();
-      
-      // Tack it onto the list of buttons that are already there...
-      $this->toolbar_menu .= '        <table border="0" cellspacing="0" cellpadding="0">
-          <tr>
-            <td>'.$t0.'</td>
-            <td>'.$t1.'</td>
-            <td>'.$t2.'</td>
-            <td>'.$t3.'</td>
-          </tr>
-        </table>';
-    }
-    
-    // Clear logs button
-    if ( $session->get_permissions('read') && $session->get_permissions('clear_logs') && $paths->wiki_mode && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
-    {
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="void(ajaxClearLogs()); return false;" title="Remove all edit and action logs for this page from the database. IRREVERSIBLE! (alt-l)" accesskey="l"',
-          'HREF'  => makeUrl($paths->page, 'do=flushlogs', true),
-          'TEXT'  => 'clear page logs',
-        ));
-      $this->toolbar_menu .= $menubtn->run();
-    }
-    
-    // Delete page button
-    if ( $session->get_permissions('read') && $session->get_permissions('delete_page') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
-    {
-      $s = 'delete this page';
-      if ( $paths->cpage['delvotes'] == 1 )
-      {
-        $s .= ' (<b>'.$paths->cpage['delvotes'].'</b> vote)';
-      }
-      else if ( $paths->cpage['delvotes'] > 1 )
-      {
-        $s .= ' (<b>'.$paths->cpage['delvotes'].'</b> votes)';
-      }
-      
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="void(ajaxDeletePage()); return false;" title="Delete this page. This is always reversible unless the logs are cleared. (alt-k)" accesskey="k"',
-          'HREF'  => makeUrl($paths->page, 'do=deletepage', true),
-          'TEXT'  => $s,
-        ));
-      $this->toolbar_menu .= $menubtn->run();
-      
-    }
-    
-    // Password-protect button
-    if(isset($paths->cpage['password']))
-    {
-      if ( $paths->cpage['password'] == '' )
-      {
-        $a = $session->get_permissions('password_set');
-      }
-      else
-      {
-        $a = $session->get_permissions('password_reset');
-      }
-    }
-    else
-    {
-      $a = $session->get_permissions('password_set');
-    }
-    if ( $a && $session->get_permissions('read') && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
-    {
-      // label at start
-      $label = $this->makeParserText($tplvars['toolbar_label']);
-      $label->assign_vars(array('TEXT' => 'password:'));
-      $t0 = $label->run();
-      
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="void(ajaxSetPassword()); return false;" title="Require a password in order for this page to be viewed"',
-          'HREF'  => '#',
-          'TEXT'  => 'set',
-        ));
-      $t = $menubtn->run();
-      
-      $this->toolbar_menu .= '<table border="0" cellspacing="0" cellpadding="0"><tr><td>'.$t0.'</td><td><input type="password" id="mdgPassSetField" size="10" /></td><td>'.$t.'</td></tr></table>';
-    }
-    
-    // Manage ACLs button
-    if($session->get_permissions('edit_acl') || $session->user_level >= USER_LEVEL_ADMIN)
-    {
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="return ajaxOpenACLManager();" title="Manage who can do what with this page (alt-m)" accesskey="m"',
-          'HREF'  => makeUrl($paths->page, 'do=aclmanager', true),
-          'TEXT'  => 'manage page access',
-        ));
-      $this->toolbar_menu .= $menubtn->run();
-    }
-    
-    // Administer page button
-    if ( $session->user_level >= USER_LEVEL_ADMIN && $paths->page_exists && $paths->namespace != 'Special' && $paths->namespace != 'Admin' )
-    {
-      $menubtn->assign_vars(array(
-          'FLAGS' => 'onclick="void(ajaxAdminPage()); return false;" title="Administrative options for this page" accesskey="g"',
-          'HREF'  => makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'PageManager', true),
-          'TEXT'  => 'administrative options',
-        ));
-      $this->toolbar_menu .= $menubtn->run();
-    }
-    
-    if ( strlen($this->toolbar_menu) > 0 )
-    {
-      $button->assign_vars(array(
-        'FLAGS'       => 'id="mdgToolbar_moreoptions" onclick="return false;" title="Additional options for working with this page"',
-        'PARENTFLAGS' => '',
-        'HREF'        => makeUrl($paths->page, 'do=moreoptions', true),
-        'TEXT'        => 'more options'
-        ));
-      $tb .= $button->run();
-    }
-    
-    $is_opera = (isset($_SERVER['HTTP_USER_AGENT']) && strstr($_SERVER['HTTP_USER_AGENT'], 'Opera')) ? true : false;
-    
-    $this->tpl_bool = Array(
-      'auth_admin'=>$session->user_level >= USER_LEVEL_ADMIN ? true : false,
-      'user_logged_in'=>$session->user_logged_in,
-      'opera'=>$is_opera,
-      );
-    
-    if($session->sid_super) { $ash = '&amp;auth='.$session->sid_super; $asq = "?auth=".$session->sid_super; $asa = "&auth=".$session->sid_super; $as2 = htmlspecialchars(urlSeparator).'auth='.$session->sid_super; }
-    else { $asq=''; $asa=''; $as2 = ''; $ash = ''; }
-    
-    $code = $plugins->setHook('compile_template');
-    foreach ( $code as $cmd )
-    {
-      eval($cmd);
-    }
-    
-    // Some additional sidebar processing
-    if($this->sidebar_extra != '') {
-      $se = $this->sidebar_extra;
-      $parser = $this->makeParserText($tplvars['sidebar_section_raw']);
-      $parser->assign_vars(Array('TITLE'=>'Links','CONTENT'=>$se));
-      $this->sidebar_extra = $parser->run();
-    }
-    
-    $this->sidebar_extra = $this->sidebar_extra.$this->sidebar_widgets;
-    
-    $this->tpl_bool['fixed_menus'] = false;
-    /* if($this->sidebar_extra == '') $this->tpl_bool['right_sidebar'] = false;
-    else */ $this->tpl_bool['right_sidebar'] = true;
-    
-    $this->tpl_bool['auth_rename'] = ( $paths->page_exists && ( $session->get_permissions('rename') && ( $paths->page_protected && $session->get_permissions('even_when_protected') || !$paths->page_protected ) ) && $paths->namespace != 'Special' && $paths->namespace != 'Admin');
-    
-    $this->tpl_bool['enable_uploads'] = ( getConfig('enable_uploads') == '1' && $session->get_permissions('upload_files') ) ? true : false;
-    
-    $this->tpl_bool['stupid_mode'] = false;
-    
-    if($paths->page == $paths->nslist['Special'].'Administration') $this->tpl_bool['in_admin'] = true;
-    else $this->tpl_bool['in_admin'] = false;
-    
-    $p = ( isset($_GET['printable']) ) ? '/printable' : '';
-    
-    // Add the e-mail address client code to the header
-    $this->add_header($email->jscode());
-    
-    // Generate the code for the Log out and Change theme sidebar buttons
-    // Once again, the new template parsing system can be used here
-    
-    $parser = $this->makeParserText($tplvars['sidebar_button']);
-    
-    $parser->assign_vars(Array(
-        'HREF'=>makeUrlNS('Special', 'Logout'),
-        'FLAGS'=>'onclick="mb_logout(); return false;"',
-        'TEXT'=>'Log out',
-      ));
-    
-    $logout_link = $parser->run();
-    
-    $parser->assign_vars(Array(
-        'HREF'=>makeUrlNS('Special', 'Login/' . $paths->page),
-        'FLAGS'=>'onclick="ajaxStartLogin(); return false;"',
-        'TEXT'=>'Log in',
-      ));
-    
-    $login_link = $parser->run();
-    
-    $parser->assign_vars(Array(
-        'HREF'=>makeUrlNS('Special', 'ChangeStyle/'.$paths->page),
-        'FLAGS'=>'onclick="ajaxChangeStyle(); return false;"',
-        'TEXT'=>'Change theme',
-      ));
-    
-    $theme_link = $parser->run();
-    
-    $SID = ($session->sid_super) ? $session->sid_super : '';
-    
-    // Generate the dynamic javascript vars
-    $js_dynamic = '    <script type="text/javascript">// <![CDATA[
-      // This section defines some basic and very important variables that are used later in the static Javascript library.
-      // SKIN DEVELOPERS: The template variable for this code block is {JS_DYNAMIC_VARS}. This MUST be inserted BEFORE the tag that links to the main Javascript lib.
-      var title=\''. str_replace('\'', '\\\'', str_replace('\\', '\\\\', $paths->fullpage)) .'\';
-      var page_exists='. ( ( $paths->page_exists) ? 'true' : 'false' ) .';
-      var scriptPath=\''. scriptPath .'\';
-      var contentPath=\''.contentPath.'\';
-      var ENANO_SID =\'' . $SID . '\';
-      var auth_level=' . $session->auth_level . ';
-      var USER_LEVEL_GUEST = ' . USER_LEVEL_GUEST . ';
-      var USER_LEVEL_MEMBER = ' . USER_LEVEL_MEMBER . ';
-      var USER_LEVEL_CHPREF = ' . USER_LEVEL_CHPREF . ';
-      var USER_LEVEL_MOD = ' . USER_LEVEL_MOD . ';
-      var USER_LEVEL_ADMIN = ' . USER_LEVEL_ADMIN . ';
-      var editNotice = \'' . ( (getConfig('wiki_edit_notice')=='1') ? str_replace("\n", "\\\n", RenderMan::render(getConfig('wiki_edit_notice_text'))) : '' ) . '\';
-      var prot = ' . ( ($paths->page_protected && !$session->get_permissions('even_when_protected')) ? 'true' : 'false' ) .'; // No, hacking this var won\'t work, it\'s re-checked on the server
-      var ENANO_SPECIAL_CREATEPAGE = \''. makeUrl($paths->nslist['Special'].'CreatePage') .'\';
-      var ENANO_CREATEPAGE_PARAMS = \'_do=&pagename='. addslashes($paths->cpage['name']) .'&namespace=' . $paths->namespace . '\';
-      var ENANO_SPECIAL_CHANGESTYLE = \''. makeUrlNS('Special', 'ChangeStyle') .'\';
-      var namespace_list = new Array();
-      var AES_BITS = '.AES_BITS.';
-      var AES_BLOCKSIZE = '.AES_BLOCKSIZE.';
-      var pagepass = \''. ( ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '' ) .'\';
-      var ENANO_THEME_LIST = \'';
-          foreach($this->theme_list as $t) {
-            if($t['enabled'])
-            {
-              $js_dynamic .= '<option value="'.$t['theme_id'].'"';
-              if($t['theme_id'] == $session->theme) $js_dynamic .= ' selected="selected"';
-              $js_dynamic .= '>'.$t['theme_name'].'</option>';
-            }
-          }
-      $js_dynamic .= '\';
-      var ENANO_CURRENT_THEME = \''. $session->theme .'\';';
-      foreach($paths->nslist as $k => $c)
-      {
-        $js_dynamic .= "namespace_list['{$k}'] = '$c';";
-      }
-      $js_dynamic .= "\n    //]]>\n    </script>";
-    
-    $tpl_strings = Array(
-      'PAGE_NAME'=>$paths->cpage['name'],
-      'PAGE_URLNAME'=>$paths->cpage['urlname'],
-      'SITE_NAME'=>getConfig('site_name'),
-      'USERNAME'=>$session->username,
-      'SITE_DESC'=>getConfig('site_desc'),
-      'TOOLBAR'=>$tb,
-      'SCRIPTPATH'=>scriptPath,
-      'CONTENTPATH'=>contentPath,
-      'ADMIN_SID_QUES'=>$asq,
-      'ADMIN_SID_AMP'=>$asa,
-      'ADMIN_SID_AMP_HTML'=>$ash,
-      'ADMIN_SID_AUTO'=>$as2,
-      'ADDITIONAL_HEADERS'=>$this->additional_headers,
-      'COPYRIGHT'=>getConfig('copyright_notice'),
-      'TOOLBAR_EXTRAS'=>$this->toolbar_menu,
-      'REQUEST_URI'=>$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
-      'STYLE_LINK'=>makeUrlNS('Special', 'CSS'.$p, null, true), //contentPath.$paths->nslist['Special'].'CSS' . $p,
-      'LOGIN_LINK'=>$login_link,
-      'LOGOUT_LINK'=>$logout_link,
-      'THEME_LINK'=>$theme_link,
-      'TEMPLATE_DIR'=>scriptPath.'/themes/'.$this->theme,
-      'THEME_ID'=>$this->theme,
-      'STYLE_ID'=>$this->style,
-      'JS_DYNAMIC_VARS'=>$js_dynamic,
-      'UNREAD_PMS'=>$session->unread_pms
-      );
-    
-    foreach ( $paths->nslist as $ns_id => $ns_prefix )
-    {
-      $tpl_strings[ 'NS_' . strtoupper($ns_id) ] = $ns_prefix;
-    }
-    
-    $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings);
-    list($this->tpl_strings['SIDEBAR_LEFT'], $this->tpl_strings['SIDEBAR_RIGHT'], $min) = $this->fetch_sidebar();
-    $this->tpl_bool['sidebar_left']  = ( $this->tpl_strings['SIDEBAR_LEFT']  != $min) ? true : false;
-    $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != $min) ? true : false;
-    $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility
-  }
-  
-  function header($simple = false) 
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    ob_start();
-    
-    if(!$this->theme_loaded)
-    {
-      $this->load_theme($session->theme, $session->style);
-    }
-    
-    $headers_sent = true;
-    dc_here('template: generating and sending the page header');
-    if(!defined('ENANO_HEADERS_SENT'))
-      define('ENANO_HEADERS_SENT', '');
-    if(!$this->no_headers) echo ( $simple ) ? $this->process_template('simple-header.tpl') : $this->process_template('header.tpl');
-    if ( !$simple && $session->user_logged_in && $session->unread_pms > 0 )
-    {
-      echo $this->notify_unread_pms();
-    }
-    if ( !$simple && $session->sw_timed_out )
-    {
-      $login_link = makeUrlNS('Special', 'Login/' . $paths->fullpage, 'level=' . $session->user_level, true);
-      echo '<div class="usermessage">';
-      echo '<b>Your administrative session has timed out.</b> <a href="' . $login_link . '">Log in again</a>';
-      echo '</div>';
-    }
-  }
-  function footer($simple = false)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    dc_here('template: generating and sending the page footer');
-    if(!$this->no_headers) {
-      
-      if(!defined('ENANO_HEADERS_SENT'))
-        $this->header();
-      
-      global $_starttime;
-      if(isset($_GET['sqldbg']) && $session->get_permissions('mod_misc'))
-      {
-        echo '<h3>Query list as requested on URI</h3><pre style="margin-left: 1em">';
-        echo $db->sql_backtrace();
-        echo '</pre>';
-      }
-      
-      $f = microtime_float();
-      $f = $f - $_starttime;
-      $f = round($f, 4);
-      $dbg = 'Time: '.$f.'s  |  Queries: '.$db->num_queries;
-      $t = ( $simple ) ? $this->process_template('simple-footer.tpl') : $this->process_template('footer.tpl');
-      $t = str_replace('[[Stats]]', $dbg, $t);
-      $t = str_replace('[[NumQueries]]', (string)$db->num_queries, $t);
-      $t = str_replace('[[GenTime]]', (string)$f, $t);
-      echo $t;
-      
-      ob_end_flush();
-    }
-    else return '';
-  }
-  function getHeader()
-  {
-    $headers_sent = true;
-    dc_here('template: generating and sending the page header');
-    if(!defined('ENANO_HEADERS_SENT'))
-      define('ENANO_HEADERS_SENT', '');
-    if(!$this->no_headers) return $this->process_template('header.tpl');
-  }
-  function getFooter()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    dc_here('template: generating and sending the page footer');
-    if(!$this->no_headers) {
-      global $_starttime;
-      $t = '';
-      
-      if(isset($_GET['sqldbg']) && $session->get_permissions('mod_misc'))
-      {
-        $t .= '<h3>Query list as requested on URI</h3><pre style="margin-left: 1em">';
-        $t .= $db->sql_backtrace();
-        $t .= '</pre>';
-      }
-      
-      $f = microtime_float();
-      $f = $f - $_starttime;
-      $f = round($f, 4);
-      $dbg = 'Time: '.$f.'s  |  Queries: '.$db->num_queries;
-      $t.= $this->process_template('footer.tpl');
-      $t = str_replace('[[Stats]]', $dbg, $t);
-      $t = str_replace('[[NumQueries]]', (string)$db->num_queries, $t);
-      $t = str_replace('[[GenTime]]', (string)$f, $t);
-      return $t;
-    }
-    else return '';
-  }
-  
-  function process_template($file) {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!defined('ENANO_TEMPLATE_LOADED'))
-    {
-      $this->load_theme();
-      $this->init_vars();
-    }
-    eval($this->compile_template($file));
-    return $tpl_code;
-  }
-  
-  function extract_vars($file) {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$this->theme)
-    {
-      die('$template->extract_vars(): theme not yet loaded, so we can\'t open template files yet...this is a bug and should be reported.<br /><br />Backtrace, most recent call first:<pre>'.enano_debug_print_backtrace(true).'</pre>');
-    }
-    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file)) die('Cannot find '.$file.' file for style "'.$this->theme.'", exiting');
-    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file);
-    preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches);
-    $tplvars = Array();
-    for($i=0;$i<sizeof($matches[1]);$i++)
-    {
-      $tplvars[$matches[1][$i]] = $matches[2][$i];
-    }
-    return $tplvars;
-  }
-  function compile_template($text) {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text)) die('Cannot find '.$text.' file for style, exiting');
-    $n = $text;
-    $tpl_filename = ENANO_ROOT . '/cache/' . $this->theme . '-' . str_replace('/', '-', $n) . '.php';
-    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text)) die('Cannot find '.$text.' file for style, exiting');
-    if(file_exists($tpl_filename) && getConfig('cache_thumbs')=='1')
-    {
-      include($tpl_filename);
-      $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text);
-      if(isset($md5) && $md5 == md5($text)) {
-        return str_replace('\\"', '"', $tpl_text);
-      }
-    }
-    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$n);
-    
-    $md5 = md5($text);
-    
-    $seed = md5 ( microtime() . mt_rand() );
-    preg_match_all("/<\?php(.*?)\?>/is", $text, $m);
-    //die('<pre>'.htmlspecialchars(print_r($m, true)).'</pre>');
-    for($i = 0; $i < sizeof($m[1]); $i++)
-    {
-      $text = str_replace("<?php{$m[1][$i]}?>", "{PHPCODE:{$i}:{$seed}}", $text);
-    }
-    //die('<pre>'.htmlspecialchars($text).'</pre>');
-    $text = 'ob_start(); echo \''.str_replace('\'', '\\\'', $text).'\'; $tpl_code = ob_get_contents(); ob_end_clean();';
-    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if(isset($this->tpl_bool[\'\\1\']) && $this->tpl_bool[\'\\1\']) { echo \'', $text);
-    $text = preg_replace('#<!-- IFSET (.*?) -->#is', '\'; if(isset($this->tpl_strings[\'\\1\'])) { echo \'', $text);
-    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { echo \'', $text);
-    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '\'; echo $template->tplWikiFormat($paths->sysMsg(\'\\1\')); echo \'', $text);
-    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { echo \'', $text);
-    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { echo \'', $text);
-    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } echo \'', $text);
-    $text = preg_replace('#\{([A-z0-9]*)\}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
-    for($i = 0; $i < sizeof($m[1]); $i++)
-    {
-      $text = str_replace("{PHPCODE:{$i}:{$seed}}", "'; {$m[1][$i]} echo '", $text);
-    }
-    if(is_writable(ENANO_ROOT.'/cache/') && getConfig('cache_thumbs')=='1')
-    {
-      //die($tpl_filename);
-      $h = fopen($tpl_filename, 'w');
-      if(!$h) return $text;
-      $t = addslashes($text);
-      fwrite($h, '<?php $md5 = \''.$md5.'\'; $tpl_text = \''.$t.'\'; ?>');
-      fclose($h);
-    }
-    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
-  }
-  
-  function compile_template_text($text) {
-    $seed = md5 ( microtime() . mt_rand() );
-    preg_match_all("/<\?php(.*?)\?>/is", $text, $m);
-    //die('<pre>'.htmlspecialchars(print_r($m, true)).'</pre>');
-    for($i = 0; $i < sizeof($m[1]); $i++)
-    {
-      $text = str_replace("<?php{$m[1][$i]}?>", "{PHPCODE:{$i}:{$seed}}", $text);
-    }
-    //die('<pre>'.htmlspecialchars($text).'</pre>');
-    $text = 'ob_start(); echo \''.str_replace('\'', '\\\'', $text).'\'; $tpl_code = ob_get_contents(); ob_end_clean(); return $tpl_code;';
-    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if(isset($this->tpl_bool[\'\\1\']) && $this->tpl_bool[\'\\1\']) { echo \'', $text);
-    $text = preg_replace('#<!-- IFSET (.*?) -->#is', '\'; if(isset($this->tpl_strings[\'\\1\'])) { echo \'', $text);
-    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { echo \'', $text);
-    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '\'; echo $template->tplWikiFormat($paths->sysMsg(\'\\1\')); echo \'', $text);
-    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { echo \'', $text);
-    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { echo \'', $text);
-    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } echo \'', $text);
-    $text = preg_replace('#\{([A-z0-9]*)\}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
-    for($i = 0; $i < sizeof($m[1]); $i++)
-    {
-      $text = str_replace("{PHPCODE:{$i}:{$seed}}", "'; {$m[1][$i]} echo '", $text);
-    }
-    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
-  }
-  
-  function parse($text)
-  {
-    $text = $this->compile_template_text($text);
-    return eval($text);
-  }
-  
-  // Steps to turn this:
-  //   [[Project:Community Portal]]
-  // into this:
-  //   <a href="/Project:Community_Portal">Community Portal</a>
-  // Must be done WITHOUT creating eval'ed code!!!
-  
-  // 1. preg_replace \[\[([a-zA-Z0-9 -_:]*?)\]\] with <a href="'.contentPath.'\\1">\\1</a>
-  // 2. preg_match_all <a href="'.preg_quote(contentPath).'([a-zA-Z0-9 -_:]*?)">
-  // 3. For each match, replace matches with identifiers
-  // 4. For each match, str_replace ' ' with '_'
-  // 5. For each match, str_replace match_id:random_val with $matches[$match_id]
-  
-  // The template language is really a miniature programming language; with variables, conditionals, everything!
-  // So you can implement custom logic into your sidebar if you wish.
-  // "Real" PHP support coming soon :-D
-  
-  function tplWikiFormat($message, $filter_links = false, $filename = 'elements.tpl') {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $filter_links = false;
-    $tplvars = $this->extract_vars($filename);
-    if($session->sid_super) $as = htmlspecialchars(urlSeparator).'auth='.$session->sid_super;
-    else $as = '';
-    error_reporting(E_ALL);
-    $random_id = sha1(microtime().''); // A temp value
-    
-    /*
-     * PREPROCESSOR
-     */
-    
-    // Variables
-    
-    preg_match_all('#\$([A-Z_-]+)\$#', $message, $links);
-    $links = $links[1];
-    
-    for($i=0;$i<sizeof($links);$i++)
-    {
-      $message = str_replace('$'.$links[$i].'$', $this->tpl_strings[$links[$i]], $message);
-    }
-    
-    // Conditionals
-    
-    preg_match_all('#\{if ([A-Za-z0-9_ &\|\!-]*)\}(.*?)\{\/if\}#is', $message, $links);
-    
-    for($i=0;$i<sizeof($links[1]);$i++)
-    {
-      $message = str_replace('{if '.$links[1][$i].'}'.$links[2][$i].'{/if}', '{CONDITIONAL:'.$i.':'.$random_id.'}', $message);
-      
-      // Time for some manual parsing...
-      $chk = false;
-      $current_id = '';
-      $prn_level = 0;
-      // Used to keep track of where we are in the conditional
-      // Object of the game: turn {if this && ( that OR !something_else )} ... {/if} into if( ( isset($this->tpl_bool['that']) && $this->tpl_bool['that'] ) && ...
-      // Method of attack: escape all variables, ignore all else. Non-valid code is filtered out by a regex above.
-      $in_var_now = true;
-      $in_var_last = false;
-      $current_var = '';
-      $current_var_start_pos = 0;
-      $current_var_end_pos   = 0;
-      $j = -1;
-      $links[1][$i] = $links[1][$i] . ' ';
-      $d = strlen($links[1][$i]);
-      while($j < $d)
-      {
-        $j++;
-        $in_var_last = $in_var_now;
-        
-        $char = substr($links[1][$i], $j, 1);
-        $in_var_now = ( preg_match('#^([A-z0-9_]*){1}$#', $char) ) ? true : false;
-        if(!$in_var_last && $in_var_now)
-        {
-          $current_var_start_pos = $j;
-        }
-        if($in_var_last && !$in_var_now)
-        {
-          $current_var_end_pos = $j;
-        }
-        if($in_var_now)
-        {
-          $current_var .= $char;
-          continue;
-        }
-        // OK we are not inside of a variable. That means that we JUST hit the end because the counter ($j) will be advanced to the beginning of the next variable once processing here is complete.
-        if($char != ' ' && $char != '(' && $char != ')' && $char != 'A' && $char != 'N' && $char != 'D' && $char != 'O' && $char != 'R' && $char != '&' && $char != '|' && $char != '!' && $char != '<' && $char != '>' && $char != '0' && $char != '1' && $char != '2' && $char != '3' && $char != '4' && $char != '5' && $char != '6' && $char != '7' && $char != '8' && $char != '9')
-        {
-          // XSS attack! Bail out
-          echo '<p><b>Error:</b> Syntax error (possibly XSS attack) caught in template code:</p>';
-          echo '<pre>';
-          echo '{if '.$links[1][$i].'}';
-          echo "\n    ";
-          for($k=0;$k<$j;$k++) echo " ";
-          echo '<span style="color: red;">^</span>';
-          echo '</pre>';
-          continue 2;
-        }
-        if($current_var != '')
-        {
-          $cd = '( isset($this->tpl_bool[\''.$current_var.'\']) && $this->tpl_bool[\''.$current_var.'\'] )';
-          $cvt = substr($links[1][$i], 0, $current_var_start_pos) . $cd . substr($links[1][$i], $current_var_end_pos, strlen($links[1][$i]));
-          $j = $j + strlen($cd) - strlen($current_var);
-          $current_var = '';
-          $links[1][$i] = $cvt;
-          $d = strlen($links[1][$i]);
-        }
-      }
-      $links[1][$i] = substr($links[1][$i], 0, strlen($links[1][$i])-1);
-      $links[1][$i] = '$chk = ( '.$links[1][$i].' ) ? true : false;';
-      eval($links[1][$i]);
-      
-      if($chk) { // isset($this->tpl_bool[$links[1][$i]]) && $this->tpl_bool[$links[1][$i]]
-        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], 0, strpos($links[2][$i], '{else}'));
-        else $c = $links[2][$i];
-        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
-      } else {
-        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], strpos($links[2][$i], '{else}')+6, strlen($links[2][$i]));
-        else $c = '';
-        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
-      }
-    }
-    
-    preg_match_all('#\{!if ([A-Za-z_-]*)\}(.*?)\{\/if\}#is', $message, $links);
-    
-    for($i=0;$i<sizeof($links[1]);$i++)
-    {
-      $message = str_replace('{!if '.$links[1][$i].'}'.$links[2][$i].'{/if}', '{CONDITIONAL:'.$i.':'.$random_id.'}', $message);
-      if(isset($this->tpl_bool[$links[1][$i]]) && $this->tpl_bool[$links[1][$i]]) {
-        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], strpos($links[2][$i], '{else}')+6, strlen($links[2][$i]));
-        else $c = '';
-        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
-      } else {
-        if(strstr($links[2][$i], '{else}')) $c = substr($links[2][$i], 0, strpos($links[2][$i], '{else}'));
-        else $c = $links[2][$i];
-        $message = str_replace('{CONDITIONAL:'.$i.':'.$random_id.'}', $c, $message);
-      }
-    }
-    
-    /*
-     * HTML RENDERER
-     */
-     
-    // Images
-    $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $message, $matchlist);
-    $matches = Array();
-    $matches['images'] = $matchlist[1];
-    for($i=0;$i<sizeof($matchlist[1]);$i++)
-    {
-      if(isPage($paths->nslist['File'].$matches['images'][$i]))
-      {
-        $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
-                               '<img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" />',
-                               $message);
-      }
-    }
-    
-    // Internal links
-    
-    $text_parser = $this->makeParserText($tplvars['sidebar_button']);
-    
-    preg_match_all('#\[\[([a-zA-Z0-9 -_]*?)\]\]#is', $message, $il);
-    for($i=0;$i<sizeof($il[1]);$i++)
-    {
-      $href = makeUrl(str_replace(' ', '_', $il[1][$i]), null, true);
-      $text_parser->assign_vars(Array(
-          'HREF'  => $href,
-          'FLAGS' => '',
-          'TEXT'  => $il[1][$i]
-        ));
-      $message = str_replace("[[{$il[1][$i]}]]", $text_parser->run(), $message);
-    }
-    
-    preg_match_all('#\[\[([a-zA-Z0-9 -_]*?)\|([a-zA-Z0-9!@\#\$%\^&\*\(\)\{\} -_]*?)\]\]#is', $message, $il);
-    for($i=0;$i<sizeof($il[1]);$i++)
-    {
-      $href = makeUrl(str_replace(' ', '_', $il[1][$i]), null, true);
-      $text_parser->assign_vars(Array(
-          'HREF'  => $href,
-          'FLAGS' => '',
-          'TEXT'  => $il[2][$i]
-        ));
-      $message = str_replace("[[{$il[1][$i]}|{$il[2][$i]}]]", $text_parser->run(), $message);
-    }
-    
-    // External links
-    $message = preg_replace('#\[(http|ftp|irc):\/\/([a-z0-9\/:_\.\?&%\#@_\\\\-]+?)\\ ([^\]]+)]#', '<a href="\\1://\\2">\\3</a><br style="display: none;" />', $message);
-    $message = preg_replace('#\[(http|ftp|irc):\/\/([a-z0-9\/:_\.\?&%\#@_\\\\-]+?)\\]#', '<a href="\\1://\\2">\\1://\\2</a><br style="display: none;" />', $message);
-    
-    $parser1 = $this->makeParserText($tplvars['sidebar_section']);
-    $parser2 = $this->makeParserText($tplvars['sidebar_section_raw']);
-                            
-    preg_match_all('#\{slider(2|)=(.*?)\}(.*?)\{\/slider(2|)\}#is',  $message, $sb);
-    
-    // Modified to support the sweet new template var system
-    for($i=0;$i<sizeof($sb[1]);$i++)
-    {
-      $p = ($sb[1][$i] == '2') ? $parser2 : $parser1;
-      $p->assign_vars(Array('TITLE'=>$sb[2][$i],'CONTENT'=>$sb[3][$i]));
-      $message = str_replace("{slider{$sb[1][$i]}={$sb[2][$i]}}{$sb[3][$i]}{/slider{$sb[4][$i]}}", $p->run(), $message);
-    }
-    
-    /*
-    Extras ;-)
-    $message = preg_replace('##is', '', $message);
-    $message = preg_replace('##is', '', $message);
-    $message = preg_replace('##is', '', $message);
-    $message = preg_replace('##is', '', $message);
-    $message = preg_replace('##is', '', $message);
-    */
-    
-    //die('<pre>'.htmlspecialchars($message).'</pre>');
-    //eval($message); exit;
-    return $message;
-  }
-  
-  /**
-   * Print a text field that auto-completes a username entered into it.
-   * @param string $name - the name of the form field
-   * @return string
-   */
-   
-  function username_field($name, $value = false)
-  {
-    $randomid = md5( time() . microtime() . mt_rand() );
-    $text = '<input name="'.$name.'" onkeyup="ajaxUserNameComplete(this)" autocomplete="off" type="text" size="30" id="userfield_'.$randomid.'"';
-    if($value) $text .= ' value="'.$value.'"';
-    $text .= ' />';
-    return $text;
-  }
-  
-  /**
-   * Print a text field that auto-completes a page name entered into it.
-   * @param string $name - the name of the form field
-   * @return string
-   */
-   
-  function pagename_field($name, $value = false)
-  {
-    $randomid = md5( time() . microtime() . mt_rand() );
-    $text = '<input name="'.$name.'" onkeyup="ajaxPageNameComplete(this)" type="text" size="30" id="pagefield_'.$randomid.'"';
-    if($value) $text .= ' value="'.$value.'"';
-    $text .= ' />';
-    $text .= '<script type="text/javascript">
-        var inp = document.getElementById(\'pagefield_' . $randomid . '\');
-        var f = get_parent_form(inp);
-        if ( f )
-        {
-          if ( typeof(f.onsubmit) != \'function\' )
-          {
-            f.onsubmit = function() {
-              if ( !submitAuthorized )
-              {
-                return false;
-              }
-            }
-          }
-        }</script>';
-    return $text;
-  }
-  
-  /**
-   * Sends a textarea that can be converted to and from a TinyMCE widget on the fly.
-   * @param string The name of the form element
-   * @param string The initial content. Optional, defaults to blank
-   * @param int Rows in textarea
-   * @param int Columns in textarea
-   * @return string HTML and Javascript code.
-   */
-  
-  function tinymce_textarea($name, $content = '', $rows = 20, $cols = 60)
-  {
-    $randomid = md5(microtime() . mt_rand());
-    $html = '';
-    $html .= '<textarea name="' . $name . '" rows="'.$rows.'" cols="'.$cols.'" style="width: 100%;" id="toggleMCEroot_'.$randomid.'">' . $content . '</textarea>';
-    $html .= '<div style="float: right; display: table;">text editor&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">graphical editor</a></div>';
-    $html .= '<script type="text/javascript">
-                function toggleMCE_'.$randomid.'()
-                {
-                  var the_obj = document.getElementById(\'toggleMCEroot_' . $randomid . '\');
-                  if ( the_obj.dnIsMCE == "yes" )
-                  {
-                    $dynano(the_obj).destroyMCE();
-                    the_obj.nextSibling.innerHTML = \'text editor&nbsp;&nbsp;|&nbsp;&nbsp;<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">graphical editor</a>\';
-                  }
-                  else
-                  {
-                    $dynano(the_obj).switchToMCE();
-                    the_obj.nextSibling.nextSibling.innerHTML = \'<a href="#" onclick="toggleMCE_'.$randomid.'(); return false;">text editor</a>&nbsp;&nbsp;|&nbsp;&nbsp;graphical editor\';
-                  }
-                }
-              </script>';
-    return $html;
-  }
-  
-  /**
-   * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;)
-   * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class.
-   * @param $filename the filename of the template to be parsed
-   * @return object
-   */
-   
-  function makeParser($filename)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $filename = ENANO_ROOT.'/themes/'.$template->theme.'/'.$filename;
-    if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist');
-    $code = file_get_contents($filename);
-    $parser = new templateIndividual($code);
-    return $parser;
-  }
-  
-  /**
-   * Same as $template->makeParser(), but takes a string instead of a filename.
-   * @param $text the text to parse
-   * @return object
-   */
-   
-  function makeParserText($code)
-  {
-    $parser = new templateIndividual($code);
-    return $parser;
-  }
-  
-  /**
-   * Fetch the HTML for a plugin-added sidebar block
-   * @param $name the plugin name
-   * @return string
-   */
-   
-  function fetch_block($id)
-  {
-    if(isset($this->plugin_blocks[$id])) return $this->plugin_blocks[$id];
-    else return false;
-  }
-  
-  /**
-   * Fetches the contents of both sidebars.
-   * @return array - key 0 is left, key 1 is right
-   * @example list($left, $right) = $template->fetch_sidebar();
-   */
-   
-  function fetch_sidebar()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    $left = '';
-    $right = '';
-    
-    if ( !$this->fetch_block('Links') )
-      $this->initLinksWidget();
-    
-    $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;');
-    if(!$q) $db->_die('The sidebar text data could not be selected.');
-    
-    $vars = $this->extract_vars('elements.tpl');
-    
-    if(isset($vars['sidebar_top'])) 
-    {
-      $left  .= $this->parse($vars['sidebar_top']);
-      $right .= $this->parse($vars['sidebar_top']);
-    }
-    while($row = $db->fetchrow())
-    {
-      switch($row['block_type'])
-      {
-        case BLOCK_WIKIFORMAT:
-        default:
-          $parser = $this->makeParserText($vars['sidebar_section']);
-          $c = RenderMan::render($row['block_content']);
-          break;
-        case BLOCK_TEMPLATEFORMAT:
-          $parser = $this->makeParserText($vars['sidebar_section']);
-          $c = $this->tplWikiFormat($row['block_content']);
-          break;
-        case BLOCK_HTML:
-          $parser = $this->makeParserText($vars['sidebar_section_raw']);
-          $c = $row['block_content'];
-          break;
-        case BLOCK_PHP:
-          $parser = $this->makeParserText($vars['sidebar_section_raw']);
-          ob_start();
-          @eval($row['block_content']);
-          $c = ob_get_contents();
-          ob_end_clean();
-          break;
-        case BLOCK_PLUGIN:
-          $parser = $this->makeParserText($vars['sidebar_section_raw']);
-          $c = (gettype($this->fetch_block($row['block_content'])) == 'string') ? $this->fetch_block($row['block_content']) : 'Can\'t find plugin block';
-          break;
-      }
-      $parser->assign_vars(Array( 'TITLE'=>$this->tplWikiFormat($row['block_name']), 'CONTENT'=>$c ));
-      if    ($row['sidebar_id'] == SIDEBAR_LEFT ) $left  .= $parser->run();
-      elseif($row['sidebar_id'] == SIDEBAR_RIGHT) $right .= $parser->run();
-      unset($parser);
-    }
-    $db->free_result();
-    if(isset($vars['sidebar_bottom'])) 
-    {
-      $left  .= $this->parse($vars['sidebar_bottom']);
-      $right .= $this->parse($vars['sidebar_bottom']);
-    }
-    $min = '';
-    if(isset($vars['sidebar_top'])) 
-    {
-      $min .= $this->parse($vars['sidebar_top']);
-    }
-    if(isset($vars['sidebar_bottom']))
-    {
-      $min .= $this->parse($vars['sidebar_bottom']);
-    }
-    return Array($left, $right, $min);
-  }
-  
-  function initLinksWidget()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    // SourceForge/W3C buttons
-    $ob = Array();
-    if(getConfig('powered_btn') =='1') $ob[] = '<a style="text-align: center;" href="http://www.enanocms.org/"                  onclick="window.open(this.href);return false;"><img alt="Powered by Enano" src="'.scriptPath.'/images/about-powered-enano.png" onmouseover="this.src=\''.scriptPath.'/images/about-powered-enano-hover.png\';" onmouseout="this.src=\''.scriptPath.'/images/about-powered-enano.png\';" style="border-width: 0px;" width="88" height="31" /></a>';
-    if(getConfig('sflogo_enabled')=='1')
-    {
-      $ob[] = '<a style="text-align: center;" href="http://sourceforge.net/" onclick="window.open(this.href);return false;"><img style="border-width: 0px;" alt="SourceForge.net Logo" src="http://sflogo.sourceforge.net/sflogo.php?group_id='.getConfig('sflogo_groupid').'&amp;type='.getConfig('sflogo_type').'" /></a>';
-    }
-    if(getConfig('w3c_v32')     =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 3.2"  src="http://www.w3.org/Icons/valid-html32" /></a>';
-    if(getConfig('w3c_v40')     =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 4.0"  src="http://www.w3.org/Icons/valid-html40" /></a>';
-    if(getConfig('w3c_v401')    =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid HTML 4.01" src="http://www.w3.org/Icons/valid-html401" /></a>';
-    if(getConfig('w3c_vxhtml10')=='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid XHTML 1.0" src="http://www.w3.org/Icons/valid-xhtml10" /></a>';
-    if(getConfig('w3c_vxhtml11')=='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid XHTML 1.1" src="http://www.w3.org/Icons/valid-xhtml11" /></a>';
-    if(getConfig('w3c_vcss')    =='1') $ob[] = '<a style="text-align: center;" href="http://validator.w3.org/check?uri=referer" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="Valid CSS"       src="http://www.w3.org/Icons/valid-css" /></a>';
-    if(getConfig('dbd_button')  =='1') $ob[] = '<a style="text-align: center;" href="http://www.defectivebydesign.org/join/button" onclick="window.open(this.href);return false;"><img style="border: 0px solid #FFFFFF;" alt="DRM technology restricts what you can do with your computer" src="http://defectivebydesign.org/sites/nodrm.civicactions.net/files/images/dbd_sm_btn.gif" /><br /><small>Protect your freedom >></small></a>';
-    
-    $code = $plugins->setHook('links_widget');
-    foreach ( $code as $cmd )
-    {
-      eval($cmd);
-    }
-    
-    if(count($ob) > 0) $sb_links = '<div style="text-align: center; padding: 5px 0;">'.implode('<br />', $ob).'</div>';
-    else $sb_links = '';
-    
-    $this->sidebar_widget('Links', $sb_links);
-  }
-  
-  /**
-   * Builds a box showing unread private messages.
-   */
-  
-  function notify_unread_pms()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if ( ( $paths->cpage['urlname_nons'] == 'PrivateMessages' || $paths->cpage['urlname_nons'] == 'Preferences' ) && $paths->namespace == 'Special' )
-    {
-      return '';
-    }
-    $ob = '<div class="usermessage">'."\n";
-    $s = ( $session->unread_pms == 1 ) ? '' : 's';
-    $ob .= "  <b>You have $session->unread_pms <a href=" . '"' . makeUrlNS('Special', 'PrivateMessages' ) . '"' . ">unread private message$s</a>.</b><br />\n  Messages: ";
-    $q = $db->sql_query('SELECT message_id,message_from,subject,date FROM '.table_prefix.'privmsgs WHERE message_to=\'' . $session->username . '\' AND message_read=0 ORDER BY date DESC;');
-    if ( !$q )
-      $db->_die();
-    $messages = array();
-    while ( $row = $db->fetchrow() )
-    {
-      $messages[] = '<a href="' . makeUrlNS('Special', 'PrivateMessages/View/' . $row['message_id']) . '" title="Sent ' . date('F d, Y h:i a', $row['date']) . ' by ' . $row['message_from'] . '">' . $row['subject'] . '</a>';
-    }
-    $ob .= implode(",\n    " , $messages)."\n";
-    $ob .= '</div>'."\n";
-    return $ob;
-  }
-  
-} // class template
-
-/**
- * Handles parsing of an individual template file. Instances should only be created through $template->makeParser(). To use:
- *   - Call $template->makeParser(template file name) - file name should be something.tpl, css/whatever.css, etc.
- *   - Make an array of strings you want the template to access. $array['STRING'] would be referenced in the template like {STRING}
- *   - Make an array of boolean values. These can be used for conditionals in the template (<!-- IF something --> whatever <!-- ENDIF something -->)
- *   - Call assign_vars() to pass the strings to the template parser. Same thing with assign_bool().
- *   - Call run() to parse the template and get your fully compiled HTML.
- * @access private
- */
-
-class templateIndividual extends template {
-  var $tpl_strings, $tpl_bool, $tpl_code;
-  var $compiled = false;
-  /**
-   * Constructor.
-   */
-  function __construct($text)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $this->tpl_code = $text;
-    $this->tpl_strings = $template->tpl_strings;
-    $this->tpl_bool = $template->tpl_bool;
-  }
-  /**
-   * PHP 4 constructor.
-   */
-  function templateIndividual($text)
-  {
-    $this->__construct($text);
-  }
-  /**
-   * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file.
-   * @param $vars array
-   */
-  function assign_vars($vars)
-  {
-    $this->tpl_strings = array_merge($this->tpl_strings, $vars);
-  }
-  /**
-   * Assigns an array of boolean values to the template. These can be used for <!-- IF ... --> statements.
-   * @param $vars array
-   */
-  function assign_bool($vars)
-  {
-    $this->tpl_bool = array_merge($this->tpl_bool, $vars);
-  }
-  /**
-   * Compiles and executes the template code.
-   * @return string
-   */
-  function run()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$this->compiled)
-    {
-      $this->tpl_code = $this->compile_template_text($this->tpl_code);
-      $this->compiled = true;
-    }
-    return eval($this->tpl_code);
-  }
-}
-
-/**
- * A version of the template compiler that does not rely at all on the other parts of Enano. Used during installation and for showing
- * "critical error" messages. ** REQUIRES ** the Oxygen theme.
- */
-
-class template_nodb {
-  var $tpl_strings, $tpl_bool, $theme, $style, $no_headers, $additional_headers, $sidebar_extra, $sidebar_widgets, $toolbar_menu, $theme_list;
-  function __construct() {
-    
-    $this->tpl_bool    = Array();
-    $this->tpl_strings = Array();
-    $this->sidebar_extra = '';
-    $this->sidebar_widgets = '';
-    $this->toolbar_menu = '';
-    $this->additional_headers = '';
-    
-    $this->theme_list = Array(Array(
-      'theme_id'=>'oxygen',
-      'theme_name'=>'Oxygen',
-      'theme_order'=>1,
-      'enabled'=>1,
-      ));
-  }
-  function template() {
-    $this->__construct();
-  }
-  function get_css($s = false) {
-    if($s)
-      return $this->process_template('css/'.$s);
-    else
-      return $this->process_template('css/'.$this->style.'.css');
-  }
-  function load_theme($name, $css, $auto_init = true) {
-    $this->theme = $name;
-    $this->style = $css;
-    
-    $this->tpl_strings['SCRIPTPATH'] = scriptPath;
-    if ( $auto_init )
-      $this->init_vars();
-  }
-  function init_vars()
-  {
-    global $sideinfo;
-    global $this_page;
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $tplvars = $this->extract_vars('elements.tpl');
-    $tb = '';
-    // Get the "article" button text (depends on namespace)
-    if(defined('IN_ENANO_INSTALL')) $ns = 'installation page';
-    else $ns = 'system error page';
-    $t = str_replace('{FLAGS}', 'onclick="return false;" title="Hey! A button that doesn\'t do anything. Clever..." accesskey="a"', $tplvars['toolbar_button']);
-    $t = str_replace('{HREF}', '#', $t);
-    $t = str_replace('{TEXT}', $ns, $t);
-    $tb .= $t;
-    
-    // Page toolbar
-    
-    $this->tpl_bool = Array(
-      'auth_admin'=>true,
-      'user_logged_in'=>true,
-      'right_sidebar'=>false,
-      );
-    $this->tpl_bool['in_sidebar_admin'] = false;
-    
-    $this->tpl_bool['auth_rename'] = false;
-    
-    $asq = $asa = '';
-    
-    $this->tpl_bool['fixed_menus'] = false;
-    $slink = defined('IN_ENANO_INSTALL') ? scriptPath.'/install.php?mode=css' : makeUrlNS('Special', 'CSS');
-    
-    $title = ( is_object($paths) ) ? $paths->page : 'Critical error';
-    
-    // The rewritten template engine will process all required vars during the load_template stage instead of (cough) re-processing everything each time around.
-    $tpl_strings = Array(
-      'PAGE_NAME'=>$this_page,
-      'PAGE_URLNAME'=>'Null',
-      'SITE_NAME'=>'Enano Installation',
-      'USERNAME'=>'admin',
-      'SITE_DESC'=>'Install Enano on your server.',
-      'TOOLBAR'=>$tb,
-      'SCRIPTPATH'=>scriptPath,
-      'CONTENTPATH'=>contentPath,
-      'ADMIN_SID_QUES'=>$asq,
-      'ADMIN_SID_AMP'=>$asa,
-      'ADMIN_SID_AMP_HTML'=>'',
-      'ADDITIONAL_HEADERS'=>'<style type="text/css">div.pagenav { border-top: 1px solid #CCC; padding-top: 7px; margin-top: 10px; }</style>',
-      'SIDEBAR_EXTRA'=>'',
-      'COPYRIGHT'=>'Enano and all of its code, graphics, and more code is copyright &copy; 2006 Dan Fuhry.<br />This program is Free Software; see the file "GPL" included with this package for details.',
-      'TOOLBAR_EXTRAS'=>'',
-      'REQUEST_URI'=>$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'],
-      'STYLE_LINK'=>$slink,
-      'LOGOUT_LINK'=>'',
-      'THEME_LINK'=>'',
-      'TEMPLATE_DIR'=>scriptPath.'/themes/'.$this->theme,
-      'THEME_ID'=>$this->theme,
-      'STYLE_ID'=>$this->style,
-      'JS_DYNAMIC_VARS'=>'<script type="text/javascript">var title="'. $title .'"; var scriptPath="'.scriptPath.'"; var ENANO_SID=""; var AES_BITS='.AES_BITS.'; var AES_BLOCKSIZE=' . AES_BLOCKSIZE . '; var pagepass=\'\';</script>',
-      'SIDEBAR_RIGHT'=>'',
-      );
-    $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings);
-    
-    $sidebar = ( gettype($sideinfo) == 'string' ) ? $sideinfo : '';
-    if($sidebar != '')
-    {
-      if(isset($tplvars['sidebar_top']))
-      {
-        $text = $this->makeParserText($tplvars['sidebar_top']);
-        $top = $text->run();
-      } else {
-        $top = '';
-      }
-      $p = $this->makeParserText($tplvars['sidebar_section']);
-      $p->assign_vars(Array(
-          'TITLE'=>'Installation progress',
-          'CONTENT'=>$sidebar,
-        ));
-      $sidebar = $p->run();
-      if(isset($tplvars['sidebar_bottom']))
-      {
-        $text = $this->makeParserText($tplvars['sidebar_bottom']);
-        $bottom = $text->run();
-      } else {
-        $bottom = '';
-      }
-      $sidebar = $top . $sidebar . $bottom;
-    }
-    $this->tpl_strings['SIDEBAR_LEFT'] = $sidebar;
-    
-    $this->tpl_bool['sidebar_left']  = ( $this->tpl_strings['SIDEBAR_LEFT']  != '') ? true : false;
-    $this->tpl_bool['sidebar_right'] = ( $this->tpl_strings['SIDEBAR_RIGHT'] != '') ? true : false;
-    $this->tpl_bool['right_sidebar'] = $this->tpl_bool['sidebar_right']; // backward compatibility
-    $this->tpl_bool['stupid_mode'] = true;
-  }
-  function header() 
-  {
-    if(!$this->no_headers) echo $this->process_template('header.tpl');
-  }
-  function footer()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$this->no_headers) {
-      global $_starttime;
-      $f = microtime(true);
-      $f = $f - $_starttime;
-      $f = round($f, 4);
-      if(defined('IN_ENANO_INSTALL')) $nq = 'N/A';
-      else $nq = $db->num_queries;
-      if($nq == 0) $nq = 'N/A';
-      $dbg = 'Time: '.$f.'s  |  Queries: '.$nq;
-      $t = $this->process_template('footer.tpl');
-      $t = str_replace('[[Stats]]', $dbg, $t);
-      echo $t;
-    }
-    else return '';
-  }
-  function getHeader()
-  {
-    if(!$this->no_headers) return $this->process_template('header.tpl');
-    else return '';
-  }
-  function getFooter()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$this->no_headers) {
-      global $_starttime;
-      $f = microtime(true);
-      $f = $f - $_starttime;
-      $f = round($f, 4);
-      if(defined('IN_ENANO_INSTALL')) $nq = 'N/A';
-      else $nq = $db->num_queries;
-      if($nq == 0) $nq = 'N/A';
-      $dbg = 'Time: '.$f.'s  |  Queries: '.$nq;
-      if($nq == 0) $nq = 'N/A';
-      $t = $this->process_template('footer.tpl');
-      $t = str_replace('[[Stats]]', $dbg, $t);
-      return $t;
-    }
-    else return '';
-  }
-  
-  function process_template($file) {
-    
-    eval($this->compile_template($file));
-    return $tpl_code;
-  }
-  
-  function extract_vars($file) {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!is_file(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file)) die('Cannot find '.$file.' file for style "'.$this->theme.'", exiting');
-    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$file);
-    preg_match_all('#<\!-- VAR ([A-z0-9_-]*) -->(.*?)<\!-- ENDVAR \\1 -->#is', $text, $matches);
-    $tplvars = Array();
-    for($i=0;$i<sizeof($matches[1]);$i++)
-    {
-      $tplvars[$matches[1][$i]] = $matches[2][$i];
-    }
-    return $tplvars;
-  }
-  function compile_template($text) {
-    global $sideinfo;
-    $text = file_get_contents(ENANO_ROOT . '/themes/'.$this->theme.'/'.$text);
-    $text = str_replace('<script type="text/javascript" src="{SCRIPTPATH}/ajax.php?title={PAGE_URLNAME}&amp;_mode=jsres"></script>', '', $text); // Remove the AJAX code - we don't need it, and it requires a database connection
-    $text = '$tpl_code = \''.str_replace('\'', '\\\'', $text).'\'; return $tpl_code;';
-    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if($this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
-    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { $tpl_code .= \'', $text);
-    if(defined('IN_ENANO_INSTALL')) $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">Installation progress</a></div><div class="slideblock">'.$sideinfo.'</div></div>', $text);
-    else $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">System error</a></div><div class="slideblock"><a href="#" onclick="return false;">Enano critical error page</a></div></div>', $text);
-    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '', $text);
-    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
-    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { $tpl_code .= \'', $text);
-    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } $tpl_code .= \'', $text);
-    $text = preg_replace('#{([A-z0-9]*)}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
-    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
-  }
-  
-  function compile_template_text($text) {
-    global $sideinfo;
-    $text = str_replace('<script type="text/javascript" src="{SCRIPTPATH}/ajax.php?title={PAGE_URLNAME}&amp;_mode=jsres"></script>', '', $text); // Remove the AJAX code - we don't need it, and it requires a database connection
-    $text = '$tpl_code = \''.str_replace('\'', '\\\'', $text).'\'; return $tpl_code;';
-    $text = preg_replace('#<!-- BEGIN (.*?) -->#is', '\'; if($this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
-    $text = preg_replace('#<!-- IFPLUGIN (.*?) -->#is', '\'; if(getConfig(\'plugin_\\1\')==\'1\') { $tpl_code .= \'', $text);
-    if(defined('IN_ENANO_INSTALL')) $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">Installation progress</a></div><div class="slideblock">'.$sideinfo.'</div></div>', $text);
-    else $text = str_replace('<!-- SYSMSG Sidebar -->', '<div class="slider"><div class="heading"><a class="head">System error</a></div><div class="slideblock"><a href="#" onclick="return false;">Enano critical error page</a></div></div>', $text);
-    $text = preg_replace('#<!-- SYSMSG (.*?) -->#is', '', $text);
-    $text = preg_replace('#<!-- BEGINNOT (.*?) -->#is', '\'; if(!$this->tpl_bool[\'\\1\']) { $tpl_code .= \'', $text);
-    $text = preg_replace('#<!-- BEGINELSE (.*?) -->#is', '\'; } else { $tpl_code .= \'', $text);
-    $text = preg_replace('#<!-- END (.*?) -->#is', '\'; } $tpl_code .= \'', $text);
-    $text = preg_replace('#{([A-z0-9]*)}#is', '\'.$this->tpl_strings[\'\\1\'].\'', $text);
-    return $text; //('<pre>'.htmlspecialchars($text).'</pre>');
-  }
-  
-  /**
-   * Allows individual parsing of template files. Similar to phpBB but follows the spirit of object-oriented programming ;)
-   * Returns on object of class templateIndividual. Usage instructions can be found in the inline docs for that class.
-   * @param $filename the filename of the template to be parsed
-   * @return object
-   */
-   
-  function makeParser($filename)
-  {
-    $filename = ENANO_ROOT.'/themes/'.$this->theme.'/'.$filename;
-    if(!file_exists($filename)) die('templateIndividual: file '.$filename.' does not exist');
-    $code = file_get_contents($filename);
-    $parser = new templateIndividualSafe($code, $this);
-    return $parser;
-  }
-  
-  /**
-   * Same as $template->makeParser(), but takes a string instead of a filename.
-   * @param $text the text to parse
-   * @return object
-   */
-   
-  function makeParserText($code)
-  {
-    $parser = new templateIndividualSafe($code, $this);
-    return $parser;
-  }
-   
-} // class template_nodb
-
-/**
- * Identical to templateIndividual, except extends template_nodb instead of template
- * @see class template
- */
- 
-class templateIndividualSafe extends template_nodb {
-  var $tpl_strings, $tpl_bool, $tpl_code;
-  var $compiled = false;
-  /**
-   * Constructor.
-   */
-  function __construct($text, $parent)
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    $this->tpl_code = $text;
-    $this->tpl_strings = $parent->tpl_strings;
-    $this->tpl_bool = $parent->tpl_bool;
-  }
-  /**
-   * PHP 4 constructor.
-   */
-  function templateIndividual($text)
-  {
-    $this->__construct($text);
-  }
-  /**
-   * Assigns an array of string values to the template. Strings can be accessed from the template by inserting {KEY_NAME} in the template file.
-   * @param $vars array
-   */
-  function assign_vars($vars)
-  {
-    if(is_array($this->tpl_strings))
-      $this->tpl_strings = array_merge($this->tpl_strings, $vars);
-    else
-      $this->tpl_strings = $vars;
-  }
-  /**
-   * Assigns an array of boolean values to the template. These can be used for <!-- IF ... --> statements.
-   * @param $vars array
-   */
-  function assign_bool($vars)
-  {
-    $this->tpl_bool = array_merge($this->tpl_bool, $vars);
-  }
-  /**
-   * Compiles and executes the template code.
-   * @return string
-   */
-  function run()
-  {
-    global $db, $session, $paths, $template, $plugins; // Common objects
-    if(!$this->compiled)
-    {
-      $this->tpl_code = $this->compile_template_text($this->tpl_code);
-      $this->compiled = true;
-    }
-    return eval($this->tpl_code);
-  }
-}
-
-?>
--- a/plugins/#Untitled-1#	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
- MAUMEE, OH,  US 	06/12/2007 	11:26 P.M. 	ARRIVAL SCAN
--- a/plugins/SpecialAdmin.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2722 +0,0 @@
-<?php
-/*
-Plugin Name: Runt - the Enano administration panel
-Plugin URI: http://enanocms.org/
-Description: Provides the page Special:Administration, which is the AJAX frontend to the various Admin:
-Author: Dan Fuhry
-Version: 1.0
-Author URI: http://enanocms.org/
-*/
-
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 release candidate 2
- * Copyright (C) 2006-2007 Dan Fuhry
- *
- * This program is Free Software; you can redistribute 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 details.
- */
- 
-global $db, $session, $paths, $template, $plugins; // Common objects
-
-$plugins->attachHook('base_classes_initted', '
-  global $paths;
-    $paths->add_page(Array(
-      \'name\'=>\'Administration\',
-      \'urlname\'=>\'Administration\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>0,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    
-    $paths->add_page(Array(
-      \'name\'=>\'Manage the Sidebar\',
-      \'urlname\'=>\'EditSidebar\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>0,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-  ');
-
-// function names are IMPORTANT!!! The name pattern is: page_<namespace ID>_<page URLname, without namespace>
-
-function page_Admin_Home() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  
-  // Basic information
-  echo RenderMan::render(
-'== Welcome to Runt, the Enano administration panel. ==
-
-Thank you for choosing Enano as your CMS. This screen allows you to see some information about your website, plus some details about how your site is doing statistically.
-
-Using the links on the left you can control every aspect of your website\'s look and feel, plus you can manage users, work with pages, and install plugins to make your Enano installation even better.');
-  
-  // Check for the installer scripts
-  if(file_exists(ENANO_ROOT.'/install.php') || file_exists(ENANO_ROOT.'/schema.sql'))
-  {
-    echo '<div class="error-box"><b>NOTE:</b> It appears that your install.php and/or schema.sql files still exist. It is HIGHLY RECOMMENDED that you delete or rename these files, to prevent getting your server hacked.</div>';
-  }
-  
-  // Inactive users
-  $q = $db->sql_query('SELECT * FROM '.table_prefix.'logs WHERE log_type=\'admin\' AND action=\'activ_req\';');
-  if($q)
-    if($db->numrows() > 0)
-    {
-      $n = $db->numrows();
-      if($n == 1) $s = $n . ' user is';
-      else $s = $n . ' users are';
-      echo '<div class="warning-box">It appears that '.$s.' awaiting account activation. You can activate those accounts by going to the <a href="#" onclick="ajaxPage(\''.$paths->nslist['Admin'].'UserManager\'); return false;">User Manager</a>.</div>';
-    }
-  $db->free_result();
-  // Stats
-  if(getConfig('log_hits') == '1')
-  {
-    $stats = stats_top_pages(10);
-    $c = 0;
-    $cls = 'row2';
-    echo '<h3>Most requested pages</h3><div class="tblholder"><table style="width: 100%;" border="0" cellspacing="1" cellpadding="4"><tr><th>Page</th><th>Hits</th></tr>';
-    foreach($stats as $page => $count)
-    {
-      if(isset($paths->pages[$page]))
-      {
-        echo '<tr>';
-        $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-        echo '<td class="'.$cls.'"><a href="'.makeUrl($page).'">'.$paths->pages[$page]['name'].'</a></td><td style="text-align: center;" class="'.$cls.'">'.$count.'</td>';
-        echo '</tr>';
-      }
-    }
-    echo '</table></div>';
-  }
-  
-  // Security log
-  echo '<h3>Security log</h3>';
-  echo '<div class="tblholder" style="/* max-height: 500px; clip: rect(0px,auto,auto,0px); overflow: auto; */"><table border="0" cellspacing="1" cellpadding="4" width="100%">';
-  $cls = 'row2';                                                                                               
-  echo '<tr><th style="width: 60%;">Type</th><th>Date</th><th>Username</th><th>IP Address</th></tr>';
-  if(isset($_GET['fulllog']))
-  {
-    $l = 'SELECT action,date_string,author,edit_summary,time_id,page_text FROM '.table_prefix.'logs WHERE log_type=\'security\' ORDER BY time_id DESC, action ASC;';
-  }
-  else
-  {
-    $l = 'SELECT action,date_string,author,edit_summary,time_id,page_text FROM '.table_prefix.'logs WHERE log_type=\'security\' ORDER BY time_id DESC, action ASC LIMIT 5';
-  }
-  $q = $db->sql_query($l);
-  while($r = $db->fetchrow())
-  {
-    if($cls == 'row2') $cls = 'row1';
-    else $cls = 'row2';
-    echo '<tr><td class="'.$cls.'">';
-    switch($r['action']) {
-      case "admin_auth_good": echo 'Successful elevated authentication'; if ( !empty($r['page_text']) ) { $level = $session->userlevel_to_string( intval($r['page_text']) ); echo "<br /><small>Authentication level: $level</small>"; } break;
-      case "admin_auth_bad":  echo 'Failed administration logon'; break;
-      case "activ_good": echo 'Successful account activation'; break;
-      case "auth_good": echo 'Successful regular user logon'; break;
-      case "activ_bad": echo 'Failed account activation'; break;
-      case "auth_bad": echo 'Failed regular user logon'; break;
-      case "sql_inject": echo 'SQL injection attempt<div style="max-width: 90%; clip: rect(0px,auto,auto,0px); overflow: auto; display: block; font-size: smaller;">Offending query: ' . htmlspecialchars($r['page_text']) . '</div>'; break;
-      case "db_backup": echo 'Database backup created<br /><small>Tables: ' . $r['page_text'] . '</small>'; break;
-      case "install_enano": echo "Installed Enano version {$r['page_text']}"; break;
-    }
-    echo '</td><td class="'.$cls.'">'.date('d M Y h:i a', $r['time_id']).'</td><td class="'.$cls.'">'.$r['author'].'</td><td class="'.$cls.'" style="cursor: pointer;" onclick="ajaxReverseDNS(this);" title="Click for reverse DNS info">'.$r['edit_summary'].'</td></tr>';
-  }
-  $db->free_result();
-  echo '</table></div>';
-  if(!isset($_GET['fulllog'])) echo '<p><a href="#" onclick="ajaxPage(\''.$paths->nslist['Admin'].'Home&amp;fulllog\'); return false;">Full security log</a></p>';
-  
-}
-
-function page_Admin_GeneralConfig() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  if(isset($_POST['submit'])) {
-    
-    // Global site options
-    setConfig('site_name', $_POST['site_name']);
-    setConfig('site_desc', $_POST['site_desc']);
-    setConfig('main_page', str_replace(' ', '_', $_POST['main_page']));
-    setConfig('copyright_notice', $_POST['copyright']);
-    setConfig('contact_email', $_POST['contact_email']);
-    
-    // Wiki mode
-    if(isset($_POST['wikimode']))                setConfig('wiki_mode', '1');
-    else                                         setConfig('wiki_mode', '0');
-    if(isset($_POST['wiki_mode_require_login'])) setConfig('wiki_mode_require_login', '1');
-    else                                         setConfig('wiki_mode_require_login', '0');
-    if(isset($_POST['editmsg']))                 setConfig('wiki_edit_notice', '1');
-    else                                         setConfig('wiki_edit_notice', '0');
-    setConfig('wiki_edit_notice_text', $_POST['editmsg_text']);
-    
-    // Stats
-    if(isset($_POST['log_hits']))                setConfig('log_hits', '1');
-    else                                         setConfig('log_hits', '0');
-    
-    // Disablement
-    if(isset($_POST['site_disabled'])) {         setConfig('site_disabled', '1'); setConfig('site_disabled_notice', $_POST['site_disabled_notice']); }
-    else                                         setConfig('site_disabled', '0');
-    
-    // Account activation
-    setConfig('account_activation', $_POST['account_activation']);
-    
-    // W3C compliance buttons
-    if(isset($_POST['w3c-vh32']))     setConfig("w3c_vh32", "1");
-    else                              setConfig("w3c_vh32", "0");
-    if(isset($_POST['w3c-vh40']))     setConfig("w3c_vh40", "1");
-    else                              setConfig("w3c_vh40", "0");
-    if(isset($_POST['w3c-vh401']))    setConfig("w3c_vh401", "1");
-    else                              setConfig("w3c_vh401", "0");
-    if(isset($_POST['w3c-vxhtml10'])) setConfig("w3c_vxhtml10", "1");
-    else                              setConfig("w3c_vxhtml10", "0");
-    if(isset($_POST['w3c-vxhtml11'])) setConfig("w3c_vxhtml11", "1");
-    else                              setConfig("w3c_vxhtml11", "0");
-    if(isset($_POST['w3c-vcss']))     setConfig("w3c_vcss", "1");
-    else                              setConfig("w3c_vcss", "0");
-    
-    // SourceForge.net logo
-    if(isset($_POST['showsf'])) setConfig('sflogo_enabled', '1');
-    else                        setConfig('sflogo_enabled', '0');
-    setConfig('sflogo_groupid', $_POST['sfgroup']);
-    setConfig('sflogo_type', $_POST['sflogo']);
-    
-    // Comment options
-    if(isset($_POST['comment-approval'])) setConfig('approve_comments', '1');
-    else                                  setConfig('approve_comments', '0');
-    if(isset($_POST['enable-comments']))  setConfig('enable_comments', '1');
-    else                                  setConfig('enable_comments', '0');
-    setConfig('comments_need_login', $_POST['comments_need_login']);
-    
-    // Powered by link
-    if ( isset($_POST['enano_powered_link']) ) setConfig('powered_btn', '1');
-    else                                       setConfig('powered_btn', '0');    
-    
-    if(isset($_POST['dbdbutton']))        setConfig('dbd_button', '1');
-    else                                  setConfig('dbd_button', '0');
-    
-    if($_POST['emailmethod'] == 'phpmail') setConfig('smtp_enabled', '0');
-    else                                   setConfig('smtp_enabled', '1');
-    
-    setConfig('smtp_server', $_POST['smtp_host']);
-    setConfig('smtp_user', $_POST['smtp_user']);
-    if($_POST['smtp_pass'] != 'XXXXXXXXXXXX') setConfig('smtp_password', $_POST['smtp_pass']);
-    
-    echo '<div class="info-box">Your changes to the site configuration have been saved.</div><br />';
-    
-  }
-  echo('<form name="main" action="'.htmlspecialchars(makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module'])).'" method="post" onsubmit="if(!submitAuthorized) return false;">');
-  ?>
-  <div class="tblholder">
-    <table border="0" width="100%" cellspacing="1" cellpadding="4">
-      
-    <!-- Global options -->
-    
-      <tr><th colspan="2">Global site options</th></tr>
-      <tr><th colspan="2" class="subhead">These options control the entire site.</th></tr>
-      
-      <tr><td class="row1" style="width: 50%;">Site name:</td>                      <td class="row1" style="width: 50%;"><input name="site_name" size="30" value="<?php echo getConfig('site_name'); ?>" /></td></tr>
-      <tr><td class="row2">Site description:</td>               <td class="row2"><input name="site_desc" size="30" value="<?php echo getConfig('site_desc'); ?>" /></td></tr>
-      <tr><td class="row1">Main page:</td>                      <td class="row1"><?php echo $template->pagename_field('main_page', str_replace('_', ' ', getConfig('main_page'))); ?></td></tr>
-      <tr><td class="row2">Copyright notice shown on pages:</td><td class="row2"><input name="copyright" size="30" value="<?php echo getConfig('copyright_notice'); ?>" /></td></tr>
-      <tr><td class="row1" colspan="2">Hint: If you're using Windows, you can make a "&copy;" symbol by holding ALT and pressing 0169 on the numeric keypad.</td></tr>
-      <tr><td class="row2">Contact e-mail<br /><small>All e-mail sent from this site will appear to have come from the address shown here.</small></td><td class="row2"><input name="contact_email" type="text" size="40" value="<?php echo htmlspecialchars(getConfig('contact_email')); ?>" /></td></tr>
-      
-    <!-- Wiki mode -->
-      
-      <tr><th colspan="2">Wiki mode</th></tr>
-      
-      <tr>
-        <td class="row3" rowspan="2">
-          Enano can also act as a wiki, meaning anyone can edit and create pages. To enable Wiki Mode, check the box to the right.<br /><br />
-          In Wiki Mode, certain HTML tags such as &lt;script&gt; and &lt;object&gt; are disabled, and all PHP code is disabled, except if the person editing the page is an administrator.<br /><br />
-          Also, Enano keeps complete page history, which makes restoring vandalized pages easy. You can also protect pages so that they cannot be edited.
-        </td>
-        <td class="row1">
-          <input type="checkbox" name="wikimode" id="wikimode" <?php if(getConfig('wiki_mode')=='1') echo('CHECKED '); ?> /><label for="wikimode">Enable Wiki Mode</label>
-        </td>
-      </tr>
-      
-      <tr><td class="row2"><label><input type="checkbox" name="wiki_mode_require_login"<?php if(getConfig('wiki_mode_require_login')=='1') echo('CHECKED '); ?>/> Only for logged in users</label></td></tr>
-      
-      <tr>
-        <td class="row3" rowspan="2">
-          <b>Edit page notice</b><br />
-          When Wiki Mode is enabled, anyone can edit pages. Check the box below and enter a message to display it whenever the page editor is opened.
-        </td>
-        <td class="row1">
-          <input onclick="if(this.checked) document.getElementById('editmsg_text').style.display='block'; else document.getElementById('editmsg_text').style.display='none';" type="checkbox" name="editmsg" id="editmsg" <?php if(getConfig('wiki_edit_notice')=='1') echo('CHECKED '); ?>/> <label for="editmsg">Show a message whenever pages are edited</label>
-        </td>
-      </tr>
-      
-      <tr>
-        <td class="row2">
-          <textarea <?php if(getConfig('wiki_edit_notice')!='1') echo('style="display:none" '); ?>rows="5" cols="30" name="editmsg_text" id="editmsg_text"><?php echo getConfig('wiki_edit_notice_text'); ?></textarea>
-        </td>
-      </tr>
-      
-    <!-- Site statistics -->
-    
-      <tr><th colspan="2">Statistics and hit counting</th></tr>
-      
-      <tr>
-        <td class="row1">Enano has the ability to show statistics for every page on the site. This allows you to keep very close track of who is visiting your site, and from where.<br /><br />Unfortunately, some users don't like being logged. For this reason, you should state clearly what is logged (usually the username or IP address, current time, page name, and referer URL) in your privacy policy.</td>
-        <td class="row1"><label><input type="checkbox" name="log_hits" <?php if(getConfig('log_hits') == '1') echo 'checked="checked" '; ?>/>  Log all page hits</label><br /><small>This excludes special and administration pages.</small></td>
-      </tr>
-      
-    <!-- Comment options -->
-      
-      <tr><th colspan="2">Comment system</th></tr>
-      <tr><td class="row1"><label for="enable-comments"><b>Enable the comment system</b></label>                      </td><td class="row1"><input name="enable-comments"  id="enable-comments"  type="checkbox" <?php if(getConfig('enable_comments')=='1')  echo('CHECKED '); ?>/></td></tr>
-      <tr><td class="row2"><label for="comment-approval">Require approval before article comments can be shown</label></td><td class="row2"><input name="comment-approval" id="comment-approval" type="checkbox" <?php if(getConfig('approve_comments')=='1') echo('CHECKED '); ?>/></td></tr>
-      <tr><td class="row1">Guest comment posting allowed                                                              </td><td class="row1"><label><input name="comments_need_login" type="radio" value="0" <?php if(getConfig('comments_need_login')=='0') echo 'CHECKED '; ?>/> Yes</label>
-                                                                                                                                            <label><input name="comments_need_login" type="radio" value="1" <?php if(getConfig('comments_need_login')=='1') echo 'CHECKED '; ?>/> Require visual confirmation</label>
-    <!-- Default permissions -->                                                                                                            <label><input name="comments_need_login" type="radio" value="2" <?php if(getConfig('comments_need_login')=='2') echo 'CHECKED '; ?>/> No (require login)</label></td></tr>
-    
-    <!--
-    
-    READ: Do not try to enable this, backend support for it has been disabled. To edit default
-          permissions, select The Entire Website in any permissions editor window.
-    
-      <tr><th colspan="2">Default permissions for pages</th></tr>
-      
-      <tr>
-        <td class="row1">You can edit the default set of permissions used when no other permissions are available. Permissions set here are used when no other permissions are available. As with other ACL rules, you can assign these defaults to every user or one specific user or group.</td>
-        <td class="row1"><a href="#" onclick="ajaxOpenACLManager('__DefaultPermissions', 'Special'); return false;">Manage default permissions</a></td>
-      </tr>
-      
-      -->
-      
-    <!-- enanocms.org link -->
-    
-    <tr>
-      <th colspan="2">Promote Enano</th>
-    </tr>
-    <tr>
-      <td class="row3">
-        If you think Enano is nice, or if you want to show your support for the Enano team, you can do so by placing a link to the Enano
-        homepage in your Links sidebar block. You absolutely don't have to do this, and you won't get degraded support if you don't. Because
-        Enano is still relatively new in the CMS world, it needs all the attention it can get - and you can easily help to spread the word
-        using this link.
-      </td>
-      <td class="row1">
-        <label>
-          <input name="enano_powered_link" type="checkbox" <?php if(getConfig('powered_btn') == '1') echo 'checked="checked"'; ?> />&nbsp;&nbsp;Place a link to www.enanocms.org on the sidebar
-        </label>
-      </td>
-    </tr>
-      
-    <!-- Site disablement -->
-    
-      <tr><th colspan="2">Disable all site access</th></tr>
-      
-      <tr>
-        <td class="row3" rowspan="2">Disabling the site allows you to work on the site without letting non-administrators see or use it.</td>
-        <td class="row1"><label><input onclick="if(this.checked) document.getElementById('site_disabled_notice').style.display='block'; else document.getElementById('site_disabled_notice').style.display='none';" type="checkbox" name="site_disabled" <?php if(getConfig('site_disabled') == '1') echo 'checked="checked" '; ?>/>  Disable this site</label></td>
-      </tr>
-      <tr>
-        <td class="row2">
-          <div id="site_disabled_notice">
-            Message to show to users:<br />
-            <textarea name="site_disabled_notice" rows="7" cols="30"><?php echo getConfig('site_disabled_notice'); ?></textarea>
-          </div>
-        </td>
-      </tr>
-    
-    <!-- Account activation -->
-      
-      <tr><th colspan="2">User account activation</th></tr>
-      
-      <tr>
-        <td class="row3" colspan="2">
-          If you would like to require users to confirm their e-mail addresses by way of account activation, you can enable this behavior here. If this option is set to "None", users will be able to register and use this site without confirming their e-mail addresses. If this option is set to "User", users will automatically be sent e-mails upon registration with a link to activate their accounts. And lastly, if this option is set to "Admin", users' accounts will not be active until an administrator activates the account.<br /><br />
-          You may also disable registration completely if needed.<br /><br />
-          <b>Note: because of abuse by project administrators, sending account activation e-mails will not work on SourceForge.net servers.</b>
-        </td>
-      </tr>
-      
-      <tr>
-        <td class="row1">Account activation:</td><td class="row1">
-          <?php
-          echo '<label><input'; if(getConfig('account_activation') == 'disable') echo ' checked="checked"'; echo ' type="radio" name="account_activation" value="disable" /> Disable registration</label><br />';
-          echo '<label><input'; if(getConfig('account_activation') != 'user' && getConfig('account_activation') != 'admin') echo ' checked="checked"'; echo ' type="radio" name="account_activation" value="none" /> None</label>';
-          echo '<label><input'; if(getConfig('account_activation') == 'user') echo ' checked="checked"'; echo ' type="radio" name="account_activation" value="user" /> User</label>';
-          echo '<label><input'; if(getConfig('account_activation') == 'admin') echo ' checked="checked"'; echo ' type="radio" name="account_activation" value="admin" /> Admin</label>';
-          ?>
-        </td>
-      </tr>
-      
-    <!-- E-mail options -->
-    
-    <tr><th colspan="2">E-mail sent from the site</th></tr>
-    <tr><td class="row1">E-mail sending method:<br /><small>Try using the built-in e-mail method first. If that doesn't work, you will need to enter valid SMTP information here.</small></td>
-        <td class="row1"><label><input <?php if(getConfig('smtp_enabled') != '1') echo 'checked="checked"'; ?> type="radio" name="emailmethod" value="phpmail" />PHP's built-in mail() function</label><br />
-                         <label><input <?php if(getConfig('smtp_enabled') == '1') echo 'checked="checked"'; ?> type="radio" name="emailmethod" value="smtp" />Use an external SMTP server</label></td>
-        </tr>
-    <tr><td class="row2">SMTP hostname:<br /><small>This option only applies to the external SMTP mode.</small></td>
-        <td class="row2"><input value="<?php echo getConfig('smtp_server'); ?>" name="smtp_host" type="text" size="30" /></td>
-        </tr>
-    <tr><td class="row1">SMTP credentials:<br /><small>This option only applies to the external SMTP mode.</small></td>
-        <td class="row1">Username: <input value="<?php echo getConfig('smtp_user'); ?>" name="smtp_user" type="text" size="30" /><br />
-            Password: <input value="<?php if(getConfig('smtp_password') != false) echo 'XXXXXXXXXXXX'; ?>" name="smtp_pass" type="password" size="30" /></td>
-        </tr>
-      
-    <!-- SourceForge.net logo -->
-      
-      <tr><th colspan="2">SourceForge.net logo</th></tr>
-      
-      <tr>
-        <td colspan="2" class="row3">
-          All projects hosted by SourceForge.net are required to display an official SourceForge.net logo on their pages.  If you want
-          to display a SourceForge.net logo on the sidebar, check the box below, enter your group ID, and select an image type.
-        </td>
-      </tr>
-      
-      <?php
-      if(getConfig("sflogo_enabled")=='1') $c='CHECKED ';
-      else $c='';
-      if(getConfig("sflogo_groupid")) $g=getConfig("sflogo_groupid");
-      else $g='';
-      if(getConfig("sflogo_type")) $t=getConfig("sflogo_type");
-      else $t='1';
-      ?>
-      
-      <tr>
-        <td class="row1">Display the SourceForge.net logo on the right sidebar</td>
-        <td class="row1"><input type=checkbox name="showsf" id="showsf" <?php echo $c; ?> /></td>
-      </tr>
-      
-      <tr>
-        <td class="row2">Group ID:</td>
-        <td class="row2"><input value="<?php echo $g; ?>" type=text size=15 name=sfgroup /></td>
-      </tr>
-      
-      <tr>
-        <td class="row1">Logo style:</td>
-        <td class="row1">
-          <select name="sflogo">
-            <option <?php if($t=='1') echo('SELECTED '); ?>value=1>88x31px, white</option>
-            <option <?php if($t=='2') echo('SELECTED '); ?>value=2>125x37px, white</option>
-            <option <?php if($t=='3') echo('SELECTED '); ?>value=3>125x37px, black</option>
-            <option <?php if($t=='4') echo('SELECTED '); ?>value=4>125x37px, blue</option>
-            <option <?php if($t=='5') echo('SELECTED '); ?>value=5>210x62px, white</option>
-            <option <?php if($t=='6') echo('SELECTED '); ?>value=6>210x62px, black</option>
-            <option <?php if($t=='7') echo('SELECTED '); ?>value=7>210x62px, blue</option>
-          </select>
-        </td>
-      </tr>
-      
-    <!-- W3C validator buttons -->
-      
-      <tr><th colspan="2">W3C compliance logos</th></tr>
-      <tr><th colspan="2" class="subhead">Enano generates (by default) Valid XHTML 1.1 code, plus valid CSS.  If you want to show this off, check the appropriate boxes below.</th></tr>
-      
-      <tr><td class="row1"><label for="w3c-vh32">HTML 3.2</label>     </td><td class="row1"><input type="checkbox" <?php if(getConfig('w3c_vh32')=='1')     echo('CHECKED '); ?> id="w3c-vh32"     name="w3c-vh32"     /></td></tr>
-      <tr><td class="row2"><label for="w3c-vh40">HTML 4.0</label>     </td><td class="row2"><input type="checkbox" <?php if(getConfig('w3c_vh40')=='1')     echo('CHECKED '); ?> id="w3c-vh40"     name="w3c-vh40"     /></td></tr>
-      <tr><td class="row1"><label for="w3c-vh401">HTML 4.01</label>   </td><td class="row1"><input type="checkbox" <?php if(getConfig('w3c_vh401')=='1')    echo('CHECKED '); ?> id="w3c-vh401"    name="w3c-vh401"    /></td></tr>
-      <tr><td class="row2"><label for="w3c-vxhtml10">XHTML 1.0</label></td><td class="row2"><input type="checkbox" <?php if(getConfig('w3c_vxhtml10')=='1') echo('CHECKED '); ?> id="w3c-vxhtml10" name="w3c-vxhtml10" /></td></tr>
-      <tr><td class="row1"><label for="w3c-vxhtml11">XHTML 1.1</label></td><td class="row1"><input type="checkbox" <?php if(getConfig('w3c_vxhtml11')=='1') echo('CHECKED '); ?> id="w3c-vxhtml11" name="w3c-vxhtml11" /></td></tr>
-      <tr><td class="row2"><label for="w3c-vcss">CSS</label>          </td><td class="row2"><input type="checkbox" <?php if(getConfig('w3c_vcss')=='1')     echo('CHECKED '); ?> id="w3c-vcss"     name="w3c-vcss"     /></td></tr>
-
-    <!-- DefectiveByDesign.org ad -->      
-      
-      <tr><th colspan="2">Defective By Design Anti-DRM button</th></tr>
-      <tr><td colspan="2" class="row3"><b>The Enano project is strongly against Digital Restrictions Management.</b> DRM removes the freedoms that every consumer should have: to freely copy and use digital media items they legally purchased to their own devices. Showing your opposition to DRM is as easy as checking the box below to place a link to <a href="http://www.defectivebydesign.org">DefectiveByDesign.org</a> on your sidebar.</td></tr>
-      <tr><td class="row1"><label for="dbdbutton">Help stop DRM by placing a link to DBD on the sidebar!</label></td><td class="row1"><input type="checkbox" name="dbdbutton" id="dbdbutton" <?php if(getConfig('dbd_button')=='1')  echo('checked="checked" '); ?>/></td></tr>
-      
-    <!-- Save button -->
-      
-      <tr><th style="text-align: right" class="subhead" colspan="2"><input type=submit name=submit value="Save changes" /></th></tr>
-      
-    </table>
-  </div>
-</form>
-  <?php
-}
-
-function page_Admin_UploadConfig()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  if(isset($_POST['save']))
-  {
-    if(isset($_POST['enable_uploads'])) setConfig('enable_uploads', '1'); else setConfig('enable_uploads', '0');
-    if(isset($_POST['enable_imagemagick'])) setConfig('enable_imagemagick', '1'); else setConfig('enable_imagemagick', '0');
-    if(isset($_POST['cache_thumbs'])) setConfig('cache_thumbs', '1'); else setConfig('cache_thumbs', '0');
-    if(isset($_POST['file_history'])) setConfig('file_history', '1'); else setConfig('file_history', '0');
-    if(file_exists($_POST['imagemagick_path'])) setConfig('imagemagick_path', $_POST['imagemagick_path']);
-    else echo '<span style="color: red"><b>Warning:</b> the file "'.$_POST['imagemagick_path'].'" was not found, and the ImageMagick file path was not updated.</span>';
-    $max_upload = floor((float)$_POST['max_file_size'] * (int)$_POST['fs_units']);
-    setConfig('max_file_size', $max_upload.'');
-  }
-  echo '<form name="main" action="'.htmlspecialchars(makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module'])).'" method="post">';
-  ?>
-  <h3>File upload configuration</h3>
-  <p>Enano supports the ability to upload files to your website and store the files in the database. This enables you to embed images
-     and such into pages without manually writing the HTML. However, the upload feature can sometimes pose a risk to your site, as viruses
-     and executable files can sometimes be uploaded.</p>
-  <p><label><input type="checkbox" name="enable_uploads" <?php if(getConfig('enable_uploads')=='1') echo 'checked="checked"'; ?> /> <b>Enable file uploads</b></label></p>
-  <p>Maximum file size: <input name="max_file_size" onkeyup="if(!this.value.match(/^([0-9\.]+)$/ig)) this.value = this.value.substr(0,this.value.length-1);" value="<?php echo getConfig('max_file_size'); ?>" /> <select name="fs_units"><option value="1" selected="selected">bytes</option><option value="1024">KB</option><option value="1048576">MB</option></select></p>
-  <p>You can allow Enano to generate thumbnails of images automatically. This feature requires ImageMagick to work properly. If your server
-     does not have ImageMagick on it, Enano will simply make your users' browsers scale the images. In most cases this is fine, but if you
-     are uploading large (>100KB) images and embedding them inside of pages, you should try to enable ImageMagick because transferring these
-     large images many times can cost you quite a lot of bandwidth.</p>
-  <p><label><input type="checkbox" name="enable_imagemagick" <?php if(getConfig('enable_imagemagick')=='1') echo 'checked="checked"'; ?> /> Use ImageMagick to scale images</label><br />
-     Path to ImageMagick: <input type="text" name="imagemagick_path" value="<?php if(getConfig('imagemagick_path')) echo getConfig('imagemagick_path'); else echo '/usr/bin/convert'; ?>" /><br />
-     On Linux and Unix servers, the most likely options here are /usr/bin/convert and /usr/local/bin/convert. If you server runs Windows, then
-     ImageMagick is most likely to be C:\Windows\Convert.exe or C:\Windows\System32\Convert.exe.
-     </p>
-  <p>If you use ImageMagick to scale images, your server will be very busy constantly scaling images if your website is busy, and your site
-     may experience slowdowns. You can dramatically speed up this scaling process if you use a directory to cache thumbnail images.</p>
-  <p><b>Please note:</b> the cache/ directory on your server <u>must</u> be writable by the server. While this is not usually a problem on
-     Windows servers, most Linux/Unix servers will require you to CHMOD the cache/ directory to 777. See your FTP client's user guide for
-     more information on how to do this.<?php if(!is_writable(ENANO_ROOT.'/cache/')) echo ' <b>At present, it seems that the cache directory
-     is not writable. The checkbox below has been disabled to maintain the stability of Enano.</b>'; ?></p>
-  <p><label><input type="checkbox" name="cache_thumbs" <?php if(getConfig('cache_thumbs')=='1' && is_writable(ENANO_ROOT.'/cache/')) echo 'checked="checked"'; elseif(!is_writable(ENANO_ROOT.'/cache/')) echo 'readonly="readonly"'; ?> /> Cache thumbnailed images</label></p>
-  <p>Lastly, you can choose whether file history will be saved. If this option is turned on, you will be able to roll back any malicious
-     changes made to uploaded files, but this requires a significant amount of database storage. You should probably leave this option
-     enabled unless you have less than 250MB of MySQL database space.</p>
-  <p><label><input type="checkbox" name="file_history" <?php if(getConfig('file_history')=='1' && is_writable(ENANO_ROOT.'/cache/')) echo 'checked="checked"'; ?> /> Keep a history of uploaded files</label></p>
-  <hr style="margin-left: 1em;" />
-  <p><input type="submit" name="save" value="Save changes" style="font-weight: bold;" /></p>
-  <?php
-  echo '</form>';
-}
-
-function page_Admin_PluginManager() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  
-  if(isset($_GET['action'])) {
-    switch($_GET['action']) {
-      case "enable":
-        setConfig('plugin_'.$_GET['plugin'], '1');
-        break;
-      case "disable":
-        if($_GET['plugin']!='admin.php') setConfig('plugin_'.$_GET['plugin'], '0');
-        else echo('<h3>Error disabling plugin</h3><p>The administration panel plugin cannot be disabled.</p>');
-        break;
-    }
-  }
-  $dir = './plugins/';
-  $plugin_list = Array();
-  $system = Array();
-  if (is_dir($dir)) {
-    if ($dh = opendir($dir)) {
-      while (($file = readdir($dh)) !== false) {
-        if(preg_match('#^(.*?)\.php$#is', $file) && $file != 'index.php')
-        {
-          if ( in_array($file, $plugins->system_plugins) )
-          {
-            $thelist =& $system;
-            continue;
-          }
-          else
-          {
-            $thelist =& $plugin_list;
-          }
-          $f = file_get_contents($dir . $file);
-          $f = explode("\n", $f);
-          $f = array_slice($f, 2, 7);
-          $f[0] = substr($f[0], 13, strlen($f[0]));
-          $f[1] = substr($f[1], 12, strlen($f[1]));
-          $f[2] = substr($f[2], 13, strlen($f[2]));
-          $f[3] = substr($f[3], 8,  strlen($f[3]));
-          $f[4] = substr($f[4], 9,  strlen($f[4]));
-          $f[5] = substr($f[5], 12, strlen($f[5]));
-          $thelist[$file] = Array();
-          $thelist[$file]['name'] = $f[0];
-          $thelist[$file]['uri']  = $f[1];
-          $thelist[$file]['desc'] = $f[2];
-          $thelist[$file]['auth'] = $f[3];
-          $thelist[$file]['vers'] = $f[4];
-          $thelist[$file]['aweb'] = $f[5];
-        }
-      }
-      closedir($dh);
-    }
-  }
-  echo('<div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4">
-      <tr><th>Plugin filename</th><th>Plugin name</th><th>Description</th><th>Author</th><th>Version</th><th></th></tr>');
-    $plugin_files = array_keys($plugin_list);
-    $cls = 'row2';
-    for ( $i = 0; $i < sizeof($plugin_files); $i++ )
-    {
-      $cls = ( $cls == 'row2' ) ? 'row3' : 'row2';
-      echo '<tr>
-              <td class="'.$cls.'">'.$plugin_files[$i].'</td>
-              <td class="'.$cls.'"><a href="'.$plugin_list[$plugin_files[$i]]['uri'].'">'.$plugin_list[$plugin_files[$i]]['name'].'</a></td>
-              <td class="'.$cls.'">'.$plugin_list[$plugin_files[$i]]['desc'].'</td>
-              <td class="'.$cls.'"><a href="'.$plugin_list[$plugin_files[$i]]['aweb'].'">'.$plugin_list[$plugin_files[$i]]['auth'].'</a></td>
-              <td class="'.$cls.'">'.$plugin_list[$plugin_files[$i]]['vers'].'</td>
-              <td class="'.$cls.'">';
-      if ( getConfig('plugin_'.$plugin_files[$i]) == '1' )
-      {
-        echo '<a href="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'&amp;action=disable&amp;plugin='.$plugin_files[$i].'">Disable</a>';
-      }
-      else
-      {
-        echo '<a href="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'&amp;action=enable&amp;plugin='.$plugin_files[$i].'">Enable</a>';
-      }
-      echo '</td></tr>';
-    }
-    echo '</table></div>';
-}
-
-function page_Admin_UploadAllowedMimeTypes()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  global $mime_types, $mimetype_exps, $mimetype_extlist;
-  if(isset($_POST['save']))
-  {
-    $bits = '';
-    $keys = array_keys($mime_types);
-    foreach($keys as $i => $k)
-    {
-      if(isset($_POST['ext_'.$k])) $bits .= '1';
-      else $bits .= '0';
-    }
-    $bits = compress_bitfield($bits);
-    setConfig('allowed_mime_types', $bits);
-    echo '<div class="info-box">Your changes have been saved.</div>';
-  }
-  $allowed = fetch_allowed_extensions();
-  ?>
-  <h3>Allowed file types</h3>
-   <p>Using the form below, you can decide which file types are allowed to be uploaded to this site.</p>
-  <?php
-  echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', (( isset($_GET['sqldbg'])) ? 'sqldbg&amp;' : '') .'module='.$paths->cpage['module']).'" method="post">';
-    $c = -1;
-    $t = -1;
-    $cl = 'row1';
-    echo "\n".'    <div class="tblholder">'."\n".'      <table cellspacing="1" cellpadding="2" style="margin: 0; padding: 0;" border="0">'."\n".'        <tr>'."\n        ";
-    foreach($mime_types as $e => $m)
-    {
-      $c++;
-      $t++;
-      if($c == 3)
-      {
-        $c = 0;
-        $cl = ( $cl == 'row1' ) ? 'row2' : 'row1';
-        echo '</tr>'."\n".'        <tr>'."\n        ";
-      }
-      $seed = "extchkbx_{$e}_".md5(microtime() . mt_rand());
-      $chk = (!empty($allowed[$e])) ? ' checked="checked"' : '';
-      echo "  <td class='$cl'>\n            <label><input id='{$seed}' type='checkbox' name='ext_{$e}'{$chk} />.{$e}\n            ({$m})</label>\n          </td>\n        ";
-    }
-    while($c < 2)
-    {
-      $c++;
-      echo "  <td class='{$cl}'></td>\n        ";
-    }
-    echo '<tr><th class="subhead" colspan="3"><input type="submit" name="save" value="Save changes" /></th></tr>';
-    echo '</tr>'."\n".'      </table>'."\n".'    </div>';
-    echo '</form>';
-  ?>
-  <?php
-}
-
-function page_Admin_Sidebar()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  ?>
-  <h2>Editing and managing the Enano sidebar</h2>
-   <p>The Enano sidebar is a versatile tool when scripted correctly. You don't have to be a programmer to enjoy the features the Sidebar
-      provides; however, editing the sidebar requires a small bit of programming knowledge and an understanding of Enano's system message
-      markup language.
-      </p>
-   <p>The Enano system markup language is somewhat similar to HTML, in that it uses tags (&lt;example&gt;like this&lt;/example&gt;) for the
-      main syntax. However, Enano uses curly brackets ({ and }) as opposed to less-than and greater-than signs (&lt; and &gt;).</p>
-   <p>Programming the Enano sidebar requires the use of two tags: {slider} and {if}. The {slider} tag is used to create a new heading
-      on the sidebar, and all text enclosed in that tag will be collapsed when the heading is clicked. To specify the text on the heading,
-      use an equals sign (=) after the "slider" text. Then insert any links (they should be wiki-formatted) to internal Enano pages and
-      external sites.</p>
-   <p>So here is what the language for the default sidebar's "Navigation" heading looks like:</p>
-   <pre>{slider=Navigation}
-  [[Main Page|Home]]
-  [[Enano:Sidebar|Edit the sidebar]]
-{/slider}</pre>
-   <p>Pretty simple, huh? Good, now we're going to learn another common aspect of Enano programming: conditionals. The {if} tag allows you
-      to decide whether a portion of the sidebar will be displayed based on a template variable. Currently the only available conditions are
-      "user_logged_in" and "auth_admin", but more will be added soon. To use a conditional, enter {if conditional_name}, and then the
-      wiki-formatted text that you want to be under that condition, and then close the tag with {/if}. In the same way, you can reverse the
-      effect with {!if}. With {!if}, the closing tag is still {/if}, so keep that in mind. An {else} tag will be supported soon.</p>
-   <p>Now it's time for some real fun: variables. All template variables can be accessed from the sidebar. A variable is simply the
-      variable name, prefixed by a dollar sign ($). Some of the most common variables are $USERNAME, $SITE_NAME, $SITE_DESC, and $PAGE_NAME.
-      The sidebar also has some special variables that it uses for some of its links. The logout link can be added with $LOGOUT_LINK, and
-      the "change theme" button can be added with $STYLE_LINK.</p>
-   <p>So here is the Enano markup for the portion of the sidebar that contains the user tools:</p>
-   <pre>{slider=$USERNAME}
-  [[User:$USERNAME|User page]]
-  [[Special:Contributions?user=$USERNAME|My Contributions]]
-  {if user_logged_in}
-    [[Special:Preferences|Preferences]]
-    $THEME_LINK
-  {/if}
-  {if auth_admin}
-    [[Special:Administration|Administration]]
-  {/if}
-  {if user_logged_in}
-    $LOGOUT_LINK
-  {/if}
-  {!if user_logged_in}
-    Create an account
-    Log in
-  {/if}
-{/slider}</pre>
-  <?php
-}
-
-function page_Admin_UserManager() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  if(isset($_POST['go'])) {
-    // We need the user ID before we can do anything
-    $q = $db->sql_query('SELECT user_id,username,email,real_name,style,user_level FROM '.table_prefix.'users WHERE username=\'' . $db->escape($_POST['username']) . '\'');
-    if(!$q) die('Error selecting user ID: '.mysql_error());
-    if($db->numrows() < 1) { echo('User does not exist, please enter another username.'); return; }
-    $r = $db->fetchrow();
-    $db->free_result();
-    if(isset($_POST['save']))
-    {
-      $_POST['level'] = intval($_POST['level']);
-      
-      $new_level = $_POST['level'];
-      $old_level = intval($r['user_level']);
-      
-      $re = $session->update_user((int)$r['user_id'], $_POST['new_username'], false, $_POST['new_pass'], $_POST['email'], $_POST['real_name'], false, $_POST['level']);
-      
-      if($re == 'success')
-      {
-        
-        if ( $new_level != $old_level )
-        {
-          $user_id = intval($r['user_id']);
-          // We need to update group memberships
-          if ( $old_level == USER_LEVEL_ADMIN ) 
-          {
-            $session->remove_user_from_group($user_id, GROUP_ID_ADMIN);
-          }
-          else if ( $old_level == USER_LEVEL_MOD ) 
-          {
-            $session->remove_user_from_group($user_id, GROUP_ID_MOD);
-          }
-          
-          if ( $new_level == USER_LEVEL_ADMIN )
-          {
-            $session->add_user_to_group($user_id, GROUP_ID_ADMIN, false);
-          }
-          else if ( $new_level == USER_LEVEL_MOD )
-          {
-            $session->add_user_to_group($user_id, GROUP_ID_MOD, false);
-          }
-        }
-        
-        echo('<div class="info-box">Your changes have been saved.</div>');
-      }
-      else
-      {
-        echo('<div class="error-box">Error saving changes: '.implode('<br />', $re).'</div>');
-      }
-      $q = $db->sql_query('SELECT user_id,username,email,real_name,style,user_level FROM '.table_prefix.'users WHERE username=\''.$db->escape($_POST['username']).'\'');
-      if ( !$q )
-      {
-        die('Error selecting user ID: '.mysql_error());
-      }
-      if($db->numrows($q) < 1)
-      {
-        die('User does not exist, please enter another username.');
-      }
-      $r = mysql_fetch_object($q);
-      $db->free_result();
-    }
-    elseif(isset($_POST['deleteme']) && isset($_POST['delete_conf']))
-    {
-      $q = $db->sql_query('DELETE FROM users WHERE user_id='.$r['user_id'].';');
-      if($q)
-      {
-        echo '<div class="error-box">The user account "'.$r['username'].'" was deleted.</div>';
-      }
-      else
-      {
-        echo '<div class="error-box">The user account "'.$r['username'].'" could not be deleted due to a database error.<br /><br />'.$db->get_error().'</div>';
-      }
-    }
-    else
-    {
-      echo('
-      <h3>Edit User Info</h3>
-      <form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post">
-        <table border="0" style="margin-left: 0.2in;">   
-          <tr><td>Username:</td><td><input type="text" name="new_username" value="'.$r['username'].'" /></td></tr>
-          <tr><td>New Password:</td><td><input type="password" name="new_pass" /></td></tr>
-          <tr><td>E-mail:</td><td><input type="text" name="email" value="'.$r['email'].'" /></td></tr>
-          <tr><td>Real Name:</td><td><input type="text" name="real_name" value="'.$r['real_name'].'" /></td></tr>
-          <tr><td>User level:</td><td><select name="level"><option '); if($r['user_level']==USER_LEVEL_CHPREF) echo('SELECTED'); echo(' value="'.USER_LEVEL_CHPREF.'">Regular User</option><option '); if($r['user_level']==USER_LEVEL_MOD) echo('SELECTED'); echo(' value="'.USER_LEVEL_MOD.'">Moderator</option><option '); if($r['user_level']==USER_LEVEL_ADMIN) echo('SELECTED'); echo(' value="'.USER_LEVEL_ADMIN.'">Administrator</option></select></td></tr>
-          <tr><td>Delete user:</td><td><input type="hidden" name="go" /><input type="hidden" name="username" value="'.$r['username'].'" /><input onclick="return confirm(\'This is your last warning.\n\nAre you sure you want to delete this user account? Even if you delete this user account, the username will be shown in page edit history, comments, and other areas of the site.\n\nDeleting a user account CANNOT BE UNDONE and should only be done in extreme circumstances.\n\nIf the user has violated the site policy, deleting the account will not prevent him from using the site, for that you need to add a new ban rule.\n\nContinue deleting this user account?\')" type="submit" name="deleteme" value="Delete this user" style="color: red;" /> <label><input type="checkbox" name="delete_conf" /> I\'m absolutely sure</label>
-          <tr><td align="center" colspan="2">
-          <input type="submit" name="save" value="Save Changes" /></td></tr>
-        </table>
-      </form>
-      ');
-    }
-  } elseif(isset($_POST['clearsessions'])) {
-    // Get the current session information so the user doesn't get logged out
-    $aes = new AESCrypt();
-    $sk = md5($session->sid_super);
-    $qb = $db->sql_query('SELECT session_key,salt,auth_level,source_ip,time FROM '.table_prefix.'session_keys WHERE session_key=\''.$sk.'\' AND user_id='.$session->user_id.' AND auth_level='.USER_LEVEL_ADMIN);
-    if(!$qb) die('Error selecting session key info block B: '.$db->get_error());
-    if($db->numrows($qb) < 1) die('Error: cannot read admin session info block B, aborting table clear process');
-    $qa = $db->sql_query('SELECT session_key,salt,auth_level,source_ip,time FROM '.table_prefix.'session_keys WHERE session_key=\''.md5($session->sid).'\' AND user_id='.$session->user_id.' AND auth_level='.USER_LEVEL_MEMBER);
-    if(!$qa) die('Error selecting session key info block A: '.$db->get_error());
-    if($db->numrows($qa) < 1) die('Error: cannot read user session info block A, aborting table clear process');
-    $ra = mysql_fetch_object($qa);
-    $rb = mysql_fetch_object($qb);
-    $db->free_result($qa);
-    $db->free_result($qb);
-    $db->sql_query('DELETE FROM '.table_prefix.'session_keys;');
-    $db->sql_query('INSERT INTO '.table_prefix.'session_keys( session_key,salt,user_id,auth_level,source_ip,time ) VALUES( \''.$ra->session_key.'\', \''.$ra->salt.'\', \''.$session->user_id.'\', \''.$ra->auth_level.'\', \''.$ra->source_ip.'\', '.$ra->time.' ),( \''.$rb->session_key.'\', \''.$rb->salt.'\', \''.$session->user_id.'\', \''.$rb->auth_level.'\', \''.$rb->source_ip.'\', '.$rb->time.' )');
-    echo('
-      <div class="info-box">The session key table has been cleared. Your database should be a little bit smaller now.</div>
-    ');
-  }   
-  echo('
-  <h3>User Management</h3>
-  <form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;">
-    <p>Username: '.$template->username_field('username').' <input type="submit" name="go" value="Go" /></p>
-    <h3>Clear session keys table</h3>
-     <p>It\'s a good idea to clean out your session keys table every once in a while, since this helps to reduce database size. During this process you will be logged off and (hopefully) logged back on automatically. The side effects of this include all users except you being logged off.</p>
-     <p><input type="submit" name="clearsessions" value="Clear session keys table" /></p>
-  </form>
-  ');
-  if(isset($_GET['action']) && isset($_GET['user']))
-  {
-    switch($_GET['action'])
-    {
-      case "activate":
-        $e = $db->sql_query('SELECT activation_key FROM '.table_prefix.'users WHERE username=\'' . $db->escape($_GET['user']) . '\'');
-        if($e)
-        {
-          $row = $db->fetchrow();
-          $db->free_result();
-          if($session->activate_account($_GET['user'], $row['activation_key'])) { echo '<div class="info-box">The user account "'.$_GET['user'].'" has been activated.</div>'; $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE time_id=' . $db->escape($_GET['logid'])); }
-          else echo '<div class="warning-box">The user account "'.$_GET['user'].'" has NOT been activated, possibly because the account is already active.</div>';
-        } else echo '<div class="error-box">Error activating account: '.mysql_error().'</div>';
-        break;
-      case "sendemail":
-        if($session->send_activation_mail($_GET['user'])) { echo '<div class="info-box">The user "'.$_GET['user'].'" has been sent an e-mail with an activation link.</div>'; $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE time_id=' . $db->escape($_GET['logid'])); }
-        else echo '<div class="error-box">The user account "'.$_GET['user'].'" has not been activated, probably because of a bad SMTP configuration.</div>';
-        break;
-      case "deny":
-        $e = $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE log_type=\'admin\' AND action=\'activ_req\' AND edit_summary=\'' . $db->escape($_GET['user']) . '\';');
-        if(!$e) echo '<div class="error-box">Error during row deletion: '.mysql_error().'</div>';
-        else echo '<div class="info-box">All activation requests for the user "'.$_GET['user'].'" have been deleted.</div>';
-        break;
-    }
-  }
-  $q = $db->sql_query('SELECT log_type, action, time_id, date_string, author, edit_summary FROM '.table_prefix.'logs WHERE log_type=\'admin\' AND action=\'activ_req\' ORDER BY time_id DESC;');
-  if($q)
-  {
-    if($db->numrows() > 0)
-    {
-      $n = $db->numrows();
-      if($n == 1) $s = $n . ' user is';
-      else $s = $n . ' users are';
-      echo '<h3>'.$s . ' awaiting account activation</h3>';
-      echo '<div class="tblholder">
-            <table border="0" cellspacing="1" cellpadding="4" width="100%">
-            <tr><th>Date of request</th><th>Requested by</th><th>Requested for</th><th colspan="3">Actions</th></tr>';
-      $cls = 'row2';
-      while($row = $db->fetchrow())
-      {
-        if($cls == 'row2') $cls = 'row1';
-        else $cls = 'row2';
-        echo '<tr><td class="'.$cls.'">'.date('F d, Y h:i a', $row['time_id']).'</td><td class="'.$cls.'">'.$row['author'].'</td><td class="'.$cls.'">'.$row['edit_summary'].'</td><td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'UserManager&amp;action=activate&amp;user='.$row['edit_summary'].'&amp;logid='.$row['time_id']).'">Activate now</a></td><td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'UserManager&amp;action=sendemail&amp;user='.$row['edit_summary'].'&amp;logid='.$row['time_id']).'">Send activation e-mail</a></td><td class="'.$cls.'" style="text-align: center;"><a href="'.makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'UserManager&amp;action=deny&amp;user='.$row['edit_summary'].'&amp;logid='.$row['time_id']).'">Deny request</a></td></tr>';
-      }
-      echo '</table>';
-    }
-    $db->free_result();
-  }
-}
-
-function page_Admin_GroupManager()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  if(isset($_POST['do_create_stage1']))
-  {
-    if(!preg_match('/^([A-z0-9 -]+)$/', $_POST['create_group_name']))
-    {
-      echo '<p>The group name you chose is invalid.</p>';
-      return;
-    }
-    echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-    echo '<div class="tblholder">
-          <table border="0" style="width:100%;" cellspacing="1" cellpadding="4">
-          <tr><th colspan="2">Creating group: '.$_POST['create_group_name'].'</th></tr>
-          <tr>
-            <td class="row1">Group moderator</td><td class="row1">' . $template->username_field('group_mod') . '</td>
-          </tr>
-          <tr><td class="row2">Group status</td><td class="row2">
-            <label><input type="radio" name="group_status" value="'.GROUP_CLOSED.'" checked="checked" /> Closed to new members</label><br />
-            <label><input type="radio" name="group_status" value="'.GROUP_REQUEST.'" /> Members can ask to be added</label><br />
-            <label><input type="radio" name="group_status" value="'.GROUP_OPEN.'" /> Members can join freely</label><br />
-            <label><input type="radio" name="group_status" value="'.GROUP_HIDDEN.'" /> Group is hidden</label>
-          </td></tr>
-          <tr>
-            <th class="subhead" colspan="2">
-              <input type="hidden" name="create_group_name" value="'.$_POST['create_group_name'].'" />
-              <input type="submit" name="do_create_stage2" value="Create group" />
-            </th>
-          </tr>
-          </table>
-          </div>';
-    echo '</form>';
-    return;
-  }
-  elseif(isset($_POST['do_create_stage2']))
-  {
-    if(!preg_match('/^([A-z0-9 -]+)$/', $_POST['create_group_name']))
-    {
-      echo '<p>The group name you chose is invalid.</p>';
-      return;
-    }
-    if(!in_array(intval($_POST['group_status']), Array(GROUP_CLOSED, GROUP_OPEN, GROUP_HIDDEN, GROUP_REQUEST)))
-    {
-      echo '<p>Hacking attempt</p>';
-      return;
-    }
-    $e = $db->sql_query('SELECT group_id FROM '.table_prefix.'groups WHERE group_name=\''.$db->escape($_POST['create_group_name']).'\';');
-    if(!$e)
-    {
-      echo $db->get_error();
-      return;
-    }
-    if($db->numrows() > 0)
-    {
-      echo '<p>The group name you entered already exists.</p>';
-      return;
-    }
-    $db->free_result();
-    $q = $db->sql_query('INSERT INTO '.table_prefix.'groups(group_name,group_type) VALUES( \''.$db->escape($_POST['create_group_name']).'\', ' . intval($_POST['group_status']) . ' )');
-    if(!$q)
-    {
-      echo $db->get_error();
-      return;
-    }
-    $e = $db->sql_query('SELECT user_id FROM '.table_prefix.'users WHERE username=\''.$db->escape($_POST['group_mod']).'\';');
-    if(!$e)
-    {
-      echo $db->get_error();
-      return;
-    }
-    if($db->numrows() < 1)
-    {
-      echo '<p>The username you entered could not be found.</p>';
-      return;
-    }
-    $row = $db->fetchrow();
-    $id = $row['user_id'];
-    $db->free_result();
-    $e = $db->sql_query('SELECT group_id FROM '.table_prefix.'groups WHERE group_name=\''.$db->escape($_POST['create_group_name']).'\';');
-    if(!$e)
-    {
-      echo $db->get_error();
-      return;
-    }
-    if($db->numrows() < 1)
-    {
-      echo '<p>The group ID could not be looked up.</p>';
-      return;
-    }
-    $row = $db->fetchrow();
-    $gid = $row['group_id'];
-    $db->free_result();
-    $e = $db->sql_query('INSERT INTO '.table_prefix.'group_members(group_id,user_id,is_mod) VALUES('.$gid.', '.$id.', 1);');
-    if(!$e)
-    {
-      echo $db->get_error();
-      return;
-    }
-    echo "<div class='info-box'>
-            <b>Information</b><br />
-            The group {$_POST['create_group_name']} has been created successfully.
-          </div>";
-  }
-  if(isset($_POST['do_edit']) || isset($_POST['edit_do']))
-  {
-    // Fetch the group name
-    $q = $db->sql_query('SELECT group_name,system_group FROM '.table_prefix.'groups WHERE group_id='.intval($_POST['group_edit_id']).';');
-    if(!$q)
-    {
-      echo $db->get_error();
-      return;
-    }
-    if($db->numrows() < 1)
-    {
-      echo '<p>Error: couldn\'t look up group name</p>';
-    }
-    $row = $db->fetchrow();
-    $name = $row['group_name'];
-    $db->free_result();
-    if(isset($_POST['edit_do']))
-    {
-      if(isset($_POST['edit_do']['del_group']))
-      {
-        if ( $row['system_group'] == 1 )
-        {
-          echo '<div class="error-box">The group "' . $name . '" could not be deleted because it is a system group required for site functionality.</div>';
-        }
-        else
-        {
-          $q = $db->sql_query('DELETE FROM '.table_prefix.'group_members WHERE group_id='.intval($_POST['group_edit_id']).';');
-          if(!$q)
-          {
-            echo $db->get_error();
-            return;
-          }
-          $q = $db->sql_query('DELETE FROM '.table_prefix.'groups WHERE group_id='.intval($_POST['group_edit_id']).';');
-          if(!$q)
-          {
-            echo $db->get_error();
-            return;
-          }
-          echo '<div class="info-box">The group "'.$name.'" has been deleted. Return to the <a href="javascript:ajaxPage(\'Admin:GroupManager\');">group manager</a>.</div>';
-          return;
-        }
-      }
-      if(isset($_POST['edit_do']['save_name']))
-      {
-        if(!preg_match('/^([A-z0-9 -]+)$/', $_POST['group_name']))
-        {
-          echo '<p>The group name you chose is invalid.</p>';
-          return;
-        }
-        $q = $db->sql_query('UPDATE '.table_prefix.'groups SET group_name=\''.$db->escape($_POST['group_name']).'\'
-            WHERE group_id='.intval($_POST['group_edit_id']).';');
-        if(!$q)
-        {
-          echo $db->get_error();
-          return;
-        }
-        else
-        {
-          echo '<div class="info-box" style="margin: 0 0 10px 0;"">
-                  The group name has been updated.
-                </div>';
-        }
-        $name = $_POST['group_name'];
-        
-      }
-      $q = $db->sql_query('SELECT member_id FROM '.table_prefix.'group_members
-                             WHERE group_id='.intval($_POST['group_edit_id']).';');
-      if(!$q)
-      {
-        echo $db->get_error();
-        return;
-      }
-      if($db->numrows() > 0)
-      {
-        while($row = $db->fetchrow($q))
-        {
-          if(isset($_POST['edit_do']['del_' . $row['member_id']]))
-          {
-            $e = $db->sql_query('DELETE FROM '.table_prefix.'group_members WHERE member_id='.$row['member_id']);
-            if(!$e)
-            {
-              echo $db->get_error();
-              return;
-            }
-          }
-        }
-      }
-      $db->free_result();
-      if(isset($_POST['edit_do']['add_member']))
-      {
-        $q = $db->sql_query('SELECT user_id FROM '.table_prefix.'users WHERE username=\''.$db->escape($_POST['edit_add_username']).'\';');
-        if(!$q)
-        {
-          echo $db->get_error();
-          return;
-        }
-        if($db->numrows() > 0)
-        {
-          $row = $db->fetchrow();
-          $user_id = $row['user_id'];
-          $is_mod = ( isset( $_POST['add_mod'] ) ) ? '1' : '0';
-          $q = $db->sql_query('INSERT INTO '.table_prefix.'group_members(group_id,user_id,is_mod) VALUES('.intval($_POST['group_edit_id']).','.$user_id.','.$is_mod.');');
-          if(!$q)
-          {
-            echo $db->get_error();
-            return;
-          }
-          else
-          {
-            echo '<div class="info-box" style="margin: 0 0 10px 0;"">
-                    The user "'.$_POST['edit_add_username'].'" has been added to this usergroup.
-                  </div>';
-          }
-        }
-        else
-          echo '<div class="warning-box"><b>The user "'.$_POST['edit_add_username'].'" could not be added.</b><br />This username does not exist.</div>';
-      }
-    }
-    $sg_disabled = ( $row['system_group'] == 1 ) ? ' value="Can\'t delete system group" disabled="disabled" style="color: #FF9773" ' : ' value="Delete this group" style="color: #FF3713" ';
-    echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-    echo '<div class="tblholder">
-          <table border="0" style="width:100%;" cellspacing="1" cellpadding="4">
-          <tr><th>Edit group name</th></tr>
-          <tr>
-            <td class="row1">
-              Group name: <input type="text" name="group_name" value="'.$name.'" />
-            </td>
-          </tr>
-          <tr>
-            <th class="subhead">
-              <input type="submit" name="edit_do[save_name]" value="Save name" />
-              <input type="submit" name="edit_do[del_group]" '.$sg_disabled.' />
-            </th>
-          </tr>
-          </table>
-          </div>
-          <input type="hidden" name="group_edit_id" value="'.$_POST['group_edit_id'].'" />';
-    echo '</form>';
-    echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-    echo '<div class="tblholder">
-          <table border="0" style="width:100%;" cellspacing="1" cellpadding="4">
-          <tr><th colspan="3">Edit group members</th></tr>';
-    $q = $db->sql_query('SELECT m.member_id,m.is_mod,u.username FROM '.table_prefix.'group_members AS m
-                           LEFT JOIN '.table_prefix.'users AS u
-                             ON u.user_id=m.user_id
-                             WHERE m.group_id='.intval($_POST['group_edit_id']).'
-                           ORDER BY m.is_mod DESC, u.username ASC;');
-    if(!$q)
-    {
-      echo $db->get_error();
-      return;
-    }
-    if($db->numrows() < 1)
-    {
-      echo '<tr><td colspan="3" class="row1">This group has no members.</td></tr>';
-    }
-    else
-    {
-      $cls = 'row2';
-      while($row = $db->fetchrow())
-      {
-        $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
-        $mod = ( $row['is_mod'] == 1 ) ? 'Mod' : '';
-        echo '<tr>
-                <td class="'.$cls.'" style="width: 100%;">
-                  ' . $row['username'] . '
-                </td>
-                <td class="'.$cls.'">
-                  '.$mod.'
-                </td>
-                <td class="'.$cls.'">
-                  <input type="submit" name="edit_do[del_'.$row['member_id'].']" value="Remove member" />
-                </td>
-              </tr>';
-      }
-    }
-    $db->free_result();
-    echo '</table>
-          </div>
-          <input type="hidden" name="group_edit_id" value="'.$_POST['group_edit_id'].'" />';
-    echo '</form>';
-    echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-    echo '<div class="tblholder">
-          <table border="0" style="width:100%;" cellspacing="1" cellpadding="4">
-            <tr>
-              <th>Add a new member</th>
-            </tr>
-            <tr>
-              <td class="row1">
-                Username: ' . $template->username_field('edit_add_username') . '
-              </td>
-            </tr>
-            <tr>
-              <td class="row2">
-                <label><input type="checkbox" name="add_mod" /> Is a group moderator</label> (can add and delete other members)
-              </td>
-            </tr>
-            <tr>
-              <th class="subhead">
-                <input type="submit" name="edit_do[add_member]" value="Add user to group" />
-              </th>
-            </tr>
-          </table>
-          </div>
-          <input type="hidden" name="group_edit_id" value="'.$_POST['group_edit_id'].'" />';
-    echo '</form>';
-    return;
-  }
-  echo '<h3>Manage Usergroups</h3>';
-  echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-  $q = $db->sql_query('SELECT group_id,group_name FROM '.table_prefix.'groups ORDER BY group_name ASC;');
-  if(!$q)
-  {
-    echo $db->get_error();
-  }
-  else
-  {
-    echo '<div class="tblholder">
-          <table border="0" cellspacing="1" cellpadding="4" style="width: 100%;">
-          <tr>
-          <th>Edit an existing group</th>
-          </tr>';
-    echo '<tr><td class="row2"><select name="group_edit_id">';
-    while ( $row = $db->fetchrow() )
-    {
-      if ( $row['group_name'] != 'Everyone' )
-      {
-        echo '<option value="' . $row['group_id'] . '">' . htmlspecialchars( $row['group_name'] ) . '</option>';
-      }
-    }
-    $db->free_result();
-    echo '</select></td></tr>';
-    echo '<tr><td class="row1" style="text-align: center;"><input type="submit" name="do_edit" value="Edit group" /></td></tr>
-          </table>
-          </div>
-          </form><br />';
-  }
-  echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-  echo '<div class="tblholder">
-        <table border="0" cellspacing="1" cellpadding="4" style="width: 100%;">
-        <tr>
-        <th colspan="2">Create a new group</th>
-        </tr>';
-  echo '<tr><td class="row2">Group name:</td><td class="row2"><input type="text" name="create_group_name" /></td></tr>';
-  echo '<tr><td colspan="2" class="row1" style="text-align: center;"><input type="submit" name="do_create_stage1" value="Continue >" /></td></tr>
-        </table>
-        </div>';
-  echo '</form>';
-}
-
-function page_Admin_PageManager()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  
-  echo '<h2>Page management</h2>';
-  
-  if(isset($_POST['search']) || isset($_POST['select']) || ( isset($_GET['source']) && $_GET['source'] == 'ajax' )) {
-    // The object of the game: using only the text a user entered, guess the page ID and namespace. *sigh* I HATE writing search algorithms...
-    $source = ( isset($_GET['source']) ) ? $_GET['source'] : false;
-    if ( $source == 'ajax' )
-    {
-      $_POST['search'] = true;
-      $_POST['page_url'] = $_GET['page_id'];
-    }
-    if(isset($_POST['search'])) $pid = $_POST['page_url'];
-    elseif(isset($_POST['select'])) $pid = $_POST['page_force_url'];
-    else { echo 'Internal error selecting page search terms'; return false; }
-    // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
-    $k = array_keys($paths->nslist);
-    for($i=0;$i<sizeof($paths->nslist);$i++)
-    {
-      $ln = strlen($paths->nslist[$k[$i]]);
-      if(substr($pid, 0, $ln) == $paths->nslist[$k[$i]])
-      {
-        $ns = $k[$i];
-        $page_id = substr($pid, $ln, strlen($pid));
-      }
-    }
-    // The namespace is in $ns and the page name or ID (we don't know which yet) is in $page_id
-    // Now, iterate through $paths->pages searching for a page with this name or ID
-    for($i=0;$i<sizeof($paths->pages)/2;$i++)
-    {
-      if(!isset($final_pid))
-      {
-        if    ($paths->pages[$i]['urlname_nons'] == str_replace(' ', '_', $page_id)) $final_pid = str_replace(' ', '_', $page_id);
-        elseif($paths->pages[$i]['name'] == $page_id) $final_pid = $paths->pages[$i]['urlname_nons'];
-        elseif(strtolower($paths->pages[$i]['urlname_nons']) == strtolower(str_replace(' ', '_', $page_id))) $final_pid = $paths->pages[$i]['urlname_nons'];
-        elseif(strtolower($paths->pages[$i]['name']) == strtolower(str_replace('_', ' ', $page_id))) $final_pid = $paths->pages[$i]['urlname_nons'];
-        if(isset($final_pid)) { $_POST['name'] = $paths->pages[$i]['name']; $_POST['urlname'] = $paths->pages[$i]['urlname_nons']; }
-      }
-    }
-    if(!isset($final_pid)) { echo 'The page you searched for cannot be found. <a href="#" onclick="ajaxPage(\''.$paths->nslist['Admin'].'PageManager\'); return false;">Back</a>'; return false; }
-    $_POST['namespace'] = $ns;
-    $_POST['old_namespace'] = $ns;
-    $_POST['page_id'] = $final_pid;
-    $_POST['old_page_id'] = $final_pid;
-    if(!isset($paths->pages[$paths->nslist[$_POST['namespace']].$_POST['urlname']])) { echo 'The page you searched for cannot be found. <a href="#" onclick="ajaxPage(\''.$paths->nslist['Admin'].'PageManager\'); return false;">Back</a>'; return false; }
-  }
-  
-  if(isset($_POST['page_id']) && isset($_POST['namespace']) && !isset($_POST['cancel']))
-  {
-    $cpage = $paths->pages[$paths->nslist[$_POST['namespace']].$_POST['old_page_id']];
-    if(isset($_POST['submit']))
-    {
-      // Create a list of things to update
-      $page_info = Array(
-          'name'=>$_POST['name'],
-          'urlname'=>$_POST['page_id'],
-          'namespace'=>$_POST['namespace'],
-          'special'=>isset($_POST['special']) ? '1' : '0',
-          'visible'=>isset($_POST['visible']) ? '1' : '0',
-          'comments_on'=>isset($_POST['comments_on']) ? '1' : '0',
-          'protected'=>isset($_POST['protected']) ? '1' : '0'
-        );
-      // Build the query
-      $q = 'UPDATE '.table_prefix.'pages SET ';
-      $k = array_keys($page_info);
-      foreach($k as $c)
-      {
-        $q .= $c.'=\''.$db->escape($page_info[$c]).'\',';
-      }
-      $q = substr($q, 0, strlen($q)-1);
-      // Build the WHERE statements
-      $q .= ' WHERE ';
-      $k = array_keys($cpage);
-      foreach($k as $c)
-      {
-        if($c != 'urlname_nons' && $c != 'urlname' && $c != 'really_protected') $q .= $c.'=\''.$cpage[$c].'\' AND ';
-        elseif($c == 'urlname') $q .= $c.'=\''.$cpage['urlname_nons'].'\' AND ';
-      }
-      $q = substr($q, 0, strlen($q)-5) . ';';
-      // Send the completed query to MySQL
-      $e = $db->sql_query($q);
-      if(!$e) $db->_die('The page data could not be updated.');
-      // Update any additional tables
-      $q = Array(
-        'UPDATE '.table_prefix.'categories SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'UPDATE '.table_prefix.'comments   SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'UPDATE '.table_prefix.'logs       SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'UPDATE '.table_prefix.'page_text  SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        );
-      foreach($q as $cq)
-      {
-        $e = $db->sql_query($cq);
-        if(!$e) $db->_die('Some of the additional tables containing page information could not be updated.');
-      }
-      // Update $cpage
-      $cpage = $page_info;
-      $cpage['urlname_nons'] = $cpage['urlname'];
-      $cpage['urlname'] = $paths->nslist[$cpage['namespace']].$cpage['urlname'];
-      $_POST['old_page_id'] = $page_info['urlname'];
-      $_POST['old_namespace'] = $page_info['namespace'];
-      echo '<div class="info-box">Your changes have been saved.</div>';
-    } elseif(isset($_POST['delete'])) {
-      $q = Array(
-        'DELETE FROM '.table_prefix.'categories WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'DELETE FROM '.table_prefix.'comments   WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'DELETE FROM '.table_prefix.'logs       WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'DELETE FROM '.table_prefix.'page_text  WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        );
-      foreach($q as $cq)
-      {
-        $e = $db->sql_query($cq);
-        if(!$e) $db->_die('Some of the additional tables containing page information could not be updated.');
-      }
-      
-      if(!$db->sql_query(
-        'DELETE FROM '.table_prefix.'pages WHERE urlname="'.$db->escape($_POST['old_page_id']).'" AND namespace="'.$db->escape($_POST['old_namespace']).'";'
-      )) $db->_die('The page could not be deleted.');
-      echo '<div class="info-box">This page has been deleted.</p><p><a href="javascript:ajaxPage(\''.$paths->nslist['Admin'].'PageManager\');">Return to Page manager</a><br /><a href="javascript:ajaxPage(\''.$paths->nslist['Admin'].'Home\');">Admin home</a></div>';
-      return;
-    }
-    echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration'.htmlspecialchars(urlSeparator).(( isset($_GET['sqldbg']) ) ? 'sqldbg&amp;' : '') .'module='.$paths->cpage['module']).'" method="post">';
-    ?>
-    <h3>Modify page: <?php echo $_POST['name']; ?></h3>
-     <table border="0">
-       <tr><td>Namespace:</td><td><select name="namespace"><?php $nm = array_keys($paths->nslist); foreach($nm as $ns) { if($ns != 'Special' && $ns != 'Admin') { echo '<option '; if($_POST['namespace']==$ns) echo 'selected="selected" '; echo 'value="'.$ns.'">'; if($paths->nslist[$ns] == '') echo '[No prefix]'; else echo $paths->nslist[$ns]; echo '</option>'; } } ?></select></td></tr>
-       <tr><td>Page title:</td><td><input type="text" name="name" value="<?php echo $cpage['name']; ?>" /></td></tr>
-       <tr><td>Page URL string:<br /><small>No spaces, and don't enter the namespace prefix (e.g. User:).<br />Changing this value is usually not a good idea, especially for templates and project pages.</small></td><td><input type="text" name="page_id" value="<?php echo $cpage['urlname_nons']; ?>" /></td></tr>
-       <tr><td></td><td><input <?php if($cpage['comments_on']) echo 'checked="checked"'; ?> name="comments_on" type="checkbox" id="cmt" />  <label for="cmt">Enable comments for this page</label></td></tr>
-       <tr><td></td><td><input <?php if($cpage['special']) echo 'checked="checked"'; ?> name="special" type="checkbox" id="spc" />  <label for="spc">Bypass the template engine for this page</label><br /><small>This option enables you to use your own HTML headers and other code. It is recommended that only advanced users enable this feature. As with other Enano pages, you may use PHP code in your pages, meaning you can use Enano's API on the page.</small></td></tr>
-       <tr><td></td><td><input <?php if($cpage['visible']) echo 'checked="checked"'; ?> name="visible" type="checkbox" id="vis" />  <label for="vis">Allow this page to be shown in page lists</label><br /><small>Unchecking this checkbox prevents the page for being indexed for searching. The index is rebuilt each time a page is saved, and you can force an index rebuild by going to the page <?php echo $paths->nslist['Special']; ?>SearchRebuild.</small></td></tr>
-       <tr><td></td><td><input <?php if($cpage['protected']) echo 'checked="checked"'; ?> name="protected" type="checkbox" id="prt" />  <label for="prt">Prevent non-administrators from editing this page</label><br /><small>This option only has an effect when Wiki Mode is enabled.</small></td></tr>
-       <tr><td></td><td><input type="submit" name="delete" value="Delete page" style="color: red" onclick="return confirm('Do you REALLY want to delete this page?')" /></td></tr>
-       <tr><td colspan="2" style="text-align: center;"><hr /></td></tr>
-       <tr><td colspan="2" style="text-align: right;">
-       <input type="hidden" name="old_page_id" value="<?php echo $_POST['old_page_id']; ?>" />
-       <input type="hidden" name="old_namespace" value="<?php echo $_POST['old_namespace']; ?>" />
-       <input type="Submit" name="submit" value="Save changes" style="font-weight: bold;" />  <input type="submit" name="cancel" value="Cancel changes" /></td></tr>
-     </table>
-    <?php
-    echo '</form>';
-  } else {
-    echo '<h3>Please select a page</h3>';
-    echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-    ?>
-      <p>Search for page title (remember prefixes like User: and File:) <?php echo $template->pagename_field('page_url'); ?>  <input type="submit" style="font-weight: bold;" name="search" value="Search" /></p>
-      <p>Select page title from a list: <select name="page_force_url">
-      <?php
-        for($i=0;$i<sizeof($paths->pages)/2;$i++)
-        {
-          if($paths->pages[$i]['namespace'] != 'Admin' && $paths->pages[$i]['namespace'] != 'Special') echo '<option value="'.$paths->nslist[$paths->pages[$i]['namespace']].$paths->pages[$i]['urlname_nons'].'">'.$paths->nslist[$paths->pages[$i]['namespace']].$paths->pages[$i]['name'].'</option>'."\n";
-        }
-      ?>
-      </select>  <input type="submit" name="select" value="Select" /></p>
-    <?php
-    echo '</form>';
-    
-  }
-}
-
-function page_Admin_PageEditor()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  
-  echo '<h2>Edit page content</h2>';
-  
-  if(isset($_POST['search']) || isset($_POST['select'])) {
-    // The object of the game: using only the text a user entered, guess the page ID and namespace. *sigh* I HATE writing search algorithms...
-    if(isset($_POST['search'])) $pid = $_POST['page_url'];
-    elseif(isset($_POST['select'])) $pid = $_POST['page_force_url'];
-    else { echo 'Internal error selecting page search terms'; return false; }
-    // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
-    $k = array_keys($paths->nslist);
-    for($i=0;$i<sizeof($paths->nslist);$i++)
-    {
-      $ln = strlen($paths->nslist[$k[$i]]);
-      if(substr($pid, 0, $ln) == $paths->nslist[$k[$i]])
-      {
-        $ns = $k[$i];
-        $page_id = substr($pid, $ln, strlen($pid));
-      }
-    }
-    // The namespace is in $ns and the page name or ID (we don't know which yet) is in $page_id
-    // Now, iterate through $paths->pages searching for a page with this name or ID
-    for($i=0;$i<sizeof($paths->pages)/2;$i++)
-    {
-      if(!isset($final_pid))
-      {
-        if    ($paths->pages[$i]['urlname_nons'] == str_replace(' ', '_', $page_id)) $final_pid = str_replace(' ', '_', $page_id);
-        elseif($paths->pages[$i]['name'] == $page_id) $final_pid = $paths->pages[$i]['urlname_nons'];
-        elseif(strtolower($paths->pages[$i]['urlname_nons']) == strtolower(str_replace(' ', '_', $page_id))) $final_pid = $paths->pages[$i]['urlname_nons'];
-        elseif(strtolower($paths->pages[$i]['name']) == strtolower(str_replace('_', ' ', $page_id))) $final_pid = $paths->pages[$i]['urlname_nons'];
-        if(isset($final_pid)) { $_POST['name'] = $paths->pages[$i]['name']; $_POST['urlname'] = $paths->pages[$i]['urlname_nons']; }
-      }
-    }
-    if(!isset($final_pid)) { echo 'The page you searched for cannot be found. <a href="#" onclick="ajaxPage(\''.$paths->nslist['Admin'].'PageManager\'); return false;">Back</a>'; return false; }
-    $_POST['namespace'] = $ns;
-    $_POST['page_id'] = $final_pid;
-    if(!isset($paths->pages[$paths->nslist[$_POST['namespace']].$_POST['urlname']])) { echo 'The page you searched for cannot be found. <a href="#" onclick="ajaxPage(\''.$paths->nslist['Admin'].'PageManager\'); return false;">Back</a>'; return false; }
-  }
-  
-  if(isset($_POST['page_id']) && !isset($_POST['cancel']))
-  {
-    echo '<form name="main" action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post">';
-    if(!isset($_POST['content']) || isset($_POST['revert'])) $content = RenderMan::getPage($_POST['page_id'], $_POST['namespace'], 0, false, false, false, false);
-    else $content = $_POST['content'];
-    if(isset($_POST['save']))
-    {
-      $data = $content;
-      $id = md5( microtime() . mt_rand() );
-      
-      $minor = isset($_POST['minor']) ? 'true' : 'false';
-      $q='INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,page_id,namespace,page_text,char_tag,author,edit_summary,minor_edit) VALUES(\'page\', \'edit\', '.time().', \''.date('d M Y h:i a').'\', \'' . $db->escape($_POST['page_id']) . '\', \'' . $db->escape($_POST['namespace']) . '\', \''.$data.'\', \''.$id.'\', \''.$session->username.'\', \''.$db->escape(htmlspecialchars($_POST['summary'])).'\', '.$minor.');';
-      if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
-      
-      $query = 'UPDATE '.table_prefix.'page_text SET page_text=\''.$db->escape($data).'\',char_tag=\''.$id.'\' WHERE page_id=\'' . $db->escape($_POST['page_id']) . '\' AND namespace=\'' . $db->escape($_POST['namespace']) . '\';';
-      $e = $db->sql_query($query);
-      if(!$e) echo '<div class="warning-box">The page data could not be saved. MySQL said: '.mysql_error().'<br /><br />Query:<br /><pre>'.$query.'</pre></div>';
-      else echo '<div class="info-box">Your page has been saved. <a href="'.makeUrlNS($_POST['namespace'], $_POST['page_id']).'">View page...</a></div>';
-    } elseif(isset($_POST['preview'])) {
-      echo '<h3>Preview</h3><p><b>Reminder:</b> This is only a preview; your changes to this page have not yet been saved.</p><div style="margin: 1em; padding: 10px; border: 1px dashed #606060; background-color: #F8F8F8; max-height: 200px; overflow: auto;">'.RenderMan::render($content).'</div>';
-    }
-    ?>
-    <p>
-    <textarea name="content" rows="20" cols="60" style="width: 100%;"><?php echo htmlspecialchars($content); ?></textarea><br />
-    Edit summary: <input name="summary" value="<?php if(isset($_POST['summary'])) echo $_POST['summary']; ?>" size="40" /><br />
-    <label><input type="checkbox" name="minor" <?php if(isset($_POST['minor'])) echo 'checked="checked" '; ?>/>  This is a minor edit</label>
-    </p>
-    <p>
-    <input type="hidden" name="page_id" value="<?php echo $_POST['page_id']; ?>" />
-    <input type="hidden" name="namespace" value="<?php echo $_POST['namespace']; ?>" />
-    <input type="submit" name="save" value="Save changes" style="font-weight: bold;" />&nbsp;&nbsp;<input type="submit" name="preview" value="Show preview" />&nbsp;&nbsp;<input type="submit" name="revert" value="Revert changes" onclick="return confirm('Do you really want to revert your changes?');" />&nbsp;&nbsp;<input type="submit" name="cancel" value="Cancel" onclick="return confirm('Do you really want to cancel your changes?');" />
-    </p>
-    <?php
-    echo '</form>';
-  } else {
-    echo '<h3>Please select a page</h3>';
-    echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-    ?>
-      <p>Search for page title (remember prefixes like User: and File:) <?php echo $template->pagename_field('page_url'); ?>  <input type="submit" style="font-weight: bold;" name="search" value="Search" /></p>
-      <p>Select page title from a list: <select name="page_force_url">
-      <?php
-        for($i=0;$i<sizeof($paths->pages)/2;$i++)
-        {
-          if($paths->pages[$i]['namespace'] != 'Admin' && $paths->pages[$i]['namespace'] != 'Special') echo '<option value="'.$paths->nslist[$paths->pages[$i]['namespace']].$paths->pages[$i]['urlname_nons'].'">'.$paths->nslist[$paths->pages[$i]['namespace']].$paths->pages[$i]['name'].'</option>'."\n";
-        }
-      ?>
-      </select>  <input type="submit" name="select" value="Select" /></p>
-    <?php
-    echo '</form>';
-  }
-}
-
-function page_Admin_ThemeManager() 
-{
-  
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  
-  // Get the list of styles in the themes/ dir
-  $h = opendir('./themes');
-  $l = Array();
-  if(!$h) die('Error opening directory "./themes" for reading.');
-  while(false !== ($n = readdir($h))) {
-    if($n != '.' && $n != '..' && is_dir('./themes/'.$n))
-      $l[] = $n;
-  }
-  closedir($h);
-  echo('
-  <h3>Theme Management</h3>
-   <p>Install, uninstall, and manage Enano themes.</p>
-  ');
-  if(isset($_POST['disenable'])) {
-    $q = 'SELECT enabled FROM '.table_prefix.'themes WHERE theme_id=\'' . $db->escape($_POST['theme_id']) . '\'';
-    $s = $db->sql_query($q);
-    if(!$s) die('Error selecting enabled/disabled state value: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    $r = $db->fetchrow_num($s);
-    $db->free_result();
-    if($r[0] == 1) $e = 0;
-    else $e = 1;
-    $s=true;
-    if($e==0)
-    {
-      $c = $db->sql_query('SELECT * FROM '.table_prefix.'themes WHERE enabled=1');
-      if(!$c) $db->_die('The backup check for having at least on theme enabled failed.');
-      if($db->numrows() <= 1) { echo '<div class="warning-box">You cannot disable the last remaining theme.</div>'; $s=false; }
-    }
-    $db->free_result();
-    if($s) {
-    $q = 'UPDATE '.table_prefix.'themes SET enabled='.$e.' WHERE theme_id=\'' . $db->escape($_POST['theme_id']) . '\'';
-    $a = $db->sql_query($q);
-    if(!$a) die('Error updating enabled/disabled state value: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    else echo('<div class="info-box">The theme "'.$_POST['theme_id'].'" has been  '. ( ( $e == '1' ) ? 'enabled' : 'disabled' ).'.</div>');
-    }
-  }
-  elseif(isset($_POST['edit'])) {
-    
-    $dir = './themes/'.$_POST['theme_id'].'/css/';
-    $list = Array();
-    // Open a known directory, and proceed to read its contents
-    if (is_dir($dir)) {
-      if ($dh = opendir($dir)) {
-        while (($file = readdir($dh)) !== false) {
-          if(preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css') {
-            $list[$file] = capitalize_first_letter(substr($file, 0, strlen($file)-4));
-          }
-        }
-        closedir($dh);
-      }
-    }
-    $lk = array_keys($list);
-    
-    $q = 'SELECT theme_name,default_style FROM '.table_prefix.'themes WHERE theme_id=\''.$db->escape($_POST['theme_id']).'\'';
-    $s = $db->sql_query($q);
-    if(!$s) die('Error selecting name value: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    $r = $db->fetchrow_num($s);
-    $db->free_result();
-    echo('<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post">');
-    echo('<div class="question-box">
-          Theme name displayed to users: <input type="text" name="name" value="'.$r[0].'" /><br /><br />
-          Default stylesheet: <select name="defaultcss">');
-    foreach ($lk as $l)
-    {
-      if($r[1] == $l) $v = ' selected="selected"';
-      else $v = '';
-      echo "<option value='{$l}'$v>{$list[$l]}</option>";
-    }
-    echo('</select><br /><br />
-          <input type="submit" name="editsave" value="OK" /><input type="hidden" name="theme_id" value="'.$_POST['theme_id'].'" />
-          </div>');
-    echo('</form>');
-  }
-  elseif(isset($_POST['editsave'])) {
-    $q = 'UPDATE '.table_prefix.'themes SET theme_name=\'' . $db->escape($_POST['name']) . '\',default_style=\''.$db->escape($_POST['defaultcss']).'\' WHERE theme_id=\'' . $db->escape($_POST['theme_id']) . '\'';
-    $s = $db->sql_query($q);
-    if(!$s) die('Error updating name value: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    else echo('<div class="info-box">Theme data updated.</div>');
-  }
-  elseif(isset($_POST['up'])) {
-    // If there is only one theme or if the selected theme is already at the top, do nothing
-    $q = 'SELECT theme_order FROM '.table_prefix.'themes ORDER BY theme_order;';
-    $s = $db->sql_query($q);
-    if(!$s) die('Error selecting order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    $q = 'SELECT theme_order FROM '.table_prefix.'themes WHERE theme_id=\''.$db->escape($_POST['theme_id']).'\'';
-    $sn = $db->sql_query($q);
-    if(!$sn) die('Error selecting order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    $r = $db->fetchrow_num($sn);
-    if( /* check for only one theme... */ $db->numrows($s) < 2 || $r[0] == 1 /* ...and check if this theme is already at the top */ ) { echo('<div class="warning-box">This theme is already at the top of the list, or there is only one theme installed.</div>'); } else {
-      // Get the order IDs of the selected theme and the theme before it
-      $q = 'SELECT theme_order FROM '.table_prefix.'themes WHERE theme_id=\'' . $db->escape($_POST['theme_id']) . '\'';
-      $s = $db->sql_query($q);
-      if(!$s) die('Error selecting order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-      $r = $db->fetchrow_num($s);
-      $r = $r[0];
-      $rb = $r - 1;
-      // Thank God for jEdit's rectangular selection and the ablity to edit multiple lines at the same time ;)
-      $q = 'UPDATE '.table_prefix.'themes SET theme_order=0 WHERE theme_order='.$rb.'';      /* Check for errors... <sigh> */ $s = $db->sql_query($q); if(!$s) die('Error updating order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-      $q = 'UPDATE '.table_prefix.'themes SET theme_order='.$rb.' WHERE theme_order='.$r.''; /* Check for errors... <sigh> */ $s = $db->sql_query($q); if(!$s) die('Error updating order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-      $q = 'UPDATE '.table_prefix.'themes SET theme_order='.$r.' WHERE theme_order=0';       /* Check for errors... <sigh> */ $s = $db->sql_query($q); if(!$s) die('Error updating order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-      echo('<div class="info-box">Theme moved up.</div>');
-    }
-    $db->free_result($s);
-    $db->free_result($sn);
-  }
-  elseif(isset($_POST['down'])) {
-    // If there is only one theme or if the selected theme is already at the top, do nothing
-    $q = 'SELECT theme_order FROM '.table_prefix.'themes ORDER BY theme_order;';
-    $s = $db->sql_query($q);
-    if(!$s) die('Error selecting order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    $r = $db->fetchrow_num($s);
-    if( /* check for only one theme... */ $db->numrows($s) < 2 || $r[0] == $db->numrows($s) /* ...and check if this theme is already at the bottom */ ) { echo('<div class="warning-box">This theme is already at the bottom of the list, or there is only one theme installed.</div>'); } else {
-      // Get the order IDs of the selected theme and the theme before it
-      $q = 'SELECT theme_order FROM '.table_prefix.'themes WHERE theme_id=\''.$db->escape($_POST['theme_id']).'\'';
-      $s = $db->sql_query($q);
-      if(!$s) die('Error selecting order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-      $r = $db->fetchrow_num($s);
-      $r = $r[0];
-      $rb = $r + 1;
-      // Thank God for jEdit's rectangular selection and the ablity to edit multiple lines at the same time ;)
-      $q = 'UPDATE '.table_prefix.'themes SET theme_order=0 WHERE theme_order='.$rb.'';      /* Check for errors... <sigh> */ $s = $db->sql_query($q); if(!$s) die('Error updating order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-      $q = 'UPDATE '.table_prefix.'themes SET theme_order='.$rb.' WHERE theme_order='.$r.''; /* Check for errors... <sigh> */ $s = $db->sql_query($q); if(!$s) die('Error updating order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-      $q = 'UPDATE '.table_prefix.'themes SET theme_order='.$r.' WHERE theme_order=0';       /* Check for errors... <sigh> */ $s = $db->sql_query($q); if(!$s) die('Error updating order information: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-      echo('<div class="info-box">Theme moved down.</div>');
-    }
-  }
-  else if(isset($_POST['uninstall'])) 
-  {
-    $q = 'SELECT * FROM '.table_prefix.'themes;';
-    $s = $db->sql_query($q);
-    if ( !$s )
-    {
-      die('Error getting theme count: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    }
-    $n = $db->numrows($s);
-    $db->free_result();
-    
-    if ( $_POST['theme_id'] == 'oxygen' )
-    {
-      echo '<div class="error-box">The Oxygen theme is used by Enano for installation, upgrades, and error messages, and cannot be uninstalled.</div>';
-    }
-    else
-    {
-      if($n < 2)
-      {
-        echo '<div class="error-box">The theme could not be uninstalled because it is the only theme left.</div>';
-      }
-      else
-      {
-        $q = 'DELETE FROM '.table_prefix.'themes WHERE theme_id=\''.$db->escape($_POST['theme_id']).'\' LIMIT 1;';
-        $s = $db->sql_query($q);
-        if ( !$s )
-        {
-          die('Error deleting theme data: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-        }
-        else
-        {
-          echo('<div class="info-box">Theme uninstalled.</div>');
-        }
-      }
-    }
-  }
-  elseif(isset($_POST['install'])) {
-    $q = 'SELECT * FROM '.table_prefix.'themes;';
-    $s = $db->sql_query($q);
-    if(!$s) die('Error getting theme count: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    $n = $db->numrows($s);
-    $n++;
-    $theme_id = $_POST['theme_id'];
-    $theme = Array();
-    include('./themes/'.$theme_id.'/theme.cfg');
-    $q = 'INSERT INTO '.table_prefix.'themes(theme_id,theme_name,theme_order,enabled) VALUES(\''.$theme['theme_id'].'\', \''.$theme['theme_name'].'\', '.$n.', 1)';
-    $s = $db->sql_query($q);
-    if(!$s) die('Error inserting theme data: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
-    else echo('<div class="info-box">Theme "'.$theme['theme_name'].'" installed.</div>');
-  }
-  echo('
-  <h3>Currently installed themes</h3>
-    <form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post">
-    <p>
-      <select name="theme_id">
-        ');
-        $q = 'SELECT theme_id,theme_name,enabled FROM '.table_prefix.'themes ORDER BY theme_order';
-        $s = $db->sql_query($q);
-        if(!$s) die('Error selecting theme data: '.mysql_error().'<br /><u>Attempted SQL:</u><br />'.$q);
-        while ( $r = $db->fetchrow_num($s) ) {
-          if($r[2] < 1) $r[1] .= ' (disabled)';
-          echo('<option value="'.$r[0].'">'.$r[1].'</option>');
-        }
-        $db->free_result();
-        echo('
-        </select> <input type="submit" name="disenable" value="Enable/Disable" /> <input type="submit" name="edit" value="Change settings" /> <input type="submit" name="up" value="Move up" /> <input type="submit" name="down" value="Move down" /> <input type="submit" name="uninstall" value="Uninstall" style="color: #DD3300; font-weight: bold;" />
-      </p>
-    </form>
-    <h3>Install a new theme</h3>
-  ');
-    $theme = Array();
-    $obb = '';
-    for($i=0;$i<sizeof($l);$i++) {
-      if(is_file('./themes/'.$l[$i].'/theme.cfg') && file_exists('./themes/'.$l[$i].'/theme.cfg')) {
-        include('./themes/'.$l[$i].'/theme.cfg');
-        $q = 'SELECT * FROM '.table_prefix.'themes WHERE theme_id=\''.$theme['theme_id'].'\'';
-        $s = $db->sql_query($q);
-        if(!$s) die('Error selecting list of currently installed themes: '.mysql_error().'<br /><u>Attempted SQL:</u><br />'.$q);
-        if($db->numrows($s) < 1) {
-          $obb .= '<option value="'.$theme['theme_id'].'">'.$theme['theme_name'].'</option>';
-        }
-        $db->free_result();
-      }
-    }
-    if($obb != '') {
-      echo('<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post"><p>');
-      echo('<select name="theme_id">');
-      echo($obb);
-      echo('</select>');
-      echo('
-      <input type="submit" name="install" value="Install this theme" />
-      </p></form>');
-    } else echo('<p>All themes are currently installed.</p>');
-}
-
-function page_Admin_BanControl()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  if(isset($_GET['action']) && $_GET['action'] == 'delete' && isset($_GET['id']) && $_GET['id'] != '')
-  {
-    $e = $db->sql_query('DELETE FROM '.table_prefix.'banlist WHERE ban_id=' . $db->escape($_GET['id']) . '');
-    if(!$e) $db->_die('The ban list entry was not deleted.');
-  }
-  if(isset($_POST['create']))
-  {
-    $q = 'INSERT INTO '.table_prefix.'banlist(ban_type,ban_value,reason,is_regex) VALUES( ' . $db->escape($_POST['type']) . ', \'' . $db->escape($_POST['value']) . '\', \''.$db->escape($_POST['reason']).'\'';
-      if(isset($_POST['regex'])) $q .= ', 1';
-      else $q .= ', 0';
-    $q .= ');';
-    $e = $db->sql_query($q);
-    if(!$e) $db->_die('The banlist could not be updated.');
-  }
-  $q = $db->sql_query('SELECT ban_id,ban_type,ban_value,is_regex FROM '.table_prefix.'banlist ORDER BY ban_type;');
-  if(!$q) $db->_die('The banlist data could not be selected.');
-  echo '<table border="0" cellspacing="1" cellpadding="4">';
-  echo '<tr><th>Type</th><th>Value</th><th>Regular Expression</th><th></th></tr>';
-  if($db->numrows() < 1) echo '<td colspan="4">No ban rules yet.</td>';
-  while($r = $db->fetchrow())
-  {
-    if($r['ban_type']==BAN_IP) $t = 'IP address';
-    elseif($r['ban_type']==BAN_USER) $t = 'Username';
-    elseif($r['ban_type']==BAN_EMAIL) $t = 'E-mail address';
-    if($r['is_regex']) $g = 'Yes'; else $g = 'No';
-    echo '<tr><td>'.$t.'</td><td>'.$r['ban_value'].'</td><td>'.$g.'</td><td><a href="'.makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'BanControl&amp;action=delete&amp;id='.$r['ban_id']).'">Delete</a></td></tr>';
-  }
-  $db->free_result();
-  echo '</table>';
-  echo '<h3>Create new ban rule</h3>';
-  echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post">';
-  ?>
-  Type: <select name="type"><option value="<?php echo BAN_IP; ?>">IP address</option><option value="<?php echo BAN_USER; ?>">Username</option><option value="<?php echo BAN_EMAIL; ?>">E-mail address</option></select><br />
-  Rule: <input type="text" name="value" size="30" /><br />
-  Reason to show to the banned user: <textarea name="reason" rows="7" cols="20"></textarea><br />
-  <input type="checkbox" name="regex" id="regex" />  <label for="regex">This rule is a regular expression</label> (advanced users only)<br />
-  <input type="submit" style="font-weight: bold;" name="create" value="Create new ban rule" />
-  <?php
-  echo '</form>';
-}
-
-function page_Admin_MassEmail()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  global $enano_config;
-  if ( isset($_POST['do_send']) )
-  {
-    $use_smtp = getConfig('smtp_enabled') == '1';
-    
-    //
-    // Let's do some checking to make sure that mass mail functions
-    // are working in win32 versions of php. (copied from phpBB)
-    //
-    if ( preg_match('/[c-z]:\\\.*/i', getenv('PATH')) && !$use_smtp)
-    {
-      $ini_val = ( @phpversion() >= '4.0.0' ) ? 'ini_get' : 'get_cfg_var';
-
-      // We are running on windows, force delivery to use our smtp functions
-      // since php's are broken by default
-      $use_smtp = true;
-      $enano_config['smtp_server'] = @$ini_val('SMTP');
-    }
-    
-    $mail = new emailer( !empty($use_smtp) );
-    
-    // Validate subject/message body
-    $subject = stripslashes(trim($_POST['subject']));
-    $message = stripslashes(trim($_POST['message']));
-    
-    if ( empty($subject) )
-      $errors[] = 'Please enter a subject.';
-    if ( empty($message) )
-      $errors[] = 'Please enter a message.';
-    
-    // Get list of members
-    if ( !empty($_POST['userlist']) )
-    {
-      $userlist = str_replace(', ', ',', $_POST['userlist']);
-      $userlist = explode(',', $userlist);
-      foreach ( $userlist as $k => $u )
-      {
-        if ( $u == $session->username )
-        {
-          // Message is automatically sent to the sender
-          unset($userlist[$k]);
-        }
-        else
-        {
-          $userlist[$k] = $db->escape($u);
-        }
-      }
-      $userlist = 'WHERE username=\'' . implode('\' OR username=\'', $userlist) . '\'';
-      
-      $q = $db->sql_query('SELECT email FROM '.table_prefix.'users ' . $userlist . ';');
-      if ( !$q )
-        $db->_die();
-      
-      if ( $row = $db->fetchrow() )
-      {
-        do {
-          $mail->cc($row['email']);
-        } while ( $row = $db->fetchrow() );
-      }
-      
-      $db->free_result();
-      
-    }
-    else
-    {
-      // Sending to a usergroup
-      
-      $group_id = intval($_POST['group_id']);
-      if ( $group_id < 1 )
-      {
-        $errors[] = 'Invalid group ID';
-      }
-      else
-      {
-        $q = $db->sql_query('SELECT u.email FROM '.table_prefix.'group_members AS g
-                               LEFT JOIN '.table_prefix.'users AS u
-                                 ON (u.user_id=g.user_id)
-                               WHERE g.group_id=' . $group_id . ';');
-        if ( !$q )
-          $db->_die();
-        
-        if ( $row = $db->fetchrow() )
-        {
-          do {
-            $mail->cc($row['email']);
-          } while ( $row = $db->fetchrow() );
-        }
-        
-        $db->free_result();
-      }
-    }
-    
-    if ( sizeof($errors) < 1 )
-    {
-    
-      $mail->from(getConfig('contact_email'));
-      $mail->replyto(getConfig('contact_email'));
-      $mail->set_subject($subject);
-      $mail->email_address(getConfig('contact_email'));
-      
-      // Copied/modified from phpBB
-      $email_headers = 'X-AntiAbuse: Website server name - ' . $_SERVER['SERVER_NAME'] . "\n";
-      $email_headers .= 'X-AntiAbuse: User_id - ' . $session->user_id . "\n";
-      $email_headers .= 'X-AntiAbuse: Username - ' . $session->username . "\n";
-      $email_headers .= 'X-AntiAbuse: User IP - ' . $_SERVER['REMOTE_ADDR'] . "\n";
-      
-      $mail->extra_headers($email_headers);
-      
-      $tpl = 'The following message was mass-mailed by {SENDER}, one of the administrators from {SITE_NAME}. If this message contains spam or any comments which you find abusive or offensive, please contact the administration team at:
-  
-{CONTACT_EMAIL}
-
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-{MESSAGE}
-';
-  
-      $mail->use_template($tpl);
-      
-      $mail->assign_vars(array(
-          'SENDER' => $session->username,
-          'SITE_NAME' => getConfig('site_name'),
-          'CONTACT_EMAIL' => getConfig('contact_email'),
-          'MESSAGE' => $message
-        ));
-      
-      //echo '<pre>'.print_r($mail,true).'</pre>';
-      
-      // All done
-      $mail->send();
-      $mail->reset();
-      
-      echo '<div class="info-box">Your message has been sent.</div>';
-      
-    }
-    else
-    {
-      echo '<div class="warning-box">Could not send message for the following reason(s):<ul><li>' . implode('</li><li>', $errors) . '</li></ul></div>';
-    }
-    
-  }
-  echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post">';
-  ?>
-  <div class="tblholder">
-    <table border="0" cellspacing="1" cellpadding="4">
-      <tr>
-        <th colspan="2">Send mass e-mail</th>
-      </tr>
-      <tr>
-        <td class="row2" rowspan="2" style="width: 30%; min-width: 200px;">
-          Send message to:<br />
-          <small>
-            By default, this message will be sent to the group selected here. You may instead send the message to a specific
-            list of users by entering them in the second row, with usernames separated by a single comma (no space).
-          </small>
-        </td>
-        <td class="row1">
-          <select name="group_id">
-            <?php
-            $q = $db->sql_query('SELECT group_name,group_id FROM '.table_prefix.'groups ORDER BY group_name ASC;');
-            if ( !$q )
-              $db->_die();
-            while ( $row = $db->fetchrow() )
-            {
-              echo '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</option>';
-            }
-            ?>
-          </select>
-        </td>
-      </tr>
-      <tr>
-        <td class="row1">
-          Usernames: <input type="text" name="userlist" size="50" />
-        </td>
-      </tr>
-      <tr>
-        <td class="row2" style="width: 30%; min-width: 200px;">
-          Subject:
-        </td>
-        <td class="row1">
-          <input name="subject" type="text" size="50" />
-        </td>
-      </tr>
-      <tr>
-        <td class="row2"  style="width: 30%; min-width: 200px;">
-          Message:
-        </td>
-        <td class="row1">
-          <textarea name="message" rows="30" cols="60" style="width: 100%;"></textarea>
-        </td>
-      </tr>
-      <tr>
-        <th class="subhead" colspan="2" style="text-align: left;" valign="middle">
-          <div style="float: right;"><input type="submit" name="do_send" value="Send message" /></div>
-          <small style="font-weight: normal;">Please be warned: it may take a LONG time to send this message. <b>Please do not stop the script until the process is finished.</b></small>
-        </th>
-      </tr>
-      
-    </table>
-  </div>
-  <?php
-  echo '</form>';
-}
-
-function page_Admin_DBBackup()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  global $system_table_list;
-  if(isset($_GET['submitting']) && $_GET['submitting'] == 'yes')
-  {
-    
-    if(defined('SQL_BACKUP_CRYPT'))
-      // Try to increase our time limit
-      @set_time_limit(300); // five minutes
-    // Do the actual export
-    $aesext = ( defined('SQL_BACKUP_CRYPT') ) ? '.tea' : '';
-    $filename = 'enano_backup_' . date('dmy') . '.sql' . $aesext;
-    ob_start();
-    header('Content-disposition: attachment, filename="'.$filename.'";');
-    header('Content-type: application/transact-sql');
-    // Spew some headers
-    $headdate = date('F d, Y \a\t h:i a');
-    echo <<<HEADER
--- Enano CMS SQL backup
--- Generated on {$headdate} by {$session->username}
-
-HEADER;
-    // build the table list
-    $base = ( isset($_POST['do_system_tables']) ) ? $system_table_list : Array();
-    $add  = ( isset($_POST['additional_tables'])) ? $_POST['additional_tables'] : Array();
-    $tables = array_merge($base, $add);
-    
-    // Log it!
-    $e = $db->sql_query('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'db_backup\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($session->username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', \'' . $db->escape(implode(', ', $tables)) . '\')');
-    if ( !$e )
-      $db->_die();
-    
-    foreach($tables as $i => $t)
-    {
-      if(!preg_match('#^([a-z0-9_]+)$#i', $t))
-        die('Hacking attempt');
-      // if($t == table_prefix.'files' && isset($_POST['do_data']))
-      //   unset($tables[$i]);
-    }
-    foreach($tables as $t)
-    {
-      // Sorry folks - this script CAN'T backup enano_files, enano_search_index, and enano_search_cache due to the sheer size of the tables.
-      // If encryption is enabled the log data will be excluded too.
-      echo export_table(
-        $t,
-        isset($_POST['do_struct']),
-        ( isset($_POST['do_data']) /* && $t != table_prefix.'files' && $t != table_prefix.'search_index' && $t != table_prefix.'search_cache' && ( !defined('SQL_BACKUP_CRYPT') || ( defined('SQL_BACKUP_CRYPT') && $t != table_prefix.'logs' ) ) */ ),
-        false
-        ) . "\n";
-    }
-    $data = ob_get_contents();
-    ob_end_clean();
-    if(defined('SQL_BACKUP_CRYPT'))
-    {
-      // Free some memory, we don't need this stuff any more
-      $db->close();
-      unset($paths, $db, $template, $plugins);
-      $tea = new TEACrypt();
-      $data = $tea->encrypt($data, $session->private_key);
-    }
-    header('Content-length: '.strlen($data));
-    echo $data;
-    exit;
-  }
-  else
-  {
-    // Show the UI
-    echo '<form action="'.makeUrlNS('Admin', 'DBBackup', 'submitting=yes', true).'" method="post" enctype="multipart/form-data">';
-    ?>
-    <p>This page allows you to back up your Enano database should something go miserably wrong.</p>
-    <p><label><input type="checkbox" name="do_system_tables" checked="checked" />  Export tables that are part of the Enano core</label><p>
-    <p>Additional tables to export:</p>
-    <p><select name="additional_tables[]" multiple="multiple">
-       <?php
-         $q = $db->sql_query('SHOW TABLES;') or $db->_die('Somehow we were denied the request to get the list of tables.');
-         while($row = $db->fetchrow_num())
-         {
-           if(!in_array($row[0], $system_table_list)) echo '<option value="'.$row[0].'">'.$row[0].'</option>';
-         }
-       ?>
-       </select>
-       </p>
-    <p><label><input type="checkbox" name="do_struct" checked="checked" /> Include table structure</label><br />
-       <label><input type="checkbox" name="do_data"   checked="checked" /> Include table data</label>
-       </p>
-    <p><input type="submit" value="Create backup" /></p>
-    <?php
-    echo '</form>';
-  }
-}
-
-function page_Admin_AdminLogout()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    echo '<h3>Error: Not authenticated</h3><p>It looks like your administration session is invalid or you are not authorized to access this administration page. Please <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true) . '">re-authenticate</a> to continue.</p>';
-    return;
-  }
-  
-  $session->logout(USER_LEVEL_ADMIN);
-  echo '<h3>You have now been logged out of the administration panel.</h3><p>You will continue to be logged into the website, but you will need to re-authenticate before you can access the administration panel again.</p><p>Return to the <a href="'.makeUrl(getConfig('main_page')).'">Main Page</a>.</p>';
-}
-
-function page_Special_Administration()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  
-  if($session->auth_level < USER_LEVEL_ADMIN) {
-    redirect(makeUrlNS('Special', 'Login/'.$paths->page, 'level='.USER_LEVEL_ADMIN), 'Not authorized', 'You need an authorization level of '.USER_LEVEL_ADMIN.' to use this page, your auth level is: ' . $session->auth_level, 0);
-    exit;
-  }
-  else
-  {
-    $template->load_theme('admin', 'default');
-    $template->init_vars();
-    if( !isset( $_GET['noheaders'] ) ) 
-    {
-      $template->header();
-    }
-    echo 'Administer your Enano website.';
-    ?>
-    <script type="text/javascript">
-    function ajaxPage(t)
-    {
-      if ( t == namespace_list.Admin + 'AdminLogout' )
-      {
-        var mb = new messagebox(MB_YESNO|MB_ICONQUESTION, 'Are you sure you want to de-authenticate?', 'If you de-authenticate, you will no longer be able to use the administration panel until you re-authenticate again. You may do so at any time using the Administration button on the sidebar.');
-        mb.onclick['Yes'] = function() {
-          var tigraentry = document.getElementById('i_div0_0').parentNode;
-          var tigraobj = $(tigraentry);
-          var div = document.createElement('div');
-          div.style.backgroundColor = '#FFFFFF';
-          domObjChangeOpac(70, div);
-          div.style.position = 'absolute';
-          var top = tigraobj.Top();
-          var left = tigraobj.Left();
-          var width = tigraobj.Width();
-          var height = tigraobj.Height();
-          div.style.top = top + 'px';
-          div.style.left = left + 'px';
-          div.style.width = width + 'px';
-          div.style.height = height + 'px';
-          var body = document.getElementsByTagName('body')[0];
-          enlighten(true);
-          body.appendChild(div);
-          ajaxPageBin(namespace_list.Admin + 'AdminLogout');
-        }
-        return;
-      }
-      ajaxPageBin(t);
-    }
-    function ajaxPageBin(t)
-    {
-      document.getElementById('ajaxPageContainer').innerHTML = '<div class="wait-box">Loading page...</div>';
-      ajaxGet('<?php echo scriptPath; ?>/ajax.php?title='+t+'&_mode=getpage&noheaders&auth=<?php echo $session->sid_super; ?>', function() {
-          if(ajax.readyState == 4) {
-            document.getElementById('ajaxPageContainer').innerHTML = ajax.responseText;
-            fadeInfoBoxes();
-          }
-        });
-    }
-    function _enanoAdminOnload() { ajaxPage('<?php echo $paths->nslist['Admin']; ?>Home'); }
-    var TREE_TPL = {
-      'target'  : '_self',  // name of the frame links will be opened in
-                  // other possible values are: _blank, _parent, _search, _self and _top
-    
-      'icon_e'  : '<?php echo scriptPath; ?>/images/icons/empty.gif',      // empty image
-      'icon_l'  : '<?php echo scriptPath; ?>/images/icons/line.gif',       // vertical line
-      'icon_32' : '<?php echo scriptPath; ?>/images/icons/base.gif',       // root leaf icon normal
-      'icon_36' : '<?php echo scriptPath; ?>/images/icons/base.gif',       // root leaf icon selected
-      'icon_48' : '<?php echo scriptPath; ?>/images/icons/base.gif',       // root icon normal
-      'icon_52' : '<?php echo scriptPath; ?>/images/icons/base.gif',       // root icon selected
-      'icon_56' : '<?php echo scriptPath; ?>/images/icons/base.gif',       // root icon opened
-      'icon_60' : '<?php echo scriptPath; ?>/images/icons/base.gif',       // root icon selected
-      'icon_16' : '<?php echo scriptPath; ?>/images/icons/folder.gif',     // node icon normal
-      'icon_20' : '<?php echo scriptPath; ?>/images/icons/folderopen.gif', // node icon selected
-      'icon_24' : '<?php echo scriptPath; ?>/images/icons/folder.gif',     // node icon opened
-      'icon_28' : '<?php echo scriptPath; ?>/images/icons/folderopen.gif', // node icon selected opened
-      'icon_0'  : '<?php echo scriptPath; ?>/images/icons/page.gif',       // leaf icon normal
-      'icon_4'  : '<?php echo scriptPath; ?>/images/icons/page.gif',       // leaf icon selected
-      'icon_8'  : '<?php echo scriptPath; ?>/images/icons/page.gif',       // leaf icon opened
-      'icon_12' : '<?php echo scriptPath; ?>/images/icons/page.gif',       // leaf icon selected
-      'icon_2'  : '<?php echo scriptPath; ?>/images/icons/joinbottom.gif', // junction for leaf
-      'icon_3'  : '<?php echo scriptPath; ?>/images/icons/join.gif',       // junction for last leaf
-      'icon_18' : '<?php echo scriptPath; ?>/images/icons/plusbottom.gif', // junction for closed node
-      'icon_19' : '<?php echo scriptPath; ?>/images/icons/plus.gif',       // junction for last closed node
-      'icon_26' : '<?php echo scriptPath; ?>/images/icons/minusbottom.gif',// junction for opened node
-      'icon_27' : '<?php echo scriptPath; ?>/images/icons/minus.gif'       // junction for last opended node
-    };
-    <?php
-    echo $paths->parseAdminTree(); // Make a Javascript array that defines the tree
-    if(!isset($_GET['module'])) { echo 'addOnloadHook(_enanoAdminOnload);'; } ?>
-    </script>
-    <table border="0" width="100%">
-      <tr>
-        <td class="holder" valign="top">
-          <div class="pad" style="padding-right: 20px;">
-            <script type="text/javascript">
-            new tree(TREE_ITEMS, TREE_TPL);
-            </script>
-          </div>
-        </td>
-        <td width="100%" valign="top">
-          <div class="pad" id="ajaxPageContainer">
-          <?php
-          if(isset($_GET['module'])) 
-          {
-            // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
-            $k = array_keys($paths->nslist);
-            for ( $i = 0; $i < sizeof($paths->nslist); $i++ )
-            {
-              $ln = strlen( $paths->nslist[ $k[ $i ] ] );
-              if ( substr($_GET['module'], 0, $ln) == $paths->nslist[$k[$i]] )
-              {
-                $ns = $k[$i];
-                $nm = substr($_GET['module'], $ln, strlen($_GET['module']));
-              }
-            }
-            $fname = 'page_'.$ns.'_'.$nm;
-            $s = strpos($fname, '?noheaders');
-            if($s) $fname = substr($fname, 0, $s);
-            $paths->cpage['module'] = $_GET['module'];
-            if ( function_exists($fname) && $_GET['module'] != $paths->nslist['Special'] . 'Administration' )
-            {
-              eval($fname.'();');
-            }
-          } 
-          else 
-          {
-            echo '<div class="wait-box">Please wait while the administration panel loads. You need to be using a recent browser with AJAX support in order to use Runt.</div>';
-          }
-          ?>
-          </div>
-        </td>
-      </tr>
-    </table>
-  
-    <?php
-  }
-  if(!isset($_GET['noheaders']))
-  {
-    $template->footer();
-  }
-}
-
-function page_Special_EditSidebar()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  
-  if($session->auth_level < USER_LEVEL_ADMIN) 
-  {
-    redirect(makeUrlNS('Special', 'Login/'.$paths->page, 'level='.USER_LEVEL_ADMIN), '', '', false);
-    exit;
-  }
-  else 
-  {
-    
-    $template->add_header('<script type="text/javascript" src="'.scriptPath.'/includes/clientside/dbx.js"></script>');
-    $template->add_header('<script type="text/javascript" src="'.scriptPath.'/includes/clientside/dbx-key.js"></script>');
-    $template->add_header('<script type="text/javascript" src="'.scriptPath.'/includes/clientside/sbedit.js"></script>');
-    $template->add_header('<link rel="stylesheet" type="text/css" href="'.scriptPath.'/includes/clientside/dbx.css" />');
-    
-    // Knock the sidebars dead to keep javascript in plugins from interfering
-    $template->tpl_strings['SIDEBAR_LEFT']  = '';
-    $template->tpl_strings['SIDEBAR_RIGHT'] = '';
-    
-    $template->load_theme('oxygen', 'bleu');
-    $template->init_vars();
-    
-    $template->header();
-    
-    if(isset($_POST['save']))
-    {
-      // Write the new block order to the database
-      // The only way to do this is with tons of queries (one per block + one select query at the start to count everything) but afaik its safe...
-      // Anyone know a better way to do this?
-      $q = $db->sql_query('SELECT item_order,item_id,sidebar_id FROM '.table_prefix.'sidebar ORDER BY sidebar_id ASC, item_order ASC;');
-      if ( !$q )
-      {
-        $db->_die('The sidebar order data could not be selected.');
-      }
-      $orders = Array();
-      while($row = $db->fetchrow())
-      {
-        $orders[] = Array(
-            count($orders),
-            $row['item_id'],
-            $row['sidebar_id'],
-          );
-      }
-      $db->free_result();
-      
-      // We now have an array with each sidebar ID in its respective order. Explode the order string in $_POST['order_(left|right)'] and use it to build a set of queries.
-      $ol = explode(',', $_POST['order_left']);
-      $odr = explode(',', $_POST['order_right']);
-      $om = array_merge($ol, $odr);
-      unset($ol, $odr);
-      $queries = Array();
-      foreach($orders as $k => $v)
-      {
-        $queries[] = 'UPDATE '.table_prefix.'sidebar SET item_order='.$om[$k].' WHERE item_id='.$v[1].';';
-      }
-      foreach($queries as $sql)
-      {
-        $q = $db->sql_query($sql);
-        if(!$q)
-        {
-          $t = $db->get_error();
-          echo $t;
-          $template->footer();
-          exit;
-        }
-      }
-      echo '<div class="info-box" style="margin: 10px 0;">The sidebar order information was updated successfully.</div>';
-    }
-    elseif(isset($_POST['create']))
-    {
-      switch((int)$_POST['type'])
-      {
-        case BLOCK_WIKIFORMAT:
-          $content = $_POST['wikiformat_content'];
-          break;
-        case BLOCK_TEMPLATEFORMAT:
-          $content = $_POST['templateformat_content'];
-          break;
-        case BLOCK_HTML:
-          $content = $_POST['html_content'];
-          break;
-        case BLOCK_PHP:
-          $content = $_POST['php_content'];
-          break;
-        case BLOCK_PLUGIN:
-          $content = $_POST['plugin_id'];
-          break;
-      }
-      // Get the value of item_order
-      
-      $q = $db->sql_query('SELECT * FROM '.table_prefix.'sidebar WHERE sidebar_id='.$db->escape($_POST['sidebar_id']).';');
-      if(!$q) $db->_die('The order number could not be selected');
-      $io = $db->numrows();
-      
-      $db->free_result();
-      
-      $q = 'INSERT INTO '.table_prefix.'sidebar(block_name, block_type, sidebar_id, block_content, item_order) VALUES ( \''.$db->escape($_POST['title']).'\', \''.$db->escape($_POST['type']).'\', \''.$db->escape($_POST['sidebar_id']).'\', \''.$db->escape($content).'\', '.$io.' );';
-      $result = $db->sql_query($q);
-      if(!$result)
-      {
-        echo $db->get_error();
-        $template->footer();
-        exit;
-      }
-      
-      echo '<div class="info-box" style="margin: 10px 0;">The item was added.</div>';
-      
-    }
-    
-    if(isset($_GET['action']) && isset($_GET['id']))
-    {
-      if(preg_match('#^([0-9]*)$#', $_GET['id']))
-      {
-      } else {
-        echo '<div class="warning-box">Error with action: $_GET["id"] was not an integer, aborting to prevent SQL injection</div>';
-      }
-      switch($_GET['action'])
-      {
-        case 'new':
-          ?>
-          <script type="text/javascript">
-          function setType(input)
-          {
-            val = input.value;
-            if(!val)
-            {
-              return false;
-            }
-            var divs = getElementsByClassName(document, 'div', 'sbadd_block');
-            for(var i in divs)
-            {
-              if(divs[i].id == 'blocktype_'+val) divs[i].style.display = 'block';
-              else divs[i].style.display = 'none';
-            }
-          }
-          </script>
-          
-          <form action="<?php echo makeUrl($paths->page); ?>" method="post">
-          
-            <p>
-              What type of block should this be?
-            </p>
-            <p>
-              <select name="type" onchange="setType(this)"> <?php /* (NOT WORKING, at least in firefox 2) onload="var thingy = this; setTimeout('setType(thingy)', 500);" */ ?>
-                <option value="<?php echo BLOCK_WIKIFORMAT; ?>">Wiki-formatted block</option>
-                <option value="<?php echo BLOCK_TEMPLATEFORMAT; ?>">Template-formatted block (old pre-beta 3 behavior)</option>
-                <option value="<?php echo BLOCK_HTML; ?>">Raw HTML block</option>
-                <option value="<?php echo BLOCK_PHP; ?>">PHP code block (danger, Will Robinson!)</option>
-                <option value="<?php echo BLOCK_PLUGIN; ?>">Use code from a plugin</option>
-              </select>
-            </p>
-            
-            <p>
-            
-              Block title: <input name="title" type="text" size="40" /><br />
-              Which sidebar: <select name="sidebar_id"><option value="<?php echo SIDEBAR_LEFT; ?>">Left</option><option value="<?php echo SIDEBAR_RIGHT; ?>">Right</option></select>
-            
-            </p>
-            
-            <div class="sbadd_block" id="blocktype_<?php echo BLOCK_WIKIFORMAT; ?>">
-              <p>
-                Wikitext:
-              </p>
-              <p>
-                <textarea style="width: 98%;" name="wikiformat_content" rows="15" cols="50"></textarea>
-              </p>
-            </div>
-            
-            <div class="sbadd_block" id="blocktype_<?php echo BLOCK_TEMPLATEFORMAT; ?>">
-              <p>
-                Template code:
-              </p>
-              <p>
-                <textarea style="width: 98%;" name="templateformat_content" rows="15" cols="50"></textarea>
-              </p>
-            </div>
-            
-            <div class="sbadd_block" id="blocktype_<?php echo BLOCK_HTML; ?>">
-              <p>
-                HTML to place inside the sidebar:
-              </p>
-              <p>
-                <textarea style="width: 98%;" name="html_content" rows="15" cols="50"></textarea>
-              </p>
-            </div>
-            
-            <div class="sbadd_block" id="blocktype_<?php echo BLOCK_PHP; ?>">
-              <p>
-                <b>WARNING:</b> If you don't know what you're doing, or if you are not fluent in PHP, stop now and choose a different block type. You will brick your Enano installation if you are not careful here.
-                ALWAYS remember to write secure code! The Enano team is not responsible if someone drops all your tables because of an SQL injection vulnerability in your sidebar code. You are probably better off using the template-formatted block type.
-              </p>
-              <p>
-                <span style="color: red;">
-                  It is especially important to note that this code is NOT checked for errors! If there is a syntax error in your code here, it will prevent any pages from loading AT ALL. So you need to use an external PHP editor (like <a href="http://www.jedit.org">jEdit</a>) to check your syntax before you hit save.
-                </span> You have been warned.
-              </p>
-              <p>
-                Also, you should avoid using output buffering functions (ob_[start|end|get_contents|clean]) here, because Enano uses those to track output from this script.
-              </p>
-              <p>
-                The standard &lt;?php and ?&gt; tags work here. Don't use an initial "&lt;?php" or it will cause a parse error.
-              </p>
-              <p>
-                PHP code:
-              </p>
-              <p>
-                <textarea style="width: 98%;" name="php_content" rows="15" cols="50"></textarea>
-              </p>
-            </div>
-            
-            <div class="sbadd_block" id="blocktype_<?php echo BLOCK_PLUGIN; ?>">
-              <p>
-                Plugin:
-              </p>
-              <p>
-                <select name="plugin_id">
-                <?php
-                  foreach($template->plugin_blocks as $k => $c)
-                  {
-                    echo '<option value="'.$k.'">'.$k.'</option>';
-                  }
-                ?>
-                </select>
-              </p>
-            </div>
-            
-            <p>
-            
-              <input type="submit" name="create" value="Create new block" style="font-weight: bold;" />&nbsp;
-              <input type="submit" name="cancel" value="Cancel" />
-            
-            </p>
-            
-          </form>
-          
-          <script type="text/javascript">
-            var divs = getElementsByClassName(document, 'div', 'sbadd_block');
-            for(var i in divs)
-            {
-              if(divs[i].id != 'blocktype_<?php echo BLOCK_WIKIFORMAT; ?>') setTimeout("document.getElementById('"+divs[i].id+"').style.display = 'none';", 500);
-            }
-          </script>
-          
-          <?php
-          $template->footer();
-          return;
-          break;
-        case 'move':
-          if( !isset($_GET['side']) || ( isset($_GET['side']) && !preg_match('#^([0-9]+)$#', $_GET['side']) ) )
-          {
-            echo '<div class="warning-box" style="margin: 10px 0;">$_GET[\'side\'] contained an SQL injection attempt</div>';
-            break;
-          }
-          $query = $db->sql_query('UPDATE '.table_prefix.'sidebar SET sidebar_id=' . $db->escape($_GET['side']) . ' WHERE item_id=' . $db->escape($_GET['id']) . ';');
-          if(!$query)
-          {
-            echo $db->get_error();
-            $template->footer();
-            exit;
-          }
-          echo '<div class="info-box" style="margin: 10px 0;">Item moved.</div>';
-          break;
-        case 'delete':
-          $query = $db->sql_query('DELETE FROM '.table_prefix.'sidebar WHERE item_id=' . $db->escape($_GET['id']) . ';'); // Already checked for injection attempts ;-)
-          if(!$query)
-          {
-            echo $db->get_error();
-            $template->footer();
-            exit;
-          }
-          if(isset($_GET['ajax']))
-          {
-            ob_end_clean();
-            die('GOOD');
-          }
-          echo '<div class="error-box" style="margin: 10px 0;">Item deleted.</div>';
-          break;
-        case 'disenable';
-          $q = $db->sql_query('SELECT item_enabled FROM '.table_prefix.'sidebar WHERE item_id=' . $db->escape($_GET['id']) . ';');
-          if(!$q)
-          {
-            echo $db->get_error();
-            $template->footer();
-            exit;
-          }
-          $r = $db->fetchrow();
-          $db->free_result();
-          $e = ( $r['item_enabled'] == 1 ) ? '0' : '1';
-          $q = $db->sql_query('UPDATE '.table_prefix.'sidebar SET item_enabled='.$e.' WHERE item_id=' . $db->escape($_GET['id']) . ';');
-          if(!$q)
-          {
-            echo $db->get_error();
-            $template->footer();
-            exit;
-          }
-          if(isset($_GET['ajax']))
-          {
-            ob_end_clean();
-            die('GOOD');
-          }
-          break;
-        case 'getsource':
-          $q = $db->sql_query('SELECT block_content,block_type FROM '.table_prefix.'sidebar WHERE item_id=' . $db->escape($_GET['id']) . ';');
-          if(!$q)
-          {
-            echo $db->get_error();
-            $template->footer();
-            exit;
-          }
-          ob_end_clean();
-          $r = $db->fetchrow();
-          $db->free_result();
-          if($r['block_type'] == BLOCK_PLUGIN) die('HOUSTON_WE_HAVE_A_PLUGIN');
-          die($r['block_content']);
-          break;
-        case 'save':
-          $q = $db->sql_query('UPDATE '.table_prefix.'sidebar SET block_content=\''.$db->escape(rawurldecode($_POST['content'])).'\' WHERE item_id=' . $db->escape($_GET['id']) . ';');
-          if(!$q)
-          {
-            echo 'var status=unescape(\''.hexencode($db->get_error()).'\');';
-            exit;
-          }
-          $q = $db->sql_query('SELECT block_type,block_content FROM '.table_prefix.'sidebar WHERE item_id=' . $db->escape($_GET['id']) . ';');
-          if(!$q)
-          {
-            echo 'var status=unescape(\''.hexencode($db->get_error()).'\');';
-            exit;
-          }
-          $row = $db->fetchrow();
-          $db->free_result();
-          switch($row['block_type'])
-          {
-            case BLOCK_WIKIFORMAT:
-            default:
-              $c = RenderMan::render($row['block_content']);
-              break;
-            case BLOCK_TEMPLATEFORMAT:
-              $c = $template->tplWikiFormat($row['block_content'], false, 'sidebar-editor.tpl');
-              $c = preg_replace('#<a (.*?)>(.*?)</a>#is', '<a href="#" onclick="return false;">\\2</a>', $c);
-              break;
-            case BLOCK_HTML:
-              $c = $row['block_content'];
-              $c = preg_replace('#<a (.*?)>(.*?)</a>#is', '<a href="#" onclick="return false;">\\2</a>', $c);
-              break;
-            case BLOCK_PHP:
-              ob_start();
-              eval($row['block_content']);
-              $c = ob_get_contents();
-              ob_end_clean();
-              $c = preg_replace('#<a (.*?)>(.*?)</a>#is', '<a href="#" onclick="return false;">\\2</a>', $c);
-              break;
-            case BLOCK_PLUGIN:
-              $c = ($template->fetch_block($row['block_content'])) ? $template->fetch_block($row['block_content']) : 'Can\'t find plugin block';
-              break;
-          }
-          die('var status = \'GOOD\'; var content = unescape(\''.hexencode($c).'\');');
-          break;
-      }
-    }
-    
-    $q = $db->sql_query('SELECT item_id,sidebar_id,item_enabled,block_name,block_type,block_content FROM '.table_prefix.'sidebar ORDER BY sidebar_id ASC, item_order ASC;');
-    if(!$q) $db->_die('The sidebar text data could not be selected.');
-    
-    $vars = $template->extract_vars('sidebar-editor.tpl');
-    
-    $parser = $template->makeParserText($vars['sidebar_button']);
-    $parser->assign_vars(Array(
-        'HREF'=>'#',
-        'FLAGS'=>'onclick="return false;"',
-        'TEXT'=>'Change theme'
-      ));
-    $template->tpl_strings['THEME_LINK'] = $parser->run();
-    $parser->assign_vars(Array(
-        'TEXT'=>'Log out',
-      ));
-    $template->tpl_strings['LOGOUT_LINK'] = $parser->run();
-    
-    $n1 = Array();
-    $n2 = Array();
-    $n  =& $n1;
-    
-    echo '<table border="0"><tr><td valign="top"><div class="dbx-group" id="sbedit_left">';
-    //if(isset($vars['sidebar_top'])) echo $template->parse($vars['sidebar_top']);
-    
-    // Time for the loop
-    // what this loop does is fetch the row data, then send it out to the appropriate parser for formatting,
-    // then puts the result into $c, which is then sent to the template compiler for insertion into the TPL code.
-    while($row = $db->fetchrow())
-    {
-      if(isset($current_side))
-      {
-        if($current_side != $row['sidebar_id'])
-        {
-          // Time to switch!
-          //if(isset($vars['sidebar_top'])) echo $template->parse($vars['sidebar_bottom']);
-          echo '</div></td><td valign="top"><div class="dbx-group" id="sbedit_right">';
-          //echo '</td><td valign="top">';
-          //if(isset($vars['sidebar_top'])) echo $template->parse($vars['sidebar_top']);
-          $n =& $n2;
-        }
-      }
-      $n[] = count($n);
-      $current_side = $row['sidebar_id'];
-      switch($row['block_type'])
-      {
-        case BLOCK_WIKIFORMAT:
-        default:
-          $parser = $template->makeParserText($vars['sidebar_section']);
-          $c = RenderMan::render($row['block_content']);
-          break;
-        case BLOCK_TEMPLATEFORMAT:
-          $parser = $template->makeParserText($vars['sidebar_section']);
-          $c = $template->tplWikiFormat($row['block_content'], false, 'sidebar-editor.tpl');
-          $c = preg_replace('#<a (.*?)>(.*?)</a>#is', '<a href="#" onclick="return false;">\\2</a>', $c);
-          break;
-        case BLOCK_HTML:
-          $parser = $template->makeParserText($vars['sidebar_section_raw']);
-          $c = $row['block_content'];
-          $c = preg_replace('#<a (.*?)>(.*?)</a>#is', '<a href="#" onclick="return false;">\\2</a>', $c);
-          break;
-        case BLOCK_PHP:
-          $parser = $template->makeParserText($vars['sidebar_section_raw']);
-          ob_start();
-          eval($row['block_content']);
-          $c = ob_get_contents();
-          ob_end_clean();
-          $c = preg_replace('#<a (.*?)>(.*?)</a>#is', '<a href="#" onclick="return false;">\\2</a>', $c);
-          break;
-        case BLOCK_PLUGIN:
-          $parser = $template->makeParserText($vars['sidebar_section_raw']);
-          $c = ($template->fetch_block($row['block_content'])) ? $template->fetch_block($row['block_content']) : 'Can\'t find plugin block';
-          break;
-      }
-      $t = $template->tplWikiFormat($row['block_name']);
-      if($row['item_enabled'] == 0) $t .= ' <span id="disabled_'.$row['item_id'].'" style="color: red;">(disabled)</span>';
-      else           $t .= ' <span id="disabled_'.$row['item_id'].'" style="color: red; display: none;">(disabled)</span>';
-      $side = ( $row['sidebar_id'] == SIDEBAR_LEFT ) ? SIDEBAR_RIGHT : SIDEBAR_LEFT;
-      $tb = '<a title="Enable or disable this block"    href="'.makeUrl($paths->page, 'action=disenable&id='.$row['item_id'].''       , true).'" onclick="ajaxDisenableBlock(\''.$row['item_id'].'\'); return false;"   ><img alt="Enable/disable this block" style="border-width: 0;" src="'.scriptPath.'/images/disenable.png" /></a>
-             <a title="Edit the contents of this block" href="'.makeUrl($paths->page, 'action=edit&id='.$row['item_id'].''            , true).'" onclick="ajaxEditBlock(\''.$row['item_id'].'\', this); return false;"><img alt="Edit this block" style="border-width: 0;" src="'.scriptPath.'/images/edit.png" /></a>
-             <a title="Permanently delete this block"   href="'.makeUrl($paths->page, 'action=delete&id='.$row['item_id'].''          , true).'" onclick="if(confirm(\'Do you really want to delete this block?\')) { ajaxDeleteBlock(\''.$row['item_id'].'\', this); } return false;"><img alt="Delete this block" style="border-width: 0;" src="'.scriptPath.'/images/delete.png" /></a>
-             <a title="Move this block to the other sidebar" href="'.makeUrl($paths->page, 'action=move&id='.$row['item_id'].'&side='.$side, true).'"><img alt="Move this block" style="border-width: 0;" src="'.scriptPath.'/images/move.png" /></a>';
-      $as = '';
-      $ae = '&nbsp;&nbsp;'.$tb;
-      $parser->assign_vars(Array('CONTENT'=>$c,'TITLE'=>$t,'ADMIN_START'=>$as,'ADMIN_END'=>$ae));
-      echo $parser->run();
-      unset($parser);
-      
-    }
-    $db->free_result();
-    //if(isset($vars['sidebar_top'])) echo $template->parse($vars['sidebar_bottom']);
-    echo '</div></td></tr></table>';
-    echo '<form action="'.makeUrl($paths->page).'" method="post">';
-    $order = implode(',', $n1);
-    echo "<input type='hidden' id='divOrder_Left' name='order_left' value='{$order}' />";
-    $order = implode(',', $n2);
-    echo "<input type='hidden' id='divOrder_Right' name='order_right' value='{$order}' />";
-    echo '
-          <div style="margin: 0 auto 0 auto; text-align: center;">
-            <input type="submit" name="save" style="font-weight: bold;" value="Save changes" />
-            <input type="submit" name="revert" style="font-weight: normal;" value="Revert" onclick="return confirm(\'Do you really want to revert your changes?\nNote: this does not revert edits or deletions, those are saved as soon as you confirm the action.\')" />
-            <br />
-            <a href="'.makeUrl($paths->page, 'action=new&id=0', true).'">Create new block</a>  |  <a href="'.makeUrl(getConfig('main_page'), false, true).'">Main Page</a>
-          </div>
-        </form>
-         ';
-  }
-  
-  $template->footer();
-}
-
-?>
\ No newline at end of file
--- a/plugins/SpecialUpdownload.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,285 +0,0 @@
-<?php
-/*
-Plugin Name: Upload/download frontend
-Plugin URI: http://enano.homelinux.org/
-Description: Provides the pages Special:UploadFile and Special:DownloadFile. UploadFile is used to upload files to the site, and DownloadFile fetches the file from the database, creates thumbnails if necessary, and sends the file to the user.
-Author: Dan Fuhry
-Version: 1.0
-Author URI: http://enano.homelinux.org/
-*/
-
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 release candidate 2
- * Copyright (C) 2006-2007 Dan Fuhry
- * SpecialUpdownload.php - handles uploading and downloading of user-uploaded files - possibly the most rigorously security-enforcing script in all of Enano, although sessions.php comes in a close second
- *
- * This program is Free Software; you can redistribute 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 details.
- */
- 
-global $db, $session, $paths, $template, $plugins; // Common objects
-
-$plugins->attachHook('base_classes_initted', '
-  global $paths;
-    $paths->add_page(Array(
-      \'name\'=>\'Upload file\',
-      \'urlname\'=>\'UploadFile\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    
-    $paths->add_page(Array(
-      \'name\'=>\'Download file\',
-      \'urlname\'=>\'DownloadFile\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>0,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    ');
-
-function page_Special_UploadFile()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  global $mime_types;
-  if(getConfig('enable_uploads')!='1') { die_friendly('Access denied', '<p>File uploads are disabled this website.</p>'); }
-  if ( !$session->get_permissions('upload_files') )
-  {
-    die_friendly('Access denied', '<p>File uploads are disabled for your user account or group.<p>');
-  }
-  if(isset($_POST['doit']))
-  {
-    if(isset($_FILES['data']))
-    {
-      $file =& $_FILES['data'];
-    }
-    else
-    {
-      $file = false;
-    }
-    if(!is_array($file)) die_friendly('Upload failed', '<p>The server could not retrieve the array $_FILES[\'data\'].</p>');
-    if($file['size'] == 0 || $file['size'] > (int)getConfig('max_file_size')) die_friendly('Upload failed', '<p>The file you uploaded is either too large or 0 bytes in length.</p>');
-    /*
-    $allowed_mime_types = Array(
-        'text/plain',
-        'image/png',
-        'image/jpeg',
-        'image/tiff',
-        'image/gif',
-        'text/html', // Safe because the file is stashed in the database
-        'application/x-bzip2',
-        'application/x-gzip',
-        'text/x-c++'
-      );
-    if(function_exists('finfo_open') && $fi = finfo_open(FILEINFO_MIME, ENANO_ROOT.'/includes/magic')) // First try to use the fileinfo extension, this is the best way to determine the mimetype
-    {
-      if(!$fi) die_friendly('Upload failed', '<p>Enano was unable to determine the format of the uploaded file.</p><p>'.@finfo_file($fi, $file['tmp_name']).'</p>');
-      $type = @finfo_file($fi, $file['tmp_name']);
-      @finfo_close($fi);
-    }
-    elseif(function_exists('mime_content_type'))
-      $type = mime_content_type($file['tmp_name']); // OK, no fileinfo function. Use a (usually) built-in PHP function
-    elseif(isset($file['type']))
-      $type = $file['type']; // LAST RESORT: use the mimetype the browser sent us, though this is likely to be spoofed
-    else // DANG! Not even the browser told us. Bail out.
-      die_friendly('Upload failed', '<p>Enano was unable to determine the format of the uploaded file.</p>');
-    */
-    $types = fetch_allowed_extensions();
-    $ext = substr($file['name'], strrpos($file['name'], '.')+1, strlen($file['name']));
-    if(!isset($types[$ext]) || ( isset($types[$ext]) && !$types[$ext] ) )
-    {
-      die_friendly('Upload failed', '<p>The file type ".'.$ext.'" is not allowed.</p>');
-    }
-    $type = $mime_types[$ext];
-    //$type = explode(';', $type); $type = $type[0];
-    //if(!in_array($type, $allowed_mime_types)) die_friendly('Upload failed', '<p>The file type "'.$type.'" is not allowed.</p>');
-    if($_POST['rename'] != '')
-    {
-      $filename = $_POST['rename'];
-    } else {
-      $filename = $file['name'];
-    }
-    $bad_chars = Array(':', '\\', '/', '<', '>', '|', '*', '?', '"', '#', '+');
-    foreach($bad_chars as $ch)
-    {
-      if(strstr($filename, $ch) || preg_match('/^([ ]+)$/is', $filename)) die_friendly('Upload failed', '<p>The filename contains invalid characters.</p>');
-    }
-    
-    if(isset($paths->pages[$paths->nslist['File'].$filename]) && !isset($_POST['update'])) die_friendly('Upload failed', '<p>The file already exists. You can <a href="'.makeUrlNS('Special', 'UploadFile/'.$filename).'">upload a new version of this file</a>.</p>');
-    elseif( isset($_POST['update']) && 
-           (!isset($paths->pages[$paths->nslist['File'].$filename]) ||
-             (isset($paths->pages[$paths->nslist['File'].$filename]) &&
-               $paths->pages[$paths->nslist['File'].$filename]['protected']==1)
-             )
-           )
-           die_friendly('Upload failed', '<p>Either the file does not exist (and therefore cannot be updated) or the file is protected.</p>');
-    
-    $utime = time();
-           
-    $filename = $db->escape($filename);
-    $ext = substr($filename, strrpos($filename, '.'), strlen($filename));
-    $flen = filesize($file['tmp_name']);
-    
-    $comments = $db->escape(RenderMan::strip_php($_POST['comments']));
-    $chartag = sha1(microtime());
-    $urln = str_replace(' ', '_', $filename);
-    
-    $key = md5($filename . '_' . file_get_contents($file['tmp_name']));
-    $targetname = ENANO_ROOT . '/files/' . $key . '_' . $utime . $ext;
-    
-    if(!@move_uploaded_file($file['tmp_name'], $targetname))
-    {
-      die_friendly('Upload failed', '<p>Could not move uploaded file to the new location.</p>');
-    }
-    
-    if(getConfig('file_history') != '1')
-      if(!$db->sql_query('DELETE FROM  '.table_prefix.'files WHERE filename=\''.$filename.'\' LIMIT 1;')) $db->_die('The old file data could not be deleted.');
-    if(!$db->sql_query('INSERT INTO '.table_prefix.'files(time_id,page_id,filename,size,mimetype,file_extension,file_key) VALUES('.$utime.', \''.$urln.'\', \''.$filename.'\', '.$flen.', \''.$type.'\', \''.$ext.'\', \''.$key.'\')')) $db->_die('The file data entry could not be inserted.');
-    if(!isset($_POST['update']))
-    {
-      if(!$db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.$utime.', \''.date('d M Y h:i a').'\', \'page\', \'create\', \''.$session->username.'\', \''.$filename.'\', \''.'File'.'\');')) $db->_die('The page log could not be updated.');
-      if(!$db->sql_query('INSERT INTO '.table_prefix.'pages(name,urlname,namespace,protected,delvotes,delvote_ips) VALUES(\''.$filename.'\', \''.$urln.'\', \'File\', 0, 0, \'\')')) $db->_die('The page listing entry could not be inserted.');
-      if(!$db->sql_query('INSERT INTO '.table_prefix.'page_text(page_id,namespace,page_text,char_tag) VALUES(\''.$urln.'\', \'File\', \''.$comments.'\', \''.$chartag.'\')')) $db->_die('The page text entry could not be inserted.');
-    } else {
-      if(!$db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.$utime.', \''.date('d M Y h:i a').'\', \'page\', \'reupload\', \''.$session->username.'\', \''.$filename.'\', \''.'File'.'\', \''.$comments.'\');')) $db->_die('The page log could not be updated.');
-    }
-    die_friendly('Upload complete', '<p>Your file has been uploaded successfully. View the <a href="'.makeUrlNS('File', $filename).'">file\'s page</a>.</p>');
-  } else {
-    $template->header();
-    $fn = $paths->getParam(0);
-    if ( $fn && !$session->get_permissions('upload_new_version') )
-    {
-      die_friendly('Access denied', '<p>Uploading new versions of files has been disabled for your user account or group.<p>');
-    }
-    ?>
-    <p>Using this form you can upload a file to the <?php echo getConfig('site_name'); ?> site.</p>
-    <p>The maximum file size is <?php 
-      // Get the max file size, and format it in a way that is user-friendly
-      $fs = getConfig('max_file_size');
-      echo $fs.' bytes';
-      $fs = (int)$fs;
-      if($fs >= 1048576)
-      {
-        $fs = round($fs / 1048576, 1);
-        echo ' ('.$fs.' MB)';
-      } elseif($fs >= 1024) {
-        $fs = round($fs / 1024, 1);
-        echo ' ('.$fs.' KB)';
-      }
-    ?>.</p>
-    <form action="<?php echo makeUrl($paths->page); ?>" method="post" enctype="multipart/form-data">
-      <table border="0" cellspacing="1" cellpadding="4">
-        <tr><td>File:</td><td><input name="data" type="file" size="40" /></td></tr>
-        <tr><td>Rename to:</td><td><input name="rename" type="text" size="40"<?php if($fn) echo ' value="'.$fn.'" readonly="readonly"'; ?> /></td></tr>
-        <?php
-        if(!$fn) echo '<tr><td>Comments:<br />(can be wiki-formatted)</td><td><textarea name="comments" rows="20" cols="60"></textarea></td></tr>';
-        else echo '<tr><td>Reason for uploading the new version: </td><td><input name="comments" size="50" /></td></tr>';
-        ?>
-        <tr><td colspan="2" style="text-align: center">
-          <?php
-          if($fn)
-            echo '<input type="hidden" name="update" value="true" />';
-          ?>
-          <input type="submit" name="doit" value="Upload file" />
-        </td></tr>
-      </table>
-    </form>
-    <?php
-    $template->footer();
-  }
-}                                                                                                                                                          
-
-function page_Special_DownloadFile()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  global $do_gzip;
-  $filename = rawurldecode($paths->getParam(0));
-  $timeid = $paths->getParam(1);
-  if($timeid && preg_match('#^([0-9]+)$#', (string)$timeid)) $tid = ' AND time_id='.$timeid;
-  else $tid = '';
-  $filename = $db->escape($filename);
-  $q = $db->sql_query('SELECT page_id,size,mimetype,time_id,file_extension,file_key FROM '.table_prefix.'files WHERE filename=\''.$filename.'\''.$tid.' ORDER BY time_id DESC;');
-  if(!$q) $db->_die('The file data could not be selected.');
-  if($db->numrows() < 1) { header('HTTP/1.1 404 Not Found'); die_friendly('File not found', '<p>The file "'.$filename.'" cannot be found.</p>'); }
-  $row = $db->fetchrow();
-  $db->free_result();
-  
-  // Check permissions
-  $perms = $session->fetch_page_acl($row['page_id'], 'File');
-  if ( !$perms->get_permissions('read') )
-  {
-    die_friendly('Access denied', '<p>Access to the specified file is denied.</p>');
-  }
-  
-  $fname = ENANO_ROOT . '/files/' . $row['file_key'] . '_' . $row['time_id'] . $row['file_extension'];
-  $data = file_get_contents($fname);
-  if(isset($_GET['preview']) && getConfig('enable_imagemagick')=='1' && file_exists(getConfig('imagemagick_path')) && substr($row['mimetype'], 0, 6) == 'image/')
-  {
-    $nam = tempnam('/tmp', $filename);
-    $h = @fopen($nam, 'w');
-    if(!$h) die('Error opening '.$nam.' for writing');
-    fwrite($h, $data);
-    fclose($h);
-    /* Make sure the request doesn't contain commandline injection - yow! */
-    if(!isset($_GET['width' ]) || (isset($_GET['width'] ) && !preg_match('#^([0-9]+)$#', $_GET['width']  ))) $width  = '320'; else $width  = $_GET['width' ];
-    if(!isset($_GET['height']) || (isset($_GET['height']) && !preg_match('#^([0-9]+)$#', $_GET['height'] ))) $height = '240'; else $height = $_GET['height'];
-    $cache_filename=ENANO_ROOT.'/cache/'.$filename.'-'.$row['time_id'].'-'.$width.'x'.$height.$row['file_extension'];
-    if(getConfig('cache_thumbs')=='1' && file_exists($cache_filename) && is_writable(ENANO_ROOT.'/cache')) {
-      $data = file_get_contents($cache_filename);
-    } elseif(getConfig('enable_imagemagick')=='1' && file_exists(getConfig('imagemagick_path'))) {
-      // Use ImageMagick to convert the image
-      //unlink($nam);
-      error_reporting(E_ALL);
-      $cmd = ''.getConfig('imagemagick_path').' "'.$nam.'" -resize "'.$width.'x'.$height.'>" "'.$nam.'.scaled'.$row['file_extension'].'"';
-      system($cmd, $stat);
-      if(!file_exists($nam.'.scaled'.$row['file_extension'])) die('Failed to call ImageMagick (return value '.$stat.'), command line was:<br />'.$cmd);
-      $data = file_get_contents($nam.'.scaled'.$row['file_extension']);
-      // Be stingy about it - better to re-generate the image hundreds of times than to fail completely
-      if(getConfig('cache_thumbs')=='1' && !file_exists($cache_filename)) {
-        // Write the generated thumbnail to the cache directory
-        $h = @fopen($cache_filename, 'w');
-        if(!$h) die('Error opening cache file "'.$cache_filename.'" for writing.');
-        fwrite($h, $data);
-        fclose($h);
-      }
-    }
-    unlink($nam);
-  }
-  $len = strlen($data);
-  header('Content-type: '.$row['mimetype']);
-  if(isset($_GET['download'])) header('Content-disposition: attachment, filename="'.$filename.'";');
-  header('Content-length: '.$len);
-  header('Last-Modified: '.date('r', $row['time_id']));
-  echo($data);
-  
-  //
-  // Compress buffered output if required and send to browser
-  //
-  if ( $do_gzip )
-  {
-    //
-    // Copied from phpBB, which was in turn borrowed from php.net
-    //
-    $gzip_contents = ob_get_contents();
-    ob_end_clean();
-  
-    $gzip_size = strlen($gzip_contents);
-    $gzip_crc = crc32($gzip_contents);
-  
-    $gzip_contents = gzcompress($gzip_contents, 9);
-    $gzip_contents = substr($gzip_contents, 0, strlen($gzip_contents) - 4);
-  
-    header('Content-encoding: gzip');
-    echo "\x1f\x8b\x08\x00\x00\x00\x00\x00";
-    echo $gzip_contents;
-    echo pack('V', $gzip_crc);
-    echo pack('V', $gzip_size);
-  }
-  
-  exit;
-  
-}
-
-?>
\ No newline at end of file
--- a/plugins/SpecialUserFuncs.php~	Wed Jun 13 16:32:27 2007 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,856 +0,0 @@
-<?php
-/*
-Plugin Name: Special user/login-related pages
-Plugin URI: http://enano.homelinux.org/
-Description: Provides the pages Special:Login, Special:Logout, Special:Register, and Special:Preferences.
-Author: Dan Fuhry
-Version: 1.0
-Author URI: http://enano.homelinux.org/
-*/
-
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.0 release candidate 2
- * Copyright (C) 2006-2007 Dan Fuhry
- *
- * This program is Free Software; you can redistribute 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 details.
- */
- 
-global $db, $session, $paths, $template, $plugins; // Common objects
-
-$plugins->attachHook('base_classes_initted', '
-  global $paths;
-    $paths->add_page(Array(
-      \'name\'=>\'Log in\',
-      \'urlname\'=>\'Login\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    $paths->add_page(Array(
-      \'name\'=>\'Log out\',
-      \'urlname\'=>\'Logout\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    $paths->add_page(Array(
-      \'name\'=>\'Register\',
-      \'urlname\'=>\'Register\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    $paths->add_page(Array(
-      \'name\'=>\'Edit Profile\',
-      \'urlname\'=>\'Preferences\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    
-    $paths->add_page(Array(
-      \'name\'=>\'Contributions\',
-      \'urlname\'=>\'Contributions\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    
-    $paths->add_page(Array(
-      \'name\'=>\'Change style\',
-      \'urlname\'=>\'ChangeStyle\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    
-    $paths->add_page(Array(
-      \'name\'=>\'Activate user account\',
-      \'urlname\'=>\'ActivateAccount\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>0,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    
-    $paths->add_page(Array(
-      \'name\'=>\'Captcha\',
-      \'urlname\'=>\'Captcha\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>0,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    
-    $paths->add_page(Array(
-      \'name\'=>\'Forgot password\',
-      \'urlname\'=>\'PasswordReset\',
-      \'namespace\'=>\'Special\',
-      \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
-      ));
-    ');
-
-// function names are IMPORTANT!!! The name pattern is: page_<namespace ID>_<page URLname, without namespace>
-
-$__login_status = '';
-
-function page_Special_Login()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  global $__login_status;
-  
-  $pubkey = $session->rijndael_genkey();
-  $challenge = $session->dss_rand();
-  
-  if ( isset($_GET['act']) && $_GET['act'] == 'getkey' )
-  {
-    $response = Array(
-      'key' => $pubkey,
-      'challenge' => $challenge
-      );
-    $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
-    $response = $json->encode($response);
-    echo $response;
-    return null;
-  }
-  
-  $level = ( isset($_GET['level']) && in_array($_GET['level'], array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') ) ) ? intval($_GET['level']) : USER_LEVEL_MEMBER;
-  if ( isset($_POST['login']) )
-  {
-    if ( in_array($_POST['auth_level'], array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') ) )
-    {
-      $level = intval($_POST['auth_level']);
-    }
-  }
-  
-  if ( $level > USER_LEVEL_MEMBER && !$session->user_logged_in )
-  {
-    $level = USER_LEVEL_MEMBER;
-  }
-  $template->header();
-  echo '<form action="'.makeUrl($paths->nslist['Special'].'Login').'" method="post" name="loginform" onsubmit="runEncryption();">';
-  $header = ( $level > USER_LEVEL_MEMBER ) ? 'Please re-enter your login details' : 'Please enter your username and password to log in.';
-  if ( isset($_POST['login']) )
-  {
-    echo '<p>'.$__login_status.'</p>';
-  }
-  if ( $p = $paths->getAllParams() )
-  {
-    echo '<input type="hidden" name="return_to" value="'.$p.'" />';
-  }
-  else if ( isset($_POST['login']) && isset($_POST['return_to']) )
-  {
-    echo '<input type="hidden" name="return_to" value="'.htmlspecialchars($_POST['return_to']).'" />';
-  }
-  ?>
-    <div class="tblholder">
-      <table border="0" style="width: 100%;" cellspacing="1" cellpadding="4">
-        <tr>
-          <th colspan="3"><?php echo $header; ?></th>
-        </tr>
-        <tr>
-          <td colspan="3" class="row1">
-            <?php
-            if ( $level <= USER_LEVEL_MEMBER )
-            {
-              echo '<p>Logging in enables you to use your preferences and access member information. If you don\'t have a username and password here, you can <a href="'.makeUrl($paths->nslist['Special'].'Register').'">create an account</a>.</p>';
-            }
-            else
-            {
-              echo '<p>You are requesting that a sensitive operation be performed. To continue, please re-enter your password to confirm your identity.</p>';
-            }
-            ?>
-          </td>
-        </tr>
-        <tr>
-          <td class="row2">
-            Username:
-          </td>
-          <td class="row1">
-            <input name="username" size="25" type="text" <?php
-              if ( $level <= USER_LEVEL_MEMBER )
-              {
-                echo 'tabindex="1" ';
-              }
-              if ( $session->user_logged_in )
-              {
-                echo 'value="' . $session->username . '"';
-              }
-              ?> />
-          </td>
-          <?php if ( $level <= USER_LEVEL_MEMBER ) { ?>
-          <td rowspan="2" class="row3">
-            <small>Forgot your password? <a href="<?php echo makeUrlNS('Special', 'PasswordReset'); ?>">No problem.</a><br />
-            Maybe you need to <a href="<?php echo makeUrlNS('Special', 'Register'); ?>">create an account</a>.</small>
-          </td>
-          <?php } ?>
-        </tr>
-        <tr>
-          <td class="row2">Password:<br /></td><td class="row1"><input name="pass" size="25" type="password" tabindex="<?php echo ( $level <= USER_LEVEL_MEMBER ) ? '2' : '1'; ?>" /></td>
-         </tr>
-         <?php if ( $level <= USER_LEVEL_MEMBER ) { ?>
-         <tr>
-           <td class="row3" colspan="3">
-             <p><b>Important note regarding cryptography:</b> Some countries do not allow the import or use of cryptographic technology. If you live in one of the countries listed below, you should <a href="<?php if($p=$paths->getParam(0))$u='/'.$p;else $u='';echo makeUrl($paths->page.$u, 'level='.$level.'&use_crypt=0', true); ?>">log in without using encryption</a>.</p>
-             <p>This restriction applies to the following countries: Belarus, China, India, Israel, Kazakhstan, Mongolia, Pakistan, Russia, Saudi Arabia, Singapore, Tunisia, Venezuela, and Vietnam.</p>
-           </td>
-         </tr>
-         <?php } ?>
-         <tr>
-           <th colspan="3" style="text-align: center" class="subhead"><input type="submit" name="login" value="Log in" tabindex="3" /></th>
-         </tr>
-      </table>
-    </div>
-      <input type="hidden" name="challenge_data" value="<?php echo $challenge; ?>" />
-      <input type="hidden" name="use_crypt" value="no" />
-      <input type="hidden" name="crypt_key" value="<?php echo $pubkey; ?>" />
-      <input type="hidden" name="crypt_data" value="" />
-      <input type="hidden" name="auth_level" value="<?php echo (string)$level; ?>" />
-    </form>
-    <?php
-      echo $session->aes_javascript('loginform', 'pass', 'use_crypt', 'crypt_key', 'crypt_data', 'challenge_data');
-    ?>
-  <?php
-  $template->footer();
-}
-
-function page_Special_Login_preloader() // adding _preloader to the end of the function name calls the function before $session and $paths setup routines are called
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  global $__login_status;
-  if ( isset($_GET['act']) && $_GET['act'] == 'ajaxlogin' )
-  {
-    $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
-    $data = $json->decode($_POST['params']);
-    $level = ( isset($data['level']) ) ? intval($data['level']) : USER_LEVEL_MEMBER;
-    $result = $session->login_with_crypto($data['username'], $data['crypt_data'], $data['crypt_key'], $data['challenge'], $level);
-    $session->start();
-    //echo "$result\n$session->sid_super";
-    //exit;
-    if ( $result == 'success' )
-    {
-      $response = Array(
-          'result' => 'success',
-          'key' => $session->sid_super // ( ( $session->sid_super ) ? $session->sid_super : $session->sid )
-        );
-    }
-    else
-    {
-      $response = Array(
-          'result' => 'error',
-          'error' => $result
-        );
-    }
-    $response = $json->encode($response);
-    echo $response;
-    $db->close();
-    exit;
-  }
-  if(isset($_POST['login'])) {
-    if($_POST['use_crypt'] == 'yes')
-    {
-      $result = $session->login_with_crypto($_POST['username'], $_POST['crypt_data'], $_POST['crypt_key'], $_POST['challenge_data'], intval($_POST['auth_level']));
-    }
-    else
-    {
-      $result = $session->login_without_crypto($_POST['username'], $_POST['pass'], false, intval($_POST['auth_level']));
-    }
-    $session->start();
-    $paths->init();
-    if($result == 'success')
-    {
-      $template->load_theme($session->theme, $session->style);
-      if(isset($_POST['return_to']))
-      {
-        $name = ( isset($paths->pages[$_POST['return_to']]['name']) ) ? $paths->pages[$_POST['return_to']]['name'] : $_POST['return_to'];
-        redirect( makeUrl($_POST['return_to']), 'Login successful', 'You have successfully logged into the '.getConfig('site_name').' site as "'.$session->username.'". Redirecting to ' . $name . '...' );
-      }
-      else
-      {
-        $paths->main_page();
-      }
-    }
-    else
-    {
-      $GLOBALS['__login_status'] = $result;
-    }
-  }
-}
-
-function page_Special_Logout() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $l = $session->logout();
-  if($l == 'success') $paths->main_page();
-  $template->header();
-  echo '<h3>An error occurred during the logout process.</h3><p>'.$l.'</p>';
-  $template->footer();
-}
-
-function page_Special_Register() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if(getConfig('account_activation') == 'disable' && ( ( $session->user_level >= USER_LEVEL_ADMIN && !isset($_GET['IWannaPlayToo']) ) || $session->user_level < USER_LEVEL_ADMIN || !$session->user_logged_in ))
-  {
-    $s = ($session->user_level >= USER_LEVEL_ADMIN) ? '<p>Oops...it seems that you <em>are</em> the administrator...hehe...you can also <a href="'.makeUrl($paths->page, 'IWannaPlayToo', true).'">force account registration to work</a>.</p>' : '';
-    die_friendly('Registration disabled', '<p>The administrator has disabled new user registration on this site.</p>' . $s);
-  }
-  if(isset($_POST['submit'])) {
-    $captcharesult = $session->get_captcha($_POST['captchahash']);
-    if($captcharesult != $_POST['captchacode'])
-      $s = 'The confirmation code you entered was incorrect.';
-    else
-      // CAPTCHA code was correct, create the account
-      $s = $session->create_user($_POST['username'], $_POST['password'], $_POST['email'], $_POST['real_name']);
-    if($s == 'success')
-    {
-      switch(getConfig('account_activation'))
-      {
-        case "none":
-        default:
-          $str = 'You may now <a href="'.makeUrlNS('Special', 'Login').'">log in</a> with the username and password that you created.';
-          break;
-        case "user":
-          $str = 'Because this site requires account activation, you have been sent an e-mail with further instructions. Please follow the instructions in that e-mail to continue your registration.';
-          break;
-        case "admin":
-          $str = 'Because this site requires administrative account activation, you cannot use your account at the moment. A notice has been sent to the site administration team that will alert them that your account has been created.';
-          break;
-      }
-      die_friendly('Registration successful', '<p>Thank you for registering, your user account has been created. '.$str.'</p>');
-    }
-  }
-  $template->header();
-  echo 'A user account enables you to have greater control over your browsing experience.';
-  $session->kill_captcha();
-  $captchacode = $session->make_captcha();
-  ?>
-    <h3>Create a user account</h3>
-    <form name="regform" action="<?php echo makeUrl($paths->page); ?>" method="post">
-      <div class="tblholder">
-        <table border="0" width="100%" cellspacing="1" cellpadding="4">
-          <tr><th class="subhead" colspan="3">Please tell us a little bit about yourself.</th></tr>
-          <?php if(isset($_POST['submit'])) echo '<tr><td colspan="3" class="row2" style="color: red;">'.$s.'</td></tr>'; ?>
-          <tr><td class="row1" style="width: 50%;">Preferred username:<span id="e_username"></span></td><td class="row1" style="width: 50%;"><input type="text" name="username" size="30" onkeyup="namegood = false; validateForm();" onblur="checkUsername();" /></td><td class="row1" style="max-width: 24px;"><img alt="Good/bad icon" src="<?php echo scriptPath; ?>/images/bad.gif" id="s_username" /></td></tr>
-          <tr><td class="row3" style="width: 50%;" rowspan="2">Password:<span id="e_password"></span></td><td class="row3" style="width: 50%;"><input type="password" name="password" size="30" onkeyup="validateForm();" /></td><td rowspan="2" class="row3" style="max-width: 24px;"><img alt="Good/bad icon" src="<?php echo scriptPath; ?>/images/bad.gif" id="s_password" /></td></tr>
-          <tr><td class="row3" style="width: 50%;"><input type="password" name="password_confirm" size="30" onkeyup="validateForm();" /> <small>Enter your password again to confirm.</small></td></tr>
-          <tr><td class="row1" style="width: 50%;">E-mail address:<?php if(getConfig('account_activation')=='user') echo '<br /><small>An e-mail with an account activation key will be sent to this address, so please ensure that it is correct.</small></td>'; ?><td class="row1" style="width: 50%;"><input type="text" name="email" size="30" onkeyup="validateForm();" /></td><td class="row1" style="max-width: 24px;"><img alt="Good/bad icon" src="<?php echo scriptPath; ?>/images/bad.gif" id="s_email" /></td></tr>
-          <tr><td class="row3" style="width: 50%;">Real name:<br /><small>Giving your real name is totally optional. If you choose to provide your real name, it will be used to provide attribution for any edits or contributions you may make to this site.</small><td class="row3" style="width: 50%;"><input type="text" name="real_name" size="30" /></td><td class="row3" style="max-width: 24px;"></td></tr>
-          <tr><td class="row1" style="width: 50%;" rowspan="2">Visual confirmation<br /><small>Please enter the code shown in the image to the right into the text box. This process helps to ensure that this registration is not being performed by an automated bot. If the image to the right is illegible, you can <a href="#" onclick="regenCaptcha(); return false;">generate a new image</a>.<br /><br />If you are visually impaired or otherwise cannot read the text shown to the right, please contact the site management and they will create an account for you.</small></td><td colspan="2" class="row1"><img id="captchaimg" alt="CAPTCHA image" src="<?php echo makeUrlNS('Special', 'Captcha/'.$captchacode); ?>" /><span id="b_username"></span></td></tr>
-          <tr><td class="row1" colspan="2">Code: <input name="captchacode" type="text" size="10" /><input type="hidden" name="captchahash" value="<?php echo $captchacode; ?>" /></td></tr>
-          <tr><td class="row2" colspan="3" style="text-align: center;"><input type="submit" name="submit" value="Create my account" /></td></tr>
-        </table>
-      </div>
-    </form>
-    <script type="text/javascript">
-      // <![CDATA[
-      var namegood = false;
-      function validateForm()
-      {
-        var frm = document.forms.regform;
-        failed = false;
-        
-        // Username
-        if(!namegood)
-        {
-          if(frm.username.value.match(/^([A-z0-9 \!@\-\(\)]+){2,}$/ig))
-          {
-            document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/unknown.gif';
-            document.getElementById('e_username').innerHTML = ''; // '<br /><small><b>Checking availability...</b></small>';
-          } else {
-            failed = true;
-            document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/bad.gif';
-            document.getElementById('e_username').innerHTML = '<br /><small>Your username must be at least two characters in length and may contain only alphanumeric characters (A-Z and 0-9), spaces, and the following characters: :, !, @, #, *.</small>';
-          }
-        }
-        document.getElementById('b_username').innerHTML = '';
-        if(hex_md5(frm.real_name.value) == 'fa8e397ae0f6cd5b0f90a3f48178cd7e')
-        {
-          document.getElementById('b_username').innerHTML = '<br /><br />Hey...I know you!<br /><img alt="" src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Bill_Gates_2004_cr.jpg/220px-Bill_Gates_2004_cr.jpg" />';
-        }
-        
-        // Password
-        if(frm.password.value.match(/^(.+){6,}$/ig) && frm.password_confirm.value.match(/^(.+){6,}$/ig) && frm.password.value == frm.password_confirm.value)
-        {
-          document.getElementById('s_password').src='<?php echo scriptPath; ?>/images/good.gif';
-          document.getElementById('e_password').innerHTML = '<br /><small>The password you entered is valid.</small>';
-        } else {
-          failed = true;
-          if(frm.password.value.length < 6)
-            document.getElementById('e_password').innerHTML = '<br /><small>Your password must be at least six characters in length.</small>';
-          else if(frm.password.value != frm.password_confirm.value)
-            document.getElementById('e_password').innerHTML = '<br /><small>The passwords you entered do not match.</small>';
-          else
-            document.getElementById('e_password').innerHTML = '';
-          document.getElementById('s_password').src='<?php echo scriptPath; ?>/images/bad.gif';
-        }
-        
-        // E-mail address
-        if(frm.email.value.match(/^(?:[\w\d]+\.?)+@(?:(?:[\w\d]\-?)+\.)+\w{2,4}$/))
-        {
-          document.getElementById('s_email').src='<?php echo scriptPath; ?>/images/good.gif';
-        } else {
-          failed = true;
-          document.getElementById('s_email').src='<?php echo scriptPath; ?>/images/bad.gif';
-        }
-        if(failed)
-        {
-          frm.submit.disabled = 'disabled';
-        } else {
-          frm.submit.disabled = false;
-        }
-      }
-      function checkUsername()
-      {
-        var frm = document.forms.regform;
-        
-        if(!namegood)
-        {
-          if(frm.username.value.match(/^([A-z0-9 \.:\!@\#\*]+){2,}$/ig))
-          {
-            document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/unknown.gif';
-            document.getElementById('e_username').innerHTML = '';
-          } else {
-            document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/bad.gif';
-            document.getElementById('e_username').innerHTML = '<br /><small>Your username must be at least two characters in length and may contain only alphanumeric characters (A-Z and 0-9), spaces, and the following characters: :, !, @, #, *.</small>';
-            return false;
-          }
-        }
-        
-        document.getElementById('e_username').innerHTML = '<br /><small><b>Checking availability...</b></small>';
-        ajaxGet('<?php echo scriptPath; ?>/ajax.php?title=null&_mode=checkusername&name='+escape(frm.username.value), function() {
-          if(ajax.readyState == 4)
-            if(ajax.responseText == 'good')
-            {
-              document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/good.gif';
-              document.getElementById('e_username').innerHTML = '<br /><small><b>This username is available.</b></small>';
-              namegood = true;
-            } else if(ajax.responseText == 'bad') {
-              document.getElementById('s_username').src='<?php echo scriptPath; ?>/images/bad.gif';
-              document.getElementById('e_username').innerHTML = '<br /><small><b>Error: that username is already taken.</b></small>';
-              namegood = false;
-            } else {
-              document.getElementById('e_username').innerHTML = ajax.responseText;
-            }
-        });
-      }
-      function regenCaptcha()
-      {
-        var frm = document.forms.regform;
-        document.getElementById('captchaimg').src = '<?php echo makeUrlNS("Special", "Captcha/"); ?>'+frm.captchahash.value+'/'+Math.floor(Math.random() * 100000);
-        return false;
-      }
-      validateForm();
-      setTimeout('checkUsername();', 1000);
-      // ]]>
-    </script>
-  <?php
-  $template->footer();
-}
-
-/*
-If you want the old preferences page back, be my guest.
-function page_Special_Preferences() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $template->header();
-  if(isset($_POST['submit'])) {
-    $data = $session->update_user($session->user_id, $_POST['username'], $_POST['current_pass'], $_POST['new_pass'], $_POST['email'], $_POST['real_name'], $_POST['sig']);
-    if($data == 'success') echo '<h3>Information</h3><p>Your profile has been updated. <a href="'.scriptPath.'/">Return to the index page</a>.</p>';
-    else echo $data;
-  } else {
-    echo '
-    <h3>Edit your profile</h3>
-    <form action="'.makeUrl($paths->nslist['Special'].'Preferences').'" method="post">
-      <table border="0" style="margin-left: 0.2in;">   
-        <tr><td>Username:</td><td><input type="text" name="username" value="'.$session->username.'" /></td></tr>
-        <tr><td>Current Password:</td><td><input type="password" name="current_pass" /></td></tr>
-        <tr><td colspan="2"><small>You only need to enter your current password if you are changing your e-mail address or changing your password.</small></td></tr>
-        <tr><td>New Password:</td><td><input type="password" name="new_pass" /></td></tr>
-        <tr><td>E-mail:</td><td><input type="text" name="email" value="'.$session->email.'" /></td></tr>
-        <tr><td>Real Name:</td><td><input type="text" name="real_name" value="'.$session->real_name.'" /></td></tr>
-        <tr><td>Signature:<br /><small>Your signature appears<br />below your comment posts.</small></td><td><textarea rows="10" cols="40" name="sig">'.$session->signature.'</textarea></td></tr>
-        <tr><td colspan="2">
-        <input type="submit" name="submit" value="Save Changes" /></td></tr>
-      </table>
-    </form>
-    ';
-  }
-  $template->footer();
-}
-*/
-
-function page_Special_Contributions() {
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $template->header();
-  $user = $paths->getParam();
-  if(!$user && isset($_GET['user']))
-  {
-    $user = $_GET['user'];
-  }
-  elseif(!$user && !isset($_GET['user']))
-  {
-    echo 'No user selected!';
-    $template->footer();
-    $db->close();
-    exit;
-  }
-  
-  $user = $db->escape($user);
-  
-  $q = 'SELECT time_id,date_string,page_id,namespace,author,edit_summary,minor_edit,page_id,namespace FROM '.table_prefix.'logs WHERE author=\''.$user.'\' AND action=\'edit\' ORDER BY time_id DESC;';
-  if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
-  echo 'History of edits and actions<h3>Edits:</h3>';
-  if($db->numrows() < 1) echo 'No history entries in this category.';
-  while($r = $db->fetchrow()) {    
-    echo '<a href="#" onclick="ajaxHistView(\''.$r['time_id'].'\', \''.$paths->nslist[$r['namespace']].$r['page_id'].'\'); return false;"><i>'.$r['date_string'].'</i></a> (<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">revert</a>) <a href="'.makeUrl($paths->nslist[$r['namespace']].$r['page_id']).'">'.$paths->nslist[$r['namespace']].$r['page_id'].'</a>: '.$r['edit_summary'];
-    if($r['minor_edit']) echo '<b> - minor edit</b>';
-    echo '<br />';
-  }
-  $db->free_result();
-  echo '<h3>Other changes:</h3>';
-  $q = 'SELECT log_type,time_id,action,date_string,page_id,namespace,author,edit_summary,minor_edit,page_id,namespace FROM '.table_prefix.'logs WHERE author=\''.$user.'\' AND action!=\'edit\' ORDER BY time_id DESC;';
-  if(!$db->sql_query($q)) $db->_die('The history data for the page "'.$paths->cpage['name'].'" could not be selected.');
-  if($db->numrows() < 1) echo 'No history entries in this category.';
-  while($r = $db->fetchrow()) {
-    if($r['log_type']=='page') {
-    echo '(<a href="#" onclick="ajaxRollback(\''.$r['time_id'].'\'); return false;">rollback</a>) <i>'.$r['date_string'].'</i> <a href="'.makeUrl($paths->nslist[$r['namespace']].$r['page_id']).'">'.$paths->nslist[$r['namespace']].$r['page_id'].'</a>: ';
-    if($r['action']=='prot') echo 'Protected page; reason: '.$r['edit_summary'];
-    elseif($r['action']=='unprot') echo 'Unprotected page; reason: '.$r['edit_summary'];
-    elseif($r['action']=='rename') echo 'Renamed page; old title was: '.$r['edit_summary'];
-    elseif($r['action']=='create') echo 'Created page';
-    elseif($r['action']=='delete') echo 'Deleted page';
-    if($r['minor_edit']) echo '<b> - minor edit</b>';
-    echo '<br />';
-    } elseif($r['log_type']=='security') {
-      // Not implemented, and when it is, it won't be public
-    }
-  }
-  $db->free_result();
-  $template->footer();
-}
-
-function page_Special_ChangeStyle()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if(!$session->user_logged_in) die_friendly('Access denied', '<p>You must be logged in to change your style. Spoofer.</p>');
-  if(isset($_POST['theme']) && isset($_POST['style']) && isset($_POST['return_to']))
-  {
-    $d = ENANO_ROOT . '/themes/' . $_POST['theme'];
-    $f = ENANO_ROOT . '/themes/' . $_POST['theme'] . '/css/' . $_POST['style'] . '.css';
-    if(!file_exists($d) || !is_dir($d)) die('The directory "'.$d.'" does not exist.');
-    if(!file_exists($f)) die('The file "'.$f.'" does not exist.');
-    $d = $db->escape($_POST['theme']);
-    $f = $db->escape($_POST['style']);
-    $q = 'UPDATE '.table_prefix.'users SET theme=\''.$d.'\',style=\''.$f.'\' WHERE username=\''.$session->username.'\'';
-    if(!$db->sql_query($q))
-    {
-      $db->_die('Your theme/style preferences were not updated.');
-    }
-    else
-    {
-      redirect(makeUrl($_POST['return_to']), '', '', 0);
-    }
-  }
-  else
-  {
-    $template->header();
-      $ret = ( isset($_POST['return_to']) ) ? $_POST['return_to'] : $paths->getParam(0);
-      if(!$ret) $ret = getConfig('main_page');
-      ?>
-        <form action="<?php echo makeUrl($paths->page); ?>" method="post">
-          <?php if(!isset($_POST['themeselected'])) { ?>
-            <h3>Please select a new theme:</h3>
-            <p>
-              <select name="theme">
-               <?php
-                foreach($template->theme_list as $t) {
-                  if($t['enabled'])
-                  {
-                    echo '<option value="'.$t['theme_id'].'"';
-                    if($t['theme_id'] == $session->theme) echo ' selected="selected"';
-                    echo '>'.$t['theme_name'].'</option>';
-                  }
-                }
-               ?>
-              </select>
-            </p>
-            <p><input type="hidden" name="return_to" value="<?php echo $ret; ?>" />
-               <input type="submit" name="themeselected" value="Continue" /></p>
-          <?php } else { 
-            $theme = $_POST['theme'];
-            if ( !preg_match('/^([0-9A-z_-]+)$/i', $theme ) )
-              die('Hacking attempt');
-            ?>
-            <h3>Please select a stylesheet:</h3>
-            <p>
-              <select name="style">
-                <?php
-                  $dir = './themes/'.$theme.'/css/';
-                  $list = Array();
-                  // Open a known directory, and proceed to read its contents
-                  if (is_dir($dir)) {
-                    if ($dh = opendir($dir)) {
-                      while (($file = readdir($dh)) !== false) {
-                        if(preg_match('#^(.*?)\.css$#is', $file) && $file != '_printable.css') {
-                          $list[] = substr($file, 0, strlen($file)-4);
-                        }
-                      }
-                      closedir($dh);
-                    }
-                  } else die($dir.' is not a dir');
-                  foreach ( $list as $l )
-                  {
-                    echo '<option value="'.$l.'">'.capitalize_first_letter($l).'</option>';
-                  }
-                ?>
-              </select>
-            </p>
-            <p><input type="hidden" name="return_to" value="<?php echo $ret; ?>" />
-               <input type="hidden" name="theme" value="<?php echo $theme; ?>" />
-               <input type="submit" name="allclear" value="Change style" /></p>
-          <?php } ?>
-        </form>
-      <?php
-    $template->footer();
-  }
-}
-
-function page_Special_ActivateAccount()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $user = $paths->getParam(0);
-  if(!$user) die_friendly('Account activation error', '<p>The URL was incorrect.</p>');
-  $key = $paths->getParam(1);
-  if(!$key) die_friendly('Account activation error', '<p>The URL was incorrect.</p>');
-  $s = $session->activate_account(str_replace('_', ' ', $user), $key);
-  if($s > 0) die_friendly('Activation successful', '<p>Your account is now active. Thank you for registering.</p>');
-  else die_friendly('Activation failed', '<p>The activation key was probably incorrect.</p>');
-}
-
-function page_Special_Captcha()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  if($paths->getParam(0) == 'make')
-  {
-    $session->kill_captcha();
-    echo $session->make_captcha();
-    return;
-  }
-  $hash = $paths->getParam(0);
-  if(!$hash || !preg_match('#^([0-9a-f]*){32,32}$#i', $hash)) $paths->main_page();
-  $code = $session->get_captcha($hash);
-  if(!$code) die('Invalid hash or IP address incorrect.');
-  require(ENANO_ROOT.'/includes/captcha.php');
-  $captcha = new captcha($code);
-  //header('Content-disposition: attachment; filename=autocaptcha.png');
-  $captcha->make_image();
-  exit;
-}
-
-function page_Special_PasswordReset()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $template->header();
-  if($paths->getParam(0) == 'stage2')
-  {
-    $user_id = intval($paths->getParam(1));
-    $encpass = $paths->getParam(2);
-    if ( $user_id < 2 )
-    {
-      echo '<p>Hacking attempt</p>';
-      $template->footer();
-      return false;
-    }
-    if(!preg_match('#^([a-f0-9]+)$#i', $encpass))
-    {
-      echo '<p>Hacking attempt</p>';
-      $template->footer();
-      return false;
-    }
-    
-    $q = $db->sql_query('SELECT username,temp_password_time FROM '.table_prefix.'users WHERE user_id='.$user_id.' AND temp_password=\'' . $encpass . '\';');
-    if($db->numrows() < 1)
-    {
-      echo '<p>Invalid credentials</p>';
-      $template->footer();
-      return false;
-    }
-    $row = $db->fetchrow();
-    $db->free_result();
-    
-    if ( ( intval($row['temp_password_time']) + 3600 * 24 ) < time() )
-    {
-      echo '<p>Password has expired</p>';
-      $template->footer();
-      return false;
-    }
-    
-    if ( isset($_POST['do_stage2']) )
-    {
-      $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
-      if($_POST['use_crypt'] == 'yes')
-      {
-        $crypt_key = $session->fetch_public_key($_POST['crypt_key']);
-        if(!$crypt_key)
-        {
-          echo 'ERROR: Couldn\'t look up public key for decryption.';
-          $template->footer();
-          return false;
-        }
-        $crypt_key = hexdecode($crypt_key);
-        $data = $aes->decrypt($_POST['crypt_data'], $crypt_key, ENC_HEX);
-        if(strlen($data) < 6)
-        {
-          echo 'ERROR: Your password must be six characters or greater in length.';
-          $template->footer();
-          return false;
-        }
-      }
-      else
-      {
-        $data = $_POST['pass'];
-        $conf = $_POST['pass_confirm'];
-        if($data != $conf)
-        {
-          echo 'ERROR: The passwords you entered do not match.';
-          $template->footer();
-          return false;
-        }
-        if(strlen($data) < 6)
-        {
-          echo 'ERROR: Your password must be six characters or greater in length.';
-          $template->footer();
-          return false;
-        }
-      }
-      if(empty($data))
-      {
-        echo 'ERROR: Sanity check failed!';
-        $template->footer();
-        return false;
-      }
-      $encpass = $aes->encrypt($data, $session->private_key, ENC_HEX);
-      $q = $db->sql_query('UPDATE '.table_prefix.'users SET password=\'' . $encpass . '\',temp_password=\'\',temp_password_time=0 WHERE user_id='.$user_id.';');
-      
-      if($q)
-      {
-        $session->login_without_crypto($row['username'], $data);
-        echo '<p>Your password has been reset. Return to the <a href="' . makeUrl(getConfig('main_page')) . '">main page</a>.</p>';
-      }
-      else
-      {
-        echo $db->get_error();
-      }
-      
-      $template->footer();
-      return false;
-    }
-    
-    // Password reset form
-    $pubkey = $session->rijndael_genkey();
-    
-    ?>
-    <form action="<?php echo makeUrl($paths->fullpage); ?>" method="post" name="resetform" onsubmit="return runEncryption();">
-      <br />
-      <div class="tblholder">
-        <table border="0" style="width: 100%;" cellspacing="1" cellpadding="4">
-          <tr><th colspan="2">Reset password</th></tr>
-          <tr><td class="row1">Password:</td><td class="row1"><input name="pass" type="password" /></td></tr>
-          <tr><td class="row2">Confirm: </td><td class="row2"><input name="pass_confirm" type="password" /></td></tr>
-          <tr>
-            <td colspan="2" class="row1" style="text-align: center;">
-              <input type="hidden" name="use_crypt" value="no" />
-              <input type="hidden" name="crypt_key" value="<?php echo $pubkey; ?>" />
-              <input type="hidden" name="crypt_data" value="" />
-              <input type="submit" name="do_stage2" value="Reset password" />
-            </td>
-          </tr>
-        </table>
-      </div>
-    </form>
-    <script type="text/javascript">
-    disableJSONExts();
-      str = '';
-      for(i=0;i<keySizeInBits/4;i++) str+='0';
-      var key = hexToByteArray(str);
-      var pt = hexToByteArray(str);
-      var ct = rijndaelEncrypt(pt, key, "ECB");
-      var ct = byteArrayToHex(ct);
-      switch(keySizeInBits)
-      {
-        case 128:
-          v = '66e94bd4ef8a2c3b884cfa59ca342b2e';
-          break;
-        case 192:
-          v = 'aae06992acbf52a3e8f4a96ec9300bd7aae06992acbf52a3e8f4a96ec9300bd7';
-          break;
-        case 256:
-          v = 'dc95c078a2408989ad48a21492842087dc95c078a2408989ad48a21492842087';
-          break;
-      }
-      var testpassed = ( ct == v && md5_vm_test() );
-      var frm = document.forms.resetform;
-      if(testpassed)
-      {
-        frm.use_crypt.value = 'yes';
-        var cryptkey = frm.crypt_key.value;
-        frm.crypt_key.value = hex_md5(cryptkey);
-        cryptkey = hexToByteArray(cryptkey);
-        if(!cryptkey || ( ( typeof cryptkey == 'string' || typeof cryptkey == 'object' ) ) && cryptkey.length != keySizeInBits / 8 )
-        {
-          frm._login.disabled = true;
-          len = ( typeof cryptkey == 'string' || typeof cryptkey == 'object' ) ? '\nLen: '+cryptkey.length : '';
-          alert('The key is messed up\nType: '+typeof(cryptkey)+len);
-        }
-      }
-      function runEncryption()
-      {
-        pass1 = frm.pass.value;
-        pass2 = frm.pass_confirm.value;
-        if ( pass1 != pass2 )
-        {
-          alert('The passwords you entered do not match.');
-          return false;
-        }
-        if ( pass1.length < 6 )
-        {
-          alert('The new password must be 6 characters or greater in length.');
-          return false;
-        }
-        if(testpassed)
-        {
-          pass = frm.pass.value;
-          pass = stringToByteArray(pass);
-          cryptstring = rijndaelEncrypt(pass, cryptkey, 'ECB');
-          if(!cryptstring)
-          {
-            return false;
-          }
-          cryptstring = byteArrayToHex(cryptstring);
-          frm.crypt_data.value = cryptstring;
-          frm.pass.value = "";
-          frm.pass_confirm.value = "";
-        }
-        return true;
-      }
-    </script>
-    <?php
-    $template->footer();
-    return true;
-  }
-  if(isset($_POST['do_reset']))
-  {
-    if($session->mail_password_reset($_POST['username']))
-    {
-      echo '<p>An e-mail has been sent to the e-mail address on file for your username with a new password in it. Please check your e-mail for further instructions.</p>';
-    }
-    else
-    {
-      echo '<p>Error occured, your new password was not sent.</p>';
-    }
-    $template->footer();
-    return true;
-  }
-  echo '<p>Don\'t worry, it happens to the best of us.</p>
-        <p>To reset your password, just enter your username below, and a new password will be e-mailed to you.</p>
-        <form action="'.makeUrl($paths->page).'" method="post" onsubmit="if(!submitAuthorized) return false;">
-          <p>Username:  '.$template->username_field('username').'</p>
-          <p><input type="submit" name="do_reset" value="Mail new password" /></p>
-        </form>';
-  $template->footer();
-}
-
-?>
\ No newline at end of file