WiP commit for admin panel localization. All modules up to Admin:UserManager (working down the list) are localized except Admin:ThemeManager, which is due for a rewrite
authorDan
Thu, 03 Jan 2008 00:53:33 -0500
changeset 345 4ccdfeee9a11
parent 344 be6c5fdd9203
child 346 cdf24ba5f114
WiP commit for admin panel localization. All modules up to Admin:UserManager (working down the list) are localized except Admin:ThemeManager, which is due for a rewrite
ajax.php
includes/clientside/jsres.php
includes/clientside/static/acl.js
includes/comment.php
includes/constants.php
includes/email.php
includes/functions.php
includes/lang.php
includes/pageprocess.php
includes/pageutils.php
includes/paths.php
includes/render.php
includes/rijndael.php
includes/sessions.php
includes/template.php
includes/wikiformat.php
install.php
language/english/admin.json
language/english/user.json
plugins/PrivateMessages.php
plugins/SpecialAdmin.php
plugins/SpecialGroups.php
plugins/SpecialPageFuncs.php
plugins/SpecialUpdownload.php
plugins/SpecialUserFuncs.php
plugins/admin/PageGroups.php
plugins/admin/PageManager.php
plugins/admin/SecurityLog.php
plugins/admin/UserManager.php
themes/admin/simple-footer.tpl
themes/admin/simple-header.tpl
themes/oxygen/acledit.tpl
upgrade.php
--- a/ajax.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/ajax.php	Thu Jan 03 00:53:33 2008 -0500
@@ -182,7 +182,7 @@
         $return = array(
           'mode' => 'obsolete',
           'author' => $row['author'],
-          'date_string' => date('d M Y h:i a', $row['time_id']),
+          'date_string' => enano_date('d M Y h:i a', $row['time_id']),
           'time' => $row['time_id'] // time() ???
           );
         echo enano_json_encode($return);
--- a/includes/clientside/jsres.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/clientside/jsres.php	Thu Jan 03 00:53:33 2008 -0500
@@ -33,7 +33,7 @@
 $everything = file_get_contents($fname);
 
 $mtime = filemtime($fname);
-header('Last-Modified: '.date('D, d M Y H:i:s T', $mtime));
+header('Last-Modified: '.enano_date('D, d M Y H:i:s T', $mtime));
 header('Content-disposition: attachment; filename=' . $file);
 
 if(defined('ENABLE_COMPRESSION'))
--- a/includes/clientside/static/acl.js	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/clientside/static/acl.js	Thu Jan 03 00:53:33 2008 -0500
@@ -363,18 +363,26 @@
                   {
                     vars['FIELD_DESC'] = data.acl_descs[i];
                   }
+                  vars['FIELD_INHERIT_CHECKED'] = '';
                   vars['FIELD_DENY_CHECKED'] = '';
                   vars['FIELD_DISALLOW_CHECKED'] = '';
                   vars['FIELD_WIKIMODE_CHECKED'] = '';
                   vars['FIELD_ALLOW_CHECKED'] = '';
                   vars['FIELD_NAME'] = i;
+                  if ( !data.current_perms[i] )
+                  {
+                    data.current_perms[i] = 'i';
+                  }
                   switch(data.current_perms[i])
                   {
+                    case 'i':
+                    default:
+                      vars['FIELD_INHERIT_CHECKED'] = 'checked="checked"';
+                      break;
                     case 1:
                       vars['FIELD_DENY_CHECKED'] = 'checked="checked"';
                       break;
                     case 2:
-                    default:
                       vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"';
                       break;
                     case 3:
--- a/includes/comment.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/comment.php	Thu Jan 03 00:53:33 2008 -0500
@@ -64,15 +64,6 @@
   }
   
   /**
-   * PHP 4 constructor.
-   * @see Comments::__construct
-   */
-  function Comments($page_id, $namespace)
-  {
-    $this->__construct($page_id, $namespace);
-  }
-  
-  /**
    * Processes a command in JSON format.
    * @param string The JSON-encoded input, probably something sent from the Javascript/AJAX frontend
    */
@@ -151,7 +142,7 @@
             }
             
             // Format date
-            $row['time'] = date('F d, Y h:i a', $row['time']);
+            $row['time'] = enano_date('F d, Y h:i a', $row['time']);
             
             // Format signature
             $row['signature'] = ( !empty($row['signature']) ) ? RenderMan::render($row['signature']) : '';
@@ -293,7 +284,7 @@
           $text = RenderMan::render($text);
           $appr = ( getConfig('approve_comments') == '1' ) ? '0' : '1';
           $time = time();
