Removed stray debugging info from ACL editor success notification; added ability for guests to set language on URI (?lang=eng); added html_in_pages ACL type and separated from php_in_pages so HTML can be embedded but not PHP; rewote portions of the path manager to better abstract URL input; added Zend Framework into list of BSD-licensed libraries; localized some remaining strings; got the migration script working, but just barely; fixed display bug in Special:Contributions; localized Main Page button in admin panel
authorDan
Sat, 26 Jan 2008 15:42:32 -0500
changeset 377 bb3e6c3bd4f4
parent 376 66732bd4532c
child 378 c1c7fa6b329f
Removed stray debugging info from ACL editor success notification; added ability for guests to set language on URI (?lang=eng); added html_in_pages ACL type and separated from php_in_pages so HTML can be embedded but not PHP; rewote portions of the path manager to better abstract URL input; added Zend Framework into list of BSD-licensed libraries; localized some remaining strings; got the migration script working, but just barely; fixed display bug in Special:Contributions; localized Main Page button in admin panel
includes/clientside/static/acl.js
includes/functions.php
includes/lang.php
includes/pageprocess.php
includes/paths.php
includes/render.php
includes/sessions.php
includes/template.php
includes/wikiengine/Tables.php
install/schemas/mysql_stage2.sql
install/schemas/postgresql_stage2.sql
install/schemas/upgrade/migration/1.0-1.1-mysql.sql
install/schemas/upgrade/migration/1.0-1.1.php
install/upgrade.php
language/english/admin.json
language/english/core.json
language/english/user.json
licenses/index.html
plugins/SpecialAdmin.php
plugins/SpecialUserFuncs.php
plugins/admin/LangManager.php
themes/admin/footer.tpl
themes/admin/header.tpl
themes/admin/simple-footer.tpl
themes/oxygen/footer.tpl
themes/oxygen/header.tpl
themes/stpatty/footer.tpl
--- a/includes/clientside/static/acl.js	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/clientside/static/acl.js	Sat Jan 26 15:42:32 2008 -0500
@@ -435,12 +435,12 @@
             note.appendChild(document.createElement('br'));
             var a = document.createElement('a');
             a.href = '#';
-            a.onclick = function(e) { alert('ONCLICK'); return false; };
+            a.onclick = function(e) { this.parentNode.parentNode.removeChild(this.parentNode); return false; };
             a.appendChild(document.createTextNode('[ ' + $lang.get('acl_btn_success_dismiss') + ' :'));
             note.appendChild(a);
             var a2 = document.createElement('a');
             a2.href = '#';
-            a2.onclick = function(e) { alert('ONCLICK'); return false; };
+            a2.onclick = function(e) { killACLManager(); return false; };
             a2.appendChild(document.createTextNode(': ' + $lang.get('acl_btn_success_close') + ' ]'));
             note.appendChild(a2);
             document.getElementById(aclManagerID + '_main').insertBefore(note, document.getElementById(aclManagerID + '_main').firstChild);
--- a/includes/functions.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/functions.php	Sat Jan 26 15:42:32 2008 -0500
@@ -82,10 +82,16 @@
     $flags .= $sep . 'theme='.$session->theme;
     $sep = '&';
   }
-  if ( isset($_GET['style'] ) ) {
+  if ( isset($_GET['style'] ) )
+  {
     $flags .= $sep . 'style='.$session->style;
     $sep = '&';
   }
+  if ( isset($_GET['lang']) && preg_match('/^[a-z0-9_]+$/', @$_GET['lang']) )
+  {
+    $flags .= $sep . 'lang=' . urlencode($_GET['lang']);
+    $sep = '&';
+  }
 
   $url = $session->append_sid(contentPath.$t.$flags);
   if($query)
@@ -133,6 +139,11 @@
     $flags .= $sep . 'style='.$session->style;
     $sep = '&';
   }
+  if ( isset($_GET['lang']) && preg_match('/^[a-z0-9_]+$/', @$_GET['lang']) )
+  {
+    $flags .= $sep . 'lang=' . urlencode($_GET['lang']);
+    $sep = '&';
+  }
 
   if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
   {
@@ -201,6 +212,11 @@
     $flags .= $sep . 'style='.$session->style;
     $sep = '&';
   }