-          $date = date('F d, Y h:i a', $time);
+          $date = enano_date('F d, Y h:i a', $time);
           
           // Send it to the database
           $q = $db->sql_query('INSERT INTO '.table_prefix.'comments(page_id,namespace,name,subject,comment_data,approved, time, user_id) VALUES' .
--- a/includes/constants.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/constants.php	Thu Jan 03 00:53:33 2008 -0500
@@ -98,6 +98,18 @@
 define('GENERAL_NOTICE', 'Information');
 define('CRITICAL_ERROR', 'Critical error');
 
+//
+// Enano versions progress
+//
+
+// These constants are used to perform "at least version X" type logic in plugins. Constants should
+// be defined as ENANO_ATLEAST_<major version>_<minor version>, and they should match the version of
+// the Enano API, not any forked version. This is to ensure that plugins know what features to enable
+// and disable for compatibility with both branches.
+
+define('ENANO_ATLEAST_1_0', '');
+define('ENANO_ATLEAST_1_1', '');
+
 // You can un-comment the next line to require database backups to be encrypted using the site's unique key.
 // This keeps the file safe in transit, but also prevents any type of editing to the file. This is NOT
 // recommended except for tiny sites because encrypting an average of 2MB of data will take a while.
--- a/includes/email.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/email.php	Thu Jan 03 00:53:33 2008 -0500
@@ -27,7 +27,7 @@
 
   var $tpl_msg;
 
-  function emailer($use_smtp)
+  function __construct($use_smtp)
   {
     $this->reset();
     $this->use_smtp = $use_smtp;
@@ -151,7 +151,7 @@
                            (($this->from != '') ? "From: $this->from\n" : "From: " . getConfig('contact_email') . "\n") .
                            "Return-Path: " . getConfig('contact_email') .
                            "\nMessage-ID: <" . md5(uniqid(time())) . "@" . $_SERVER['SERVER_NAME'] . ">\nMIME-Version: 1.0\nContent-type: text/plain; charset=" . $this->encoding .
-                           "\nContent-transfer-encoding: 8bit\nDate: " . date('r', time()) .
+                           "\nContent-transfer-encoding: 8bit\nDate: " . enano_date('r', time()) .
                            "\nX-Priority: 3\nX-MSMail-Priority: Normal\nX-Mailer: PHP\nX-MimeOLE: Produced By Enano CMS\n" .
                            $this->extra_headers .
                            (($cc != '') ? "Cc: $cc\n" : '')  .
@@ -247,7 +247,7 @@
     {
       $this->mimeOut .= "From: ".$szFromAddress."\n";
       $this->mimeOut .= "To: ".$this->emailAddress."\n";
-      $this->mimeOut .= "Date: ".date("D, d M Y H:i:s") . " UT\n";
+      $this->mimeOut .= "Date: ".enano_date("D, d M Y H:i:s") . " UT\n";
       $this->mimeOut .= "Reply-To:".$szFromAddress."\n";
       $this->mimeOut .= "Subject: ".$this->mailSubject."\n";
       $this->mimeOut .= "X-Mailer: PHP/".phpversion()."\n";
@@ -349,11 +349,6 @@
     }
   }
   
-  function EmailEncryptor()
-  {
-    $this->__construct();
-  }
-  
   function testAll() {
     $size = sizeof($this->primes);
     
--- a/includes/functions.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/functions.php	Thu Jan 03 00:53:33 2008 -0500
@@ -225,6 +225,21 @@
 }
 
 /**
+ * Enano replacement for date(). Accounts for individual users' timezone preferences.
+ * @param string Date-formatted string
+ * @param int Optional - UNIX timestamp value to use. If omitted, the current time is used.
+ * @return string Formatted string
+ */
+
+function enano_date($string, $timestamp = false)
+{
+  if ( !is_int($timestamp) && !is_double($timestamp) && strval(intval($timestamp)) !== $timestamp )
+    $timestamp = time();
+  // FIXME: Offset $timestamp by user's timezone
+  return gmdate($string, $timestamp);
+}
+
+/**
  * Tells you the title for the given page ID string
  * @param string Page ID string (ex: Special:Administration)
  * @param bool Optional. If true, and if the namespace turns out to be something other than Article, the namespace prefix will be prepended to the return value.
@@ -747,7 +762,7 @@
   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->page_id).'">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']);
+  $datestring = enano_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';
@@ -784,7 +799,7 @@
       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']);
+      $datestring = enano_date('F d, Y h:i a', (int)$r['time_id']);
       echo $datestring.': '.$r['mimetype'].', ';
       $fs = $r['size'];
       $fs = (int)$fs;
--- a/includes/lang.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/lang.php	Thu Jan 03 00:53:33 2008 -0500
@@ -105,16 +105,6 @@
   }
   
   /**
-   * PHP 4 constructor.
-   * @param int|string Language ID or code to load.
-   */
-  
-  function Language($lang)
-  {
-    $this->__construct($lang);
-  }
-  
-  /**
    * Fetches language strings from the database, or a cache file if it's available.
    * @param bool If true (default), allows the cache to be used.
    */
--- a/includes/pageprocess.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/pageprocess.php	Thu Jan 03 00:53:33 2008 -0500
@@ -427,7 +427,7 @@
     $time = time();
     $edit_summary = ( strval($edit_summary) === $edit_summary ) ? $db->escape($edit_summary) : '';
     $minor_edit = ( $minor_edit ) ? '1' : '0';
-    $date_string = date('d M Y h:i a');
+    $date_string = enano_date('d M Y h:i a');
     
     // Insert log entry
     $sql = 'INSERT INTO ' . table_prefix . "logs ( time_id, date_string, log_type, action, page_id, namespace, author, page_text, edit_summary, minor_edit )\n"
@@ -681,7 +681,7 @@
     
     if ( $this->revision_id )
     {
-      echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;"><b>Notice:</b><br />The page you are viewing was archived on '.date('F d, Y \a\t h:i a', $this->revision_id).'.<br /><a href="'.makeUrlNS($this->namespace, $this->page_id).'" onclick="ajaxReset(); return false;">View current version</a>  |  <a href="'.makeUrlNS($this->namespace, $this->page_id, 'do=rollback&amp;id='.$this->revision_id).'" onclick="ajaxRollback(\''.$this->revision_id.'\')">Restore this version</a></div><br />';
+      echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;"><b>Notice:</b><br />The page you are viewing was archived on '.enano_date('F d, Y \a\t h:i a', $this->revision_id).'.<br /><a href="'.makeUrlNS($this->namespace, $this->page_id).'" onclick="ajaxReset(); return false;">View current version</a>  |  <a href="'.makeUrlNS($this->namespace, $this->page_id, 'do=rollback&amp;id='.$this->revision_id).'" onclick="ajaxRollback(\''.$this->revision_id.'\')">Restore this version</a></div><br />';
     }
     
     if ( $redir_enabled )
@@ -689,6 +689,12 @@
       echo $redir_html;
     }
     
+    $code = $plugins->setHook('pageprocess_render_head');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
     if ( $incl_inner_headers )
     {
       $text = '?>' . RenderMan::render($text);
@@ -701,6 +707,12 @@
     // echo('<pre>'.htmlspecialchars($text).'</pre>');
     eval ( $text );
     
+    $code = $plugins->setHook('pageprocess_render_tail');
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    
     if ( $incl_inner_headers )
     {
       display_page_footers();
@@ -941,7 +953,7 @@
     {
       echo '<tr><td class="row1" style="text-align: center;"><img alt="' . $lang->get('usercp_avatar_image_alt', array('username' => $userdata['username'])) . '" src="' . make_avatar_url(intval($userdata['authoritative_uid']), $userdata['avatar_type']) . '" /></td></tr>';
     }
-    echo '<tr><td class="row3">Joined: ' . date('F d, Y h:i a', $userdata['reg_time']) . '</td></tr>';
+    echo '<tr><td class="row3">Joined: ' . enano_date('F d, Y h:i a', $userdata['reg_time']) . '</td></tr>';
     echo '<tr><td class="row1">Total comments: ' . $userdata['n_comments'] . '</td></tr>';
     
     if ( !empty($userdata['real_name']) )
@@ -970,7 +982,7 @@
     {
       do 
       {
-        $row['time'] = date('F d, Y', $row['time']);
+        $row['time'] = enano_date('F d, Y', $row['time']);
         $comments[] = $row;
       }
       while ( $row = $db->fetchrow() );
@@ -1241,7 +1253,7 @@
     global $email;
     
     // Log it for crying out loud
-    $q = $db->sql_query('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'illegal_page\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($session->username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', \'' . $db->escape(serialize(array($this->page_id, $this->namespace))) . '\')');
+    $q = $db->sql_query('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'illegal_page\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($session->username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', \'' . $db->escape(serialize(array($this->page_id, $this->namespace))) . '\')');
     
     $ob = '';
     //$template->tpl_strings['PAGE_NAME'] = 'Access denied';
@@ -1458,16 +1470,6 @@
   }
   
   /**
-   * PHP 4 constructor.
-   * @see PageProcessor::__construct()
-   */
-  
-  function PageProcessor( $page_id, $namespace, $revision_id = 0 )
-  {
-    $this->__construct($page_id, $namespace, $revision_id);
-  }
-  
-  /**
    * Send an error message and die. For debugging or critical technical errors only - nothing that would under normal circumstances be shown to the user.
    * @var string Error message
    * @var bool If true, send DBAL's debugging information as well
--- a/includes/pageutils.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/pageutils.php	Thu Jan 03 00:53:33 2008 -0500
@@ -28,7 +28,7 @@
     $q = $db->sql_query('SELECT username FROM ' . table_prefix.'users WHERE username=\'' . $db->escape(rawurldecode($name)) . '\'');
     if ( !$q )
     {
-      die(mysql_error());
+      die($db->get_error());
     }
     if ( $db->numrows() < 1)
     {
@@ -380,7 +380,7 @@
     $msg = $db->escape($message);
     
     $minor = $minor ? ENANO_SQL_BOOLEAN_TRUE : ENANO_SQL_BOOLEAN_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->page_id . '\', \'' . $paths->namespace . '\', ' . ENANO_SQL_MULTISTRING_PRFIX . '\'' . $msg . '\', \'' . $uid . '\', \'' . $session->username . '\', \'' . $db->escape(htmlspecialchars($summary)) . '\', ' . $minor . ');';
+    $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().', \''.enano_date('d M Y h:i a').'\', \'' . $paths->page_id . '\', \'' . $paths->namespace . '\', ' . ENANO_SQL_MULTISTRING_PRFIX . '\'' . $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=' . ENANO_SQL_MULTISTRING_PRFIX . '\'' . $msg . '\',char_tag=\'' . $uid . '\' WHERE page_id=\'' . $page_id . '\' AND namespace=\'' . $namespace . '\';';
@@ -472,7 +472,7 @@
     
     $qa = $db->sql_query('INSERT INTO ' . table_prefix.'pages(name,urlname,namespace,visible,protected,delvote_ips) VALUES(\'' . $db->escape($name) . '\', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\', '. ( $visible ? '1' : '0' ) .', ' . $prot . ', \'' . $db->escape(serialize($ips)) . '\');');
     $qb = $db->sql_query('INSERT INTO ' . table_prefix.'page_text(page_id,namespace) VALUES(\'' . $db->escape($page_id) . '\', \'' . $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_id) . '\', \'' . $namespace . '\');');
+    $qc = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.time().', \''.enano_date('d M Y h:i a').'\', \'page\', \'create\', \'' . $session->username . '\', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\');');
     
     if($qa && $qb && $qc)
       return 'good';
@@ -514,13 +514,13 @@
     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)) . '\');';
+        $q = 'INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.enano_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)) . '\');';
+        $q = 'INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.enano_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)) . '\');';
+        $q = 'INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.time().', \''.enano_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';
@@ -807,7 +807,7 @@
             $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());
+              return("An error occurred during the rollback operation.\nMySQL said: ".$db->get_error()."\n\nSQL backtrace:\n".$db->sql_backtrace());
             }
             else
             {
@@ -821,7 +821,7 @@
             $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();
+              return "An error occurred during the rollback operation.\nMySQL said: ".$db->get_error()."\n\nSQL backtrace:\n".$db->sql_backtrace();
             }
             else
             {
@@ -833,7 +833,7 @@
               return "You don't have permission to protect pages, so rolling back protection can't be allowed either.";
             $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();
+              return "An error occurred during the rollback operation.\nMySQL said: ".$db->get_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;
@@ -842,7 +842,7 @@
               return "You don't have permission to protect pages, so rolling back protection can't be allowed either.";
             $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();
+              return "An error occurred during the rollback operation.\nMySQL said: ".$db->get_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;
@@ -851,7 +851,7 @@
               return "You don't have permission to protect pages, so rolling back protection can't be allowed either.";
             $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();
+              return "An error occurred during the rollback operation.\nMySQL said: ".$db->get_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;
@@ -861,10 +861,10 @@
             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());
+            $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: ".$db->get_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: ".$db->get_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());
+            $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: ".$db->get_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":
@@ -873,12 +873,12 @@
               return 'Administrative privileges are required for file rollbacks.';
             }
             $newtime = time();
-            $newdate = date('d M Y h:i a');
+            $newdate = enano_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();
+              return 'Error during query: '.$db->get_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).'.';
+              return 'Error during query: '.$db->get_error();
+            return 'The file has been rolled back to the version uploaded on '.enano_date('d M Y h:i a', (int)$id).'.';
             break;
           default:
             return('Rollback of the action "' . $rb['action'] . '" is not yet supported.');
@@ -923,7 +923,7 @@
     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) . '\'))');
+    if(!$e) die('alert(unescape(\''.rawurlencode('Error inserting comment data: '.$db->get_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);
   }
@@ -962,7 +962,7 @@
           $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) . '\'));');
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));');
         break;
       case "approve":
         if(isset($flags['id']))
@@ -976,13 +976,13 @@
         }
         $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) . '\'));');
+        if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.$db->get_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(!$e) die('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));');
         if($a=='1') $v = $lang->get('comment_btn_mod_unapprove');
         else $v = $lang->get('comment_btn_mod_approve');
         echo 'document.getElementById("mdgApproveLink'.intval($_GET['id']).'").innerHTML="' . $v . '";';
@@ -1011,7 +1011,7 @@
                     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());
+    if(!$lq) _die('The comment text data could not be selected. '.$db->get_error());
     $_ob .= '<h3>' . $lang->get('comment_heading') . '</h3>';
     
     $n = ( $session->get_permissions('mod_comments')) ? $db->numrows() : $num_app;
@@ -1062,7 +1062,7 @@
         $strings['SUBJECT'] = $s;
         
         // Date and time
-        $strings['DATETIME'] = date('F d, Y h:i a', $row['time']);
+        $strings['DATETIME'] = enano_date('F d, Y h:i a', $row['time']);
         
         // User level
         switch($row['user_level'])
@@ -1247,7 +1247,7 @@
       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>');
+      if(!$s) _die('SQL error during safety check: '.$db->get_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.');
@@ -1270,7 +1270,7 @@
       Performed SQL:
       ' . $sql . '
     
-      Error returned by MySQL: '.mysql_error()).'");';
+      Error returned by MySQL: '.$db->get_error()).'");';
     }
   }
   
@@ -1296,7 +1296,7 @@
       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>');
+      if(!$s) _die('SQL error during safety check: '.$db->get_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();
@@ -1311,7 +1311,7 @@
     Performed SQL:
     ' . $sql . '
     
-    Error returned by MySQL: '.mysql_error();
+    Error returned by MySQL: '.$db->get_error();
   }
   
   /**
@@ -1343,14 +1343,14 @@
       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>');
+      if(!$s) _die('SQL error during safety check: '.$db->get_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) . '\'));');
+    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));');
     return('good');
   }
   
@@ -1377,14 +1377,14 @@
       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>');
+      if(!$s) _die('SQL error during safety check: '.$db->get_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) . '\'));');
+    if(!$e) return('alert(unesape(\''.rawurlencode('Error during query: '.$db->get_error().'\n\nQuery:\n' . $q) . '\'));');
     return('good');
   }
   
@@ -1412,7 +1412,7 @@
     }
     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\', \'' . $db->escape($paths->page_id) . '\', \'' . $paths->namespace . '\', \'' . $db->escape($session->username) . '\', \'' . $db->escape($paths->cpage['name']) . '\')');
+      $e = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.enano_date('d M Y h:i a').'\', \'page\', \'rename\', \'' . $db->escape($paths->page_id) . '\', \'' . $paths->namespace . '\', \'' . $db->escape($session->username) . '\', \'' . $db->escape($paths->cpage['name']) . '\')');
       if ( !$e )
       {
         $db->_die('The page title could not be updated.');
@@ -1469,7 +1469,7 @@
       $row = $db->fetchrow();
       $db->free_result();
       $minor_edit = ( ENANO_DBLAYER == 'MYSQL' ) ? 'false' : '0';
-      $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".'\', '.$minor_edit.');';
+      $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().', \''.enano_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".'\', '.$minor_edit.');';
       if(!$db->sql_query($q)) $db->_die('The history (log) entry could not be inserted into the logs table.');
     }
     return $lang->get('ajax_clearlogs_success');
@@ -1494,7 +1494,7 @@
       return $lang->get('ajax_delete_need_reason');
     }
     if(!$perms->get_permissions('delete_page')) return('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,edit_summary) VALUES('.time().', \''.date('d M Y h:i a').'\', \'page\', \'delete\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $session->username . '\', \'' . $db->escape(htmlspecialchars($reason)) . '\')');
+    $e = $db->sql_query('INSERT INTO ' . table_prefix.'logs(time_id,date_string,log_type,action,page_id,namespace,author,edit_summary) VALUES('.time().', \''.enano_date('d M Y h:i a').'\', \'page\', \'delete\', \'' . $page_id . '\', \'' . $namespace . '\', \'' . $session->username . '\', \'' . $db->escape(htmlspecialchars($reason)) . '\')');
     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.');
@@ -1662,7 +1662,7 @@
     ob_start();
     $_ob = '';
     $e = $db->sql_query('SELECT category_id FROM ' . table_prefix.'categories WHERE page_id=\'' . $paths->page_id . '\' AND namespace=\'' . $paths->namespace . '\'');
-    if(!$e) jsdie('Error selecting category information for current page: '.mysql_error());
+    if(!$e) jsdie('Error selecting category information for current page: '.$db->get_error());
     $cat_current = Array();
     while($r = $db->fetchrow())
     {
@@ -1820,7 +1820,7 @@
     $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('Error during update query: '.$db->get_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
     }
     return('GOOD');
   }
@@ -1856,7 +1856,7 @@
     $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());
+      die('PageUtils::setpass(): Error during update query: '.$db->get_error()."\n\nSQL Backtrace:\n".$db->sql_backtrace());
     }
     // Is the new password blank?
     if ( $p == '' )
@@ -1920,8 +1920,8 @@
        !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();
+    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: '.$db->get_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: '.$db->get_error();
     $row1 = $db->fetchrow($q1);
     $db->free_result($q1);
     $row2 = $db->fetchrow($q2);
@@ -1929,8 +1929,8 @@
     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);
+    $time1 = enano_date('F d, Y h:i a', $id1);
+    $time2 = enano_date('F d, Y h:i a', $id2);
     $_ob = "
     <p>" . $lang->get('history_lbl_comparingrevisions') . " {$time1} &rarr; {$time2}</p>
     ";
@@ -2027,19 +2027,19 @@
                     AND u.username=\'' . $db->escape($parms['target_id']) . '\'
                     ' . $page_where_clause . ';');
               if(!$q)
-                return(Array('mode'=>'error','error'=>mysql_error()));
+                return(Array('mode'=>'error','error'=>$db->get_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()));
+                  return(Array('mode'=>'error','error'=>$db->get_error()));
                 if($db->numrows() < 1)
                   return Array('mode'=>'error','error'=>$lang->get('acl_err_user_not_found'));
                 $row = $db->fetchrow();
                 $return['target_name'] = $return['target_id'];
                 $return['target_id'] = intval($row['user_id']);
-                $return['current_perms'] = $session->acl_types;
+                $return['current_perms'] = array();
               }
               else
               {
@@ -2047,7 +2047,7 @@
                 $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']));
+                $return['current_perms'] = $session->string_to_perm($row['rules']);
               }
               $db->free_result();
               // Eliminate types that don't apply to this namespace
@@ -2074,19 +2074,19 @@
                     AND g.group_id=\''.intval($parms['target_id']).'\'
                     ' . $page_where_clause . ';');
               if(!$q)
-                return(Array('mode'=>'error','error'=>mysql_error()));
+                return(Array('mode'=>'error','error'=>$db->get_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()));
+                  return(Array('mode'=>'error','error'=>$db->get_error()));
                 if($db->numrows() < 1)
                   return Array('mode'=>'error','error'=>$lang->get('acl_err_bad_group_id'));
                 $row = $db->fetchrow();
                 $return['target_name'] = $row['group_name'];
                 $return['target_id'] = intval($row['group_id']);
-                $return['current_perms'] = $session->acl_types;
+                $return['current_perms'] = array();
               }
               else
               {
@@ -2094,7 +2094,7 @@
                 $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']));
+                $return['current_perms'] = $session->string_to_perm($row['rules']);
               }
               $db->free_result();
               // Eliminate types that don't apply to this namespace
@@ -2129,20 +2129,25 @@
           $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'=>$db->get_error());
+          if ( sizeof ( $parms['perms'] ) < 1 )
           {
-            return array(
-                'mode' => 'error', 
-                'error' => $lang->get('acl_err_zero_list')
-              );
+            // As of 1.1.x, this returns success because the rule length is zero if the user selected "inherit" in all columns
+            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,
+            );
           }
+          $rules = $session->perm_to_string($parms['perms']);
           $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());
+          if(!$db->sql_query($q)) return Array('mode'=>'error','error'=>$db->get_error());
           return Array(
               'mode' => 'success',
               'target_type' => $parms['target_type'],
@@ -2160,7 +2165,7 @@
           $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'=>'error','error'=>$db->get_error());
           return Array(
               'mode' => 'delete',
               'target_type' => $parms['target_type'],
@@ -2317,6 +2322,7 @@
         foreach ( $response['acl_types'] as $acl_type => $value )
         {
           $vars = Array(
+              'FIELD_INHERIT_CHECKED' => '',
               'FIELD_DENY_CHECKED' => '',
               'FIELD_DISALLOW_CHECKED' => '',
               'FIELD_WIKIMODE_CHECKED' => '',
@@ -2327,6 +2333,10 @@
           
           switch ( $response['current_perms'][$acl_type] )
           {
+            case 'i':
+            default:
+              $vars['FIELD_INHERIT_CHECKED'] = 'checked="checked"';
+              break;
             case AUTH_ALLOW:
               $vars['FIELD_ALLOW_CHECKED'] = 'checked="checked"';
               break;
@@ -2334,7 +2344,6 @@
               $vars['FIELD_WIKIMODE_CHECKED'] = 'checked="checked"';
               break;
             case AUTH_DISALLOW:
-            default:
               $vars['FIELD_DISALLOW_CHECKED'] = 'checked="checked"';
               break;
              case AUTH_DENY:
--- a/includes/paths.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/paths.php	Thu Jan 03 00:53:33 2008 -0500
@@ -101,10 +101,6 @@
     $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
--- a/includes/render.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/render.php	Thu Jan 03 00:53:33 2008 -0500
@@ -644,8 +644,8 @@
       $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('~~~~~', enano_date('G:i, j F Y (T)'), $text);
+    $text = str_replace('~~~~', "[[User:$session->username|$session->username]] ".enano_date('G:i, j F Y (T)'), $text);
     $text = str_replace('~~~', "[[User:$session->username|$session->username]] ", $text);
     
     // Reinsert <nowiki> sections
--- a/includes/rijndael.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/rijndael.php	Thu Jan 03 00:53:33 2008 -0500
@@ -95,11 +95,6 @@
    23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12,
   125 );
   
-  function AESCrypt($ks = 128, $bs = 128, $debug = false)
-  {
-    $this->__construct($ks, $bs, $debug);
-  }
-  
   function __construct($ks = 128, $bs = 128, $debug = false)
   {
     $this->keySizeInBits = $ks;
@@ -1028,7 +1023,7 @@
       return (int)$n;
   }
    
-  function encrypt($str, $key) {
+  function encrypt($str, $key, $return_encoding = ENC_HEX) {
       if ($str == "")
       {
           return "";
@@ -1062,7 +1057,7 @@
       return $this->long2str($v, false);
   }
    
-  function decrypt($str, $key) {
+  function decrypt($str, $key, $encoding = ENC_HEX) {
       if ($str == "") {
           return "";
       }
--- a/includes/sessions.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/sessions.php	Thu Jan 03 00:53:33 2008 -0500
@@ -324,13 +324,15 @@
   }
   
   /**
-   * PHP 4 compatible constructor.
+   * PHP 4 compatible constructor. Deprecated in 1.1.x.
    */
    
+  /*
   function sessionManager()
   {
     $this->__construct();
   }
+  */
   
   /**
    * Wrapper function to sanitize strings for MySQL and HTML
@@ -593,7 +595,7 @@
         // policy is captcha -- check if it's correct, and if so, bypass lockout check
         $real_code = $this->get_captcha($captcha_hash);
       }
-      if ( $policy != 'disable' && !( $policy == 'captcha' && isset($real_code) && $real_code == $captcha_code ) )
+      if ( $policy != 'disable' && !( $policy == 'captcha' && isset($real_code) && strtolower($real_code) == strtolower($captcha_code) ) )
       {
         $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
         $timestamp_cutoff = time() - $duration;
@@ -668,9 +670,9 @@
     {
       // This wasn't logged in <1.0.2, dunno how it slipped through
       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) . ')');
+        $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().', \''.enano_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']).'\')');
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
     
       if ( $policy != 'disable' && !defined('IN_ENANO_INSTALL') )
       {
@@ -758,9 +760,9 @@
         $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) . ')');
+          $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().', \''.enano_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']).'\')');
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
         
         $code = $plugins->setHook('login_success');
         foreach ( $code as $cmd )
@@ -780,9 +782,9 @@
     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) . ')');
+        $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().', \''.enano_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']).'\')');
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
         
       // Do we also need to increment the lockout countdown?
       if ( $policy != 'disable' && !defined('IN_ENANO_INSTALL') )
@@ -886,9 +888,9 @@
     {
       // This wasn't logged in <1.0.2, dunno how it slipped through
       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) . ')');
+        $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().', \''.enano_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']).'\')');
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
       
       // Do we also need to increment the lockout countdown?
       if ( $policy != 'disable' && !defined('IN_ENANO_INSTALL') )
@@ -968,9 +970,9 @@
       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) . ')');
+          $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().', \''.enano_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']).'\')');
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
         
         $code = $plugins->setHook('login_success');
         foreach ( $code as $cmd )
@@ -991,9 +993,9 @@
     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) . ')');
+        $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().', \''.enano_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']).'\')');
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
         
       // Do we also need to increment the lockout countdown?
       if ( $policy != 'disable' && !defined('IN_ENANO_INSTALL') )
@@ -2046,7 +2048,7 @@
   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).'\');');
+    $this->sql('INSERT INTO '.table_prefix.'logs(log_type, action, time_id, date_string, author, edit_summary) VALUES(\'admin\', \'activ_req\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$this->username.'\', \''.$db->escape($u).'\');');
   }
   
   /**
@@ -2062,11 +2064,11 @@
     $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'].'\')');
+      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_good\', '.time().', \''.enano_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'].'\')');
+      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
     }
     return $r;
   }
@@ -2549,6 +2551,8 @@
     $s = '';
     foreach($perms as $perm => $ac)
     {
+      if ( $ac == 'i' )
+        continue;
       $s .= "$perm=$ac;";
     }
     return $s;
@@ -2597,6 +2601,31 @@
   }
   
   /**
+   * Merges two ACL arrays, but instead of calculating inheritance for missing permission types, just returns 'i' for that type. Useful
+   * for explicitly requiring inheritance in ACL editing interfaces
+   * @param array $perm1 The first set of permissions
+   * @param array $perm2 The second, authoritative set of permissions
+   */
+  
+  function acl_merge_inherit($perm1, $perm2)
+  {
+    foreach ( $perm1 as $type => $level )
+    {
+      $perm1[$type][$level] = 'i';
+    }
+    $ret = $perm1;
+    foreach ( $perm2 as $type => $level )
+    {
+      if ( isset( $ret[$type] ) )
+      {
+        if ( $ret[$type] != AUTH_DENY )
+          $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"
--- a/includes/template.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/template.php	Thu Jan 03 00:53:33 2008 -0500
@@ -81,10 +81,6 @@
     $this->style_list = $list;
     
   }
-  function template()
-  {
-    $this->__construct();
-  }
   function sidebar_widget($t, $h)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
@@ -1777,7 +1773,7 @@
     $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>';
+      $messages[] = '<a href="' . makeUrlNS('Special', 'PrivateMessages/View/' . $row['message_id']) . '" title="Sent ' . enano_date('F d, Y h:i a', $row['date']) . ' by ' . $row['message_from'] . '">' . $row['subject'] . '</a>';
     }
     $ob .= implode(",\n    " , $messages)."\n";
     $ob .= '</div>'."\n";
@@ -1810,12 +1806,14 @@
     $this->tpl_bool = $template->tpl_bool;
   }
   /**
-   * PHP 4 constructor.
+   * PHP 4 constructor. Deprecated in 1.1.x.
    */
+  /*
   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
--- a/includes/wikiformat.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/includes/wikiformat.php	Thu Jan 03 00:53:33 2008 -0500
@@ -154,7 +154,7 @@
         
         chdir($d);
 
-        $obj =& new $class($rules);
+        $obj = new $class($rules);
         return $obj;
     }
 
@@ -514,7 +514,7 @@
             }
         }
 
-        $this->parseObj[$rule] =& new $class($this);
+        $this->parseObj[$rule] = new $class($this);
 
     }
 
@@ -536,7 +536,7 @@
             }
         }
 
-        $this->renderObj[$rule] =& new $class($this);
+        $this->renderObj[$rule] = new $class($this);
     }
 
     function loadFormatObj($format)
@@ -556,7 +556,7 @@
             }
         }
 
-        $this->formatObj[$format] =& new $class($this);
+        $this->formatObj[$format] = new $class($this);
     }
 
     function addPath($type, $dir)
--- a/install.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/install.php	Thu Jan 03 00:53:33 2008 -0500
@@ -754,7 +754,7 @@
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
   
-  $q = $db->sql_query('INSERT INTO ' . table_prefix . 'logs(log_type,action,time_id,date_string,author,page_text,edit_summary) VALUES(\'security\', \'install_enano\', ' . time() . ', \'' . date('d M Y h:i a') . '\', \'' . mysql_real_escape_string($_POST['admin_user']) . '\', \'' . mysql_real_escape_string(ENANO_VERSION) . '\', \'' . mysql_real_escape_string($_SERVER['REMOTE_ADDR']) . '\');');
+  $q = $db->sql_query('INSERT INTO ' . table_prefix . 'logs(log_type,action,time_id,date_string,author,page_text,edit_summary) VALUES(\'security\', \'install_enano\', ' . time() . ', \'' . enano_date('d M Y h:i a') . '\', \'' . mysql_real_escape_string($_POST['admin_user']) . '\', \'' . mysql_real_escape_string(ENANO_VERSION) . '\', \'' . mysql_real_escape_string($_SERVER['REMOTE_ADDR']) . '\');');
   if ( !$q )
   {
     echo '<p><tt>MySQL return: ' . mysql_error() . '</tt></p>';
--- a/language/english/admin.json	Mon Dec 31 21:43:51 2007 -0500
+++ b/language/english/admin.json	Thu Jan 03 00:53:33 2008 -0500
@@ -18,7 +18,7 @@
 var enano_lang = {
   categories: [
     'adm', 'acl', 'adminusers',
-    'acphome', 'acpgc', 'acpup', 'acpft', 'acppl', 'acppm',
+    'acphome', 'acpgc', 'acpup', 'acpft', 'acppl', 'acppm', 'acped', 'acpdb', 'acppg', 'acpum',
   ],
   strings: {
     meta: {
@@ -29,8 +29,11 @@
       acpup: 'ACP: File uploads',
       acpft: 'ACP: Allowed file types',
       acppl: 'ACP: Manage plugins',
+      acpdb: 'ACP: Database backup',
       acppm: 'ACP: Manage pages',
-      adminusers: 'ACP: User management'
+      acped: 'ACP: Edit page content',
+      acppg: 'ACP: Page groups',
+      acpum: 'ACP: User management',
     },
     adm: {
       cat_general: 'General',
@@ -97,11 +100,21 @@
       lbl_save_success_body: 'The permissions for %target_name% on this page have been updated successfully. If you changed permissions that affect your user account, you may not see changes until you reload the page.',
       lbl_delete_success_title: 'Rule deleted',
       lbl_delete_success_body: 'The access rules for %target_name% on this page have been deleted.',
+      lbl_field_inherit: 'Inherit',
       lbl_field_deny: 'Deny',
       lbl_field_disallow: 'Disallow',
       lbl_field_wikimode: 'Wiki mode',
       lbl_field_allow: 'Allow',
-      lbl_help: '<p><b>Permission types:</b></p><ul><li><b>Allow</b> means that the user is allowed to access the item</li><li><b>Wiki mode</b> means the user can access the item if wiki mode is active (per-page wiki mode is taken into account)</li><li><b>Disallow</b> means the user is denied access unless something allows it.</li><li><b>Deny</b> means that the user is denied access to the item. This setting overrides all other permissions.</li></ul>',
+      lbl_help: '<p>
+                   <b>Permission types:</b>
+                 </p>
+                 <ul>
+                   <li><b>Allow</b> means that the user is allowed to access the item</li>
+                   <li><b>Wiki mode</b> means the user can access the item if wiki mode is active (per-page wiki mode is taken into account)</li>
+                   <li><b>Disallow</b> means the user is denied access unless something allows it.</li>
+                   <li><b>Deny</b> means that the user is denied access to the item. This setting overrides all other permissions.</li>
+                   <li><b>Inherit</b> forces the permission to be unset and thus inherited from the defaults. Setting every permission to Inherit is the same as deleting the rule.</li>
+                 </ul>',
       
       scope_type_wholesite: 'this entire site',
       scope_type_thispage: 'this page',
@@ -137,6 +150,7 @@
       th_toppages_page: 'Page',
       th_toppages_hits: 'Hits',
       heading_seclog: 'Security log',
+      msg_seclog_info: 'This list shows the 5 most recent actions/attempted actions performed by administrators on this site. This also includes attempts to view blocked pages and use the administration panel without appropriate privileges. You can view a complete list using the link below.',
       btn_seclog_full: 'Full security log',
     },
     acpgc: {
@@ -392,7 +406,200 @@
       
       msg_save_success: 'Your changes to the page have been saved. <a href="%viewpage_url%">View page &raquo;</a>',
     },
-    adminusers: {
+    acped: {
+      heading_main: 'Edit page content',
+      hint: 'This panel allows you to edit the contents of pages that are stored in the database.',
+      // The rest of this section is identical to the first parts of the acppm category by default (you can copy and paste).
+      err_page_not_found: 'No pages matching that search string could be found.',
+      msg_results_ambiguous_title: 'Ambiguous search results',
+      msg_results_ambiguous_body: 'Multiple pages that matched your search terms were found. Please select the page you wish to edit:',
+      ambig_btn_viewpage: 'View',
+      err_ambig_absolute: 'Your database is corrupt as it contains multiple pages with the same urlname and namespace.',
+      lbl_field_search: 'Search for a page title or URL string:',
+      heading_select_page_from_list: 'Select page from a list',
+      hint_select_page_from_list: 'You can also select the page you want to edit from the list below. The list is broken into sections of 100 pages, so if you have a lot of pages on your site, you can click the pagination control below to view more pages.',
+    },
+    acpdb: {
+      err_not_supported_title: 'Not supported',
+      err_not_supported_desc: 'This function is only supported under the MySQL database driver.',
+      err_demo_mode_title: 'Access denied',
+      err_demo_mode_desc: 'Since you\'re using the Enano demo, we can\'t allow database backups. Sorry.',
+      
+      intro: 'This page allows you to back up your Enano database should something go miserably wrong.',
+      lbl_system_tables: 'Export tables that are part of the Enano core',
+      lbl_additional_tables: 'Additional tables to export:',
+      lbl_include_structure: 'Include table structure',
+      lbl_include_data: 'Include table data',
+      btn_create_backup: 'Create backup',
+    },
+    acppg: {
+      // Main menu
+      heading_main: 'Manage page groups',
+      hint_intro: 'Enano\'s page grouping system allows you to build sets of pages that can be controlled by a single ACL rule. This makes managing features such as a members-only section of your site a lot easier. If you don\'t use the ACL system, you probably don\'t need to use page groups.',
+      col_group_name: 'Group name',
+      col_type: 'Type',
+      col_target: 'Target',
+      col_actions: 'Actions',
+      gtype_catlink: 'Link to category',
+      gtype_tagged: 'Group of pages with one tag',
+      gtype_static: 'Static group of pages',
+      gtype_regex: 'Regular expression match',
+      gtype_regex_long: 'Perl-compatible regular expression (advanced)',
+      lbl_tag: 'Tag:',
+      lbl_category: 'Category:',
+      lbl_regex: 'Expression:',
+      btn_edit: 'Edit',
+      btn_delete: 'Delete',
+      msg_no_groups: 'No page groups defined.',
+      btn_create_new: 'Create new group',
+      
+      // Creation form
+      err_no_cats: 'There aren\'t any categories on this site.',
+      th_create: 'Create page group',
+      field_group_name: 'Group name:',
+      field_group_name_hint: 'This should be short, descriptive, and human-readable.',
+      field_group_type: 'Group type:',
+      
+      field_member_pages: 'Member pages:',
+      field_member_pages_hint: 'Click the "plus" button to add more fields.',
+      field_target_category: 'Include pages in this category:',
+      field_target_category_hint: 'Pages in subcategories are <u>not</u> included, however subcategory pages themselves are.',
+      field_target_category_hint2: '<b>Reminder:</b> Enano does not automatically place any access controls on the category. If you don\'t want users to be able to freely add and remove pages from the category (assuming Wiki Mode is enabled for the category) then you need to enable protection on the category using the button on the more options menu.',
+      field_target_tag: 'Include pages with this tag:',
+      field_target_regex: 'Regular expression:',
+      field_target_regex_hint: 'Be sure to include the starting and ending delimiters and any flags you might need.<br />
+                                These pages might help: <a href="http://us.php.net/manual/en/reference.pcre.pattern.modifiers.php">Pattern modifiers</a> &bull; <a href="http://us.php.net/manual/en/reference.pcre.pattern.syntax.php">Pattern syntax</a><br />
+                                Examples: <tt>/^(Special|Admin):/i</tt> &bull; <tt>/^Image:([0-9]+)$/</tt><br />
+                                Developers, remember that this will be matched against the full page identifier string. This means that <tt>/^About_Enano$/</tt> will NOT match the page Special:About_Enano.',
+      btn_create_finish: 'Create page group',
+      
+      err_need_name: 'Please enter a name for the page group.',
+      err_need_tag: 'Please enter a page tag.',
+      err_need_cat: 'Please create a category page before linking a page group to a category.',
+      err_need_page: 'Please specify at least one page to place in this group.',
+      err_need_regex: 'Please specify a regular expression to match page IDs against.',
+      msg_create_success: 'The page group "%group_name%" has been created.',
+      
+      // Delete form
+      th_delete_confirm: 'Confirm deletion',
+      msg_delete_confirm: 'Are you sure you want to delete this page group?',
+      btn_delete_confirm: 'Yes, delete group',
+      msg_delete_success: 'The group "%pg_name%" has been deleted.',
+      
+      // Editor
+      th_editing_group: 'Editing page group:',
+      btn_save_name: 'Save group name',
+      th_remove_selected: 'Remove pages from this group',
+      field_remove: '<b>Remove</b> pages:',
+      btn_do_remove: 'Remove selected',
+      btn_save_update: 'Save and update',
+      btn_cancel_all: 'Cancel all changes',
+      th_onthefly: 'On-the-fly tools',
+      field_add_page: 'Add page:',
+      field_add_page_hint: 'You can add multiple pages by entering part of a page title, and it will be auto-completed. Press Enter to quickly add the page. This only works if you a really up-to-date browser.',
+      
+      // Validation messages and errors
+      err_ajaxadd_need_title: 'Please enter a page title.',
+      err_ajaxadd_already_in: 'The page you are trying to add is already in this group.',
+      ajaxadd_success: 'The page has been added to the specified group.',
+      err_save_need_name: 'Please enter a valid name for this group.',
+      msg_save_name_updated: 'The group name was updated successfully.',
+      err_save_need_tag: 'Please enter a valid tag.',
+      msg_save_tag_updated: 'The affecting tag was updated.',
+      err_save_need_regex: 'Please enter an expression to match against.',
+      msg_save_regex_updated: 'The expression to match against was updated.',
+      err_save_bad_category: 'No category ID specified on POST URI.',
+      msg_save_cat_updated: 'The affecting category was updated.',
+      err_save_no_pages: 'No pages were selected for deletion, and thus none were deleted.',
+      msg_save_pages_deleted: 'The requested page group members have been deleted.',
+    },
+    acpum: {
+      heading_main: 'User administration panel',
+      hint_intro: 'From this panel you can modify or delete user accounts.',
+      field_search_user: 'Search for user:',
+      field_search_user_hint: 'If your browser supports AJAX, this will provide suggestions for you.',
+      btn_search_user_go: 'Go',
+      heading_clear_sessions: 'Clear session key table',
+      hint_clear_sessions: '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. If you do this, all users besides you will be logged off, so be sure to do this at a time when traffic is low.',
+      btn_clear_sessions: 'Clear session keys',
+      
+      heading_activation_one: '1 user is awaiting account activation',
+      heading_activation_plural: '%count% users are awaiting account activation',
+      col_activate_timestamp: 'Date of request',
+      col_activate_requestedby: 'Requested by',
+      col_activate_requestedfor: 'Requested for',
+      col_activate_coppauser: 'COPPA user',
+      col_activate_actions: 'Actions',
+      coppauser_yes: 'Yes',
+      coppauser_no: 'No',
+      btn_activate_now: 'Activate now',
+      btn_send_email: 'Send activation e-mail',
+      btn_activate_deny: 'Deny request',
+      msg_activate_success: 'The user account "%username%" has been activated.',
+      err_activate_fail: 'The user account %username% has NOT been activated, possibly because the account is already active.',
+      msg_activate_email_success: 'The user %username% has been sent an e-mail with an activation link.',
+      err_activate_email_fail: 'The user account %username% has not been activated, probably because of a bad SMTP configuration.',
+      msg_activate_deny_success: 'All activation requests for the user %username% have been deleted.',
+      
+      msg_sessionclear_success: 'The session key table has been cleared. Your database should be a little bit smaller now.',
+      err_sessionclear_demo: 'Sorry Charlie, no can do. You might mess up other people logged into the demo site.',
+      
+      // VALIDATION ERRORS
+      err_bad_username: 'The username you entered could not be found.',
+      err_validation_fail: 'Your request could not be processed due to the following validation errors:',
+      err_nosave_demo: 'Users cannot be modified or deleted in demo mode.',
+      msg_delete_success: 'The user account has been deleted.',
+      // Note the difference between this and err_bad_username. err_bad_username is shown when the username entered
+      // doesn't match any usernames in the database (e.g. no search results); err_illegal_username is shown when
+      // the admin tries to change the username to one that has illegal characters in it.
+      err_illegal_username: 'The username you entered contains invalid characters.',
+      err_no_aes_key: 'Session manager denied public encryption key lookup request',
+      err_illegal_email: 'You have entered an invalid e-mail address.',
+      msg_save_success: 'Your changes have been saved.',
+      
+      // EDITOR SMARTFORM
+      heading_editing_user: 'Editing user:',
+      heading_basic_options: 'Basic options',
+      
+      field_username: 'Username:',
+      field_username_hint: 'Must be at least 2 characters in length',
+      msg_same_user_username: 'You cannot change your own username. To change your username you must log into a different administrative account.',
+      
+      field_password: 'Password:',
+      field_password_hint: 'Password strength requirements are not enforced here.',
+      msg_password_unchanged: 'Password will be left unchanged.',
+      btn_reset_password: 'Reset password...',
+      msg_same_user_password: 'To change your password, please use the user preferences panel.',
+      field_password_title: 'Change password to:',
+      field_newpassword: 'New password:',
+      field_newpassword_confirm: 'Confirm:',
+      
+      field_email: 'E-mail address:',
+      msg_same_user_email: 'To change your e-mail address, please use the user preferences panel.',
+      
+      field_realname: 'Real name:',
+      msg_same_user_realname: 'To change your real name on file, please use the user preferences panel.',
+      
+      field_signature: 'Signature:',
+      
+      heading_imcontact: 'Instant messenger contact information',
+      
+      field_aim: 'AIM handle:',
+      field_wlm: '<acronym title="Windows&trade; Live Messenger">WLM</acronym> handle:',
+      field_wlm_hint: 'If you don\'t specify the domain (@whatever.com), "@hotmail.com" will be assumed.',
+      field_yim: 'Yahoo! IM handle:',
+      field_xmpp: 'Jabber&trade;/XMPP handle:',
+      
+      heading_contact_extra: 'Extra contact information',
+      
+      field_homepage: 'Homepage:',
+      field_homepage_hint: 'Please remember the http:// prefix.',
+      field_location: 'Location:',
+      field_job: 'Job:',
+      field_hobbies: 'Hobbies:',
+      field_email_public: 'E-mail address is public',
+      field_email_public_hint: 'If this is checked, the user\'s e-mail address will be displayed on your the page. To protect the address from spambots, it will be encrypted.',
+      
       avatar_heading: 'Avatar settings',
       avatar_image_none: 'This user does not currently have an avatar.',
       avatar_lbl_change: 'Change avatar:',
@@ -400,6 +607,21 @@
       avatar_lbl_remove: 'Delete this user\'s avatar',
       avatar_lbl_set_http: 'Replace avatar using a new image from a URL',
       avatar_lbl_set_file: 'Replace avatar using a new image from my computer',
+      
+      heading_adminonly: 'Administrator-only options',
+      
+      field_active_title: 'User account is active',
+      field_active_hint: 'If this is unchecked, the existing activation key will be overwritten in the database, thus invalidating any activation e-mails sent to the user.',
+      field_active: 'Account is active and enabled',
+      field_userlevel: 'User\'s site access level',
+      field_userlevel_hint: 'If this is changed, the relevant group memberships will be updated accordingly.',
+      
+      field_deleteaccount_title: 'Delete user account',
+      field_deleteaccount: 'Permanently delete this user account when I click Save',
+      msg_delete_own_account: '<blink style="color: red;">WARNING!</blink> This will delete your own user account!',
+      field_deleteaccount_hint: 'Even if you delete this user account, the username will be shown in page edit history, comments, and other areas of the site. Deleting a user account CANNOT BE UNDONE and should only be done in extreme circumstances. If the user has violated the site policy, deleting the account will not prevent him from using the site or creating a new account, for that you need to add a new ban rule.',
+      
+      btn_save: 'Save changes',
     }
   }
 };
--- a/language/english/user.json	Mon Dec 31 21:43:51 2007 -0500
+++ b/language/english/user.json	Thu Jan 03 00:53:33 2008 -0500
@@ -110,7 +110,7 @@
       reg_msg_password_needmatch: 'The passwords you entered do not match.',
       reg_msg_email_activuser: 'An e-mail with an account activation key will be sent to this address, so please ensure that it is correct.',
       reg_msg_realname_optional: '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.',
-      reg_msg_captcha_pleaseenter: '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 %regen_flags%>generate a new image</a>.',
+      reg_msg_captcha_pleaseenter: 'Please enter the code shown in the image to the right into the text box. The code is case-insensitive and the numeral zero is never used. 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 %regen_flags%>generate a new image</a>.',
       reg_msg_captcha_blind: '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.',
       reg_msg_success_title: 'Registration successful',
       reg_msg_success_body: 'Thank you for registering, your user account has been created.',
--- a/plugins/PrivateMessages.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/PrivateMessages.php	Thu Jan 03 00:53:33 2008 -0500
@@ -86,7 +86,7 @@
         <div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4">
           <tr><th colspan="2"><?php echo $lang->get('privmsgs_lbl_message_from', array('sender' => htmlspecialchars($r['message_from']))); ?></th></tr>
           <tr><td class="row1"><?php echo $lang->get('privmsgs_lbl_subject') ?></td><td class="row1"><?php echo $r['subject']; ?></td></tr>
-          <tr><td class="row2"><?php echo $lang->get('privmsgs_lbl_date') ?></td><td class="row2"><?php echo date('M j, Y G:i', $r['date']); ?></td></tr>
+          <tr><td class="row2"><?php echo $lang->get('privmsgs_lbl_date') ?></td><td class="row2"><?php echo enano_date('M j, Y G:i', $r['date']); ?></td></tr>
           <tr><td class="row1"><?php echo $lang->get('privmsgs_lbl_message') ?></td><td class="row1"><?php echo RenderMan::render($r['message_text']);
           if ( $r['signature'] != '' )
           {
@@ -262,7 +262,7 @@
           die_friendly($lang->get('etc_access_denied_short'), '<p>You are not authorized to view the contents of this message.</p>');
         }
         $subj = 'Re: ' . $r['subject'];
-        $text = "\n\n\nOn " . date('M j, Y G:i', $r['date']) . ", " . $r['message_from'] . " wrote:\n> " . str_replace("\n", "\n> ", $r['message_text']); // Way less complicated than using a regex ;-)
+        $text = "\n\n\nOn " . enano_date('M j, Y G:i', $r['date']) . ", " . $r['message_from'] . " wrote:\n> " . str_replace("\n", "\n> ", $r['message_text']); // Way less complicated than using a regex ;-)
         
         $tbuf = $text;
         while( preg_match("/\n([\> ]*?)\> \>/", $text) )
@@ -332,7 +332,7 @@
             <td class="row1">
               <?php echo $lang->get('privmsgs_lbl_message'); ?>
             </td>
-            <td class="row1" style="width: 80%;">
+            <td class="row1" style="min-width: 80%;">
               <?php
                 if ( isset($_POST['_savedraft']) )
                 {
@@ -640,7 +640,7 @@
               {
                 echo '</b>';
               }
-              echo '</a></td><td class="'.$cls.'">'.date('M j, Y G:i', $r['date']).'</td><td class="'.$cls.'" style="text-align: center;"><input name="marked_'.$r['message_id'].'" type="checkbox" /></td></tr>';
+              echo '</a></td><td class="'.$cls.'">'.enano_date('M j, Y G:i', $r['date']).'</td><td class="'.$cls.'" style="text-align: center;"><input name="marked_'.$r['message_id'].'" type="checkbox" /></td></tr>';
             }
             $db->free_result();
           }
--- a/plugins/SpecialAdmin.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/SpecialAdmin.php	Thu Jan 03 00:53:33 2008 -0500
@@ -41,6 +41,7 @@
 
 // Admin pages that were too enormous to be in this file were split off into the plugins/admin/ directory in 1.0.1
 require(ENANO_ROOT . '/plugins/admin/PageManager.php');
+require(ENANO_ROOT . '/plugins/admin/PageEditor.php');
 require(ENANO_ROOT . '/plugins/admin/PageGroups.php');
 require(ENANO_ROOT . '/plugins/admin/SecurityLog.php');
 require(ENANO_ROOT . '/plugins/admin/UserManager.php');
@@ -161,6 +162,7 @@
   
   // Security log
   echo '<h3>' . $lang->get('acphome_heading_seclog') . '</h3>';
+  echo '<p>' . $lang->get('acphome_msg_seclog_info') . '</p>';
   $seclog = get_security_log(5);
   echo $seclog;
   
@@ -1228,8 +1230,7 @@
     echo '</table></div>';
 }
 
-/*
-function page_Admin_PageManager()
+function page_Admin_DBBackup()
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
   global $lang;
@@ -1241,411 +1242,125 @@
     return;
   }
   
-  echo '<h2>Page management</h2>';
+  if ( ENANO_DBLAYER != 'MYSQL' )
+    die('<h3>' . $lang->get('acpdb_err_not_supported_title') . '</h3>
+          <p>' . $lang->get('acpdb_err_not_supported_desc') . '</p>');
   
-  if ( isset($_POST['search']) || isset($_POST['select']) || ( isset($_GET['source']) && $_GET['source'] == 'ajax' ) )
+  if(isset($_GET['submitting']) && $_GET['submitting'] == 'yes' && defined('ENANO_DEMO_MODE') )
   {
-    // 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);
-        }
-        else if ( $paths->pages[$i]['name'] == $page_id )
-        {
-          $final_pid = $paths->pages[$i]['urlname_nons'];
-        }
-        else if ( strtolower($paths->pages[$i]['urlname_nons']) == strtolower(str_replace(' ', '_', $page_id)) )
-        {
-          $final_pid = $paths->pages[$i]['urlname_nons'];
-        }
-        else if ( 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;
-    }
+    redirect(makeUrlComplete('Special', 'Administration'), $lang->get('acpdb_err_demo_mode_title'), $lang->get('acpdb_err_demo_mode_desc'), 5);
   }
   
-  if ( isset($_POST['page_id']) && isset($_POST['namespace']) && !isset($_POST['cancel']) )
+  global $system_table_list;
+  if(isset($_GET['submitting']) && $_GET['submitting'] == 'yes')
   {
-    $cpage = $paths->pages[$paths->nslist[$_POST['old_namespace']].$_POST['old_page_id']];
-    if(isset($_POST['submit']))
+    
+    if(defined('SQL_BACKUP_CRYPT'))
+      // Try to increase our time limit
+      @set_time_limit(0);
+    // Do the actual export
+    $aesext = ( defined('SQL_BACKUP_CRYPT') ) ? '.tea' : '';
+    $filename = 'enano_backup_' . enano_date('ymd') . '.sql' . $aesext;
+    ob_start();
+    // Spew some headers
+    $headdate = enano_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().', \''.enano_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)
     {
-      switch(true)
-      {
-        case true:
-          // Create a list of things to update
-          $page_info = Array(
-              'name'=>$_POST['name'],
-              'urlname'=>sanitize_page_id($_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'
-            );
-          
-          $updating_urlname_or_namespace = ( $page_info['namespace'] != $cpage['namespace'] || $page_info['urlname'] != $cpage['urlname_nons'] );
-          
-          if ( !isset($paths->nslist[ $page_info['namespace'] ]) )
-          {
-            echo '<div class="error-box">The namespace you selected is not properly registered.</div>';
-            break;
-          }
-          if ( isset($paths->pages[ $paths->nslist[$page_info['namespace']] . $page_info[ 'urlname' ] ]) && $updating_urlname_or_namespace )
-          {
-            echo '<div class="error-box">There is already a page that exists with that URL string and namespace.</div>';
-            break;
-          }
-          // 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);
-          if ( !isset($cpage) )
-            die('[internal] no cpage');
-          foreach($k as $c)
-          {
-            if($c != 'urlname_nons' && $c != 'urlname' && $c != 'really_protected')
-            {
-              $q .= $c.'=\''.$db->escape($cpage[$c]).'\' AND ';
-            }
-            else if($c == 'urlname')
-            {
-              $q .= $c.'=\''.$db->escape($cpage['urlname_nons']).'\' AND ';
-            }
-          }
-          // Trim off the last " AND " and append a semicolon
-          $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']) . '\';',
-            'UPDATE '.table_prefix.'acl        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>';
-          break;
-      }
-    } 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;
+      if(!preg_match('#^([a-z0-9_]+)$#i', $t))
+        die('Hacking attempt');
+      // if($t == table_prefix.'files' && isset($_POST['do_data']))
+      //   unset($tables[$i]);
     }
-    $url = makeUrlNS('Special', 'Administration', 'module='.$paths->cpage['module'], true);
-    echo '<form action="'.$url.'" method="post">';
-    ?>
-    <h3>Modify page: <?php echo htmlspecialchars($_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 htmlspecialchars($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 htmlspecialchars(dirtify_page_id($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 htmlspecialchars($_POST['old_page_id']); ?>" />
-           <input type="hidden" name="old_namespace" value="<?php echo htmlspecialchars($_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>';
+    foreach($tables as $t)
+    {
+      // THE FOLLOWING COMMENT DOES NOT APPLY AS OF 1.0.
+      // Sorry folks - this script CAN'T backup enano_files and enano_search_index due to the sheer size of the tables.
+      // If encryption is enabled the log data will be excluded too.
+      $result = export_table(
+        $t,
+        isset($_POST['do_struct']),
+        ( isset($_POST['do_data']) ),
+        false
+        ) . "\n";
+      if ( !$result )
+      {
+        $db->_die();
+      }
+      echo $result;
+    }
+    $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-disposition: attachment; filename='.$filename.'');
+    header('Content-type: application/octet-stream');
+    header('Content-length: '.strlen($data));
+    echo $data;
+    exit;
   }
   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">';
+    // Show the UI
+    echo '<form action="'.makeUrlNS('Admin', 'DBBackup', 'submitting=yes', true).'" method="post" 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'].'">'.htmlspecialchars($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
-  global $lang;
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    $login_link = makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true);
-    echo '<h3>' . $lang->get('adm_err_not_auth_title') . '</h3>';
-    echo '<p>' . $lang->get('adm_err_not_auth_body', array( 'login_link' => $login_link )) . '</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']) . '\', \''.$db->escape($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 htmlspecialchars($_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 htmlspecialchars($_POST['page_id']); ?>" />
-    <input type="hidden" name="namespace" value="<?php echo htmlspecialchars($_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>
+    <p><?php echo $lang->get('acpdb_intro'); ?></p>
+    <p><label><input type="checkbox" name="do_system_tables" checked="checked" /> <?php echo $lang->get('acpdb_lbl_system_tables'); ?></label><p>
+    <p><?php echo $lang->get('acpdb_lbl_additional_tables'); ?></p>
+    <p><select name="additional_tables[]" multiple="multiple">
+       <?php
+         if ( ENANO_DBLAYER == 'MYSQL' )
+         {
+           $q = $db->sql_query('SHOW TABLES;') or $db->_die('Somehow we were denied the request to get the list of tables.');
+         }
+         else if ( ENANO_DBLAYER == 'PGSQL' )
+         {
+           $q = $db->sql_query('SELECT relname FROM pg_stat_user_tables ORDER BY relname;') 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" /> <?php echo $lang->get('acpdb_lbl_include_structure'); ?></label><br />
+       <label><input type="checkbox" name="do_data"   checked="checked" /> <?php echo $lang->get('acpdb_lbl_include_data'); ?></label>
+       </p>
+    <p><input type="submit" value="<?php echo $lang->get('acpdb_btn_create_backup'); ?>" /></p>
     <?php
     echo '</form>';
   }
 }
 
+/*
+ * Admin:PageManager sources are in /plugins/admin/PageManager.php.
+ */
+
+/*
+ * Admin:PageEditor sources are in /plugins/admin/PageEditor.php.
+ */
+
 function page_Admin_ThemeManager() 
 {
   
@@ -1676,7 +1391,7 @@
   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);
+    if(!$s) die('Error selecting enabled/disabled state value: '.$db->get_error().'<br /><u>SQL:</u><br />'.$q);
     $r = $db->fetchrow_num($s);
     $db->free_result();
     if($r[0] == 1) $e = 0;
@@ -1692,7 +1407,7 @@
     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);
+    if(!$a) die('Error updating enabled/disabled state value: '.$db->get_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>');
     }
   }
@@ -1715,7 +1430,7 @@
     
     $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);
+    if(!$s) die('Error selecting name value: '.$db->get_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">');
@@ -1736,30 +1451,30 @@
   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);
+    if(!$s) die('Error updating name value: '.$db->get_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);
+    if(!$s) die('Error selecting order information: '.$db->get_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);
+    if(!$sn) die('Error selecting order information: '.$db->get_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);
+      if(!$s) die('Error selecting order information: '.$db->get_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);
+      $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: '.$db->get_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: '.$db->get_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: '.$db->get_error().'<br /><u>SQL:</u><br />'.$q);
       echo('<div class="info-box">Theme moved up.</div>');
     }
     $db->free_result($s);
@@ -1769,20 +1484,20 @@
     // 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);
+    if(!$s) die('Error selecting order information: '.$db->get_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);
+      if(!$s) die('Error selecting order information: '.$db->get_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);
+      $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: '.$db->get_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: '.$db->get_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: '.$db->get_error().'<br /><u>SQL:</u><br />'.$q);
       echo('<div class="info-box">Theme moved down.</div>');
     }
   }
@@ -1792,7 +1507,7 @@
     $s = $db->sql_query($q);
     if ( !$s )
     {
-      die('Error getting theme count: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
+      die('Error getting theme count: '.$db->get_error().'<br /><u>SQL:</u><br />'.$q);
     }
     $n = $db->numrows($s);
     $db->free_result();
@@ -1813,7 +1528,7 @@
         $s = $db->sql_query($q);
         if ( !$s )
         {
-          die('Error deleting theme data: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
+          die('Error deleting theme data: '.$db->get_error().'<br /><u>SQL:</u><br />'.$q);
         }
         else
         {
@@ -1825,7 +1540,7 @@
   elseif(isset($_POST['install'])) {
     $q = 'SELECT theme_id FROM '.table_prefix.'themes;';
     $s = $db->sql_query($q);
-    if(!$s) die('Error getting theme count: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
+    if(!$s) die('Error getting theme count: '.$db->get_error().'<br /><u>SQL:</u><br />'.$q);
     $n = $db->numrows($s);
     $n++;
     $theme_id = $_POST['theme_id'];
@@ -1859,7 +1574,7 @@
       {
         $q = 'INSERT INTO '.table_prefix.'themes(theme_id,theme_name,theme_order,enabled,default_style) VALUES(\''.$db->escape($theme['theme_id']).'\', \''.$db->escape($theme['theme_name']).'\', '.$n.', 1, \'' . $db->escape($default_style) . '\')';
         $s = $db->sql_query($q);
-        if(!$s) die('Error inserting theme data: '.mysql_error().'<br /><u>SQL:</u><br />'.$q);
+        if(!$s) die('Error inserting theme data: '.$db->get_error().'<br /><u>SQL:</u><br />'.$q);
         else echo('<div class="info-box">Theme "'.$theme['theme_name'].'" installed.</div>');
       }
       else
@@ -1876,7 +1591,7 @@
         ');
         $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);
+        if(!$s) die('Error selecting theme data: '.$db->get_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>');
@@ -1895,7 +1610,7 @@
         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(!$s) die('Error selecting list of currently installed themes: '.$db->get_error().'<br /><u>Attempted SQL:</u><br />'.$q);
         if($db->numrows($s) < 1) {
           $obb .= '<option value="'.$theme['theme_id'].'">'.$theme['theme_name'].'</option>';
         }
@@ -1935,7 +1650,7 @@
     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><th colspan="2">Creating group: '.htmlspecialchars($_POST['create_group_name']).'</th></tr>
           <tr>
             <td class="row1">Group moderator</td><td class="row1">' . $template->username_field('group_mod') . '</td>
           </tr>
@@ -1947,7 +1662,7 @@
           </td></tr>
           <tr>
             <th class="subhead" colspan="2">
-              <input type="hidden" name="create_group_name" value="'.$_POST['create_group_name'].'" />
+              <input type="hidden" name="create_group_name" value="'.htmlspecialchars($_POST['create_group_name']).'" />
               <input type="submit" name="do_create_stage2" value="Create group" />
             </th>
           </tr>
@@ -2020,9 +1735,10 @@
       echo $db->get_error();
       return;
     }
+    $g_name = htmlspecialchars($_POST['create_group_name']);
     echo "<div class='info-box'>
             <b>Information</b><br />
-            The group {$_POST['create_group_name']} has been created successfully.
+            The group {$g_name} has been created successfully.
           </div>";
   }
   if(isset($_POST['do_edit']) || isset($_POST['edit_do']))
@@ -2039,7 +1755,7 @@
       echo '<p>Error: couldn\'t look up group name</p>';
     }
     $row = $db->fetchrow();
-    $name = $row['group_name'];
+    $name = htmlspecialchars($row['group_name']);
     $db->free_result();
     if(isset($_POST['edit_do']))
     {
@@ -2087,7 +1803,7 @@
                   The group name has been updated.
                 </div>';
         }
-        $name = $_POST['group_name'];
+        $name = htmlspecialchars($_POST['group_name']);
         
       }
       $q = $db->sql_query('SELECT member_id FROM '.table_prefix.'group_members
@@ -2140,7 +1856,7 @@
           }
         }
         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>';