+  if ( isset($_GET['lang']) && preg_match('/^[a-z0-9_]+$/', @$_GET['lang']) )
+  {
+    $flags .= $sep . 'lang=' . urlencode($_GET['lang']);
+    $sep = '&';
+  }
 
   if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
   {
@@ -2453,9 +2469,9 @@
   
   if ( isset($paths->nslist['User']) )
   {
-    if ( preg_match('/^' . preg_quote($paths->nslist['User']) . '/', $page_id) )
+    if ( preg_match('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', $page_id) )
     {
-      $ip = preg_replace('/^' . preg_quote($paths->nslist['User']) . '/', '', $page_id);
+      $ip = preg_replace('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', '', $page_id);
       if ( is_valid_ip($ip) )
       {
         return $page_id;
--- a/includes/lang.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/lang.php	Sat Jan 26 15:42:32 2008 -0500
@@ -360,26 +360,33 @@
     }
     
     $delete_list = implode(" OR\n  ", $delete_list);
-    $sql = "DELETE FROM " . table_prefix . "language_strings WHERE $delete_list;";
     
-    // Free some memory
-    unset($delete_list);
-    
-    // Run the query
-    $q = $db->sql_query($sql);
-    if ( !$q )
-      $db->_die('lang.php - couldn\'t kill off them old strings');
+    if ( !empty($delete_list) )
+    {
+      $sql = "DELETE FROM " . table_prefix . "language_strings WHERE $delete_list;";
+      
+      // Free some memory
+      unset($delete_list);
+      
+      // Run the query
+      $q = $db->sql_query($sql);
+      if ( !$q )
+        $db->_die('lang.php - couldn\'t kill off them old strings');
+    }
     
-    $insert_list = implode(",\n  ", $insert_list);
-    $sql = "INSERT INTO " . table_prefix . "language_strings(lang_id, string_category, string_name, string_content) VALUES\n  $insert_list;";
-    
-    // Free some memory
-    unset($insert_list);
-    
-    // Run the query
-    $q = $db->sql_query($sql);
-    if ( !$q )
-      $db->_die('lang.php - couldn\'t insert strings in import()');
+    if ( !empty($insert_list) )
+    {
+      $insert_list = implode(",\n  ", $insert_list);
+      $sql = "INSERT INTO " . table_prefix . "language_strings(lang_id, string_category, string_name, string_content) VALUES\n  $insert_list;";
+      
+      // Free some memory
+      unset($insert_list);
+      
+      // Run the query
+      $q = $db->sql_query($sql);
+      if ( !$q )
+        $db->_die('lang.php - couldn\'t insert strings in import()');
+    }
     
     // YAY! done!
     // This will regenerate the cache file if possible.
--- a/includes/pageprocess.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/pageprocess.php	Sat Jan 26 15:42:32 2008 -0500
@@ -905,13 +905,12 @@
         '>' => '>'
         ));
     
-    $target_username = preg_replace('/^' . preg_quote($paths->nslist['User']) . '/', '', $target_username);
-    $target_username = explode('/', $target_username);
-    $target_username = $target_username[0];
+    $target_username = preg_replace('/^' . str_replace('/', '\\/', preg_quote($paths->nslist['User'])) . '/', '', $target_username);
+    list($target_username) = explode('/', $target_username);
     
     if ( ( $page_name == str_replace('_', ' ', $this->page_id) || $page_name == $paths->nslist['User'] . str_replace('_', ' ', $this->page_id) ) || !$this->page_exists )
     {
-      $page_name = "$target_username's user page";
+      $page_name = $lang->get('userpage_page_title', array('username' => htmlspecialchars($target_username)));
     }
     else
     {
--- a/includes/paths.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/paths.php	Sat Jan 26 15:42:32 2008 -0500
@@ -72,7 +72,8 @@
     $session->register_acl_type('upload_files',           AUTH_DISALLOW, 'perm_upload_files',           Array('create_page'),                                     'Article|User|Project|Template|File|Help|System|Category|Special');
     $session->register_acl_type('upload_new_version',     AUTH_WIKIMODE, 'perm_upload_new_version',     Array('upload_files'),                                    'Article|User|Project|Template|File|Help|System|Category|Special');
     $session->register_acl_type('create_page',            AUTH_WIKIMODE, 'perm_create_page',            Array(),                                                  'Article|User|Project|Template|File|Help|System|Category|Special');
-    $session->register_acl_type('php_in_pages',           AUTH_DISALLOW, 'perm_php_in_pages',           Array('edit_page'),                                       'Article|User|Project|Template|File|Help|System|Category|Admin');
+    $session->register_acl_type('html_in_pages',          AUTH_DISALLOW, 'perm_html_in_pages',          Array('edit_page'),                                       'Article|User|Project|Template|File|Help|System|Category|Admin');
+    $session->register_acl_type('php_in_pages',           AUTH_DISALLOW, 'perm_php_in_pages',           Array('edit_page', 'html_in_pages'),                      'Article|User|Project|Template|File|Help|System|Category|Admin');
     $session->register_acl_type('edit_acl',               AUTH_DISALLOW, 'perm_edit_acl',               Array('read', 'post_comments', 'edit_comments', 'edit_page', 'view_source', 'mod_comments', 'history_view', 'history_rollback', 'history_rollback_extra', 'protect', 'rename', 'clear_logs', 'vote_delete', 'vote_reset', 'delete_page', 'set_wiki_mode', 'password_set', 'password_reset', 'mod_misc', 'edit_cat', 'even_when_protected', 'upload_files', 'upload_new_version', 'create_page', 'php_in_pages'));
     
     // DO NOT add new admin pages here! Use a plugin to call $paths->addAdminNode();
@@ -102,6 +103,32 @@
     $this->wiki_mode = (int)getConfig('wiki_mode')=='1';
     $this->template_cache = Array();
   }
+  function parse_url($sanitize = true)
+  {
+    $title = '';
+    if( isset($_GET['title']) )
+    {
+      $title = $_GET['title'];
+    }
+    elseif( isset($_SERVER['PATH_INFO']) )
+    {
+      $title = substr($_SERVER['PATH_INFO'], ( strpos($_SERVER['PATH_INFO'], '/') ) + 1 );
+    }
+    else
+    {
+      // This method really isn't supported because apache has a habit of passing dots as underscores, thus corrupting the request
+      // If you really want to try it, the URI format is yoursite.com/?/Page_title
+      if ( count($_GET) > 0 )
+      {
+        list($getkey) = array_keys($_GET);
+        if ( substr($getkey, 0, 1) == '/' )
+        {
+          $title = substr($getkey, 1);
+        }
+      }
+    }
+    return ( $sanitize ) ? sanitize_page_id($title) : $title;
+  }
   function init()
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
@@ -148,105 +175,38 @@
     $db->free_result();
     if ( defined('ENANO_INTERFACE_INDEX') || defined('ENANO_INTERFACE_AJAX') || defined('IN_ENANO_UPGRADE') )
     {
-      if( isset($_GET['title']) )
+      $title = $this->parse_url(false);
+      if ( empty($title) )
+      {
+        $this->main_page();
+      }
+      if ( strstr($title, ' ') || strstr($title, '+') || strstr($title, '%20') )
       {
-        if ( $_GET['title'] == '' && getConfig('main_page') != '' )
-        {
-          $this->main_page();
-        }
-        if(strstr($_GET['title'], ' '))
-        {
-          $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
-          $loc = str_replace(' ', '_', $loc);
-          $loc = str_replace('+', '_', $loc);
-          $loc = str_replace('%20', '_', $loc);
-          redirect($loc, 'Redirecting...', 'Space detected in the URL, please wait whilst you are redirected', 0);
-          exit;
-        }
-        $url_namespace_special = substr($_GET['title'], 0, strlen($this->nslist['Special']) );
-        $url_namespace_template = substr($_GET['title'], 0, strlen($this->nslist['Template']) );
-        if($url_namespace_special == $this->nslist['Special'] || $url_namespace_template == $this->nslist['Template'] )
-        {
-          $ex = explode('/', $_GET['title']);
-          $this->page = $ex[0];
-        }
-        else
-        {
-          $this->page = $_GET['title'];
-        }
-        $this->fullpage = $_GET['title'];
+        $title = sanitize_page_id($title);
+        redirect(makeUrl($title), '', '', 0);
       }
-      elseif( isset($_SERVER['PATH_INFO']) )
+      $title = sanitize_page_id($title);
+      // We've got the title, pull the namespace from it
+      $namespace = 'Article';
+      $page_id = $title;
+      foreach ( $this->nslist as $ns => $prefix )
       {
-        $pi = explode('/', $_SERVER['PATH_INFO']);
-        
-        if( !isset($pi[1]) || (isset($pi[1]) && $pi[1] == '' && getConfig('main_page') != '') )
-        {
-          $this->main_page();
-        }
-        if( strstr($pi[1], ' ') )
-        {
-          $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
-          $loc = str_replace('+', '_', $loc);
-          $loc = str_replace('%20', '_', $loc);
-          redirect($loc, 'Redirecting...', 'Please wait whilst you are redirected', 3);
-          exit;
-        }
-        unset($pi[0]);
-        if( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] || substr($pi[1], 0, strlen($this->nslist['Template'])) == $this->nslist['Template'] )
+        $prefix_len = strlen($prefix);
+        if ( substr($title, 0, $prefix_len) == $prefix )
         {
-          $pi2 = $pi[1];
-        }
-        else
-        {
-          $pi2 = implode('/', $pi);
-        }
-        $this->page = $pi2;
-        $this->fullpage = implode('/', $pi);
-      }
-      else
-      {
-        $k = array_keys($_GET);
-        foreach($k as $c)
-        {
-          if(substr($c, 0, 1) == '/')
-          {
-            $this->page = substr($c, 1, strlen($c));
-            
-            // Bugfix for apache somehow passing dots as underscores
-            global $mime_types;
-            
-            $exts = array_keys($mime_types);
-            $exts = '(' . implode('|', $exts) . ')';
-            
-            if ( preg_match( '#_'.$exts.'#i', $this->page ) )
-            {
-              $this->page = preg_replace( '#_'.$exts.'#i', '.\\1', $this->page );
-            }
-            
-            $this->fullpage = $this->page;
-            
-            if(substr($this->page, 0, strlen($this->nslist['Special']))==$this->nslist['Special'] || substr($this->page, 0, strlen($this->nslist['Template']))==$this->nslist['Template'])
-            {
-              $ex = explode('/', $this->page);
-              $this->page = $ex[0];
-            }
-            if(strstr($this->page, ' '))
-            {
-              $loc = str_replace(' ', '_', urldecode(rawurldecode($_SERVER['REQUEST_URI'])));
-              $loc = str_replace('+', '_', $loc);
-              $loc = str_replace('%20', '_', $loc);
-              redirect($loc, 'Redirecting...', 'Space in the URL detected, please wait whilst you are redirected', 0);
-              exit;
-            }
-            break;
-          }
-        }
-        if(!$this->page && !($this->page == '' && getConfig('main_page') == ''))
-        {
-          $this->main_page();
+          $page_id = substr($title, $prefix_len);
+          $namespace = $ns;
         }
       }
+      $this->namespace = $namespace;
+      $this->fullpage = $title;
+      if ( $namespace == 'Special' || $namespace == 'Admin' )
+      {
+        list($page_id) = explode('/', $page_id);
+      }
+      $this->page = $this->nslist[$namespace] . $page_id;
+      $this->page_id = $page_id;
+      // die("All done setting parameters. What we've got:<br/>namespace: $namespace<br/>fullpage: $this->fullpage<br/>page: $this->page<br/>page_id: $this->page_id");
     }
     else
     {
@@ -469,71 +429,7 @@
   }
   function get_pageid_from_url()
   {
-    if(isset($_GET['title']))
-    {
-      if( $_GET['title'] == '' && getConfig('main_page') != '' )
-      {
-        $this->main_page();
-      }
-      if(strstr($_GET['title'], ' '))
-      {
-        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
-        $loc = str_replace(' ', '_', $loc);
-        $loc = str_replace('+', '_', $loc);
-        header('Location: '.$loc);
-        exit;
-      }
-      $ret = $_GET['title'];
-      if ( substr($ret, 0, strlen($this->nslist['Special'])) === $this->nslist['Special'] ||
-           substr($ret, 0, strlen($this->nslist['Admin'])) === $this->nslist['Admin'] )
-      {
-        list($ret) = explode('/', $ret);
-      }
-    }
-    elseif(isset($_SERVER['PATH_INFO']))
-    {
-      $pi = explode('/', $_SERVER['PATH_INFO']);
-      
-      if(!isset($pi[1]) || (isset($pi[1]) && $pi[1] == ''))
-      {
-        return false;
-      }
-      
-      if(strstr($pi[1], ' '))
-      {
-        $loc = urldecode(rawurldecode($_SERVER['REQUEST_URI']));
-        $loc = str_replace(' ', '_', $loc);
-        $loc = str_replace('+', '_', $loc);
-        header('Location: '.$loc);
-        exit;
-      }
-      if( !( substr($pi[1], 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ) )
-      {
-        unset($pi[0]);
-        $pi[1] = implode('/', $pi);
-      }
-      $ret = $pi[1];
-    }
-    else
-    {
-      $k = array_keys($_GET);
-      foreach($k as $c)
-      {
-        if(substr($c, 0, 1) == '/')
-        {
-          $ret = substr($c, 1, strlen($c));
-          if(substr($ret, 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ||
-             substr($ret, 0, strlen($this->nslist['Admin'])) == $this->nslist['Admin'])
-          {
-            $ret = explode('/', $ret);
-            $ret = $ret[0];
-          }
-          break;
-        }
-      }
-    }
-    
-    return ( isset($ret) ) ? $ret : false;
+    return $this->parse_url();
   }
   // Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
   function parseAdminTree() 
@@ -580,80 +476,22 @@
   }
   function getParam($id = 0)
   {
-    // using !empty here is a bugfix for IIS 5.x on Windows 2000 Server
-    // It may affect other IIS versions as well
-    if(isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO']))
-    {
-      $pi = explode('/', $_SERVER['PATH_INFO']);
-      $id = $id + 2;
-      return isset($pi[$id]) ? $pi[$id] : false;
-    }
-    else if( isset($_GET['title']) )
-    {
-      $pi = explode('/', $_GET['title']);
-      $id = $id + 1;
-      return isset($pi[$id]) ? $pi[$id] : false;
-    }
-    else
-    {
-      $k = array_keys($_GET);
-      foreach($k as $c)
-      {
-        if(substr($c, 0, 1) == '/')
-        {
-          // Bugfix for apache somehow passing dots as underscores
-          global $mime_types;
-          $exts = array_keys($mime_types);
-          $exts = '(' . implode('|', $exts) . ')';
-          if ( preg_match( '#_'.$exts.'#i', $c ) )
-            $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
-          
-          $pi = explode('/', $c);
-          $id = $id + 2;
-          return isset($pi[$id]) ? $pi[$id] : false;
-        }
-      }
-      return false;
-    }
+    $title = $this->parse_url(false);
+    $regex = '/^' . str_replace('/', '\\/', preg_quote($this->nslist[$this->namespace])) . '\\/?/';
+    $title = preg_replace($regex, '', $title);
+    $title = explode('/', $title);
+    $id = $id + 1;
+    return ( isset($title[$id]) ) ? $title[$id] : false;
   }
   
   function getAllParams()
   {
-    // using !empty here is a bugfix for IIS 5.x on Windows 2000 Server
-    // It may affect other IIS versions as well
-    if(isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO']))
-    {
-      $pi = explode('/', $_SERVER['PATH_INFO']);
-      unset($pi[0], $pi[1]);
-      return implode('/', $pi);
-    }
-    else if( isset($_GET['title']) )
-    {
-      $pi = explode('/', $_GET['title']);
-      unset($pi[0]);
-      return implode('/', $pi);
-    }
-    else
-    {
-      $k = array_keys($_GET);
-      foreach($k as $c)
-      {
-        if(substr($c, 0, 1) == '/')
-        {
-          // Bugfix for apache somehow passing dots as underscores
-          global $mime_types;
-          $exts = array_keys($mime_types);
-          $exts = '(' . implode('|', $exts) . ')';
-          if ( preg_match( '#_'.$exts.'#i', $c ) )
-            $c = preg_replace( '#_'.$exts.'#i', '.\\1', $c );
-          
-          $pi = explode('/', $c);
-          unset($pi[0], $pi[1]);
-          return implode('/', $pi);
-        }
-      }
-      return false;
-    }
+    $title = $this->parse_url(false);
+    $regex = '/^' . str_replace('/', '\\/', preg_quote($this->nslist[$this->namespace])) . '\\/?/';
+    $title = preg_replace($regex, '', $title);
+    $title = explode('/', $title);
+    unset($title[0]);
+    return implode('/', $title);
   }
   
   /**
--- a/includes/render.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/render.php	Sat Jan 26 15:42:32 2008 -0500
@@ -215,6 +215,8 @@
   public static function next_gen_wiki_format($text, $plaintext = false, $filter_links = true, $do_params = false)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
+    global $lang;
+    
     $random_id = md5( time() . mt_rand() );
     
     // Strip out <nowiki> sections and PHP code
@@ -239,6 +241,19 @@
       $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
     }
     
+    preg_match_all('/<lang code="([a-z0-9_]+)">([\w\W]+?)<\/lang>/', $text, $langmatch);
+    foreach ( $langmatch[0] as $i => $match )
+    {
+      if ( $langmatch[1][$i] == $lang->lang_code )
+      {
+        $text = str_replace_once($match, $langmatch[2][$i], $text);
+      }
+      else
+      {
+        $text = str_replace_once($match, '', $text);
+      }
+    }
+    
     $code = $plugins->setHook('render_wikiformat_pre');
     foreach ( $code as $cmd )
     {
@@ -618,8 +633,13 @@
     $random_id = md5( time() . mt_rand() );
     
     $can_do_php = ( $session->get_permissions('php_in_pages') && !$strip_all_php );
+    $can_do_html = $session->get_permissions('html_in_pages');
     
-    if ( !$can_do_php )
+    if ( $can_do_html && !$can_do_php )
+    {
+      $text = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $text);
+    }
+    else if ( !$can_do_html && !$can_do_php )
     {
       $text = sanitize_html($text, true);
       // If we can't do PHP, we can't do Javascript either.
@@ -825,7 +845,7 @@
     $taglist = array();
     
     // Wicked huh?
-    $regex = '/\[\[:' . $paths->nslist['File'] . '([\w\s0-9_\(\)!@%\^\+\|\.-]+?)((\|thumb)|(\|([0-9]+)x([0-9]+)))?(\|left|\|right)?(\|raw|\|(.+))?\]\]/i';
+    $regex = '/\[\[:' . str_replace('/', '\\/', preg_quote($paths->nslist['File'])) . '([\w\s0-9_\(\)!@%\^\+\|\.-]+?)((\|thumb)|(\|([0-9]+)x([0-9]+)))?(\|left|\|right)?(\|raw|\|(.+))?\]\]/i';
     
     preg_match_all($regex, $text, $matches);
     
--- a/includes/sessions.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/sessions.php	Sat Jan 26 15:42:32 2008 -0500
@@ -894,7 +894,7 @@
         $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') )
+      if ( @$policy != 'disable' && !defined('IN_ENANO_INSTALL') )
       {
         $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
         // increment fail count
@@ -1166,10 +1166,10 @@
       $this->style = ( isset($_GET['style']) && file_exists(ENANO_ROOT.'/themes/'.$this->theme . '/css/'.$_GET['style'].'.css' )) ? $_GET['style'] : substr($template->named_theme_list[$this->theme]['default_style'], 0, strlen($template->named_theme_list[$this->theme]['default_style'])-4);
     }
     $this->user_id = 1;
+    // This is a VERY special case we are allowing. It lets the installer create languages using the Enano API.
     if ( !defined('ENANO_ALLOW_LOAD_NOLANG') )
     {
-      // This is a VERY special case we are allowing. It lets the installer create languages using the Enano API.
-      $language = intval(getConfig('default_language'));
+      $language = ( isset($_GET['lang']) && preg_match('/^[a-z0-9_]+$/', @$_GET['lang']) ) ? $_GET['lang'] : intval(getConfig('default_language'));
       $lang = new Language($language);
     }
   }
@@ -3120,7 +3120,7 @@
     {
       if ( isset($perm[$i]) )
       {
-        if ( $is_everyone && !$this->acl_defaults_used[$i] )
+        if ( $is_everyone && !@$this->acl_defaults_used[$i] )
           continue;
         // Decide precedence
         if ( isset($this->acl_defaults_used[$i]) )
--- a/includes/template.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/template.php	Sat Jan 26 15:42:32 2008 -0500
@@ -1981,7 +1981,8 @@
       'STYLE_ID'=>$this->style,
       'JS_DYNAMIC_VARS'=>$js_dynamic,
       'SIDEBAR_RIGHT'=>'',
-      'REPORT_URI' => ''
+      'REPORT_URI' => '',
+      'URL_ABOUT_ENANO' => 'http://enanocms.org/'
       );
     $this->tpl_strings = array_merge($tpl_strings, $this->tpl_strings);
     
--- a/includes/wikiengine/Tables.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/includes/wikiengine/Tables.php	Sat Jan 26 15:42:32 2008 -0500
@@ -574,6 +574,7 @@
       'nowiki'     => array(),
       'noinclude'  => array(),
       'nodisplay'  => array(),
+      'lang'       => array('code'),
       
       # XHTML stuff
       'acronym'    => $common
--- a/install/schemas/mysql_stage2.sql	Sat Jan 26 11:51:19 2008 -0500
+++ b/install/schemas/mysql_stage2.sql	Sat Jan 26 15:42:32 2008 -0500
@@ -334,7 +334,7 @@
 INSERT INTO {{TABLE_PREFIX}}group_members(group_id,user_id,is_mod) VALUES(2, 2, 1);
 
 INSERT INTO {{TABLE_PREFIX}}acl(target_type,target_id,page_id,namespace,rules) VALUES
-  (1,2,NULL,NULL,'read=4;post_comments=4;edit_comments=4;edit_page=4;view_source=4;mod_comments=4;history_view=4;history_rollback=4;history_rollback_extra=4;protect=4;rename=4;clear_logs=4;vote_delete=4;vote_reset=4;delete_page=4;tag_create=4;tag_delete_own=4;tag_delete_other=4;set_wiki_mode=4;password_set=4;password_reset=4;mod_misc=4;edit_cat=4;even_when_protected=4;upload_files=4;upload_new_version=4;create_page=4;php_in_pages={{ADMIN_EMBED_PHP}};edit_acl=4;'),
+  (1,2,NULL,NULL,'read=4;post_comments=4;edit_comments=4;edit_page=4;view_source=4;mod_comments=4;history_view=4;history_rollback=4;history_rollback_extra=4;protect=4;rename=4;clear_logs=4;vote_delete=4;vote_reset=4;delete_page=4;tag_create=4;tag_delete_own=4;tag_delete_other=4;set_wiki_mode=4;password_set=4;password_reset=4;mod_misc=4;edit_cat=4;even_when_protected=4;upload_files=4;upload_new_version=4;create_page=4;html_in_pages=4;php_in_pages={{ADMIN_EMBED_PHP}};edit_acl=4;'),
   (1,3,NULL,NULL,'read=4;post_comments=4;edit_comments=4;edit_page=4;view_source=4;mod_comments=4;history_view=4;history_rollback=4;history_rollback_extra=4;protect=4;rename=3;clear_logs=2;vote_delete=4;vote_reset=4;delete_page=4;set_wiki_mode=2;password_set=2;password_reset=2;mod_misc=2;edit_cat=4;even_when_protected=4;upload_files=2;upload_new_version=3;create_page=3;php_in_pages=2;edit_acl=2;');
 
 INSERT INTO {{TABLE_PREFIX}}sidebar(item_id, item_order, sidebar_id, block_name, block_type, block_content) VALUES
--- a/install/schemas/postgresql_stage2.sql	Sat Jan 26 11:51:19 2008 -0500
+++ b/install/schemas/postgresql_stage2.sql	Sat Jan 26 15:42:32 2008 -0500
@@ -332,7 +332,7 @@
 INSERT INTO {{TABLE_PREFIX}}group_members(group_id,user_id,is_mod) VALUES(2, 2, 1);
 
 INSERT INTO {{TABLE_PREFIX}}acl(target_type,target_id,page_id,namespace,rules) VALUES
-  (1,2,NULL,NULL,'read=4;post_comments=4;edit_comments=4;edit_page=4;view_source=4;mod_comments=4;history_view=4;history_rollback=4;history_rollback_extra=4;protect=4;rename=4;clear_logs=4;vote_delete=4;vote_reset=4;delete_page=4;tag_create=4;tag_delete_own=4;tag_delete_other=4;set_wiki_mode=4;password_set=4;password_reset=4;mod_misc=4;edit_cat=4;even_when_protected=4;upload_files=4;upload_new_version=4;create_page=4;php_in_pages={{ADMIN_EMBED_PHP}};edit_acl=4;'),
+  (1,2,NULL,NULL,'read=4;post_comments=4;edit_comments=4;edit_page=4;view_source=4;mod_comments=4;history_view=4;history_rollback=4;history_rollback_extra=4;protect=4;rename=4;clear_logs=4;vote_delete=4;vote_reset=4;delete_page=4;tag_create=4;tag_delete_own=4;tag_delete_other=4;set_wiki_mode=4;password_set=4;password_reset=4;mod_misc=4;edit_cat=4;even_when_protected=4;upload_files=4;upload_new_version=4;create_page=4;html_in_pages=4;php_in_pages={{ADMIN_EMBED_PHP}};edit_acl=4;'),
   (1,3,NULL,NULL,'read=4;post_comments=4;edit_comments=4;edit_page=4;view_source=4;mod_comments=4;history_view=4;history_rollback=4;history_rollback_extra=4;protect=4;rename=3;clear_logs=2;vote_delete=4;vote_reset=4;delete_page=4;set_wiki_mode=2;password_set=2;password_reset=2;mod_misc=2;edit_cat=4;even_when_protected=4;upload_files=2;upload_new_version=3;create_page=3;php_in_pages=2;edit_acl=2;');
 
 INSERT INTO {{TABLE_PREFIX}}sidebar(item_id, item_order, sidebar_id, block_name, block_type, block_content) VALUES
--- a/install/schemas/upgrade/migration/1.0-1.1-mysql.sql	Sat Jan 26 11:51:19 2008 -0500
+++ b/install/schemas/upgrade/migration/1.0-1.1-mysql.sql	Sat Jan 26 15:42:32 2008 -0500
@@ -13,6 +13,8 @@
 ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_lang smallint(5) NOT NULL;
 ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_has_avatar tinyint(1) NOT NULL;
 ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN avatar_type ENUM('jpg', 'png', 'gif') NOT NULL;
+ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_registration_ip varchar(39);
+ALTER TABLE {{TABLE_PREFIX}}comments ADD COLUMN ip_address varchar(39);
 
 CREATE TABLE {{TABLE_PREFIX}}lockout(
   id int(12) NOT NULL auto_increment,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/install/schemas/upgrade/migration/1.0-1.1.php	Sat Jan 26 15:42:32 2008 -0500
@@ -0,0 +1,44 @@
+<?php
+
+function MIGRATE()
+{
+  global $languages;
+  global $db, $dbdriver;
+  
+  // Database upgrade
+  try
+  {
+    $sql_parser = new SQL_Parser('install/schemas/upgrade/migration/1.0-1.1-' . $dbdriver . '.sql');
+  }
+  catch ( Exception $e )
+  {
+    die("<pre>$e</pre>");
+  }
+  
+  $sql_parser->assign_vars(array(
+      'TABLE_PREFIX' => table_prefix
+    ));
+  
+  $sql_list = $sql_parser->parse();
+  foreach ( $sql_list as $sql )
+  {
+    if ( !$db->sql_query($sql) )
+      $db->_die();
+  }
+  
+  // Install default language
+  $lang_id = 'eng';
+  $lang_data =& $languages[$lang_id];
+  $lang_dir = ENANO_ROOT . "/language/{$lang_data['dir']}/";
+  // function install_language($lang_code, $lang_name_neutral, $lang_name_local, $lang_file = false)
+  install_language($lang_id, $lang_data['name_eng'], $lang_data['name'], $lang_dir . 'core.json');
+  $lang_local = new Language($lang_id);
+  $lang_local->import($lang_dir . "tools.json");
+  $lang_local->import($lang_dir . "user.json");
+  $lang_local->import($lang_dir . "admin.json");
+  
+  setConfig('enano_version', installer_enano_version());
+  
+  return true;
+}
+
--- a/install/upgrade.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/install/upgrade.php	Sat Jan 26 15:42:32 2008 -0500
@@ -16,6 +16,16 @@
 
 define('IN_ENANO', 1);
 
+// Turn on every imaginable API hack to make common load on older databases
+define('IN_ENANO_UPGRADE', 1);
+define('IN_ENANO_MIGRATION', 1);
+define('ENANO_ALLOW_LOAD_NOLANG', 1);
+@ini_set('display_errors', 'on');
+
+require('includes/sql_parse.php');
+
+require_once('includes/common.php');
+// when the installer's common is loaded, it runs chdir() to the ENANO_ROOT, thus making this Enano's common.php
 require_once('includes/common.php');
 @ini_set('display_errors', 'on');
 
@@ -70,6 +80,83 @@
   exit(0);
 }
 
+// Version check
+if ( enano_version() == installer_enano_version() )
+{
+  $ui->show_header();
+  echo '<h3>Already upgraded</h3>' . '<p>You don\'t need to migrate, you\'re already on <del>crack</del> the 1.1 platform.</p>';
+  $ui->show_footer();
+  exit();
+}
+
+// Start session manager
+$session->start();
+if ( !$session->user_logged_in || ( $session->user_logged_in && $session->auth_level < USER_LEVEL_ADMIN ) )
+{
+  if ( isset($_POST['do_login']) )
+  {
+    if ( !$session->user_logged_in )
+    {
+      $result = $session->login_without_crypto($_POST['username'], $_POST['password'], false, USER_LEVEL_MEMBER);
+    }
+    $result = $session->login_without_crypto($_POST['username'], $_POST['password'], false, USER_LEVEL_ADMIN);
+    if ( $result['success'] )
+    {
+      header('HTTP/1.1 302 Some kind of redirect with implied no content');
+      header('Location: ' . scriptPath . '/install/' . $session->append_sid('upgrade.php'));
+      exit();
+    }
+  }
+  
+  $ui->show_header();
+  
+  ?>
+  <h3>Authentication needed</h3>
+  <?php
+  
+  echo '<form action="upgrade.php" method="post">';
+  
+  if ( isset($result) )
+  {
+    echo '<b>Session manager returned error: ' . $result['error'] . '</b>';
+  }
+  
+  ?>
+  <p>You need an active admin session to continue.</p>
+  <p>
+    Username:&nbsp;&nbsp;&nbsp;<input type="text" name="username" /><br />
+    Password:&nbsp;&nbsp;&nbsp;<input type="password" name="password" /><br />
+    <input type="submit" name="do_login" value="Log in" />
+  </p>
+  <?php
+  
+  echo '</form>';
+  
+  $ui->show_footer();
+  exit();
+}
+
+// The real migration code
 $ui->show_header();
+
+if ( isset($_GET['stage']) && @$_GET['stage'] == 'pimpmyenano' )
+{
+  require('install/schemas/upgrade/migration/1.0-1.1.php');
+  if ( MIGRATE() )
+  {
+    echo '<p>Enano survived the migration. Congratulations, you\'re one of the lucky ones, <a href="' . scriptPath . '/index.php">check out the alpha</a>.</p>';
+  }
+  else
+  {
+    echo '<p>Something went wrong, you should have gotten an error message.</p>';
+  }
+}
+else
+{
+  ?>
+  <p>Nothing's really implemented for now except the actual migration code, which is not very smart. Just <a href="<?php echo $session->append_sid('upgrade.php?stage=pimpmyenano'); ?>">do the upgrade and get it over with</a>.</p>
+  <?php
+}
+
 $ui->show_footer();
 
--- a/language/english/admin.json	Sat Jan 26 11:51:19 2008 -0500
+++ b/language/english/admin.json	Sat Jan 26 15:42:32 2008 -0500
@@ -40,6 +40,8 @@
       sbedit: 'Sidebar editor',
     },
     adm: {
+      page_tagline: 'Administer your Enano website.',
+      
       cat_general: 'General',
       cat_content: 'Content',
       cat_appearance: 'Appearance',
@@ -487,7 +489,7 @@
       
       // Backup interface
       heading_backup: 'Backup language',
-      backup_intro: 'You can back up this language to make preserving custom strings easier if you ever migrate your Enano installation or re-install. Backed-up language files can be restored by using FTP or equivalent to copy the backup file to the language\'s folder and renaming it to "backup.json".',
+      backup_intro: 'You can back up this language to make preserving custom strings easier if you ever migrate your Enano installation or re-install. Backed-up language files can be restored by using FTP or equivalent to copy the backup file to the language\'s folder, renaming it to "backup.json", and re-importing the language.',
       btn_create_backup: 'Download backup',
       
       // Uninstaller
--- a/language/english/core.json	Sat Jan 26 11:51:19 2008 -0500
+++ b/language/english/core.json	Sat Jan 26 15:42:32 2008 -0500
@@ -438,6 +438,7 @@
       upload_files: 'Upload files',
       upload_new_version: 'Upload new versions of files',
       create_page: 'Create pages',
+      html_in_pages: 'Embed unrestricted HTML in pages',
       php_in_pages: 'Embed PHP code in pages',
       edit_acl: 'Edit access control lists',
     },
@@ -511,6 +512,8 @@
       wizard_next: 'Next >',
       wizard_back: '< Back',
       wizard_previous: '< Previous',
+      // Generic link to main page
+      btn_main_page: 'Main page',
       // Generic switchable editor buttons
       tinymce_btn_text: 'text editor',
       tinymce_btn_graphical: 'graphical editor',
--- a/language/english/user.json	Sat Jan 26 11:51:19 2008 -0500
+++ b/language/english/user.json	Sat Jan 26 15:42:32 2008 -0500
@@ -59,7 +59,7 @@
       err_too_big_for_britches: 'You are trying to authenticate at a level that your user account does not permit.',
       err_invalid_credentials: 'You have entered an invalid username or password. Please enter your login details again.',
       err_invalid_credentials_lockout: ' You have used up %fails% out of %config.lockout_threshold% login attempts. After you have used up all %config.lockout_threshold% login attempts, you will be locked out from logging in for %config.lockout_duration% minutes.',
-      err_invalid_credentials_lockout_captcha: ' You have used up %lockout_fails% out of %config.lockout_threshold% login attempts. After you have used up all %config.lockout_threshold% login attempts, you will have to enter a visual confirmation code while logging in, effective for %config.lockout_duration% minutes.',
+      err_invalid_credentials_lockout_captcha: ' You have used up %fails% out of %config.lockout_threshold% login attempts. After you have used up all %config.lockout_threshold% login attempts, you will have to enter a visual confirmation code while logging in, effective for %config.lockout_duration% minutes.',
       err_backend_fail: 'You entered the right credentials and everything was validated, but for some reason Enano couldn\'t register your session. This is an internal problem with the site and you are encouraged to contact site administration.',
       err_locked_out: 'You have used up all %config.lockout_threshold% allowed login attempts. Please wait %time_rem% minute%plural% before attempting to log in again%captcha_blurb%.',
       err_locked_out_captcha_blurb: ', or enter the visual confirmation code shown above in the appropriate box',
@@ -528,6 +528,7 @@
       ml_msg_matches: 'Search returned %matches% matches',
     },
     userpage: {
+      page_title: '%username%\'s user page',
       heading_basics: 'All about %username%',
       lbl_joined: 'Joined:',
       lbl_num_comments: 'Total comments:',
--- a/licenses/index.html	Sat Jan 26 11:51:19 2008 -0500
+++ b/licenses/index.html	Sat Jan 26 15:42:32 2008 -0500
@@ -106,12 +106,13 @@
 <ul>
   <li><a href="http://pajhome.org.uk/">Paul Johnston</a>'s implementations of the MD5 and SHA1 algorithms in Javascript</li>
   <li><a href="http://labs.adobe.com/technologies/spry/">Adobe Spry</a>, used for some Javascript effects</li>
+  <li><a href="http://framework.zend.com/">Zend Framework</a>, for the majority of JSON operations</li>
 </ul>
 
 <h2>The MIT/X License</h2>
 <p><a href="mitlic.html">View the text of this license</a></p>
 <ul>
-  <li><a href="http://www.3site.it/">FastJSON</a> - a JSON encoder/decoder. Copyright &copy; 2006 - 2007 Andrea Giammarchi.</li>
+  <li><a href="http://www.3site.it/">FastJSON</a> - a JSON encoder/decoder. Only used when PHP4 compatibility is a must (early in the installer). Copyright &copy; 2006 - 2007 Andrea Giammarchi.</li>
 </ul>
 
 <h2>Unknown license</h2>
--- a/plugins/SpecialAdmin.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/plugins/SpecialAdmin.php	Sat Jan 26 15:42:32 2008 -0500
@@ -2140,7 +2140,7 @@
     {
       $template->header();
     }
-    echo 'Administer your Enano website.';
+    echo $lang->get('adm_page_tagline');
     ?>
     <script type="text/javascript">
     function ajaxPage(t)
--- a/plugins/SpecialUserFuncs.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/plugins/SpecialUserFuncs.php	Sat Jan 26 15:42:32 2008 -0500
@@ -1071,7 +1071,7 @@
       echo '    <th>' . $lang->get('history_col_actions') . '</th>
               </tr>';
     }
-    ++$$current;
+    $$current++;
     $cls = ( $cls == 'row1' ) ? 'row2' : 'row1';
     
     echo '<tr>';
@@ -1162,7 +1162,10 @@
   if ( $current == 'cnt_edits' )
   {
     // no "other" edits, close the table
-    echo '</table></div>';
+    if ( $cnt_edits > 0 )
+      echo '</table></div>';
+    else
+      echo '<p>' . $lang->get('userfuncs_contribs_msg_no_edits') . '</p>';
     echo '<h3>' . $lang->get('userfuncs_contribs_heading_other') . '</h3>';
     echo '<p>' . $lang->get('userfuncs_contribs_msg_no_other') . '</p>';
   }
--- a/plugins/admin/LangManager.php	Sat Jan 26 11:51:19 2008 -0500
+++ b/plugins/admin/LangManager.php	Sat Jan 26 15:42:32 2008 -0500
@@ -540,7 +540,10 @@
   echo '</table></div>';
   
   // Reset the result pointer to zero so we can fetch that list of languages again
-  $db->sql_data_seek(0, $q);
+  if ( !$db->sql_data_seek(0, $q) )
+  {
+    $db->_die('LangManager doing seek back to zero for installation blacklist');
+  }
   
   // $lang_list is fetched by the posthandler sometimes
   if ( !isset($lang_list) )
@@ -550,7 +553,7 @@
     $lang_list = list_available_languages();
   }
   
-  while ( $row = $db->fetchrow() )
+  while ( $row = $db->fetchrow($q) )
   {
     $lang_code =& $row['lang_code'];
     if ( isset($lang_list[$lang_code]) )
--- a/themes/admin/footer.tpl	Sat Jan 26 11:51:19 2008 -0500
+++ b/themes/admin/footer.tpl	Sat Jan 26 15:42:32 2008 -0500
@@ -1,6 +1,6 @@
           </div>
           <div class="footer">
-            {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
+            {COPYRIGHT}<br />Powered by <a href="{URL_ABOUT_ENANO}">Enano</a> &bull; Copyright &copy; 2006-2008 Dan Fuhry
           </div>
         </td>
         <td class="right"></td>
@@ -38,16 +38,5 @@
     </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="root3" class="jswindow" style="display: none;">
-      <div id="tb3" class="titlebar">Wiki formatting help</div>
-      <div class="content" id="cn3">
-        Loading...
-      </div>
-    </div>
   </body>
 </html>
--- a/themes/admin/header.tpl	Sat Jan 26 11:51:19 2008 -0500
+++ b/themes/admin/header.tpl	Sat Jan 26 15:42:32 2008 -0500
@@ -17,10 +17,10 @@
     <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_QUES}">Main page &#0187;</a>&nbsp;]
+      [&nbsp;<a href="{SCRIPTPATH}/{ADMIN_SID_QUES}">{lang:etc_btn_main_page} &#0187;</a>&nbsp;]
     </div>
     <div class="menu_nojs" id="pagebar_main">
-      <div class="label">Page tools</div>
+      <div class="label">{lang:onpage_lbl_pagetools}</div>
       {TOOLBAR}
       <ul>
         {TOOLBAR_EXTRAS}
--- a/themes/admin/simple-footer.tpl	Sat Jan 26 11:51:19 2008 -0500
+++ b/themes/admin/simple-footer.tpl	Sat Jan 26 15:42:32 2008 -0500
@@ -1,6 +1,6 @@
           </div>
           <div class="footer">
-            {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
+            {COPYRIGHT}<br />Powered by <a href="{URL_ABOUT_ENANO}">Enano</a> &bull; Copyright &copy; 2007 Dan Fuhry
           </div>
         </td>
         <td class="right"></td>
--- a/themes/oxygen/footer.tpl	Sat Jan 26 11:51:19 2008 -0500
+++ b/themes/oxygen/footer.tpl	Sat Jan 26 15:42:32 2008 -0500
@@ -12,7 +12,7 @@
                  -->
             <div id="credits">
               <b>{COPYRIGHT}</b><br />
-              Website engine powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>&nbsp;&nbsp;|&nbsp;&nbsp;Generated in [[GenTime]]sec<!-- BEGIN auth_admin -->&nbsp;&nbsp;|&nbsp;&nbsp;<a href="{REPORT_URI}">[[NumQueries]] SQL</a><!-- END auth_admin -->
+              Website engine powered by <a href="{URL_ABOUT_ENANO}">Enano</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>&nbsp;&nbsp;|&nbsp;&nbsp;Generated in [[GenTime]]sec<!-- BEGIN auth_admin -->&nbsp;&nbsp;|&nbsp;&nbsp;<a href="{REPORT_URI}">[[NumQueries]] SQL</a><!-- END auth_admin -->
               <!-- Do not remove this line or scheduled tasks will not run. -->
               <img alt=" " src="{SCRIPTPATH}/cron.php" width="1" height="1" />
             </div>
--- a/themes/oxygen/header.tpl	Sat Jan 26 11:51:19 2008 -0500
+++ b/themes/oxygen/header.tpl	Sat Jan 26 15:42:32 2008 -0500
@@ -159,7 +159,13 @@
           <td id="mdg-bl"></td>
           <td class="menu_bg">
           <div class="menu_nojs" id="pagebar_main">
-            <div class="label">{lang:onpage_lbl_pagetools}</div>
+            <div class="label">
+              <!-- BEGIN stupid_mode -->
+              Page tools
+              <!-- BEGINELSE stupid_mode -->
+              {lang:onpage_lbl_pagetools}
+              <!-- END stupid_mode -->
+            </div>
             {TOOLBAR}
             <ul>
               {TOOLBAR_EXTRAS}
--- a/themes/stpatty/footer.tpl	Sat Jan 26 11:51:19 2008 -0500
+++ b/themes/stpatty/footer.tpl	Sat Jan 26 15:42:32 2008 -0500
@@ -10,7 +10,7 @@
                  -Dan
                  -->
           <b>{COPYRIGHT}</b><br />
-          Powered by <a href="<!-- BEGIN stupid_mode -->http://enanocms.org/<!-- BEGINELSE stupid_mode -->{URL_ABOUT_ENANO}<!-- END stupid_mode -->">Enano</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>&nbsp;&nbsp;|&nbsp;&nbsp;Time: [[GenTime]]s<!-- BEGIN auth_admin -->&nbsp;&nbsp;|&nbsp;&nbsp;<a href="{REPORT_URI}">[[NumQueries]] SQL</a><!-- END auth_admin -->
+          Powered by <a href="{URL_ABOUT_ENANO}">Enano</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.1</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href="http://jigsaw.w3.org/css-validator/validator?uri=referer">Valid CSS</a>&nbsp;&nbsp;|&nbsp;&nbsp;Time: [[GenTime]]s<!-- BEGIN auth_admin -->&nbsp;&nbsp;|&nbsp;&nbsp;<a href="{REPORT_URI}">[[NumQueries]] SQL</a><!-- END auth_admin -->
           <!-- Do not remove this line or scheduled tasks will not run. -->
           <img alt=" " src="{SCRIPTPATH}/cron.php" width="1" height="1" />
         </div>