+          echo '<div class="warning-box"><b>The user "'.htmlspecialchars($_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" ';
@@ -2161,7 +1877,7 @@
           </tr>
           </table>
           </div>
-          <input type="hidden" name="group_edit_id" value="'.$_POST['group_edit_id'].'" />';
+          <input type="hidden" name="group_edit_id" value="'.htmlspecialchars($_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">
@@ -2204,7 +1920,7 @@
     $db->free_result();
     echo '</table>
           </div>
-          <input type="hidden" name="group_edit_id" value="'.$_POST['group_edit_id'].'" />';
+          <input type="hidden" name="group_edit_id" value="'.htmlspecialchars($_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">
@@ -2229,7 +1945,7 @@
             </tr>
           </table>
           </div>
-          <input type="hidden" name="group_edit_id" value="'.$_POST['group_edit_id'].'" />';
+          <input type="hidden" name="group_edit_id" value="'.htmlspecialchars($_POST['group_edit_id']).'" />';
     echo '</form>';
     return;
   }
@@ -2682,129 +2398,6 @@
   echo '</form>';
 }
 
-function page_Admin_DBBackup()
-{
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  global $lang;
-  if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN )
-  {
-    $login_link = makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true);
-    echo '<h3>' . $lang->get('adm_err_not_auth_title') . '</h3>';
-    echo '<p>' . $lang->get('adm_err_not_auth_body', array( 'login_link' => $login_link )) . '</p>';
-    return;
-  }
-  
-  if ( ENANO_DBLAYER != 'MYSQL' )
-    die('<h3>Not supported</h3>
-          <p>This function is only supported under the MySQL database driver.</p>');
-  
-  if(isset($_GET['submitting']) && $_GET['submitting'] == 'yes' && defined('ENANO_DEMO_MODE') )
-  {
-    redirect(makeUrlComplete('Special', 'Administration'), 'Access denied', 'You\'ve got to be kidding me. Forget it, kid.', 4 );
-  }
-  
-  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(0);
-    // Do the actual export
-    $aesext = ( defined('SQL_BACKUP_CRYPT') ) ? '.tea' : '';
-    $filename = 'enano_backup_' . date('ymd') . '.sql' . $aesext;
-    ob_start();
-    // 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)
-    {
-      // THE FOLLOWING COMMENT DOES NOT APPLY AS OF 1.0.
-      // Sorry folks - this script CAN'T backup enano_files and enano_search_index due to the sheer size of the tables.
-      // If encryption is enabled the log data will be excluded too.
-      $result = export_table(
-        $t,
-        isset($_POST['do_struct']),
-        ( isset($_POST['do_data']) ),
-        false
-        ) . "\n";
-      if ( !$result )
-      {
-        $db->_die();
-      }
-      echo $result;
-    }
-    $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-disposition: attachment, filename="'.$filename.'";');
-    header('Content-type: application/transact-sql');
-    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
-         if ( ENANO_DBLAYER == 'MYSQL' )
-         {
-           $q = $db->sql_query('SHOW TABLES;') or $db->_die('Somehow we were denied the request to get the list of tables.');
-         }
-         else if ( ENANO_DBLAYER == 'PGSQL' )
-         {
-           $q = $db->sql_query('SELECT relname FROM pg_stat_user_tables ORDER BY relname;') 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
--- a/plugins/SpecialGroups.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/SpecialGroups.php	Thu Jan 03 00:53:33 2008 -0500
@@ -369,7 +369,7 @@
       foreach ( $pending as $member )
       {
         
-        $date = date('F d, Y', $member['reg_time']);
+        $date = enano_date('F d, Y', $member['reg_time']);
         $cls = ( $cls == 'row2' ) ? 'row1' : 'row2';
         $addy = $email->encryptEmail($member['email']);
         
@@ -415,7 +415,7 @@
       if ( $member['is_mod'] != 1 )
         break;
       
-      $date = date('F d, Y', $member['reg_time']);
+      $date = enano_date('F d, Y', $member['reg_time']);
       $cls = ( $cls == 'row2' ) ? 'row1' : 'row2';
       $addy = $email->encryptEmail($member['email']);
       
@@ -439,7 +439,7 @@
       if ( $member['is_mod'] == 1 )
         continue;
       
-      $date = date('F d, Y', $member['reg_time']);
+      $date = enano_date('F d, Y', $member['reg_time']);
       $cls = ( $cls == 'row2' ) ? 'row1' : 'row2';
       $addy = $email->encryptEmail($member['email']);
       
--- a/plugins/SpecialPageFuncs.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/SpecialPageFuncs.php	Thu Jan 03 00:53:33 2008 -0500
@@ -161,7 +161,7 @@
     if ( !$perms->get_permissions('create_page') )
       die_friendly($lang->get('pagetools_create_err_title'), '<p>An access control rule is preventing you from creating pages.</p>');
     
-    $q = $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.'\', \''.$urlname.'\', \''.$_POST['namespace'].'\');');
+    $q = $db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.time().', \''.enano_date('d M Y h:i a').'\', \'page\', \'create\', \''.$session->username.'\', \''.$urlname.'\', \''.$_POST['namespace'].'\');');
     if ( !$q )
     {
       $db->_die('The page log could not be updated.');
@@ -333,6 +333,8 @@
 {
   // This should be an easy one
   global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang;
+  
   $template->header();
   $sz = sizeof($paths->pages) / 2;
   echo '<p>' . $lang->get('pagetools_specialpages_blurb') . '</p><div class="tblholder"><table border="0" width="100%" cellspacing="1" cellpadding="4">';
--- a/plugins/SpecialUpdownload.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/SpecialUpdownload.php	Thu Jan 03 00:53:33 2008 -0500
@@ -33,7 +33,7 @@
       ));
     
     $paths->add_page(Array(
-      \'name\'=>\'download_file\',
+      \'name\'=>\'specialpage_download_file\',
       \'urlname\'=>\'DownloadFile\',
       \'namespace\'=>\'Special\',
       \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\',
@@ -154,13 +154,13 @@
     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.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.$utime.', \''.enano_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.');
+      if(!$db->sql_query('INSERT INTO '.table_prefix.'logs(time_id,date_string,log_type,action,author,page_id,namespace,edit_summary) VALUES('.$utime.', \''.enano_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>');
   }
@@ -235,7 +235,7 @@
   if ( $db->numrows() < 1 )
   {
     header('HTTP/1.1 404 Not Found');
-    die_friendly('File not found', '<p>The file "'.$filename.'" cannot be found.</p>');
+    die_friendly('File not found', '<p>The file "'.htmlspecialchars($filename).'" cannot be found.</p>');
   }
   $row = $db->fetchrow();
   $db->free_result();
@@ -307,7 +307,7 @@
     header('Content-disposition: attachment, filename="' . $filename . '";');
   }
   header('Content-length: '.$len);
-  header('Last-Modified: '.date('r', $row['time_id']));
+  header('Last-Modified: '.enano_date('r', $row['time_id']));
   
   // using this method limits RAM consumption
   while ( !feof($handle) )
--- a/plugins/SpecialUserFuncs.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/SpecialUserFuncs.php	Thu Jan 03 00:53:33 2008 -0500
@@ -517,7 +517,7 @@
     
     $captcharesult = $session->get_captcha($_POST['captchahash']);
     $session->kill_captcha();
-    if($captcharesult != $_POST['captchacode'])
+    if ( strtolower($captcharesult) != strtolower($_POST['captchacode']) )
     {
       $s = $lang->get('user_reg_err_captcha');
     }
@@ -946,10 +946,10 @@
   }
   else
   {
-    $year = intval( date('Y') );
+    $year = intval( enano_date('Y') );
     $year = $year - 13;
-    $month = date('F');
-    $day = date('d');
+    $month = enano_date('F');
+    $day = enano_date('d');
     
     $yo13_date = "$month $day, $year";
     $link_coppa_yes = makeUrlNS('Special', 'Register', 'coppa=yes', true);
@@ -1051,7 +1051,7 @@
     echo '<tr>';
     
     // date & time
-    echo '  <td class="' . $cls . '">' . date('d M Y h:i a', $row['time_id']) . '</td>';
+    echo '  <td class="' . $cls . '">' . enano_date('d M Y h:i a', $row['time_id']) . '</td>';
     
     // page & link to said page
     echo '  <td class="' . $cls . '"><a href="' . makeUrlNS($row['namespace'], $row['page_id']) . '">' . get_page_title_ns($row['page_id'], $row['namespace']) . '</a></td>';
@@ -1810,21 +1810,21 @@
   function format_date($time)
   {
     global $lang;
-    // Our formattting string to pass to date()
+    // Our formattting string to pass to enano_date()
     // This should not include minute/second info, only today's date in whatever format suits your fancy
     $formatstring = 'F j, Y';
     // Today's date
-    $today = date($formatstring);
+    $today = enano_date($formatstring);
     // Yesterday's date
-    $yesterday = date($formatstring, (time() - (24*60*60)));
+    $yesterday = enano_date($formatstring, (time() - (24*60*60)));
     // Date on the input
-    $then = date($formatstring, $time);
+    $then = enano_date($formatstring, $time);
     // "X days ago" logic
     for ( $i = 2; $i <= 6; $i++ )
     {
       // hours_in_day * minutes_in_hour * seconds_in_minute * num_days
       $offset = 24 * 60 * 60 * $i;
-      $days_ago = date($formatstring, (time() - $offset));
+      $days_ago = enano_date($formatstring, (time() - $offset));
       // so does the input timestamp match the date from $i days ago?
       if ( $then == $days_ago )
       {
@@ -1870,7 +1870,7 @@
     $lang_local = new Language($lang_id);
   
   
-  $timestamp = date('D, j M Y H:i:s T', $lang_local->lang_timestamp);
+  $timestamp = enano_date('D, j M Y H:i:s T', $lang_local->lang_timestamp);
   header("Last-Modified: $timestamp");
   header("Date: $timestamp");
   header('Content-type: text/javascript');
--- a/plugins/admin/PageGroups.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/admin/PageGroups.php	Thu Jan 03 00:53:33 2008 -0500
@@ -15,9 +15,12 @@
 function page_Admin_PageGroups()
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang;
   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>';
+    $login_link = makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true);
+    echo '<h3>' . $lang->get('adm_err_not_auth_title') . '</h3>';
+    echo '<p>' . $lang->get('adm_err_not_auth_body', array( 'login_link' => $login_link )) . '</p>';
     return;
   }
   
@@ -30,27 +33,27 @@
         case true:
           if ( empty($_POST['pg_name']) || empty($_POST['group_type']) )
           {
-            echo '<div class="error-box">Please enter a name for the page group.</div>';
+            echo '<div class="error-box">' . $lang->get('acppg_err_need_name') . '</div>';
             return;
           }
           if ( $_POST['group_type'] == PAGE_GRP_TAGGED && empty($_POST['member_tag']) )
           {
-            echo '<div class="error-box">Please enter a page tag.</div>';
+            echo '<div class="error-box">' . $lang->get('acppg_err_need_tag') . '</div>';
             return;
           }
           if ( $_POST['group_type'] == PAGE_GRP_CATLINK && empty($_POST['member_cat']) )
           {
-            echo '<div class="error-box">Please create a category page before linking a page group to a category.</div>';
+            echo '<div class="error-box">' . $lang->get('acppg_err_need_cat') . '</div>';
             return;
           }
           if ( $_POST['group_type'] == PAGE_GRP_NORMAL && empty($_POST['member_page_0']) )
           {
-            echo '<div class="error-box">Please specify at least one page to place in this group.</div>';
+            echo '<div class="error-box">' . $lang->get('acppg_err_need_page') . '</div>';
             return;
           }
           if ( $_POST['group_type'] == PAGE_GRP_REGEX && empty($_POST['regex']) )
           {
-            echo '<div class="error-box">Please specify a regular expression to match page IDs against.</div>';
+            echo '<div class="error-box">' . $lang->get('acppg_err_need_regex') . '</div>';
             return;
           }
           if ( $_POST['group_type'] != PAGE_GRP_TAGGED && $_POST['group_type'] != PAGE_GRP_CATLINK && $_POST['group_type'] != PAGE_GRP_NORMAL && $_POST['group_type'] != PAGE_GRP_REGEX )
@@ -117,7 +120,7 @@
                 $db->_die();
               break;
           }
-          echo '<div class="info-box">The page group "' . htmlspecialchars($_POST['pg_name']) . '" has been created.</div>';
+          echo '<div class="info-box">' . $lang->get('acppg_msg_create_success', array('group_name' => htmlspecialchars($_POST['pg_name']))) . '</div>';
           break;
       }
       // A little Javascript magic
@@ -295,7 +298,7 @@
       
       if ( $db->numrows() < 1 )
       {
-        $catlist = 'There aren\'t any categories on this site.';
+        $catlist = $lang->get('acppg_err_no_cats');
       }
       else
       {
@@ -316,14 +319,14 @@
       echo '<div class="tblholder">
             <table border="0" cellspacing="1" cellpadding="4">
               <tr>
-              <th colspan="2">Create page group</th>
+              <th colspan="2">' . $lang->get('acppg_th_create') . '</th>
               </tr>';
       
       // Name
       echo '<tr>
               <td class="row2">
-              Group name:<br />
-              <small>This should be short, descriptive, and human-readable.</small>
+              ' . $lang->get('acppg_field_group_name') . '<br />
+              <small>' . $lang->get('acppg_field_group_name_hint') . '</small>
               </td>
               <td class="row1">
               <input type="text" name="pg_name" size="30" />
@@ -333,14 +336,14 @@
       // Group type
       echo '<tr>
               <td class="row2">
-              Group type:
+              ' . $lang->get('acppg_field_group_type') . '
               </td>
               <td class="row1">
               <select name="group_type" onchange="pg_create_typeset(this);">
-                <option value="' . PAGE_GRP_NORMAL  . '" selected="selected">Static group of pages</option>
-                <option value="' . PAGE_GRP_TAGGED  . '">Group of pages with one tag</option>
-                <option value="' . PAGE_GRP_CATLINK . '">Link to category</option>
-                <option value="' . PAGE_GRP_REGEX   . '">Perl-compatible regular expression (advanced)</option>
+                <option value="' . PAGE_GRP_NORMAL  . '" selected="selected">' . $lang->get('acppg_gtype_static') . '</option>
+                <option value="' . PAGE_GRP_TAGGED  . '">' . $lang->get('acppg_gtype_tagged') . '</option>
+                <option value="' . PAGE_GRP_CATLINK . '">' . $lang->get('acppg_gtype_catlink') . '</option>
+                <option value="' . PAGE_GRP_REGEX   . '">' . $lang->get('acppg_gtype_regex_long') . '</option>
               </select>
               </td>
             </tr>';
@@ -349,16 +352,16 @@
       echo '<tr>
               <th colspan="2">
                 <span id="pg_create_title_normal">
-                  Static group of pages
+                  ' . $lang->get('acppg_gtype_static') . '
                 </span>
                 <span id="pg_create_title_tagged">
-                  Group of commonly tagged pages
+                  ' . $lang->get('acppg_gtype_tagged') . '
                 </span>
                 <span id="pg_create_title_catlink">
-                  Mirror a category
+                  ' . $lang->get('acppg_gtype_catlink') . '
                 </span>
                 <span id="pg_create_title_regex">
-                  Filter through a regular expression
+                  ' . $lang->get('acppg_gtype_regex') . '
                 </span>
               </th>
             </tr>';
@@ -366,24 +369,19 @@
       echo '<tr>
               <td class="row2">
                 <div id="pg_create_normal_1">
-                  Member pages:<br />
-                  <small>Click the "plus" button to add more fields.</small>
+                  ' . $lang->get('acppg_field_member_pages') . '<br />
+                  <small>' . $lang->get('acppg_field_member_pages_hint') . '</small>
                 </div>
                 <div id="pg_create_catlink_1">
-                  Include pages in this category:<br />
-                  <small>Pages in subcategories are <u>not</u> included, however subcategory pages themselves are.</small>
+                  ' . $lang->get('acppg_field_target_category') . '<br />
+                  <small>' . $lang->get('acppg_field_target_category_hint') . '</small>
                 </div>
                 <div id="pg_create_tagged_1">
-                  Include pages with this tag:
+                  ' . $lang->get('acppg_field_target_tag') . '
                 </div>
                 <div id="pg_create_regex_1">
-                  Regular expression:<br />
-                  <small>Be sure to include the starting and ending delimiters and any flags you might need.<br />
-                         These pages might help: <a href="http://us.php.net/manual/en/reference.pcre.pattern.modifiers.php">Pattern modifiers</a> &bull;
-                         <a href="http://us.php.net/manual/en/reference.pcre.pattern.syntax.php">Pattern syntax</a><br />
-                         Examples: <tt>/^(Special|Admin):/i</tt> &bull; <tt>/^Image:([0-9]+)$/</tt><br />
-                         Developers, remember that this will be matched against the full page identifier string. This means that <tt>/^About_Enano$/</tt>
-                         will NOT match the page Special:About_Enano.</small>
+                  ' . $lang->get('acppg_field_target_regex') . '<br />
+                  <small>' . $lang->get('acppg_field_target_regex_hint') . '</small>
               </td>';
             
       echo '  <td class="row1">
@@ -409,7 +407,7 @@
             
       // Submit button
       echo '<tr>
-              <th class="subhead" colspan="2"><input type="submit" name="action[create_stage2]" value="Create page group" style="font-weight: bold;" /> <input type="submit" name="action[noop]" value="Cancel" style="font-weight: normal;" /></th>
+              <th class="subhead" colspan="2"><input type="submit" name="action[create_stage2]" value="' . $lang->get('acppg_btn_create_finish') . '" style="font-weight: bold;" /> <input type="submit" name="action[noop]" value="' . $lang->get('etc_cancel') . '" style="font-weight: normal;" /></th>
             </tr>';
             
       echo '</table>
@@ -427,18 +425,18 @@
       
       if ( !empty($delete_id) )
       {
-        echo '<form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" onsubmit="if(!submitAuthorized) return false;" enctype="multipart/form-data">';
-        echo '<input type="hidden" name="delete_id" value="' . $delete_id . '" />';
-        echo '<div class="tblholder">';
-        echo '  <table border="0" cellspacing="1" cellpadding="4">';
-        echo '    <tr><th>Confirm deletion</th></tr>';
-        echo '    <tr><td class="row2" style="text-align: center; padding: 20px 0;">Are you sure you want to delete this page group?</td></tr>';
-        echo '    <tr><td class="row1" style="text-align: center;">';
-        echo '        <input type="submit" name="action[del_confirm]" value="Yes, delete group" style="font-weight: bold;" />';
-        echo '        <input type="submit" name="action[noop]" value="Cancel" style="font-weight: normal;" />';
-        echo '        </td></tr>';
-        echo '  </table>';
-        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">' . "\n";
+        echo '<input type="hidden" name="delete_id" value="' . $delete_id . '" />' . "\n";
+        echo '<div class="tblholder">' . "\n";
+        echo '  <table border="0" cellspacing="1" cellpadding="4">' . "\n";
+        echo '    <tr><th>' . $lang->get('acppg_th_delete_confirm') . '</th></tr>' . "\n";
+        echo '    <tr><td class="row2" style="text-align: center; padding: 20px 0;">' . $lang->get('acppg_msg_delete_confirm') . '</td></tr>' . "\n";
+        echo '    <tr><td class="row1" style="text-align: center;">' . "\n";
+        echo '        <input type="submit" name="action[del_confirm]" value="' . $lang->get('acppg_btn_delete_confirm') . '" style="font-weight: bold;" />' . "\n";
+        echo '        <input type="submit" name="action[noop]" value="' . $lang->get('etc_cancel') . '" style="font-weight: normal;" />' . "\n";
+        echo '        </td></tr>' . "\n";
+        echo '  </table>' . "\n";
+        echo '</form>' . "\n";
         
         return;
       }
@@ -471,7 +469,9 @@
       $q = $db->sql_query('DELETE FROM '.table_prefix.'page_group_members WHERE pg_id=' . $delete_id . ';');
       if ( !$q )
         $db->_die();
-      echo "<div class='info-box'>The group ".'"'.htmlspecialchars("$pg_name").'"'." has been deleted.</div>";
+      
+      $del_msg = $lang->get('acppg_msg_delete_success', array('pg_name' => htmlspecialchars($pg_name)));
+      echo "<div class=\"info-box\">$del_msg</div>";
     }
     else if ( isset($_POST['action']['edit']) && !isset($_POST['action']['noop']) )
     {
@@ -500,7 +500,7 @@
         $page = $_POST['new_page'];
         if ( empty($page) )
         {
-          $return = array('mode' => 'error', 'text' => 'Please enter a page title.');
+          $return = array('mode' => 'error', 'text' => $lang->get('acppg_err_ajaxadd_need_title'));
           echo enano_json_encode($return);
           return;
         }
@@ -534,7 +534,7 @@
         }
         if ( $db->numrows() > 0 )
         {
-          $return = array('mode' => 'error', 'text' => 'The page you are trying to add is already in this group.');
+          $return = array('mode' => 'error', 'text' => $lang->get('acppg_err_ajaxadd_already_in'));
           echo enano_json_encode($return);
           return;
         }
@@ -549,7 +549,7 @@
         
         $title = "($namespace) " . get_page_title($paths->nslist[$namespace] . $page_id);
         
-        $return = array('mode' => 'info', 'text' => 'The page has been added to the specified group.', 'successful' => true, 'title' => $title, 'member_id' => $db->insert_id());
+        $return = array('mode' => 'info', 'text' => $lang->get('acppg_ajaxadd_success'), 'successful' => true, 'title' => $title, 'member_id' => $db->insert_id());
         
         echo enano_json_encode($return);
         return;
@@ -565,7 +565,7 @@
           $new_name = $_POST['pg_name'];
           if ( empty($new_name) )
           {
-            echo '<div class="error-box">Please enter a valid name for this group.</div>';
+            echo '<div class="error-box">' . $lang->get('acppg_err_save_need_name') . '</div>';
           }
           else
           {
@@ -581,7 +581,7 @@
               if ( !$q )
                 $db->_die();
               else
-                echo '<div class="info-box">The group name was updated successfully.</div>';
+                echo '<div class="info-box">' . $lang->get('acppg_msg_save_name_updated') . '</div>';
             }
             if ( $_POST['pg_type'] == PAGE_GRP_TAGGED )
             {
@@ -589,7 +589,7 @@
               $target = sanitize_tag($target);
               if ( empty($target) )
               {
-                echo '<div class="error-box">Please enter a valid tag.</div>';
+                echo '<div class="error-box">' . $lang->get('acppg_err_save_need_tag') . '</div>';
               }
               else
               {
@@ -598,7 +598,7 @@
                 if ( !$q )
                   $db->_die();
                 else
-                  echo '<div class="info-box">The affecting tag was updated.</div>';
+                  echo '<div class="info-box">' . $lang->get('acppg_msg_save_tag_updated') . '</div>';
               }
             }
             else if ( $_POST['pg_type'] == PAGE_GRP_REGEX )
@@ -606,7 +606,7 @@
               $target = $_POST['pg_target'];
               if ( empty($target) )
               {
-                echo '<div class="error-box">Please enter an expression to match against..</div>';
+                echo '<div class="error-box">' . $lang->get('acppg_err_save_need_regex') . '</div>';
               }
               else
               {
@@ -615,7 +615,7 @@
                 if ( !$q )
                   $db->_die();
                 else
-                  echo '<div class="info-box">The expression to match against was updated.</div>';
+                  echo '<div class="info-box">' . $lang->get('acppg_msg_save_regex_updated') . '</div>';
               }
             }
             else if ( $_POST['pg_type'] == PAGE_GRP_CATLINK )
@@ -623,7 +623,7 @@
               $target = $_POST['pg_target'];
               if ( empty($target) )
               {
-                echo '<div class="error-box">No category ID specified on POST URI.</div>';
+                echo '<div class="error-box">' . $lang->get('acppg_err_save_bad_category') . '</div>';
               }
               else
               {
@@ -632,7 +632,7 @@
                 if ( !$q )
                   $db->_die();
                 else
-                  echo '<div class="info-box">The affecting category was updated.</div>';
+                  echo '<div class="info-box">' . $lang->get('acppg_msg_save_cat_updated') . '</div>';
               }
             }
           }
@@ -667,7 +667,7 @@
         $subquery = ( count($good) > 0 ) ? 'pg_member_id=' . implode(' OR pg_member_id=', $good) : "'foo'='bar'";
         if ( $subquery == "'foo'='bar'" )
         {
-          echo '<div class="warning-box">No pages were selected for deletion, and thus none were deleted.</div>';
+          echo '<div class="warning-box">' . $lang->get('acppg_err_save_no_pages') . '</div>';
         }
         else
         {
@@ -676,7 +676,7 @@
           {
             $db->_die();
           }
-          echo '<div class="info-box">The requested page group members have been deleted.</div>';
+          echo '<div class="info-box">' . $lang->get('acppg_msg_save_pages_deleted') . '</div>';
         }
       }
       
@@ -700,12 +700,12 @@
       echo '<div class="tblholder">
               <table border="0" cellspacing="1" cellpadding="4">
                 <tr>
-                  <th colspan="3">Editing page group: ' . htmlspecialchars($row['pg_name']) . '</th>
+                  <th colspan="3">' . $lang->get('acppg_th_editing_group') . ' ' . htmlspecialchars($row['pg_name']) . '</th>
                 </tr>';
       // Group name
       
       echo '    <tr>
-                  <td class="row2">Group name:</td>
+                  <td class="row2">' . $lang->get('acppg_field_group_name') . '</td>
                   <td class="row1" colspan="2"><input type="text" name="pg_name" value="' . htmlspecialchars($row['pg_name']) . '" size="30" /></td>
                 </tr>';
       
@@ -725,7 +725,7 @@
           // You have guessed correct.
           // *Sits in chair for 10 minutes listening to the radio in an effort to put off writing the code you see below*
           
-          echo '<tr><th colspan="3" class="subhead"><input type="submit" name="action[edit_save]" value="Save group name" /></th></tr>';
+          echo '<tr><th colspan="3" class="subhead"><input type="submit" name="action[edit_save]" value="' . $lang->get('acppg_btn_save_name') . '" /></th></tr>';
           echo '</table></div>';
           echo '</form>';
           echo '<form name="pg_static_rm_frm" action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post" enctype="multipart/form-data">';
@@ -733,7 +733,7 @@
           echo '<div class="tblholder">
                   <table border="0" cellspacing="1" cellpadding="4">
                     <tr>
-                      <th colspan="3">Remove pages from this group</th>
+                      <th colspan="3">' . $lang->get('acppg_th_remove_selected') . '</th>
                     </tr>';
           
           $q = $db->sql_query('SELECT m.pg_member_id,m.page_id,m.namespace FROM '.table_prefix.'page_group_members AS m
@@ -744,11 +744,11 @@
           if ( !$q )
             $db->_die();
           
-          $delim = ceil( $db->numrows() / 2 );
+          $delim = ceil( $db->numrows($q) / 2 );
           if ( $delim < 5 )
           {
             $delim = 0xFFFFFFFE;
-            // stupid hack
+            // stupid hack. I'm XSSing my own code.
             $colspan = '2" id="pg_edit_tackon2me';
           }
           else
@@ -756,10 +756,10 @@
             $colspan = "1";
           }
           
-          echo '<tr><td class="row2" rowspan="2"><b>Remove</b> pages:</td><td class="row1" colspan="' . $colspan . '">';
+          echo '<tr><td class="row2" rowspan="2">' . $lang->get('acppg_field_remove') . '</td><td class="row1" colspan="' . $colspan . '">';
           $i = 0;
           
-          while ( $row = $db->fetchrow() )
+          while ( $row = $db->fetchrow($q) )
           {
             $i++;
             if ( $i == $delim )
@@ -771,7 +771,7 @@
           }
           
           echo '</td></tr>';
-          echo '<tr><th colspan="2" class="subhead" style="width: 70%;"><input type="submit" name="action[edit_save][do_rm]" value="Remove selected" /></th></tr>';
+          echo '<tr><th colspan="2" class="subhead" style="width: 70%;"><input type="submit" name="action[edit_save][do_rm]" value="' . $lang->get('acppg_btn_do_remove') . '" /></th></tr>';
           
           // More javascript magic!
           ?>
@@ -781,7 +781,10 @@
             {
               var input = document.getElementById('inptext_pg_add_member');
               input.onkeyup = function(e) { ajaxPageNameComplete(this); };
-              input.onkeypress = function(e) { if ( e.keyCode == 13 ) { setTimeout('__pg_edit_ajaxadd(document.getElementById(\'' + this.id + '\'));', 500); } };
+              <?php
+              // stupid jEdit hack
+              echo "input.onkeypress = function(e) { if ( e.keyCode == 13 ) { setTimeout('__pg_edit_ajaxadd(document.getElementById(\'' + this.id + '\'));', 500); } };";
+              ?>
             }
             addOnloadHook(__ol_pg_edit_setup);
             var __pg_edit_objcache = false;
@@ -869,7 +872,7 @@
         case PAGE_GRP_TAGGED:
           echo '<tr>
                   <td class="row2">
-                    Include pages with this tag:
+                    ' . $lang->get('acppg_field_target_tag') . '
                   </td>
                   <td class="row1">
                     <input type="text" name="pg_target" value="' . htmlspecialchars($row['pg_target']) . '" size="30" />
@@ -879,13 +882,8 @@
         case PAGE_GRP_REGEX:
           echo '<tr>
                   <td class="row2">
-                    Regular expression to use:<br />
-                    <small>Be sure to include the starting and ending delimiters and any flags you might need.<br />
-                           These pages might help: <a href="http://us.php.net/manual/en/reference.pcre.pattern.modifiers.php">Pattern modifiers</a> &bull;
-                           <a href="http://us.php.net/manual/en/reference.pcre.pattern.syntax.php">Pattern syntax</a><br />
-                           Examples: <tt>/^(Special|Admin):/i</tt> &bull; <tt>/^Image:([0-9]+)$/</tt><br />
-                           Developers, remember that this will be matched against the full page identifier string. This means that <tt>/^About_Enano$/</tt>
-                           will NOT match the page Special:About_Enano.</small>
+                    ' . $lang->get('acppg_field_target_regex') . '<br />
+                    <small>' . $lang->get('acppg_field_target_regex_hint') . '</small>
                   </td>
                   <td class="row1">
                     <input type="text" name="pg_target" value="' . htmlspecialchars($row['pg_target']) . '" size="30" />
@@ -916,11 +914,8 @@
           
           echo '<tr>
                   <td class="row2">
-                    Include pages that are in this category:<br />
-                    <small><b>Reminder:</b> Enano does not automatically place any access controls on the category. If you
-                           don\'t want users to be able to freely add and remove pages from the category (assuming Wiki Mode is enabled
-                           for the category) then you need to enable protection on the category using the button on the more options menu.
-                           </small>
+                    ' . $lang->get('acppg_field_target_category') . '<br />
+                    <small>' . $lang->get('acppg_field_target_category_hint2') . '</small>
                   </td>
                   <td class="row1">
                     ' . $catlist . '
@@ -932,13 +927,13 @@
       
       if ( $ajax_page_add )
       {
-        echo '<tr><th colspan="3"><input type="submit" name="action[noop]" value="Cancel all changes" /></th></tr>';
+        echo '<tr><th colspan="3"><input type="submit" name="action[noop]" value="' . $lang->get('acppg_btn_cancel_all') . '" /></th></tr>';
       }
       else
       {
         echo '<tr><th colspan="3" class="subhead">
-                <input type="submit" name="action[edit_save]" value="Save and update" />
-                <input type="submit" name="action[noop]" value="Cancel all changes" />
+                <input type="submit" name="action[edit_save]" value="' . $lang->get('acppg_btn_save_update') . '" />
+                <input type="submit" name="action[noop]" value="' . $lang->get('acppg_btn_cancel_all') . '" />
               </th></tr>';
       }
       
@@ -950,10 +945,10 @@
       {
         // This needs to be outside of the form.
         echo '<div class="tblholder"><table border="0" cellspacing="1" cellpadding="4"><tr>';
-        echo '<th colspan="2">On-the-fly tools</th></tr>';
+        echo '<th colspan="2">' . $lang->get('acppg_th_onthefly') . '</th></tr>';
         echo '<tr>';
         // Add pages AJAX form
-        echo '<td class="row2">Add page:<br /><small>You can add multiple pages by entering part of a page title, and it will be auto-completed. Press Enter to quickly add the page. This only works if you a really up-to-date browser.</small></td>';
+        echo '<td class="row2">' . $lang->get('acppg_field_add_page') . '<br /><small>' . $lang->get('acppg_field_add_page_hint') . '</small></td>';
         echo '<td class="row1"><input type="text" size="30" name="pg_add_member" id="inptext_pg_add_member" /></td>';
         echo '</tr></table></div>';
       }
@@ -971,8 +966,8 @@
   }
   // No action defined - show default menu
   
-  echo '<h2>Manage page groups</h2>';
-  echo '<p>Enano\'s page grouping system allows you to build sets of pages that can be controlled by a single ACL rule. This makes managing features such as a members-only section of your site a lot easier. If you don\'t use the ACL system, you probably don\'t need to use page groups.</p>';
+  echo '<h2>' . $lang->get('acppg_heading_main') . '</h2>';
+  echo '<p>' . $lang->get('acppg_hint_intro') . '</p>';
   
   $q = $db->sql_query('SELECT pg_id, pg_type, pg_name, pg_target FROM '.table_prefix.'page_groups;');
   if ( !$q )
@@ -983,13 +978,13 @@
   echo '<div class="tblholder">
           <table border="0" cellspacing="1" cellpadding="4">
             <tr>
-              <th>Group name</th>
-              <th>Type</th>
-              <th>Target</th>
-              <th colspan="2">Actions</th>
+              <th>' . $lang->get('acppg_col_group_name') . '</th>
+              <th>' . $lang->get('acppg_col_type') . '</th>
+              <th>' . $lang->get('acppg_col_target') . '</th>
+              <th colspan="2">' . $lang->get('acppg_col_actions') . '</th>
             </tr>';
   
-  if ( $row = $db->fetchrow() )
+  if ( $row = $db->fetchrow($q) )
   {
     do
     {
@@ -998,53 +993,51 @@
       switch ( $row['pg_type'] )
       {
         case PAGE_GRP_CATLINK:
-          $type = 'Link to category';
+          $type = $lang->get('acppg_gtype_catlink');
           break;
         case PAGE_GRP_TAGGED:
-          $type = 'Set of tagged pages';
+          $type = $lang->get('acppg_gtype_tagged');
           break;
         case PAGE_GRP_NORMAL:
-          $type = 'Static set of pages';
+          $type = $lang->get('acppg_gtype_static');
           break;
         case PAGE_GRP_REGEX:
-          $type = 'Regular expression match';
+          $type = $lang->get('acppg_gtype_regex');
           break;
       }
       $target = '';
       if ( $row['pg_type'] == PAGE_GRP_TAGGED )
       {
-        $target = 'Tag: ' . htmlspecialchars($row['pg_target']);
+        $target = $lang->get('acppg_lbl_tag') . ' ' . htmlspecialchars($row['pg_target']);
       }
       else if ( $row['pg_type'] == PAGE_GRP_CATLINK )
       {
-        $target = 'Category: ' . htmlspecialchars(get_page_title($paths->nslist['Category'] . sanitize_page_id($row['pg_target'])));
+        $target = $lang->get('acppg_lbl_category') . ' ' . htmlspecialchars(get_page_title($paths->nslist['Category'] . sanitize_page_id($row['pg_target'])));
       }
       else if ( $row['pg_type'] == PAGE_GRP_REGEX )
       {
-        $target = 'Expression: <tt>' . htmlspecialchars($row['pg_target']) . '</tt>';
+        $target = $lang->get('acppg_lbl_regex') . ' <tt>' . htmlspecialchars($row['pg_target']) . '</tt>';
       }
-      $btn_edit = '<input type="submit" name="action[edit][' . $row['pg_id'] . ']" value="Edit" />';
-      $btn_del = '<input type="submit" name="action[del][' . $row['pg_id'] . ']" value="Delete" />';
-      // stupid jEdit bug/hack
-      $quot = '"';
+      $btn_edit = '<input type="submit" name="action[edit][' . $row['pg_id'] . ']" value="' . $lang->get('acppg_btn_edit') . '" />';
+      $btn_del = '<input type="submit" name="action[del][' . $row['pg_id'] . ']" value="' . $lang->get('acppg_btn_delete') . '" />';
       echo "<tr>
-              <td class={$quot}row1{$quot}>$name</td>
-              <td class={$quot}row2{$quot}>$type</td>
-              <td class={$quot}row1{$quot}>$target</td>
-              <td class={$quot}row3{$quot} style={$quot}text-align: center;{$quot}>$btn_edit</td>
-              <td class={$quot}row3{$quot} style={$quot}text-align: center;{$quot}>$btn_del</td>
+              <td class=\"row1\">$name</td>
+              <td class=\"row2\">$type</td>
+              <td class=\"row1\">$target</td>
+              <td class=\"row3\" style=\"text-align: center;\">$btn_edit</td>
+              <td class=\"row3\" style=\"text-align: center;\">$btn_del</td>
             </tr>";
     }
-    while ( $row = $db->fetchrow() );
+    while ( $row = $db->fetchrow($q) );
   }
   else
   {
-    echo '  <tr><td class="row3" colspan="5" style="text-align: center;">No page groups defined.</td></tr>';
+    echo '  <tr><td class="row3" colspan="5" style="text-align: center;">' . $lang->get('acppg_msg_no_groups') . '</td></tr>';
   }
   
   echo '    <tr>
               <th class="subhead" colspan="5">
-                <input type="submit" name="action[create]" value="Create new group" />
+                <input type="submit" name="action[create]" value="' . $lang->get('acppg_btn_create_new') . '" />
               </th>
             </tr>';
   
--- a/plugins/admin/PageManager.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/admin/PageManager.php	Thu Jan 03 00:53:33 2008 -0500
@@ -569,7 +569,14 @@
   }
   $title = get_page_title_ns($row['urlname'], $row['namespace']);
   $pathskey = $paths->nslist[$row['namespace']] . $row['urlname'];
-  $url = makeUrlNS('Special', 'Administration', "module={$paths->nslist['Admin']}PageManager&action=select&page_id=$pathskey", true);
+  if ( isset($row['mode']) && $row['mode'] == 'edit' )
+  {
+    $url = makeUrlNS($row['namespace'], $row['urlname'], false, true) . '#do:edit';
+  }
+  else
+  {
+    $url = makeUrlNS('Special', 'Administration', "module={$paths->nslist['Admin']}PageManager&action=select&page_id=$pathskey", true);
+  }
   $url = '<a href="' . $url . '">' . htmlspecialchars($title) . '</a>';
   $return .= '  <td class="' . $td_class . '" style="width: 33%;">' . $url . '</td>' . "\n";
   $cell_count++;
--- a/plugins/admin/SecurityLog.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/admin/SecurityLog.php	Thu Jan 03 00:53:33 2008 -0500
@@ -161,7 +161,7 @@
     case "u_to_admin":       $return .= "User {$r['page_text']} added to Administrators group"; break;
     case "u_to_mod":         $return .= "User {$r['page_text']} added to Moderators group"; break;
   }
-  $return .= '</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>';
+  $return .= '</td><td class="'.$cls.'">'.enano_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>';
   return $return;
 }
 
--- a/plugins/admin/UserManager.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/plugins/admin/UserManager.php	Thu Jan 03 00:53:33 2008 -0500
@@ -36,7 +36,7 @@
     
     if ( defined('ENANO_DEMO_MODE') )
     {
-      $errors[] = 'Users cannot be modified or deleted in demo mode.';
+      $errors[] = $lang->get('acpum_err_nosave_demo');
     }
     
     $user_id = intval($_POST['user_id']);
@@ -51,7 +51,7 @@
       $q = $db->sql_query('DELETE FROM '.table_prefix."users WHERE user_id=$user_id;");
       if ( !$q )
         $db->_die();
-      echo '<div class="info-box">The user account has been deleted.</div>';
+      echo '<div class="info-box">' . $lang->get('acpum_msg_delete_success') . '</div>';
     }
     else
     {
@@ -66,7 +66,7 @@
       {
         $username = $_POST['username'];
         if ( !preg_match('#^'.$session->valid_username.'$#', $username) )
-          $errors[] = 'The username you entered contains invalid characters.';
+          $errors[] = $lang->get('acpum_err_illegal_username');
         
         $password = false;
         if ( $_POST['changing_pw'] == 'yes' )
@@ -82,13 +82,13 @@
           }
           else
           {
-            $errors[] = 'Session manager denied public encryption key lookup request';
+            $errors[] = $lang->get('acpum_err_no_aes_key');
           }
         }
         
         $email = $_POST['email'];
         if ( !preg_match('/^(?:[\w\d]+\.?)+@((?:(?:[\w\d]\-?)+\.)+\w{2,4}|localhost)$/', $email) )
-          $errors[] = 'You have entered an invalid e-mail address.';
+          $errors[] = $lang->get('acpum_err_illegal_email');
         
         $real_name = $_POST['real_name'];
       }
@@ -389,7 +389,7 @@
             }
           }
           
-          echo '<div class="info-box">Your changes have been saved.</div>';
+          echo '<div class="info-box">' . $lang->get('acpum_msg_save_success') . '</div>';
         }
       }
     }
@@ -397,7 +397,7 @@
     if ( count($errors) > 0 )
     {
       echo '<div class="error-box">
-              <b>Your request could not be processed due to the following validation errors:</b>
+              <b>' . $lang->get('acpum_err_validation_fail') . '</b>
               <ul>
                 <li>' . implode("</li>\n        <li>", $errors) . '</li>
               </ul>
@@ -455,7 +455,7 @@
     
     if ( $db->numrows() < 1 )
     {
-      echo '<div class="error-box">The username you entered could not be found.</div>';
+      echo '<div class="error-box">' . $lang->get('acpum_err_bad_username') . '</div>';
     }
     else
     {
@@ -501,7 +501,7 @@
   {
     if ( defined('ENANO_DEMO_MODE') )
     {
-      echo '<div class="error-box">Sorry Charlie, no can do. You might mess up other people logged into the demo site.</div>';
+      echo '<div class="error-box">' . $lang->get('acpum_err_sessionclear_demo') . '</div>';
     }
     else
     {
@@ -534,27 +534,27 @@
       $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 '<div class="info-box">' . $lang->get('acpum_msg_sessionclear_success') . '</div>';
     }
   }
   echo '<form action="' . makeUrlNS('Special', 'Administration', 'module=' . $paths->cpage['module'], true) . '" method="post" enctype="multipart/form-data" onsubmit="if ( !submitAuthorized ) return false;">';
-  echo '<h3>User administration panel</h3>';
-  echo '<p>From this panel you can modify or delete user accounts.</p>';
+  echo '<h3>' . $lang->get('acpum_heading_main') . '</h3>';
+  echo '<p>' . $lang->get('acpum_hint_intro') . '</p>';
   echo '<table border="0">
           <tr>
-            <td><b>Search for user:</b><br />
-                <small>If your browser supports AJAX, this will provide suggestions for you.</small>
+            <td><b>' . $lang->get('acpum_field_search_user') . '</b><br />
+                <small>' . $lang->get('acpum_field_search_user_hint') . '</small>
                 </td>
             <td style="width: 10px;"></td>
             <td>' . $template->username_field('username') . '</td>
             <td>
-              <input type="submit" name="action[go]" value="Go &raquo;" />
+              <input type="submit" name="action[go]" value="' . $lang->get('acpum_btn_search_user_go') . ' &raquo;" />
             </td>
           </tr>
         </table>';
-  echo '<h3>Clear session key table</h3>';
-  echo '<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. If you do this, all users besides you will be logged off, so be sure to do this at a time when traffic is low.</p>';
-  echo '<p><input type="submit" name="action[clear_sessions]" value="Clear session keys" /></p>';
+  echo '<h3>' . $lang->get('acpum_heading_clear_sessions') . '</h3>';
+  echo '<p>' . $lang->get('acpum_hint_clear_sessions') . '</p>';
+  echo '<p><input type="submit" name="action[clear_sessions]" value="' . $lang->get('acpum_btn_clear_sessions') . '" /></p>';
   echo '</form>';
   
   if(isset($_GET['action']) && isset($_GET['user']))
@@ -563,22 +563,47 @@
     {
       case "activate":
         $e = $db->sql_query('SELECT activation_key FROM '.table_prefix.'users WHERE username=\'' . $db->escape($_GET['user']) . '\'');
-        if($e)
+        if ( $e )
         {
+          // attempt to activate the account
           $row = $db->fetchrow();
           $db->free_result();
-          if($session->activate_account($_GET['user'], $row['activation_key'])) { echo '<div class="info-box">The user account "' . htmlspecialchars($_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 "' . htmlspecialchars($_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>';
+          if ( $session->activate_account($_GET['user'], $row['activation_key']) )
+          {
+            echo '<div class="info-box">' . $lang->get('acpum_msg_activate_success', array('username' => htmlspecialchars($_GET['user']))) . '</div>';
+            $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE time_id=' . $db->escape($_GET['logid']));
+          }
+          else
+          {
+            echo '<div class="warning-box">' . $lang->get('acpum_err_activate_fail', array('username' => htmlspecialchars($_GET['user']))) . '</div>';
+          }
+        }
+        else
+        {
+          echo '<div class="error-box">Error activating account: '.$db->get_error().'</div>';
+        }
         break;
       case "sendemail":
-        if($session->send_activation_mail($_GET['user'])) { echo '<div class="info-box">The user "' . htmlspecialchars($_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 "' . htmlspecialchars($_GET['user']) . '" has not been activated, probably because of a bad SMTP configuration.</div>';
+        if ( $session->send_activation_mail($_GET['user'] ) )
+        {
+          echo '<div class="info-box">' . $lang->get('acpum_msg_activate_email_success', array('username' => htmlspecialchars($_GET['user']))) . '</div>';
+          $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE time_id=' . $db->escape($_GET['logid']));
+        }
+        else
+        {
+          echo '<div class="error-box">' . $lang->get('acpum_err_activate_email_fail', array('username' => htmlspecialchars($_GET['user']))) . '</div>';
+        }
         break;
       case "deny":
         $e = $db->sql_query('DELETE FROM '.table_prefix.'logs WHERE log_type=\'admin\' AND action=\'activ_req\' AND time_id=\'' . $db->escape($_GET['logid']) . '\';');
-        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 "' . htmlspecialchars($_GET['user']) . '" have been deleted.</div>';
+        if ( !$e )
+        {
+          echo '<div class="error-box">Error during row deletion: '.$db->get_error().'</div>';
+        }
+        else
+        {
+          echo '<div class="info-box">' . $lang->get('acpum_msg_activate_deny_success', array('username' => htmlspecialchars($_GET['user']))) . '</div>';
+        }
         break;
     }
   }
@@ -591,19 +616,42 @@
     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>';
+      $str = ( $n == 1 ) ?
+        $lang->get('acpum_heading_activation_one') :
+        $lang->get('acpum_heading_activation_plural', array('count' => strval($n)));
+        
+      echo '<h3>' . $str . '</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>COPPA user</th><th colspan="3">Actions</th></tr>';
+              <table border="0" cellspacing="1" cellpadding="4" width="100%">
+                <tr>
+                  <th>' . $lang->get('acpum_col_activate_timestamp') . '</th>
+                  <th>' . $lang->get('acpum_col_activate_requestedby') . '</th>
+                  <th>' . $lang->get('acpum_col_activate_requestedfor') . '</th>
+                  <th>' . $lang->get('acpum_col_activate_coppauser') . '</th>
+                  <th colspan="3">' . $lang->get('acpum_col_activate_actions') . '</th>
+                </tr>';
       $cls = 'row2';
       while($row = $db->fetchrow())
       {
         if($cls == 'row2') $cls = 'row1';
         else $cls = 'row2';
-        $coppa = ( $row['user_coppa'] == '1' ) ? '<b>Yes</b>' : 'No';
-        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 style="text-align: center;" class="' . $cls . '">' . $coppa . '</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>';
+        $coppa = ( $row['user_coppa'] == '1' ) ? '<b>' . $lang->get('acpum_coppauser_yes') . '</b>' : $lang->get('acpum_coppauser_no');
+        echo '<tr>
+                <td class="'.$cls.'">'.enano_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 style="text-align: center;" class="' . $cls . '">' . $coppa . '</td>
+                <td class="'.$cls.'" style="text-align: center;">
+                  <a href="'.makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'UserManager&action=activate&user='.rawurlencode($row['edit_summary']).'&logid='.$row['time_id'], true).'">' . $lang->get('acpum_btn_activate_now') . '</a>
+                </td>
+                <td class="'.$cls.'" style="text-align: center;">
+                  <a href="'.makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'UserManager&action=sendemail&user='.rawurlencode($row['edit_summary']).'&logid='.$row['time_id'], true).'">' . $lang->get('acpum_btn_send_email') . '</a>
+                </td>
+                <td class="'.$cls.'" style="text-align: center;">
+                  <a href="'.makeUrlNS('Special', 'Administration', 'module='.$paths->nslist['Admin'].'UserManager&action=deny&user='.rawurlencode($row['edit_summary']).'&logid='.$row['time_id'], true).'">' . $lang->get('acpum_btn_activate_deny') . '</a>
+                </td>
+              </tr>';
       }
       echo '</table>';
     }
@@ -768,7 +816,7 @@
             {
               if ( form.new_password.value != form.new_password_confirm.value )
               {
-                alert('The passwords you entered did not match.');
+                alert(\$lang.get('user_reg_err_alert_password_nomatch'));
                 return false;
               }
               form.new_password_confirm.value = '';
@@ -790,7 +838,7 @@
             
               <tr>
                 <th colspan="2">
-                  Editing user: {USERNAME}
+                  {lang:acpum_heading_editing_user} {USERNAME}
                 </th>
               </tr>
               
@@ -798,35 +846,36 @@
               
                 <tr>
                   <th colspan="2" class="subhead">
-                    Basic options
+                    {lang:acpum_heading_basic_options}
                   </th>
                 </tr>
                 
                 <tr>
                   <td class="row2" style="width: 25%;">
-                    Username:<br />
-                    <small>Must be at least 2 characters in length</small>
+                    {lang:acpum_field_username}<br />
+                    <small>{lang:acpum_field_username_hint}</small>
                   </td>
                   <td class="row1" style="width: 75%;">
-                    <input type="text" name="username" value="{USERNAME}" size="40" <!-- BEGIN same_user -->disabled="disabled" <!-- END same_user -->/><!-- BEGIN same_user --> <small>You cannot change your own username. To change your username you must log into a different administrative account.</small><!-- END same_user -->
+                    <input type="text" name="username" value="{USERNAME}" size="40" <!-- BEGIN same_user -->disabled="disabled" <!-- END same_user -->/>
+                    <!-- BEGIN same_user --><small>{lang:acpum_msg_same_user_username}</small><!-- END same_user -->
                   </td>
                 </tr>
                 
                 <tr>
                   <td class="row2">
-                    Password:
+                    {lang:acpum_field_password}
                     <!-- BEGIN password_meter -->
                     <br />
-                    <small>Password strength requirements are not enforced here.</small>
+                    <small>{lang:acpum_field_password_hint}</small>
                     <!-- END password_meter -->
                   </td>
                   <td class="row1">
                     <div id="userform_{UUID}_pwlink">
-                      <b>Password will be left unchanged.</b> <a href="#" onclick="userform_{UUID}_chpasswd(); return false;">Reset password...</a>
+                      <b>{lang:acpum_msg_password_unchanged}</b> <a href="#" onclick="userform_{UUID}_chpasswd(); return false;">{lang:acpum_btn_reset_password}</a>
                     </div>
                     <div id="userform_{UUID}_pwform" style="display: none;">
                       <!-- BEGIN same_user -->
-                      To change your password, please use the user preferences panel. <a href="#" onclick="userform_{UUID}_chpasswd_cancel(); return false;">Cancel</a>
+                        {lang:acpum_msg_same_user_password} <a href="#" onclick="userform_{UUID}_chpasswd_cancel(); return false;">{lang:etc_cancel}</a>
                       <!-- BEGINELSE same_user -->
                       <input type="hidden" name="changing_pw" value="no" />
                       <input type="hidden" name="challenge_data" value="{MD5_CHALLENGE}" />
@@ -836,11 +885,12 @@
                       <table border="0" style="background-color: transparent;" cellspacing="0" cellpadding="0">
                         <tr>
                           <td colspan="2">
-                            <b>Change password to:</b>
+                            <b>{lang:acpum_field_password_title}</b>
                           </td>
                         </tr>
                         <tr>
-                          <td>New password:</td>
+                          <td>{lang:acpum_field_newpassword}</td>
+                          <!-- FIXME: localize password strength widget -->
                           <td><input type="password" name="new_password" value="" <!-- BEGIN password_meter -->onkeyup="password_score_field(this);" /><span class="password-checker" style="font-weight: bold; color: #AA0000"> Weak (score: -10)</span><!-- BEGINELSE password_meter --> /><!-- END password_meter -->
                             <!-- BEGIN password_meter -->
                               <div id="pwmeter" style="margin: 4px 0; height: 8px;"></div>
@@ -848,12 +898,12 @@
                           </td>
                         </tr>
                         <tr>
-                          <td>Confirm:</td>
+                          <td>{lang:acpum_field_newpassword_confirm}</td>
                           <td><input type="password" name="new_password_confirm" value="" /></td>
                         </tr>
                         <tr>
                           <td colspan="2">
-                            <a href="#" onclick="userform_{UUID}_chpasswd_cancel(); return false;">Cancel</a>
+                            <a href="#" onclick="userform_{UUID}_chpasswd_cancel(); return false;">{lang:etc_cancel}</a>
                           </td>
                         </tr>
                       </table>
@@ -864,25 +914,27 @@
                 
                 <tr>
                   <td class="row2" style="width: 25%;">
-                    E-mail address:
+                    {lang:acpum_field_email}
                   </td>
                   <td class="row1" style="width: 75%;">
-                    <input type="text" name="email" value="{EMAIL}" size="40" <!-- BEGIN same_user -->disabled="disabled" <!-- END same_user -->/><!-- BEGIN same_user --> <small>To change your e-mail address, please use the user preferences panel.</small><!-- END same_user -->
+                    <input type="text" name="email" value="{EMAIL}" size="40" <!-- BEGIN same_user -->disabled="disabled" <!-- END same_user -->/>
+                    <!-- BEGIN same_user --><small>{lang:acpum_msg_same_user_email}</small><!-- END same_user -->
                   </td>
                 </tr>
                 
                 <tr>
                   <td class="row2" style="width: 25%;">
-                    Real name:
+                    {lang:acpum_field_realname}
                   </td>
                   <td class="row1" style="width: 75%;">
-                    <input type="text" name="real_name" value="{REAL_NAME}" size="40" <!-- BEGIN same_user -->disabled="disabled" <!-- END same_user -->/><!-- BEGIN same_user --> <small>To change your real name on file, please use the user preferences panel.</small><!-- END same_user -->
+                    <input type="text" name="real_name" value="{REAL_NAME}" size="40" <!-- BEGIN same_user -->disabled="disabled" <!-- END same_user -->/>
+                    <!-- BEGIN same_user --><small>{lang:acpum_msg_same_user_realname}</small><!-- END same_user -->
                   </td>
                 </tr>
                 
                 <tr>
                   <td class="row2" style="width: 25%;">
-                    Signature:
+                    {lang:acpum_field_signature}
                   </td>
                   <td class="row1" style="width: 75%;">
                     {SIGNATURE_FIELD}
@@ -895,47 +947,47 @@
               
                 <tr>
                   <th class="subhead" colspan="2">
-                    Instant messenger contact information
+                    {lang:acpum_heading_imcontact}
                   </th>
                 <tr>
-                  <td class="row2">AIM handle:</td>
+                  <td class="row2">{lang:acpum_field_aim}</td>
                   <td class="row1"><input type="text" name="imaddr_aim" value="{IM_AIM}" size="30" /></td>
                 </tr>
                 <tr>
-                  <td class="row2"><acronym title="Windows&trade; Live Messenger">WLM</acronym> handle:<br /><small>If you don't specify the domain (@whatever.com), "@hotmail.com" will be assumed.</small></td>
+                  <td class="row2">{lang:acpum_field_wlm}<br /><small>{lang:acpum_field_wlm_hint}</small></td>
                   <td class="row1"><input type="text" name="imaddr_msn" value="{IM_WLM}" size="30" /></td>
                 </tr>
                 <tr>
-                  <td class="row2">Yahoo! IM handle:</td>
+                  <td class="row2">{lang:acpum_field_yim}</td>
                   <td class="row1"><input type="text" name="imaddr_yahoo" value="{IM_YAHOO}" size="30" /></td>
                 </tr>
                 <tr>
-                  <td class="row2">Jabber/XMPP handle:</td>
+                  <td class="row2">{lang:acpum_field_xmpp}</td>
                   <td class="row1"><input type="text" name="imaddr_xmpp" value="{IM_XMPP}" size="30" /></td>
                 </tr>
                 <tr>
                   <th class="subhead" colspan="2">
-                    Extra contact information
+                    {lang:acpum_heading_contact_extra}
                   </th>
                 </tr>
                 <tr>
-                  <td class="row2">Homepage:<br /><small>Please remember the http:// prefix.</small></td>
+                  <td class="row2">{lang:acpum_field_homepage}<br /><small>{lang:acpum_field_homepage_hint}</small></td>
                   <td class="row1"><input type="text" name="homepage" value="{HOMEPAGE}" size="30" /></td>
                 </tr>
                 <tr>
-                  <td class="row2">Location:</td>
+                  <td class="row2">{lang:acpum_field_location}</td>
                   <td class="row1"><input type="text" name="location" value="{LOCATION}" size="30" /></td>
                 </tr>
                 <tr>
-                  <td class="row2">Job:</td>
+                  <td class="row2">{lang:acpum_field_job}</td>
                   <td class="row1"><input type="text" name="occupation" value="{JOB}" size="30" /></td>
                 </tr>
                 <tr>
-                  <td class="row2">Hobbies:</td>
+                  <td class="row2">{lang:acpum_field_hobbies}</td>
                   <td class="row1"><input type="text" name="hobbies" value="{HOBBIES}" size="30" /></td>
                 </tr>
                 <tr>
-                  <td class="row2"><label for="chk_email_public_{UUID}">E-mail address is public</label><br /><small>If this is checked, the user's e-mail address will be displayed on your the page. To protect the address from spambots, it will be encrypted.</small></td>
+                  <td class="row2"><label for="chk_email_public_{UUID}">{lang:acpum_field_email_public}</label><br /><small>{lang:acpum_field_email_public_hint}</small></td>
                   <td class="row1"><input type="checkbox" id="chk_email_public_{UUID}" name="email_public" <!-- BEGIN email_public -->checked="checked" <!-- END email_public -->size="30" /></td>
                 </tr>
               
@@ -945,7 +997,7 @@
               
                 <tr>
                   <th class="subhead" colspan="2">
-                    {lang:adminusers_avatar_heading}
+                    {lang:acpum_avatar_heading}
                   </th>
                 </tr>
                 
@@ -957,14 +1009,14 @@
                     <!-- BEGIN user_has_avatar -->
                       <img alt="{AVATAR_ALT}" src="{AVATAR_SRC}" />
                     <!-- BEGINELSE user_has_avatar -->
-                      {lang:adminusers_avatar_image_none}
+                      {lang:acpum_avatar_image_none}
                     <!-- END user_has_avatar -->
                   </td>
                 </tr>
                 
                 <tr>
                   <td class="row2">
-                    {lang:adminusers_avatar_lbl_change}
+                    {lang:acpum_avatar_lbl_change}
                   </td>
                   <td class="row1">
                     <script type="text/javascript">
@@ -988,14 +1040,14 @@
                         }
                       }
                     </script>
-                    <label><input onclick="admincp_users_avatar_set_{UUID}(this);" type="radio" name="avatar_action" value="keep" checked="checked" /> {lang:adminusers_avatar_lbl_keep}</label><br />
-                    <label><input onclick="admincp_users_avatar_set_{UUID}(this);" type="radio" name="avatar_action" value="remove" /> {lang:adminusers_avatar_lbl_remove}</label><br />
-                    <label><input onclick="admincp_users_avatar_set_{UUID}(this);" type="radio" name="avatar_action" value="set_http" /> {lang:adminusers_avatar_lbl_set_http}</label><br />
+                    <label><input onclick="admincp_users_avatar_set_{UUID}(this);" type="radio" name="avatar_action" value="keep" checked="checked" /> {lang:acpum_avatar_lbl_keep}</label><br />
+                    <label><input onclick="admincp_users_avatar_set_{UUID}(this);" type="radio" name="avatar_action" value="remove" /> {lang:acpum_avatar_lbl_remove}</label><br />
+                    <label><input onclick="admincp_users_avatar_set_{UUID}(this);" type="radio" name="avatar_action" value="set_http" /> {lang:acpum_avatar_lbl_set_http}</label><br />
                       <div id="avatar_upload_http_{UUID}" style="display: none; margin: 10px 0 0 2.2em;">
                         {lang:usercp_avatar_lbl_url} <input type="text" name="avatar_http_url" size="40" value="http://" /><br />
                         <small>{lang:usercp_avatar_lbl_url_desc} {lang:usercp_avatar_limits}</small>
                       </div>
-                    <label><input onclick="admincp_users_avatar_set_{UUID}(this);" type="radio" name="avatar_action" value="set_file" /> {lang:adminusers_avatar_lbl_set_file}</label>
+                    <label><input onclick="admincp_users_avatar_set_{UUID}(this);" type="radio" name="avatar_action" value="set_file" /> {lang:acpum_avatar_lbl_set_file}</label>
                       <div id="avatar_upload_file_{UUID}" style="display: none; margin: 10px 0 0 2.2em;">
                         {lang:usercp_avatar_lbl_file} <input type="file" name="avatar_file" size="40" value="http://" /><br />
                         <small>{lang:usercp_avatar_lbl_file_desc} {lang:usercp_avatar_limits}</small>
@@ -1009,44 +1061,43 @@
               
                 <tr>
                   <th class="subhead" colspan="2">
-                    Administrator-only options
+                    {lang:acpum_heading_adminonly}
                   </th>
                 </tr>
                 
                 <tr>
-                  <td class="row2">User account is active<br />
-                                   <small>If this is unchecked, the existing activation key will be overwritten in the database, thus invalidating any activation e-mails sent to the user.</small>
+                  <td class="row2">{lang:acpum_field_active_title}<br />
+                                   <small>{lang:acpum_field_active_hint}</small>
                                    </td>
-                  <td class="row1"><label><input type="checkbox" name="account_active" <!-- BEGIN account_active -->checked="checked" <!-- END account_active -->/> Account is active and enabled</label></td>
+                  <td class="row1"><label><input type="checkbox" name="account_active" <!-- BEGIN account_active -->checked="checked" <!-- END account_active -->/> {lang:acpum_field_active}</label></td>
                 </tr>
                 
                 <tr>
                   <td class="row2">
-                    User's site access level<br />
-                    <small>If this is changed, the relevant group memberships will be updated accordingly.</small>
+                    {lang:acpum_field_userlevel}<br />
+                    <small>{lang:acpum_field_userlevel_hint}</small>
                   </td>
                   <td class="row1">
                     <select name="user_level">
-                      <option value="{USER_LEVEL_MEMBER}"<!-- BEGIN ul_member --> selected="selected"<!-- END ul_member -->>Normal member</option>
-                      <option value="{USER_LEVEL_MOD}"<!-- BEGIN ul_mod --> selected="selected"<!-- END ul_mod -->>Moderator</option>
-                      <option value="{USER_LEVEL_ADMIN}"<!-- BEGIN ul_admin --> selected="selected"<!-- END ul_admin -->>Site administrator</option>
+                      <option value="{USER_LEVEL_MEMBER}"<!-- BEGIN ul_member --> selected="selected"<!-- END ul_member -->>{lang:userfuncs_ml_level_member}</option>
+                      <option value="{USER_LEVEL_MOD}"<!-- BEGIN ul_mod --> selected="selected"<!-- END ul_mod -->>{lang:userfuncs_ml_level_mod}</option>
+                      <option value="{USER_LEVEL_ADMIN}"<!-- BEGIN ul_admin --> selected="selected"<!-- END ul_admin -->>{lang:userfuncs_ml_level_admin}</option>
                     </select>
                   </td>
                 </tr>
                 
                 <tr>
                   <td class="row2">
-                    Delete user account
+                    {lang:acpum_field_deleteaccount_title}
                   </td>
                   <td class="row1">
-                    <label><input type="checkbox" name="delete_account" onclick="var d = (this.checked) ? 'block' : 'none'; document.getElementById('delete_blurb_{UUID}').style.display = d;" /> Permanently delete this user account when I click Save</label>
+                  <label><input type="checkbox" name="delete_account" onclick="var d = (this.checked) ? 'block' : 'none'; document.getElementById('delete_blurb_{UUID}').style.display = d;" /> {lang:acpum_field_deleteaccount}</label>
                     <div id="delete_blurb_{UUID}" style="display: none;">
                       <!-- BEGIN same_user -->
-                      <p><b><blink style="color: red;">WARNING!</blink> This will delete your own user account!</b></p>
+                      <!-- Obnoxious I know, but it's needed. -->
+                      <p><b>{lang:acpum_msg_delete_own_account}</b></p>
                       <!-- END same_user -->
-                      <p><small>Even if you delete this user account, the username will be shown in page edit history, comments, and other areas of the site.
-                      Deleting a user account CANNOT BE UNDONE and should only be done in extreme circumstances.
-                      If the user has violated the site policy, deleting the account will not prevent him from using the site or creating a new account, for that you need to add a new ban rule.</small></p>
+                      <p><small>{lang:acpum_field_deleteaccount_hint}</small></p>
                     </div>
                   </td>
                 </tr>
@@ -1055,8 +1106,8 @@
               <!-- Save button -->
               <tr>
                 <th colspan="2">
-                  <input type="submit" name="action[save]" value="Save changes" style="font-weight: bold;" />
-                  <input type="submit" name="action[noop]" value="Cancel" style="font-weight: normal;" />
+                  <input type="submit" name="action[save]" value="{lang:acpum_btn_save}" style="font-weight: bold;" />
+                  <input type="submit" name="action[noop]" value="{lang:etc_cancel}" style="font-weight: normal;" />
                 </th>
               </tr>
             
--- a/themes/admin/simple-footer.tpl	Mon Dec 31 21:43:51 2007 -0500
+++ b/themes/admin/simple-footer.tpl	Thu Jan 03 00:53:33 2008 -0500
@@ -1,6 +1,6 @@
           </div>
           <div class="footer">
-            {COPYRIGHT}<br />Powered by <a href="{CONTENTPATH}{NS_SPECIAL}About_Enano{ADMIN_SID_AUTO}">Enano</a> &bull; Copyright &copy; 2007 Dan Fuhry
+            {COPYRIGHT}<br />Powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a> &bull; Copyright &copy; 2007 Dan Fuhry
           </div>
         </td>
         <td class="right"></td>
@@ -9,28 +9,40 @@
         <td class="bottom-left"></td><td class="bottom"></td><td class="bottom-right"></td>
       </tr>
     </table>
+    
+    </td>
+    <td id="td-sidebar" valign="top">
+    
+      <table border="0" cellspacing="0" cellpadding="0" class="wrapper" id="sidebar-show">
+        <tr>
+          <td class="top-left"></td><td class="top">&nbsp;</td><td class="top-right"></td>
+        </tr>
+        <tr>
+          <td class="left"></td>
+          <td class="main">
+            <div id="sidebar">
+              {SIDEBAR_LEFT}
+              {SIDEBAR_RIGHT}
+            </div>
+          </td>
+          <td class="right"></td>
+        </tr>
+        <tr>
+          <td class="bottom-left"></td><td class="bottom"></td><td class="bottom-right"></td>
+        </tr>
+      </table>
+      
+      <div id="sidebar-hide" onclick="admin_expand();" class="collapsed" title="Click to expand the sidebar"></div>
+    
+    </td>
+    </tr>
+    </table>
+    
     <div style="display: none;">
     <h2>Your browser does not support CSS.</h2>
      <p>If you can see this text, it means that your browser does not support Cascading Style Sheets (CSS). CSS is a fundemental aspect of XHTML, and as a result it is becoming very widely adopted by websites, including this one. You should consider switching to a more modern web browser, such as Mozilla Firefox or Opera 9.</p>
      <p>Because of this, there are a few minor issues that you may experience while browsing this site, not the least of which is some visual elements below that would normally be hidden in most browsers. Please excuse these minor inconveniences.</p>
     </div>
-    <div id="root1" class="jswindow" style="display: none;">
-      <div id="tb1" class="titlebar">Confirm Logout</div>
-      <div class="content" id="cn1">
-        <form action="{CONTENTPATH}Special:Logout" method="get">
-          <div style="text-align: center">
-            <h3>Are you sure you want to log out?</h3>
-            <input type="submit" value="Log out" style="font-weight: bold;" />  <input type="button" onclick="jws.closeWin('root1');" value="Cancel" />
-          </div>
-        </form>
-      </div>  
-    </div>
-    <div id="root2" class="jswindow" style="display: none;">
-      <div id="tb2" class="titlebar">Change style</div>
-      <div class="content" id="cn2">
-        
-      </div>
-    </div>
     <div id="root3" class="jswindow" style="display: none;">
       <div id="tb3" class="titlebar">Wiki formatting help</div>
       <div class="content" id="cn3">
--- a/themes/admin/simple-header.tpl	Mon Dec 31 21:43:51 2007 -0500
+++ b/themes/admin/simple-header.tpl	Thu Jan 03 00:53:33 2008 -0500
@@ -1,20 +1,23 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html>
+<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <title>{PAGE_NAME} &bull; {SITE_NAME}</title>
     <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
     <link rel="stylesheet" type="text/css" href="{SCRIPTPATH}/includes/clientside/css/enano-shared.css" />
     <link id="mdgCss" rel="stylesheet" type="text/css" href="{SCRIPTPATH}/themes/{THEME_ID}/css/{STYLE_ID}.css" />
+    <!--[if IE]>
+    <link id="mdgCss" rel="stylesheet" type="text/css" href="{SCRIPTPATH}/themes/{THEME_ID}/css-ie/iefixes.css" />
+    <![endif]-->
     {JS_DYNAMIC_VARS}
+    <script type="text/javascript" src="{SCRIPTPATH}/includes/clientside/static/enano-lib-basic.js"></script>
     <script type="text/javascript" src="{SCRIPTPATH}/themes/admin/js/menu.js"></script>
-    <script type="text/javascript" src="{SCRIPTPATH}/includes/clientside/static/enano-lib-basic.js"></script>
     {ADDITIONAL_HEADERS}
     </head>
   <body>
     <div id="header">
       <div class="sitename">{SITE_NAME}</div>
-      <div class="menulink"><a href="#" onclick="adminOpenMenu('sidebar', this); return false;">expand menu</a></div>
-      [&nbsp;<a href="{SCRIPTPATH}/{ADMIN_SID_AUTO}">Main page &#0187;</a>&nbsp;]
+      <!-- div class="menulink"><a href="#" onclick="adminOpenMenu('sidebar', this); return false;">expand menu</a></div -->
+      [&nbsp;<a href="{SCRIPTPATH}/{ADMIN_SID_QUES}">Main page &#0187;</a>&nbsp;]
     </div>
     <div class="menu_nojs" id="pagebar_main">
       <div class="label">Page tools</div>
@@ -24,11 +27,11 @@
       </ul>
       <span class="menuclear">&nbsp;</span>
     </div>
-    <div id="sidebar">
-      {SIDEBAR_LEFT}
-      {SIDEBAR_RIGHT}
-    </div>
-    <table border="0" cellspacing="0" cellpadding="0" id="wrapper">
+    <table border="0" cellspacing="0" cellpadding="0" id="sidebarholder">
+    <tr>
+    <td valign="top">
+    
+    <table border="0" cellspacing="0" cellpadding="0" class="wrapper">
       <tr>
         <td class="top-left"></td><td class="top">&nbsp;</td><td class="top-right"></td>
       </tr>
--- a/themes/oxygen/acledit.tpl	Mon Dec 31 21:43:51 2007 -0500
+++ b/themes/oxygen/acledit.tpl	Thu Jan 03 00:53:33 2008 -0500
@@ -3,6 +3,7 @@
   <table border="0" cellspacing="1" cellpadding="4" style="width: 100%;">
     <tr>
       <th></th>
+      <th style='cursor: pointer;' title="Click to change all columns" onclick="__aclSetAllRadios('i');">{lang:acl_lbl_field_inherit}</th>
       <th style='cursor: pointer;' title="Click to change all columns" onclick="__aclSetAllRadios('1');">{lang:acl_lbl_field_deny}</th>
       <th style='cursor: pointer;' title="Click to change all columns" onclick="__aclSetAllRadios('2');">{lang:acl_lbl_field_disallow}</th>
       <th style='cursor: pointer;' title="Click to change all columns" onclick="__aclSetAllRadios('3');">{lang:acl_lbl_field_wikimode}</th>
@@ -12,6 +13,7 @@
 <!-- VAR acl_field_item -->
     <tr>
       <td class="{ROW_CLASS}">{FIELD_DESC}</td>
+      <td class="{ROW_CLASS}" style="text-align: center;"><input type="radio" value="i" name="{FIELD_NAME}" {FIELD_INHERIT_CHECKED} /></td>
       <td class="{ROW_CLASS}" style="text-align: center;"><input type="radio" value="1" name="{FIELD_NAME}" {FIELD_DENY_CHECKED} /></td>
       <td class="{ROW_CLASS}" style="text-align: center;"><input type="radio" value="2" name="{FIELD_NAME}" {FIELD_DISALLOW_CHECKED} /></td>
       <td class="{ROW_CLASS}" style="text-align: center;"><input type="radio" value="3" name="{FIELD_NAME}" {FIELD_WIKIMODE_CHECKED} /></td>
@@ -20,7 +22,7 @@
 <!-- ENDVAR acl_field_item -->
 <!-- VAR acl_field_end -->
     <tr>
-      <td colspan="5" class="row3">
+      <td colspan="6" class="row3">
         {lang:acl_lbl_help}
       </td>
     </tr>
--- a/upgrade.php	Mon Dec 31 21:43:51 2007 -0500
+++ b/upgrade.php	Thu Jan 03 00:53:33 2008 -0500
@@ -799,7 +799,7 @@
       }
       
       // Log the upgrade
-      $q = $db->sql_query('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,page_text,edit_summary) VALUES(\'security\', \'upgrade_enano\', ' . time() . ', \'' . date('d M Y h:i a') . '\', \'' . mysql_real_escape_string($session->username) . '\', \'' . mysql_real_escape_string($this_version) . '\', \'' . mysql_real_escape_string($_SERVER['REMOTE_ADDR']) . '\');');
+      $q = $db->sql_query('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,page_text,edit_summary) VALUES(\'security\', \'upgrade_enano\', ' . time() . ', \'' . enano_date('d M Y h:i a') . '\', \'' . mysql_real_escape_string($session->username) . '\', \'' . mysql_real_escape_string($this_version) . '\', \'' . mysql_real_escape_string($_SERVER['REMOTE_ADDR']) . '\');');
       
       echo 'done!</p>';
       echo '<p>You will be redirected shortly. If you aren\'t redirected, <a href="index.php">click here</a>.</p>