Merging in work done on Charlie with upstream
authorDan
Tue, 25 Aug 2009 01:43:40 -0400
changeset 1103 90225c988124
parent 1102 faef5e62e1e0 (current diff)
parent 1101 30d8bb88572d (diff)
child 1104 299d7e6e328b
Merging in work done on Charlie with upstream
ajax.php
--- a/README	Tue Aug 25 01:43:11 2009 -0400
+++ b/README	Tue Aug 25 01:43:40 2009 -0400
@@ -1,5 +1,5 @@
 Enano CMS
-Version 1.1.6
+Version 1.1.7
 -----------------------------
 
 Thanks for downloading Enano! If you're looking for an installation guide,
@@ -44,81 +44,59 @@
 from other projects that are also released under Free licenses; see the various
 files under the licenses/ directory included with this release for details.
 
-MODIFIED DISTRIBUTIONS / FORKS
------------------------------
-
-Please note that the Enano team does not provide any support for modified or
-"modded" releases. So if you modify the Enano sources at all, you will not
-receive any support from official sources. If you distribute your modified
-versions, providing support is entirely up to you. You also must remove any
-links to official Enano support channels contained in the source code if you
-distribute any modified version of Enano. We also respectfully request that you
-not call any modified distributions "Enano" or any deviation thereof; while the
-term "Enano" is not a registered trademark, we do ask that you respect it.
-
-Please note that the official Enano artwork is copyrighted and not under the
-GPL. If you distribute any modified version of Enano, you must change the
-artwork. (If you're seeking to include Enano as part of a larger software
-distribution, such as GNU/Linux or BSD, e-mail Dan for special terms.)
-
-As permitted by the GPL, you may charge for the service of downloading Enano
-from your server; however, you may not prevent others from distributing Enano
-or any modified version.
-
 CHANGES IN THIS RELEASE
 -----------------------------
 
-Please see <http://enanocms.org/Release_notes/1.1.5> for a list of changes in
+Please see <http://enanocms.org/Release_notes/1.1.7> for a list of changes in
 this release.
 
 UPGRADING FROM PREVIOUS RELEASES
 -----------------------------
 
 This archive includes a script that can migrate an Enano 1.0.x installation to
-Enano 1.1. Before running the migration script, you should always be sure to
-upgrade to the latest version of Enano 1.0.x (1.0.4 "Ellyyllon" at the time of
-this writing). Migration is NOT REVERSIBLE. This is alpha-quality code. DO NOT
+Enano 1.2. Before running the migration script, you should always be sure to
+upgrade to the latest version of Enano 1.0.x (1.0.7 "FIXME" at the time of
+this writing). Migration is NOT REVERSIBLE. This is beta-quality code. DO NOT
 UNDER ANY CIRCUMSTANCES UPGRADE A PRODUCTION SITE.
 
-As of Enano 1.1.2, upgrades from previous 1.1.x versions are supported. The API
-is considered fairly stable as of 1.1.4, but the interface is still a work in
-progress except for the installer UI core, which is quite close to final.
+Upgrades from any 1.1.x version are fully supported and generally more stable
+than upgrades from 1.0 because of all the API changes. If you experience
+trouble upgrading from a 1.0 version to 1.2, try upgrading first to version
+1.1.6 or so.
 
 TRANSLATING ENANO
 -----------------------------
 
-This is the only the fifth formal release of Enano that is localized. Right
-now since this is an alpha, you probably don't want to do any translation
-because you'll be doing a TON more strings at every release. HOWEVER, we're
-looking for people to sign up and volunteer for translation efforts later on.
-If you have a native or very good knowledge of a language, drop us an e-mail
-and we'll get you onto the translator list and eventually onto a mailing list
-specifically for l10n.
+There have been quite a few changes to strings in the 1.2 series. Since this
+is a beta, you probably don't want to do a lot of translation because you'll
+be doing a TON more strings at every release. HOWEVER, we're looking for
+people to sign up and volunteer for translation efforts later on. If you have
+a native or very good knowledge of a language, drop us an e-mail and we'll get
+you onto the translator list and eventually onto a mailing list specifically
+for l10n if that effort becomes big enough.
 
-EXPANDING YOUR SITE'S CAPABILITIES
+PLUG-INS
 -----------------------------
 
-There is a gallery of plugins for Enano at
-<http://enanocms.org/Category:Plugins>. It's not very full right now because
-not every plugin has a page on the website yet, and some plugins still have
-yet to be ported to work with some of the newer API changes. Being an alpha
-release you'll probably need to look in the Mercurial repositories at
-<http://hg.enanocms.org/> for the latest versions of plugins that are designed
-to work under both 1.0.x and 1.1.x.
+Most Enano features you see are actually the work of plugins. You can see a
+gallery of plugins at <http://enanocms.org/Category:Plugins>. Most of the
+plugins there work under Enano 1.2, but some don't. Plugins with known
+compatibility problems are marked; if you don't see any notes to the
+contrary, it's probably compatible with Enano 1.2.
 
-GIVING YOUR SITE A NEW LOOK
+THEMES
 -----------------------------
 
 You can find more themes for Enano at <http://enanocms.org/Category:Themes>.
-Again, we're still working on packaging up themes and creating pages for them,
-so try to be patient. We have quite a few themes in the works. You can create
-your own themes too; for more information, see Chapter V of the Enano
-Administrator's handbook, at <http://docs.enanocms.org/Help:5>. Unless
-specifically marked, themes on the Enano website are compatible with 1.0.x.
-While you can use 1.0.x themes under 1.1.x, some features (namely viewing IPs
-on comments and the default "Inherit" option in the ACL editor) will be missing
-unless you copy over comment.tpl and acledit.tpl respectively from Oxygen or
-one of the other themes included with this 1.1.x package.
+We're not doing too great with developing themes, and what we have developed
+often doesn't make it up to the website. :) So your choices on the website
+look a little bit more limited than they really are.
+
+Unlike plugins, themes are generally very easy to port from 1.0 to 1.2. Copy
+over acledit.tpl, comment.tpl, and toolbar.tpl from a 1.2 theme and remove
+the <script> tag that includes jsres.php, replacing it with {JS_HEADER} in
+header.tpl. Then put {JS_FOOTER} right before </body> in footer.tpl. Do the
+same in simple_header.tpl and simple_footer.tpl. That's pretty much it.
 
 PLUGIN DEVELOPMENT
 -----------------------------
@@ -127,21 +105,14 @@
 effort has been made to allow 1.0.x plugins that don't hook very deeply to
 continue to work; however with all of the new functionality (localization
 especially) we recommend that developers take the time to learn how to use the
-new plugin management platform. This system is fully documented in the large
-comment block in plugins/admin/PluginManager.php.
+newer parts of the Enano platform. Enano tries to be very developer-friendly;
+our full API documentation is at <http://docs.enanocms.org/API>.
 
 GETTING SUPPORT
 -----------------------------
 
-This is an alpha release. No support of any kind will be provided, but proper
-bug reports are appreciated. See the Enano forums at
-<http://forum.enanocms.org/> for more information.
+This is a beta release. No support of any kind will be provided, but proper bug
+reports are appreciated. See the Enano forums at <http://forum.enanocms.org/>
+for more information.
 
 Have fun with Enano!
-
-- The Enano team
-  Dan Fuhry     <dan@enanocms.org>
-  Neal Gompa    <neal@enanocms.org>
-  Manoj Maddali <manoj@enanocms.org>
-  ThGeneral8    <the.true.general@googlemail.com>
-
--- a/ajax.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/ajax.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -96,7 +95,7 @@
         $row =& $draft_row;
         $return['have_draft'] = true;
         $return['draft_author'] = $row['author'];
-        $return['draft_time'] = enano_date('d M Y h:i a', intval($row['time_id']));
+        $return['draft_time'] = enano_date(ED_DATE | ED_TIME, intval($row['time_id']));
         if ( isset($_GET['get_draft']) && @$_GET['get_draft'] === '1' )
         {
           $return['src'] = $row['page_text'];
@@ -286,7 +285,7 @@
           $return = array(
             'mode' => 'obsolete',
             'author' => $row['author'],
-            'date_string' => enano_date('d M Y h:i a', $row['time_id']),
+            'date_string' => enano_date(ED_DATE | ED_TIME, $row['time_id']),
             'time' => $row['time_id'] // time() ???
             );
           echo enano_json_encode($return);
--- a/cron.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/cron.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/cache.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/cache.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/captcha.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/captcha.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * captcha.php - visual confirmation system used during registration
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/captcha/engine_default.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/captcha/engine_default.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * captcha.php - visual confirmation system used during registration
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/captcha/engine_failsafe.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/captcha/engine_failsafe.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * captcha.php - visual confirmation system used during registration
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/captcha/engine_potpourri.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/captcha/engine_potpourri.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * captcha.php - visual confirmation system used during registration
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/clientside/jscompress.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/clientside/jscompress.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * jsres.php - the Enano client-side runtime, a.k.a. AJAX on steroids
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/clientside/jsres.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/clientside/jsres.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * jsres.php - the Enano client-side runtime, a.k.a. AJAX on steroids
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/clientside/static/login.js	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/clientside/static/login.js	Tue Aug 25 01:43:40 2009 -0400
@@ -1247,30 +1247,26 @@
   window.location = loc;
 }
 
-var navto_ns;
-var navto_pg;
-var navto_ul;
-
-window.ajaxLoginNavTo = function(namespace, page_id, min_level)
+window.ajaxLoginNavTo = function(namespace, page_id, min_level, get)
 {
   // IE <6 pseudo-compatibility
   if ( KILL_SWITCH )
     return true;
-  navto_pg = page_id;
-  navto_ns = namespace;
-  navto_ul = min_level;
+  void(namespace);
+  void(page_id);
+  get = get || false;
   if ( auth_level < min_level )
   {
     ajaxPromptAdminAuth(function(k) {
       ENANO_SID = k;
-      auth_level = navto_ul;
-      var loc = makeUrlNS(navto_ns, navto_pg);
+      auth_level = min_level;
+      var loc = makeUrlNS(namespace, page_id, get);
       if ( (ENANO_SID + ' ').length > 1 )
         window.location = loc;
     }, min_level);
     return false;
   }
-  var loc = makeUrlNS(navto_ns, navto_pg);
+  var loc = makeUrlNS(namespace, page_id, get);
   window.location = loc;
 }
 
--- a/includes/clientside/static/messagebox.js	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/clientside/static/messagebox.js	Tue Aug 25 01:43:40 2009 -0400
@@ -66,7 +66,7 @@
     master_div.style.top = '-10000px';
     master_div.style.position = ( IE ) ? 'absolute' : 'fixed';
   }
-  z = ( aclDisableTransitionFX ) ? document.getElementById('specialLayer_darkener').style.zIndex : getHighestZ();
+  z = ( aclDisableTransitionFX ) ? document.getElementById('specialLayer_darkener').style.zIndex + 1: getHighestZ() + 1;
   mydiv.style.backgroundColor = '#FFFFFF';
   mydiv.style.padding = '10px';
   mydiv.style.marginBottom = '1px';
--- a/includes/clientside/tinymce/tiny_mce_gzip.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/clientside/tinymce/tiny_mce_gzip.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * tiny_mce_gzip.php - TinyMCE gzip and caching script, stock from MoxieCode with one modification
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/comment.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/comment.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -157,7 +156,7 @@
             }
             
             // Format date
-            $row['time'] = enano_date('F d, Y h:i a', $row['time']);
+            $row['time'] = enano_date(ED_DATE | ED_TIME, $row['time']);
             
             // Format signature
             $row['signature'] = ( !empty($row['signature']) ) ? RenderMan::render($row['signature']) : '';
@@ -313,20 +312,21 @@
           $subj = htmlspecialchars($data['subj']);
           $text = RenderMan::preprocess_text($data['text'], true, false);
           $src = $text;
+          $sql_subj = $db->escape($subj);
           $sql_text = $db->escape($text);
           $text = RenderMan::render($text);
           $appr = ( getConfig('approve_comments', '0') == '1' ) ? COMMENT_UNAPPROVED : COMMENT_APPROVED;
           if ( $appr === COMMENT_APPROVED && $spam_policy === 'moderate' && !$spamcheck )
             $appr = COMMENT_SPAM;
           $time = time();
-          $date = enano_date('F d, Y h:i a', $time);
+          $date = enano_date(ED_DATE | ED_TIME, $time);
           $ip = $_SERVER['REMOTE_ADDR'];
           if ( !is_valid_ip($ip) )
             die('Hacking attempt');
           
           // 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, ip_address) VALUES' . "\n  " .
-                             "('$this->page_id', '$this->namespace', '$name', '$subj', '$sql_text', $appr, $time, {$session->user_id}, '$ip');");
+                             "('$this->page_id', '$this->namespace', '$name', '$sql_subj', '$sql_text', $appr, $time, {$session->user_id}, '$ip');");
           if(!$q)
             $db->die_json();
           
--- a/includes/common.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/common.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -44,7 +43,7 @@
 // be the expected output of enano_version(), which will always be in the
 // format of 1.0.2, 1.0.2a1, 1.0.2b1, 1.0.2RC1
 // You'll want to change this for custom distributions.
-$version = '1.1.6';
+$version = '1.1.7';
 
 /**
  * Returns a floating-point number with the current UNIX timestamp in microseconds. Defined very early because we gotta call it
@@ -227,21 +226,6 @@
 define('urlSeparator', $sep);
 unset($sep); // save 10 bytes of memory...
 
-// Sometimes there are critical failures triggered by initialization functions in the Enano API that are recurring
-// and cannot be fixed except for manual intervention. This is where that code should go.
-if ( isset($_GET['do']) && $_GET['do'] == 'diag' && isset($_GET['sub']) )
-{
-  switch($_GET['sub'])
-  {
-    case 'cookie_destroy':
-      unset($_COOKIE['sid']);
-      setcookie('sid', '', time()-3600*24, scriptPath);
-      setcookie('sid', '', time()-3600*24, scriptPath.'/');
-      die('Session cookie cleared. <a href="'.htmlspecialchars($_SERVER['PHP_SELF']).'">Continue</a>');
-      break;
-  }
-}
-
 // Build the list of system tables (this is mostly done in constants.php, but that's before table_prefix is known)
 if ( defined('table_prefix') && !defined('ENANO_TABLELIST_PREFIXED') )
 {
@@ -397,22 +381,25 @@
   
   profiler_log('Finished base_classes_initted hook');
   
-  // For special and administration pages, sometimes there is a "preloader" function that must be run
-  // before the session manager and/or path manager get the init signal. Call it here.  
-  $p = RenderMan::strToPageId($paths->get_pageid_from_url());
-  if( ( $p[1] == 'Admin' || $p[1] == 'Special' ) && function_exists('page_'.$p[1].'_'.$p[0].'_preloader'))
-  {
-    call_user_func('page_'.$p[1].'_'.$p[0].'_preloader');
-  }
-  
-  profiler_log('Checked for preloader');
-  
   // One quick security check...
   if ( !is_valid_ip($_SERVER['REMOTE_ADDR']) )
   {
     die('SECURITY: spoofed IP address: ' . htmlspecialchars($_SERVER['REMOTE_ADDR']));
   }
-
+  
+  // For special and administration pages, sometimes there is a "preloader" function that must be run
+  // before the session manager and/or path manager get the init signal. Call it here.
+  $title = get_title(true);
+  list($page_id, $namespace) = RenderMan::strToPageID($title);
+  list($page_id_top) = explode('/', $page_id);
+  $fname = "page_{$namespace}_{$page_id_top}_preloader";
+  if( ( $namespace == 'Admin' || $namespace == 'Special' ) && function_exists($fname))
+  {
+    call_user_func($fname);
+  }
+  
+  profiler_log('Checked for (and ran, if applicable) preloader');
+  
   // All checks passed! Start the main components up.  
   $session->start();
   
@@ -439,7 +426,7 @@
   
   profiler_log('Ran session_started hook');
   
-  $paths->init();
+  $paths->init($title);
   
   // setup output format
   if ( defined('ENANO_OUTPUT_FORMAT') )
--- a/includes/common_cli.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/common_cli.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -181,16 +180,6 @@
   
   profiler_log('Finished base_classes_initted hook');
   
-  // For special and administration pages, sometimes there is a "preloader" function that must be run
-  // before the session manager and/or path manager get the init signal. Call it here.  
-  $p = RenderMan::strToPageId($paths->get_pageid_from_url());
-  if( ( $p[1] == 'Admin' || $p[1] == 'Special' ) && function_exists('page_'.$p[1].'_'.$p[0].'_preloader'))
-  {
-    call_user_func('page_'.$p[1].'_'.$p[0].'_preloader');
-  }
-  
-  profiler_log('Checked for preloader');
-  
   // One quick security check...
   if ( isset($_SERVER['REMOTE_ADDR']) )
   {
--- a/includes/constants.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/constants.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * constants.php - important defines used Enano-wide
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -103,6 +102,24 @@
 define('THIRD_SUNDAY', 3);
 define('LAST_SUNDAY', 4);
 
+// Date types
+define('DATE_1', 'y/m/d');
+define('DATE_2', 'y/d/m');
+define('DATE_3', 'Y-m-d');
+define('DATE_4', 'F d, Y');
+// 12 hour, no seconds
+define('TIME_12_NS', 'g:i A');
+// 12 hour, seconds
+define('TIME_12_S', 'g:i:s A');
+// 24 hour, no seconds
+define('TIME_24_NS', 'G:i');
+// 24 hour, seconds
+define('TIME_24_S', 'G:i:s');
+
+define('ED_DATE', 1);
+define('ED_TIME', 2);
+define('ED_DATE_FULL', 4);
+
 // Rendering options!
 
 /**
--- a/includes/dbal.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/dbal.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/diff.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/diff.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/diffiehellman.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/diffiehellman.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * diffiehellman.php - Diffie Hellman key exchange and supporting functions
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/email.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/email.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -247,7 +246,7 @@
     {
       $this->mimeOut .= "From: ".$szFromAddress."\n";
       $this->mimeOut .= "To: ".$this->emailAddress."\n";
-      $this->mimeOut .= "Date: ".enano_date("D, d M Y H:i:s") . " UT\n";
+      $this->mimeOut .= "Date: ".enano_date('r') . " UT\n";
       $this->mimeOut .= "Reply-To:".$szFromAddress."\n";
       $this->mimeOut .= "Subject: ".$this->mailSubject."\n";
       $this->mimeOut .= "X-Mailer: PHP/".phpversion()."\n";
--- a/includes/functions.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/functions.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -247,6 +246,56 @@
 }
 
 /**
+ * Get the requested page title, taking into account all the different possible URL parsing schemes.
+ * @param bool If true (default), runs the result through sanitize_page_id().
+ * @param bool If true (default is false), and the return is a Special or Admin page, trims off anything beyond and including the first slash.
+ * @return string
+ */
+
+function get_title($sanitize = true, $chop_special = false)
+{
+  $title = '';
+  if ( isset($_GET['title']) )
+  {
+    $title = $_GET['title'];
+  }
+  else if ( isset($_SERVER['PATH_INFO']) )
+  {
+    // fix for apache + CGI (occurred on a GoDaddy server, thanks mm3)
+    if ( @substr(@$_SERVER['GATEWAY_INTERFACE'], 0, 3) === 'CGI' && $_SERVER['PATH_INFO'] == scriptPath . '/index.php' )
+    {
+      // do nothing; ignore PATH_INFO
+    }
+    else
+    {
+      $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 ( !empty($_SERVER['QUERY_STRING']) && substr($_SERVER['QUERY_STRING'], 0, 1) == '/' )
+    {
+      $pos = ( ($_ = strpos($_SERVER['QUERY_STRING'], '&')) !== false ) ? $_ - 1: 0x7FFFFFFF;
+      $title = substr($_SERVER['QUERY_STRING'], 1, $pos);
+    }
+  }
+  
+  if ( $chop_special )
+  {
+    list(, $ns) = RenderMan::strToPageID($title);
+    if ( $ns == 'Special' || $ns == 'Admin' )
+    {
+      list($title) = explode('/', $title);
+    }
+  }
+  
+  return ( $sanitize ) ? sanitize_page_id($title) : $title;
+}
+ 
+
+/**
  * 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.
@@ -258,6 +307,31 @@
   if ( !is_int($timestamp) && !is_double($timestamp) && strval(intval($timestamp)) !== $timestamp )
     $timestamp = time();
   
+  if ( is_int($string) )
+  {
+    global $session, $lang;
+    $date_fmt = is_object($session) ? $session->date_format : DATE_4;
+    $time_fmt = is_object($session) ? $session->time_format : TIME_24_NS;
+    
+    // within a week? use a relative date
+    if ( $timestamp + ( 86400 * 7 ) >= time() && $string & ED_DATE && is_object($lang) && is_object($session) && !($string & ED_DATE_FULL) )
+    {
+      $relative_date = get_relative_date($timestamp);
+      if ( $string === ED_DATE )
+        // why do more work if we're done?
+        return $relative_date;
+    }
+    
+    $flags = $string;
+    $string = array();
+    if ( $flags & ED_DATE && !isset($relative_date) )
+      $string[] = $date_fmt;
+    if ( $flags & ED_TIME )
+      $string[] = $time_fmt;
+    
+    $string = implode(' ', $string);
+  }
+  
   // perform timestamp offset
   global $timezone;
   // it's gonna be in minutes, so multiply by 60 to offset the unix timestamp
@@ -272,7 +346,63 @@
   }
   
   // Let PHP do the work for us =)
-  return gmdate($string, $timestamp);
+  $result = gmdate($string, $timestamp);
+  if ( isset($relative_date) )
+  {
+    $result = "$relative_date, $result";
+  }
+  return $result;
+}
+
+/**
+ * Get a relative date ("Today"/"Yesterday"/"N days ago")
+ * @param int Timestamp
+ * @return string
+ */
+
+function get_relative_date($time)
+{
+  global $lang, $session;
+  // Our formatting string to pass to enano_date()
+  // This should not include minute/second info, only today's date in whatever format suits your fancy
+  $formatstring = $session->date_format;
+  // Today's date
+  $today = enano_date($formatstring);
+  // Yesterday's date
+  $yesterday = enano_date($formatstring, (time() - (24*60*60)));
+  // Date on the input
+  $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 = enano_date($formatstring, (time() - $offset));
+    // so does the input timestamp match the date from $i days ago?
+    if ( $then == $days_ago )
+    {
+      // yes, return $i
+      return $lang->get('userfuncs_ml_date_daysago', array('days_ago' => $i));
+    }
+  }
+  // either yesterday, today, or before 6 days ago
+  switch($then)
+  {
+    case $today:
+      return $lang->get('userfuncs_ml_date_today');
+    case $yesterday:
+      return $lang->get('userfuncs_ml_date_yesterday');
+    default:
+      return $then;
+  }
+  //     .--.
+  //    |o_o |
+  //    |!_/ |
+  //   //   \ \
+  //  (|     | )
+  // /'\_   _/`\
+  // \___)=(___/
+  return 'Linux rocks!';
 }
 
 /**
@@ -485,7 +615,7 @@
     }
   }
   
-  ob_end_clean();
+  @ob_end_clean();
   
   $output->set_title($lang->get('user_csrf_confirm_title'));
   $output->header();
@@ -768,7 +898,7 @@
   global $db, $session, $paths, $template, $plugins; // Common objects
   $db->close();
   
-  if ( ob_get_status() )
+  if ( @ob_get_status() )
     ob_end_clean();
 
   // If the config hasn't been fetched yet, call grinding_halt.
@@ -809,7 +939,7 @@
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
 
-  if ( ob_get_status() )
+  if ( @ob_get_status() )
     ob_end_clean();
 
   $paths->cpage['name'] = $t;
@@ -838,7 +968,7 @@
   if ( is_object($db) )
     $db->close();
   
-  if ( ob_get_status() )
+  if ( @ob_get_status() )
     ob_end_clean();
   
   if ( defined('ENANO_CLI') )
@@ -1233,7 +1363,8 @@
       '1.1.3'  => 'Caoineag alpha 3',
       '1.1.4'  => 'Caoineag alpha 4',
       '1.1.5'  => 'Caoineag alpha 5',
-      '1.1.6'  => 'Caoineag beta 1'
+      '1.1.6'  => 'Caoineag beta 1',
+      '1.1.7'  => 'Caoineag beta 2'
     );
   $version = enano_version();
   if ( isset($names[$version]) )
@@ -3345,6 +3476,7 @@
   //   2001:470-471:054-b02b::5-bb
   // up to:
   //   2001:0470-0471:0054-b02b:0000:0000:0000:0005-00bb
+  $range = preg_replace('/^:/', '0000:', $range);
   $range = explode(':', $range);
   $expanded = '';
   $size = count($range);
@@ -3569,6 +3701,36 @@
 }
 
 /**
+ * Expand an IPv6 address to full form
+ * @param string ::1, 2001:470:e054::2
+ * @return string 0000:0000:0000:0000:0000:0000:0000:0001, 2001:0470:e054:0000:0000:0000:0000:0002
+ */
+
+function expand_ipv6_address($addr)
+{
+  $expanded = array();
+  $addr = explode(':', $addr);
+  foreach ( $addr as $i => $bytepair )
+  {
+    if ( empty($bytepair) )
+    {
+      // ::
+      while ( count($expanded) < (8 - count($addr) + $i + 1) )
+      {
+        $expanded[] = '0000';
+      }
+    }
+    else
+    {
+      while ( strlen($bytepair) < 4 )
+        $bytepair = "0$bytepair";
+      $expanded[] = $bytepair;
+    }
+  }
+  return implode(':', $expanded);
+}
+
+/**
  * Validates an e-mail address. Uses a compacted version of the regular expression generated by the scripts at <http://examples.oreilly.com/regex/>.
  * @param string E-mail address
  * @return bool
--- a/includes/hmac.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/hmac.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * hmac.php - HMAC cryptographic functions
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/http.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/http.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * class_http.php - Pure PHP HTTP client library
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -198,8 +197,9 @@
   
   function Request_HTTP($host, $uri, $method = 'GET', $port = 80)
   {
-    if ( !preg_match('/^(([a-z0-9-]+\.)*?)([a-z0-9-]+)$/', $host) )
+    if ( !preg_match('/^(?:(([a-z0-9-]+\.)*?)([a-z0-9-]+)|\[[a-f0-9:]+\])$/', $host) )
       throw new Exception(__CLASS__ . ': Invalid hostname');
+    // Yes - this really does support IPv6 URLs!
     $this->host = $host;
     $this->uri = $uri;
     if ( is_int($port) && $port >= 1 && $port <= 65535 )
--- a/includes/js-compressor.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/js-compressor.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Javascript compression library - used to compact the client-side Javascript code (all 72KB of it!) to save some bandwidth
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/lang.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/lang.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/log.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/log.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * log.php - Logs table parsing and displaying
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/math.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/math.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * diffiehellman.php - Diffie Hellman key exchange and supporting functions
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/namespaces/admin.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/namespaces/admin.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/namespaces/api.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/namespaces/api.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/namespaces/default.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/namespaces/default.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -398,8 +397,8 @@
       echo '<div class="info-box" style="margin-left: 0; margin-top: 5px;">
               <b>' . $lang->get('page_msg_archived_title') . '</b><br />
               ' . $lang->get('page_msg_archived_body', array(
-                  'archive_date' => enano_date('F d, Y', $this->revision_time),
-                  'archive_time' => enano_date('h:i a', $this->revision_time),
+                  'archive_date' => enano_date(ED_DATE, $this->revision_time),
+                  'archive_time' => enano_date(ED_TIME, $this->revision_time),
                   'current_link' => makeUrlNS($this->namespace, $this->page_id),
                   'restore_link' => makeUrlNS($this->namespace, $this->page_id, 'do=edit&amp;revid='.$this->revision_id),
                   'restore_onclick' => 'ajaxEditor(\''.$this->revision_id.'\'); return false;',
@@ -580,7 +579,7 @@
       {
         $r = $db->fetchrow();
         $standard_404 .= '<p>' . $lang->get('page_msg_404_was_deleted', array(
-                  'delete_time' => enano_date('d M Y h:i a', $r['time_id']),
+                  'delete_time' => enano_date(ED_DATE | ED_TIME, $r['time_id']),
                   'delete_reason' => htmlspecialchars($r['edit_summary']),
                   'rollback_flags' => 'href="'.makeUrl($paths->page, 'do=rollback&amp;id='.$r['log_id']).'" onclick="ajaxRollback(\''.$r['log_id'].'\'); return false;"'
                 ))
--- a/includes/namespaces/file.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/namespaces/file.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -70,7 +69,7 @@
     }
     $r = $db->fetchrow();
     $mimetype = $r['mimetype'];
-    $datestring = enano_date('F d, Y h:i a', (int)$r['time_id']);
+    $datestring = enano_date(ED_DATE | ED_TIME, (int)$r['time_id']);
     $html .= '<div class="mdg-comment" style="margin-left: 0;">
             <h3>' . $lang->get('onpage_filebox_heading') . '</h3>
             <p>' . $lang->get('onpage_filebox_lbl_type') . ' '.$r['mimetype'].'<br />';
--- a/includes/namespaces/special.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/namespaces/special.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/namespaces/template.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/namespaces/template.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/namespaces/user.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/namespaces/user.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -201,7 +200,7 @@
                 ' . $lang->get('userpage_lbl_joined') . '
               </td>
               <td class="row1" style="text-align: left; width: 25%;">
-                ' . enano_date('F d, Y h:i a', $userdata['reg_time']) . '
+                ' . enano_date(ED_DATE | ED_TIME, $userdata['reg_time']) . '
               </td>';
       echo '  <td class="row2" style="text-align: right; width: 25%;">
                 ' . $lang->get('userpage_lbl_num_comments') . '
@@ -238,7 +237,7 @@
       {
         do 
         {
-          $row['time'] = enano_date('F d, Y', $row['time']);
+          $row['time'] = enano_date(ED_DATE, $row['time']);
           $comments[] = $row;
         }
         while ( $row = $db->fetchrow() );
--- a/includes/output.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/output.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,9 +2,8 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
  * output.php - Controls output format, messages of death, that kind of stuff
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/pageprocess.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/pageprocess.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,9 +2,8 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
  * pageprocess.php - intelligent retrieval of pages
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -457,7 +456,7 @@
     $time = time();
     $edit_summary = ( strval($edit_summary) === $edit_summary ) ? $db->escape($edit_summary) : '';
     $minor_edit = ( $minor_edit ) ? '1' : '0';
-    $date_string = enano_date('d M Y h:i a');
+    $date_string = enano_date(ED_DATE | ED_TIME);
     
     // 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, page_format )\n"
@@ -590,7 +589,7 @@
     
     // Query 3: Log entry
     $db->sql_query('INSERT INTO ' . table_prefix."logs(time_id, date_string, log_type, action, author, page_id, namespace)\n"
-                   . "  VALUES ( " . time() . ", '" . enano_date('d M Y h:i a') . "', 'page', 'create', \n"
+                   . "  VALUES ( " . time() . ", 'DEPRECATED', 'page', 'create', \n"
                    . "          '" . $db->escape($session->username) . "', '" . $db->escape($this->page_id) . "', '" . $this->namespace . "');");
     if ( !$q )
       $db->_die('PageProcessor page creation - logging stage');
@@ -653,7 +652,7 @@
     $log_entry = $db->fetchrow();
     $db->free_result();
     
-    $dateline = enano_date('d M Y h:i a', $log_entry['time_id']);
+    $dateline = enano_date(ED_DATE | ED_TIME, $log_entry['time_id']);
     
     // Let's see, what do we have here...
     switch ( $log_entry['action'] )
@@ -1133,7 +1132,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().', \''.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))) . '\')');
+    $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().', \'DEPRECATED\', \''.$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';
--- a/includes/pageutils.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/pageutils.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * pageutils.php - a class that handles raw page manipulations, used mostly by AJAX requests or their old-fashioned form-based counterparts
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -205,7 +204,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().', \''.enano_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().', \'DEPRECATED\', \'page\', \'create\', \'' . $session->username . '\', \'' . $db->escape($page_id) . '\', \'' . $namespace . '\');');
     
     if($qa && $qb && $qc)
       return 'good';
@@ -332,7 +331,7 @@
         if($ticker < $numrows) echo '<td class="' . $cls . '" style="padding: 0;"><input ' . $s2 . 'name="diff2" type="radio" value="' . $r['time_id'] . '" id="diff2_' . $r['time_id'] . '" class="clsDiff2Radio" onclick="selectDiff2Button(this);" /></td>'."\n"; else echo '<td class="' . $cls . '"></td>';
         
         // Date and time
-        echo '<td class="' . $cls . '" style="white-space: nowrap;">' . enano_date('d M Y h:i a', intval($r['time_id'])) . '</td class="' . $cls . '">'."\n";
+        echo '<td class="' . $cls . '" style="white-space: nowrap;">' . enano_date(ED_DATE | ED_TIME, intval($r['time_id'])) . '</td class="' . $cls . '">'."\n";
         
         // User
         if ( $session->get_permissions('mod_misc') && is_valid_ip($r['author']) )
@@ -408,7 +407,7 @@
         echo '<tr>';
         
         // Date and time
-        echo '<td class="' . $cls . '">' . enano_date('d M Y h:i a', intval($r['time_id'])) . '</td class="' . $cls . '">';
+        echo '<td class="' . $cls . '">' . enano_date(ED_DATE | ED_TIME, intval($r['time_id'])) . '</td class="' . $cls . '">';
         
         // User
         echo '<td class="' . $cls . '"><a href="'.makeUrlNS('User', sanitize_page_id($r['author'])).'" ';
@@ -630,7 +629,7 @@
         $strings['SUBJECT'] = $s;
         
         // Date and time
-        $strings['DATETIME'] = enano_date('F d, Y h:i a', $row['time']);
+        $strings['DATETIME'] = enano_date(ED_DATE | ED_TIME, $row['time']);
         
         // User level
         switch($row['user_level'])
@@ -1011,7 +1010,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().', \''.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.');';
+      $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(ED_DATE | ED_TIME).'\', \'' . $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');
@@ -1043,7 +1042,7 @@
       return $lang->get('etc_access_denied_need_reauth');
     }
     
-    $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)) . '\')');
+    $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(ED_DATE | ED_TIME).'\', \'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.');
@@ -1600,8 +1599,8 @@
     }
     $text1 = $row1['page_text'];
     $text2 = $row2['page_text'];
-    $time1 = enano_date('F d, Y h:i a', $row1['time_id']);
-    $time2 = enano_date('F d, Y h:i a', $row2['time_id']);
+    $time1 = enano_date(ED_DATE | ED_TIME, $row1['time_id']);
+    $time2 = enano_date(ED_DATE | ED_TIME, $row2['time_id']);
     $_ob = "
     <p>" . $lang->get('history_lbl_comparingrevisions') . " {$time1} &rarr; {$time2}</p>
     ";
--- a/includes/paths.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/paths.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /**
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * paths.php - The part of Enano that actually manages content. Everything related to page handling and namespaces is in here.
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -19,7 +18,7 @@
  
 class pathManager
 {
-  public $pages, $custom_page, $cpage, $page, $fullpage, $page_exists, $page_id, $namespace, $nslist, $admin_tree, $wiki_mode, $page_protected, $template_cache, $external_api_page;
+  public $title, $pages, $custom_page, $cpage, $page, $fullpage, $page_exists, $page_id, $namespace, $nslist, $admin_tree, $wiki_mode, $page_protected, $template_cache, $external_api_page;
   
   /**
    * List of custom processing functions for namespaces. This is protected so trying to do anything with it will throw an error.
@@ -119,39 +118,7 @@
     $this->template_cache = Array();
   }
   
-  function parse_url($sanitize = true)
-  {
-    $title = '';
-    if ( isset($_GET['title']) )
-    {
-      $title = $_GET['title'];
-    }
-    else if ( isset($_SERVER['PATH_INFO']) )
-    {
-      // fix for apache + CGI (occurred on a GoDaddy server, thanks mm3)
-      if ( @substr(@$_SERVER['GATEWAY_INTERFACE'], 0, 3) === 'CGI' && $_SERVER['PATH_INFO'] == scriptPath . '/index.php' )
-      {
-        // do nothing; ignore PATH_INFO
-      }
-      else
-      {
-        $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 ( !empty($_SERVER['QUERY_STRING']) && substr($_SERVER['QUERY_STRING'], 0, 1) == '/' )
-      {
-        $pos = ( ($_ = strpos($_SERVER['QUERY_STRING'], '&')) !== false ) ? $_ - 1: 0x7FFFFFFF;
-        $title = substr($_SERVER['QUERY_STRING'], 1, $pos);
-      }
-    }
-    return ( $sanitize ) ? sanitize_page_id($title) : $title;
-  }
-  
-  function init()
+  function init($title)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
     global $lang;
@@ -165,7 +132,9 @@
     
     if ( defined('ENANO_INTERFACE_INDEX') || defined('ENANO_INTERFACE_AJAX') || defined('IN_ENANO_UPGRADE') )
     {
-      $title = $this->parse_url(false);
+      if ( empty($title) )
+        $title = get_title();
+      
       if ( empty($title) && get_main_page() != '' )
       {
         $this->main_page();
@@ -471,16 +440,7 @@
   }
   function get_pageid_from_url()
   {
-    $url = $this->parse_url();
-    if ( substr($url, 0, strlen($this->nslist['Special'])) == $this->nslist['Special'] ||
-         substr($url, 0, strlen($this->nslist['Admin']))   == $this->nslist['Admin'])
-    {
-      list(, $ns) = RenderMan::strToPageID($url);
-      $upart = substr($url, strlen($this->nslist[$ns]));
-      list($upart) = explode('/', $upart);
-      $url = $this->nslist[$ns] . $upart;
-    }
-    return $url;
+    return get_title(true, true);
   }
   // Parses a (very carefully formed) array into Javascript code compatible with the Tigra Tree Menu used in the admin menu
   function parseAdminTree() 
@@ -591,7 +551,7 @@
   }
   function getParam($id = 0)
   {
-    $title = $this->parse_url(false);
+    $title = $this->fullpage;
     list(, $ns) = RenderMan::strToPageID($title);
     $title = substr($title, strlen($this->nslist[$ns]));
     $regex = '/^' . str_replace('/', '\\/', preg_quote($this->nslist[$ns])) . '\\/?/';
@@ -603,7 +563,7 @@
   
   function getAllParams()
   {
-    $title = $this->parse_url(false);
+    $title = $this->fullpage;
     $regex = '/^' . str_replace('/', '\\/', preg_quote($this->nslist[$this->namespace])) . '\\/?/';
     $title = preg_replace($regex, '', $title);
     $title = explode('/', $title);
--- a/includes/plugins.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/plugins.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/render.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/render.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * render.php - handles fetching pages and parsing them into HTML
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -618,51 +617,15 @@
   public static function parse_internal_links($text, $tplcode = false, $do_exist_check = true, $match_page_id = false, $match_namespace = false)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
-    
-    if ( is_string($tplcode) )
-    {
-      $parser = $template->makeParserText($tplcode);
-    }
+  
+    $parser = is_string($tplcode) ? $template->makeParserText($tplcode) : false;
     
     // stage 1 - links with alternate text
     preg_match_all('/\[\[([^\[\]<>\{\}\|]+)\|(.+?)\]\]/', $text, $matches);
     foreach ( $matches[0] as $i => $match )
     {
       list($page_id, $namespace) = RenderMan::strToPageID($matches[1][$i]);
-      if ( ($pos = strrpos($page_id, '#')) !== false )
-      {
-        $hash = substr($page_id, $pos);
-        $page_id = substr($page_id, 0, $pos);
-      }
-      else
-      {
-        $hash = '';
-      }
-      $pid_clean = $paths->nslist[$namespace] . sanitize_page_id($page_id);
-      
-      $url = makeUrl($pid_clean, false, true) . $hash;
-      $inner_text = $matches[2][$i];
-      $quot = '"';
-      $exists = ( ($do_exist_check && isPage($pid_clean)) || !$do_exist_check ) ? '' : ' class="wikilink-nonexistent"';
-      
-      if ( $match_page_id && $match_namespace && $pid_clean === $paths->get_pathskey($match_page_id, $match_namespace) )
-        $exists .= ' class="currentpage"';
-      
-      if ( $tplcode )
-      {
-        $parser->assign_vars(array(
-            'HREF' => $url,
-            'FLAGS' => $exists,
-            'TEXT' => $inner_text
-          ));
-        $link = $parser->run();
-      }
-      else
-      {
-        $omatch = self::escape_parser_hint_attrib($match);
-        $link = "<!--#internallink src=\"$omatch\" --><a href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a><!--#/internallink-->";
-      }
-      
+      $link = self::generate_internal_link($namespace, $page_id, $matches[2][$i], $match, $parser, $do_exist_check, $match_page_id, $match_namespace);
       $text = str_replace($match, $link, $text);
     }
     
@@ -672,29 +635,9 @@
     {
       list($page_id, $namespace) = RenderMan::strToPageID($matches[1][$i]);
       $pid_clean = $paths->nslist[$namespace] . sanitize_page_id($page_id);
-      
-      $url = makeUrl($pid_clean, false, true);
       $inner_text = ( isPage($pid_clean) ) ? htmlspecialchars(get_page_title($pid_clean)) : htmlspecialchars($matches[1][$i]);
-      $quot = '"';
-      $exists = ( ($do_exist_check && isPage($pid_clean)) || !$do_exist_check ) ? '' : ' class="wikilink-nonexistent"';
-      
-      if ( $match_page_id && $match_namespace && $pid_clean === $paths->get_pathskey($match_page_id, $match_namespace) )
-        $exists .= ' class="currentpage"';
       
-      if ( $tplcode )
-      {
-        $parser->assign_vars(array(
-            'HREF' => $url,
-            'FLAGS' => $exists,
-            'TEXT' => $inner_text
-          ));
-        $link = $parser->run();
-      }
-      else
-      {
-        $omatch = self::escape_parser_hint_attrib($match);
-        $link = "<!--#internallink src=\"$omatch\" --><a href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a><!--#/internallink-->";
-      }
+      $link = self::generate_internal_link($namespace, $page_id, $inner_text, $match, $parser, $do_exist_check, $match_page_id, $match_namespace);
       
       $text = str_replace($match, $link, $text);
     }
@@ -703,6 +646,65 @@
   }
   
   /**
+   * Internal link generation function
+   * @access private
+   * @return string HTML
+   */
+  
+  private static function generate_internal_link($namespace, $page_id, $inner_text, $match, $parser = false, $do_exist_check = true, $match_page_id = false, $match_namespace = false)
+  {
+    global $db, $session, $paths, $template, $plugins; // Common objects
+    
+    if ( ($pos = strrpos($page_id, '#')) !== false )
+    {
+      $hash = substr($page_id, $pos);
+      $page_id = substr($page_id, 0, $pos);
+    }
+    else
+    {
+      $hash = '';
+    }
+    
+    if ( $namespace == 'Admin' )
+    {
+      // No linking directly to Admin pages!
+      $get = 'module=' . $paths->nslist[$namespace] . sanitize_page_id($page_id);
+      $pid_clean = $paths->nslist['Special'] . 'Administration';
+      $onclick = ' onclick="ajaxLoginNavTo(\'Special\', \'Administration\', USER_LEVEL_ADMIN, \'' . addslashes($get) . '\'); return false;"';
+    }
+    else
+    {
+      $get = false;
+      $onclick = '';
+      $pid_clean = $paths->nslist[$namespace] . sanitize_page_id($page_id);
+    }
+    
+    $url = makeUrl($pid_clean, $get, true) . $hash;
+    $quot = '"';
+    $exists = ( ($do_exist_check && isPage($pid_clean)) || !$do_exist_check ) ? '' : ' class="wikilink-nonexistent"';
+    
+    if ( $match_page_id && $match_namespace && $pid_clean === $paths->get_pathskey($match_page_id, $match_namespace) )
+      $exists .= ' class="currentpage"';
+    
+    if ( $parser )
+    {
+      $parser->assign_vars(array(
+          'HREF' => $url,
+          'FLAGS' => $exists,
+          'TEXT' => $inner_text
+        ));
+      $link = $parser->run();
+    }
+    else
+    {
+      $omatch = self::escape_parser_hint_attrib($match);
+      $link = "<!--#internallink src=\"$omatch\" --><a{$onclick} href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a><!--#/internallink-->";
+    }
+    
+    return $link;
+  }
+  
+  /**
    * Parses a partial template tag in wikitext, and return an array with the parameters.
    * @param string The portion of the template tag that contains the parameters.
    * @example
--- a/includes/search.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/search.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * search.php - algorithm used to search pages
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/sessions.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/sessions.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * sessions.php - everything related to security and user management
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -158,6 +157,20 @@
   var $auth_level = 1;
   
   /**
+   * Preference for date formatting
+   * @var string
+   */
+  
+  var $date_format = DATE_4;
+  
+  /**
+   * Preference for time formatting
+   * @var string
+   */
+  
+  var $time_format = TIME_24_NS;
+  
+  /**
    * State variable to track if a session timed out
    * @var bool
    */
@@ -413,6 +426,28 @@
     return $result;
   }
   
+  /**
+   * Returns true if we're currently on a page that shouldn't be blocked even if we have an inactive or banned account
+   * @param bool strict - if true, whitelist of pages is even stricter (Login, Logout and CSS only). if false (default), admin access is allowed, assuming other factors allow it
+   * @return bool
+   */
+  
+  function on_critical_page($strict = false)
+  {
+    global $title;
+    list($page_id, $namespace) = RenderMan::strToPageID($title);
+    list($page_id) = explode('/', $page_id);
+    
+    if ( $strict )
+    {
+      return $namespace == 'Special' && in_array($page_id, array('CSS', 'Login', 'Logout'));
+    }
+    else
+    {
+      return $namespace == 'Admin' || ($namespace == 'Special' && in_array($page_id, array('CSS', 'Login', 'Logout', 'Administration')));
+    }
+  }
+  
   # Session restoration and permissions
   
   /**
@@ -439,13 +474,6 @@
       }
       if ( is_array($userdata) )
       {
-        $data = RenderMan::strToPageID($paths->get_pageid_from_url());
-        
-        if(!$this->compat && $userdata['account_active'] != 1 && $data[1] != 'Special' && $data[1] != 'Admin')
-        {
-          $this->show_inactive_error($userdata);
-        }
-        
         $this->sid = $_COOKIE['sid'];
         $this->user_logged_in = true;
         $this->user_id =       intval($userdata['user_id']);
@@ -553,6 +581,12 @@
     // make sure we aren't banned
     $this->check_banlist();
     
+    // make sure the account is active
+    if ( !$this->compat && $this->user_logged_in && $userdata['account_active'] != 1 && !$this->on_critical_page() )
+    {
+      $this->show_inactive_error($userdata);
+    }
+    
     // Printable page view? Probably the wrong place to control
     // it but $template is pretty dumb, it will just about always
     // do what you ask it to do, which isn't always what we want
@@ -724,11 +758,11 @@
       // 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\n"
-                   . '  (\'security\', \'admin_auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', '
+                   . '  (\'security\', \'admin_auth_bad\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$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\n"
-                   . '  (\'security\', \'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', '
+                   . '  (\'security\', \'auth_bad\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', '
                       . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
       
       // Do we also need to increment the lockout countdown?
@@ -822,13 +856,16 @@
           'success' => false,
           'error' => 'too_big_for_britches'
         );
+      
+      // grant session
       $sess = $this->register_session($row['user_id'], $username, ( isset($password_hmac) ? $password_hmac : $password ), $level, $remember);
+      
       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().', \''.enano_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(ED_DATE | ED_TIME).'\', \''.$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().', \''.enano_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(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
         
         $code = $plugins->setHook('login_success');
         foreach ( $code as $cmd )
@@ -849,9 +886,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().', \''.enano_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(ED_DATE | ED_TIME).'\', \''.$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().', \''.enano_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(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
         
       // Do we also need to increment the lockout countdown?
       if ( !defined('IN_ENANO_INSTALL') && $lockout_data['lockout_policy'] != 'disable' )
@@ -967,6 +1004,7 @@
       // For now, make the cookie last forever, we can change this in 1.1.x
       setcookie( 'sid', $session_key, time()+15552000, scriptPath.'/', null, $GLOBALS['is_https']);
       $_COOKIE['sid'] = $session_key;
+      $this->sid = $session_key;
     }
     // $keyhash is stored in the database, this is for compatibility with the older DB structure
     $keyhash = md5($session_key);
@@ -1192,7 +1230,7 @@
                       . "           u.reg_time, u.account_active, u.activation_key, u.user_lang, u.user_timezone, u.user_title, u.user_dst,\n"
                       . "           k.salt, k.source_ip, k.time, k.auth_level, k.key_type, x.user_id, x.user_aim, x.user_yahoo, x.user_msn,\n"
                       . "           x.user_xmpp, x.user_homepage, x.user_location, x.user_job, x.user_hobbies, x.email_public,\n"
-                      . "           x.disable_js_fx";
+                      . "           x.disable_js_fx, x.date_format, x.time_format";
     
     $joins = "  LEFT JOIN " . table_prefix . "users AS u\n"
             . "    ON ( u.user_id=k.user_id )\n"
@@ -1221,14 +1259,14 @@
     
     if ( !$query && ( defined('IN_ENANO_INSTALL') or defined('IN_ENANO_UPGRADE') ) )
     {
-      $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,\'\' AS password_salt,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms, 1440 AS user_timezone, \'0;0;0;0;60\' AS user_dst, ' . SK_SHORT . ' AS key_type FROM '.table_prefix.'session_keys AS k
+      $key_md5 = $loose_call ? $key : md5($key);
+      $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,\'\' AS password_salt,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms, 1440 AS user_timezone, \'0;0;0;0;60\' AS user_dst, ' . SK_SHORT . ' AS key_type, k.salt FROM '.table_prefix.'session_keys AS k
                              LEFT JOIN '.table_prefix.'users AS u
                                ON ( u.user_id=k.user_id )
                              LEFT JOIN '.table_prefix.'privmsgs AS p
                                ON ( p.message_to=u.username AND p.message_read=0 )
-                             WHERE k.session_key=\''.$key.'\'
-                               AND k.salt=\''.$salt.'\'
-                             GROUP BY u.user_id,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level;');
+                             WHERE k.session_key=\''.$key_md5.'\'
+                             GROUP BY u.user_id,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,k.salt;');
     }
     else if ( !$query )
     {
@@ -1236,7 +1274,7 @@
     }
     if($db->numrows() < 1)
     {
-      // echo '(debug) $session->validate_session: Key was not found in database<br />';
+      // echo '(debug) $session->validate_session: Key was not found in database: ' . $key_md5 . '<br />';
       return false;
     }
     $row = $db->fetchrow();
@@ -1346,6 +1384,11 @@
         $user_extra[$column] = '';
     }
     
+    if ( isset($row['date_format']) )
+      $this->date_format = $row['date_format'];
+    if ( isset($row['time_format']) )
+      $this->time_format = $row['time_format'];
+    
     $this->user_extra = $user_extra;
     // Leave the rest to PHP's automatic garbage collector ;-)
     
@@ -1476,6 +1519,9 @@
     global $db, $session, $paths, $template, $plugins; // Common objects
     global $lang;
     
+    global $title;
+    $paths->init($title);
+    
     $language = intval(getConfig('default_language'));
     $lang = new Language($language);
     @setlocale(LC_ALL, $lang->lang_code);
@@ -1541,7 +1587,10 @@
       }
     }
     
-    die_semicritical($lang->get('user_login_noact_title'), '<p>' . $lang->get('user_login_noact_msg_intro') . ' '.$solution.'</p>' . $form);
+    global $output;
+    $output = new Output_HTML();
+    $output->set_title($lang->get('user_login_noact_title'));
+    die_friendly($lang->get('user_login_noact_title'), '<p>' . $lang->get('user_login_noact_msg_intro') . ' '.$solution.'</p>' . $form);
   }
   
   /**
@@ -1757,7 +1806,9 @@
     global $db, $session, $paths, $template, $plugins; // Common objects
     global $lang;
     
-    $col_reason = ( $this->compat ) ? '"No reason entered (session manager is in compatibility mode)" AS reason' : 'reason';
+    $col_reason = ( $this->compat ) ? '\'No reason available (session manager is in compatibility mode)\' AS reason' : 'reason';
+    $remote_addr = ( strstr($_SERVER['REMOTE_ADDR'], ':') ) ? expand_ipv6_address($_SERVER['REMOTE_ADDR']) : $_SERVER['REMOTE_ADDR'];
+    
     $banned = false;
     if ( $this->user_logged_in )
     {
@@ -1797,7 +1848,7 @@
             {
               continue;
             }
-            if ( preg_match("/$regexp/", $_SERVER['REMOTE_ADDR']) )
+            if ( preg_match("/$regexp/", $remote_addr) )
             {
               $reason = $reason_temp;
               $banned = true;
@@ -1840,8 +1891,11 @@
             // check range
             $regexp = parse_ip_range_regex($ban_value);
             if ( !$regexp )
+            {
+              die("bad regexp for $ban_value");
               continue;
-            if ( preg_match("/$regexp/", $_SERVER['REMOTE_ADDR']) )
+            }
+            if ( preg_match("/$regexp/", $remote_addr) )
             {
               $reason = $reason_temp;
               $banned = true;
@@ -1857,7 +1911,7 @@
       }
       $db->free_result();
     }
-    if ( $banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS' )
+    if ( $banned && !$this->on_critical_page(true) )
     {
       // This guy is banned - kill the session, kill the database connection, bail out, and be pretty about it
       die_semicritical($lang->get('user_ban_msg_title'), '<p>' . $lang->get('user_ban_msg_body') . '</p><div class="error-box"><b>' . $lang->get('user_ban_lbl_reason') . '</b><br />' . $reason . '</div>');
@@ -2229,7 +2283,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().', \''.enano_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(ED_DATE | ED_TIME).'\', \''.$this->username.'\', \''.$db->escape($u).'\');');
   }
   
   /**
@@ -2245,11 +2299,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().', \''.enano_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(ED_DATE | ED_TIME).'\', \''.$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().', \''.enano_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(ED_DATE | ED_TIME).'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
     }
     return $r;
   }
--- a/includes/sql_parse.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/sql_parse.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * sql_parse.php - SQL query splitter and templater
  *
--- a/includes/stats.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/stats.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * stats.php - handles statistics for pages (disablable in the admin CP)
  *
  *   ***** UNFINISHED ***** 
--- a/includes/tagcloud.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/tagcloud.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/template.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/template.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -1179,7 +1178,7 @@
     
     $this->assign_vars(array(
         'PAGE_NAME' => htmlspecialchars($this->page->ns->cdata['name']),
-        'PAGE_URLNAME' => sanitize_page_id($this->page_id),
+        'PAGE_URLNAME' => $paths->nslist[$this->namespace] . sanitize_page_id($this->page_id),
         'TOOLBAR' => $tb,
         'TOOLBAR_EXTRAS' => $this->toolbar_menu,
         'STYLE_LINK' => makeUrlNS('Special', 'CSS', null, true), //contentPath.$paths->nslist['Special'].'CSS' . $p,
@@ -2596,7 +2595,7 @@
     $messages = array();
     while ( $row = $db->fetchrow() )
     {
-      $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>';
+      $messages[] = '<a href="' . makeUrlNS('Special', 'PrivateMessages/View/' . $row['message_id']) . '" title="Sent ' . enano_date(ED_DATE | ED_TIME, $row['date']) . ' by ' . $row['message_from'] . '">' . $row['subject'] . '</a>';
     }
     $ob .= implode(",\n    " , $messages)."\n";
     $ob .= '</div>'."\n";
@@ -3016,7 +3015,7 @@
     {
       $js_dynamic .= '<script type="text/javascript" src="install.php?mode=langjs"></script>';
     }
-    $js_dynamic .= '<script type="text/javascript">var title="'. $title .'"; var scriptPath="'.scriptPath.'"; var cdnPath="'.scriptPath.'"; var ENANO_SID=""; var AES_BITS='.AES_BITS.'; var AES_BLOCKSIZE=' . AES_BLOCKSIZE . '; var pagepass=\'\'; var ENANO_LANG_ID = 1;</script>';
+    $js_dynamic .= '<script type="text/javascript">var title="'. $title .'"; var scriptPath="'.scriptPath.'"; var cdnPath="'.scriptPath.'"; var ENANO_SID=""; var AES_BITS='.AES_BITS.'; var AES_BLOCKSIZE=' . AES_BLOCKSIZE . '; var pagepass=\'\'; var ENANO_LANG_ID = 1; var msg_loading_component = \'Loading %component%...\';</script>';
     
     global $site_name, $site_desc;
     $site_default_name = ( !empty($site_name) ) ? $site_name : 'Critical error';
--- a/includes/wikiengine/Tables.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/wikiengine/Tables.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/wikiengine/TagSanitizer.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/wikiengine/TagSanitizer.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/wikiengine/parse_mediawiki.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/wikiengine/parse_mediawiki.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/includes/wikiengine/render_xhtml.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/wikiengine/render_xhtml.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -26,11 +25,10 @@
   
   public function heading($text, $pieces)
   {
-    static $tocid = -1;
     foreach ( $pieces as $i => $piece )
     {
-      $tocid++;
-      $tag = '<h' . $piece['level'] . ' id="toc' . $tocid . '">';
+      $tocid = sanitize_page_id(trim($piece['text']));
+      $tag = '<h' . $piece['level'] . ' id="head:' . $tocid . '">';
       $tag .= trim($piece['text']);
       $tag .= '</h' . $piece['level'] . '>';
       
--- a/includes/wikiformat.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/wikiformat.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -100,6 +99,10 @@
     $parser_class = "Carpenter_Parse_" . ucwords($this->parser);
     $renderer_class = "Carpenter_Render_" . ucwords($this->renderer);
     
+    // empty?
+    if ( trim($text) === '' )
+      return $text;
+    
     // include files, if we haven't already
     if ( !class_exists($parser_class) )
     {
--- a/index.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/index.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -15,690 +14,690 @@
  * @subpackage Frontend
  */
  
-  define('ENANO_INTERFACE_INDEX', '');
-  
-  // start up Enano
-  require('includes/common.php');
-  
-  // decide on HTML compacting
-  $aggressive_optimize_html = !defined('ENANO_DEBUG') && !isset($_GET['nocompress']);
-  
-  // Set up gzip encoding before any output is sent
-  global $do_gzip;
-  // FIXME: make this configurable
-  $do_gzip = !defined('ENANO_DEBUG');
-  
-  error_reporting(E_ALL);
-  
-  if($aggressive_optimize_html || $do_gzip)
-  {
+define('ENANO_INTERFACE_INDEX', '');
+
+// start up Enano
+require('includes/common.php');
+
+// decide on HTML compacting
+$aggressive_optimize_html = !defined('ENANO_DEBUG') && !isset($_GET['nocompress']);
+
+// Set up gzip encoding before any output is sent
+global $do_gzip;
+// FIXME: make this configurable
+$do_gzip = !defined('ENANO_DEBUG');
+
+error_reporting(E_ALL);
+
+if($aggressive_optimize_html || $do_gzip)
+{
+  ob_start();
+}
+
+global $db, $session, $paths, $template, $plugins; // Common objects
+$page_timestamp = time();
+
+if ( !isset($_GET['do']) )
+{
+  $_GET['do'] = 'view';
+}
+switch($_GET['do'])
+{
+  default:
+    $code = $plugins->setHook('page_action');
     ob_start();
-  }
-  
-  global $db, $session, $paths, $template, $plugins; // Common objects
-  $page_timestamp = time();
-  
-  if ( !isset($_GET['do']) )
-  {
-    $_GET['do'] = 'view';
-  }
-  switch($_GET['do'])
-  {
-    default:
-      $code = $plugins->setHook('page_action');
-      ob_start();
-      foreach ( $code as $cmd )
-      {
-        eval($cmd);
-      }
-      if ( $contents = ob_get_contents() )
-      {
-        ob_end_clean();
-        echo $contents;
-      }
-      else
-      {
-        die_friendly('Invalid action', '<p>The action "'.htmlspecialchars($_GET['do']).'" is not defined. Return to <a href="'.makeUrl($paths->page).'">viewing this page\'s text</a>.</p>');
-      }
-      break;
-    case 'view':
-      // echo PageUtils::getpage($paths->page, true, ( (isset($_GET['oldid'])) ? $_GET['oldid'] : false ));
-      $rev_id = ( (isset($_GET['oldid'])) ? intval($_GET['oldid']) : 0 );
-      $page = new PageProcessor( $paths->page_id, $paths->namespace, $rev_id );
-      // Feed this PageProcessor to the template processor. This prevents $template from starting another
-      // PageProcessor when we already have one going.
-      $template->set_page($page);
-      $page->send_headers = true;
-      $page->allow_redir = ( !isset($_GET['redirect']) || (isset($_GET['redirect']) && $_GET['redirect'] !== 'no') );
-      $pagepass = ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '';
-      $page->password = $pagepass;
-      $page->send(true);
-      $page_timestamp = $page->revision_time;
-      break;
-    case 'comments':
-      $output->header();
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      $sub = ( isset ($_GET['sub']) ) ? $_GET['sub'] : false;
-      switch($sub)
-      {
-        case 'admin':
-        default:
-          $act = ( isset ($_GET['action']) ) ? $_GET['action'] : false;
-          $id = ( isset ($_GET['id']) ) ? intval($_GET['id']) : -1;
-          echo PageUtils::comments_html($paths->page_id, $paths->namespace, $act, Array('id'=>$id));
-          break;
-        case 'postcomment':
-          if(empty($_POST['name']) ||
-             empty($_POST['subj']) ||
-             empty($_POST['text'])
-             ) { echo 'Invalid request'; break; }
-          $cid = ( isset($_POST['captcha_id']) ) ? $_POST['captcha_id'] : false;
-          $cin = ( isset($_POST['captcha_input']) ) ? $_POST['captcha_input'] : false;
-          
-          require_once('includes/comment.php');
-          $comments = new Comments($paths->page_id, $paths->namespace);
-          
-          $submission = array(
-              'mode' => 'submit',
-              'captcha_id' => $cid,
-              'captcha_code' => $cin,
-              'name' => $_POST['name'],
-              'subj' => $_POST['subj'],
-              'text' => $_POST['text'],
-            );
-          
-          $result = $comments->process_json($submission);
-          if ( $result['mode'] == 'error' )
-          {
-            echo '<div class="error-box">' . htmlspecialchars($result['error']) . '</div>';
-          }
-          else
-          {
-            echo '<div class="info-box">' . $lang->get('comment_msg_comment_posted') . '</div>';
-          }
-          
-          echo PageUtils::comments_html($paths->page_id, $paths->namespace);
-          break;
-        case 'editcomment':
-          if(!isset($_GET['id']) || ( isset($_GET['id']) && !preg_match('#^([0-9]+)$#', $_GET['id']) )) { echo '<p>Invalid comment ID</p>'; break; }
-          $q = $db->sql_query('SELECT subject,comment_data,comment_id FROM '.table_prefix.'comments WHERE comment_id='.$_GET['id']);
-          if(!$q) $db->_die('The comment data could not be selected.');
-          $row = $db->fetchrow();
-          $db->free_result();
-          $row['subject'] = str_replace('\'', '&#039;', $row['subject']);
-          echo '<form action="'.makeUrl($paths->page, 'do=comments&amp;sub=savecomment').'" method="post">';
-          echo "<br /><div class='tblholder'><table border='0' width='100%' cellspacing='1' cellpadding='4'>
-                  <tr><td class='row1'>" . $lang->get('comment_postform_field_subject') . "</td><td class='row1'><input type='text' name='subj' value='{$row['subject']}' /></td></tr>
-                  <tr><td class='row2'>" . $lang->get('comment_postform_field_comment') . "</td><td class='row2'><textarea rows='10' cols='40' style='width: 98%;' name='text'>{$row['comment_data']}</textarea></td></tr>
-                  <tr><td class='row1' colspan='2' class='row1' style='text-align: center;'><input type='hidden' name='id' value='{$row['comment_id']}' /><input type='submit' value='" . $lang->get('etc_save_changes') . "' /></td></tr>
-                </table></div>";
-          echo '</form>';
-          break;
-        case 'savecomment':
-          if(empty($_POST['subj']) || empty($_POST['text'])) { echo '<p>Invalid request</p>'; break; }
-          $r = PageUtils::savecomment_neater($paths->page_id, $paths->namespace, $_POST['subj'], $_POST['text'], (int)$_POST['id']);
-          if($r != 'good') { echo "<pre>$r</pre>"; break; }
-          echo PageUtils::comments_html($paths->page_id, $paths->namespace);
-          break;
-        case 'deletecomment':
-          if(!empty($_GET['id']))
-          {
-            PageUtils::deletecomment_neater($paths->page_id, $paths->namespace, (int)$_GET['id']);
-          }
-          echo PageUtils::comments_html($paths->page_id, $paths->namespace);
-          break;
-      }
-      $output->footer();
-      break;
-    case 'edit':
-      if(isset($_POST['_cancel']))
-      {
-        redirect(makeUrl($paths->page), '', '', 0);
+    foreach ( $code as $cmd )
+    {
+      eval($cmd);
+    }
+    if ( $contents = ob_get_contents() )
+    {
+      ob_end_clean();
+      echo $contents;
+    }
+    else
+    {
+      die_friendly('Invalid action', '<p>The action "'.htmlspecialchars($_GET['do']).'" is not defined. Return to <a href="'.makeUrl($paths->page).'">viewing this page\'s text</a>.</p>');
+    }
+    break;
+  case 'view':
+    // echo PageUtils::getpage($paths->page, true, ( (isset($_GET['oldid'])) ? $_GET['oldid'] : false ));
+    $rev_id = ( (isset($_GET['oldid'])) ? intval($_GET['oldid']) : 0 );
+    $page = new PageProcessor( $paths->page_id, $paths->namespace, $rev_id );
+    // Feed this PageProcessor to the template processor. This prevents $template from starting another
+    // PageProcessor when we already have one going.
+    $template->set_page($page);
+    $page->send_headers = true;
+    $page->allow_redir = ( !isset($_GET['redirect']) || (isset($_GET['redirect']) && $_GET['redirect'] !== 'no') );
+    $pagepass = ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '';
+    $page->password = $pagepass;
+    $page->send(true);
+    $page_timestamp = $page->revision_time;
+    break;
+  case 'comments':
+    $output->header();
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    $sub = ( isset ($_GET['sub']) ) ? $_GET['sub'] : false;
+    switch($sub)
+    {
+      case 'admin':
+      default:
+        $act = ( isset ($_GET['action']) ) ? $_GET['action'] : false;
+        $id = ( isset ($_GET['id']) ) ? intval($_GET['id']) : -1;
+        echo PageUtils::comments_html($paths->page_id, $paths->namespace, $act, Array('id'=>$id));
         break;
-      }
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      if(isset($_POST['_save']))
-      {
-        $captcha_valid = true;
-        if ( !$session->user_logged_in && getConfig('guest_edit_require_captcha') == '1' )
-        {
-          $captcha_valid = false;
-          if ( isset($_POST['captcha_id']) && isset($_POST['captcha_code']) )
-          {
-            $hash_correct = strtolower($session->get_captcha($_POST['captcha_id']));
-            $hash_input   = strtolower($_POST['captcha_code']);
-            if ( $hash_input === $hash_correct )
-              $captcha_valid = true;
-          }
-        }
-        if ( $captcha_valid )
+      case 'postcomment':
+        if(empty($_POST['name']) ||
+           empty($_POST['subj']) ||
+           empty($_POST['text'])
+           ) { echo 'Invalid request'; break; }
+        $cid = ( isset($_POST['captcha_id']) ) ? $_POST['captcha_id'] : false;
+        $cin = ( isset($_POST['captcha_input']) ) ? $_POST['captcha_input'] : false;
+        
+        require_once('includes/comment.php');
+        $comments = new Comments($paths->page_id, $paths->namespace);
+        
+        $submission = array(
+            'mode' => 'submit',
+            'captcha_id' => $cid,
+            'captcha_code' => $cin,
+            'name' => $_POST['name'],
+            'subj' => $_POST['subj'],
+            'text' => $_POST['text'],
+          );
+        
+        $result = $comments->process_json($submission);
+        if ( $result['mode'] == 'error' )
         {
-          $e = PageUtils::savepage($paths->page_id, $paths->namespace, $_POST['page_text'], $_POST['edit_summary'], isset($_POST['minor']));
-          if ( $e == 'good' )
-          {
-            redirect(makeUrl($paths->page), $lang->get('editor_msg_save_success_title'), $lang->get('editor_msg_save_success_body'), 3);
-          }
-        }
-      }
-      $template->header();
-      if ( isset($captcha_valid) )
-      {
-        echo '<div class="usermessage">' . $lang->get('editor_err_captcha_wrong') . '</div>';
-      }
-      if(isset($_POST['_preview']))
-      {
-        $text = $_POST['page_text'];
-        $edsumm = $_POST['edit_summary'];
-        echo PageUtils::genPreview($_POST['page_text']);
-        $text = htmlspecialchars($text);
-        $revid = 0;
-      }
-      else
-      {
-        $revid = ( isset($_GET['revid']) ) ? intval($_GET['revid']) : 0;
-        $page = new PageProcessor($paths->page_id, $paths->namespace, $revid);
-        $text = $page->fetch_source();
-        $edsumm = '';
-        // $text = RenderMan::getPage($paths->cpage['urlname_nons'], $paths->namespace, 0, false, false, false, false);
-      }
-      if ( $revid > 0 )
-      {
-        $time = $page->revision_time;
-        // Retrieve information about this revision and the current one
-        $q = $db->sql_query('SELECT l1.author AS currentrev_author, l2.author AS oldrev_author FROM ' . table_prefix . 'logs AS l1
-  LEFT JOIN ' . table_prefix . 'logs AS l2
-    ON ( l2.log_id = ' . $revid . '
-         AND l2.log_type  = \'page\'
-         AND l2.action    = \'edit\'
-         AND l2.page_id   = \'' . $db->escape($paths->page_id) . '\'
-         AND l2.namespace = \'' . $db->escape($paths->namespace) . '\'
-         AND l1.is_draft != 1
-        )
-  WHERE l1.log_type  = \'page\'
-    AND l1.action    = \'edit\'
-    AND l1.page_id   = \'' . $db->escape($paths->page_id) . '\'
-    AND l1.namespace = \'' . $db->escape($paths->namespace) . '\'
-    AND l1.time_id > ' . $time . '
-    AND l1.is_draft != 1
-  ORDER BY l1.time_id DESC;');
-        if ( !$q )
-          $db->die_json();
-        
-        if ( $db->numrows() > 0 )
-        {
-          echo '<div class="usermessage">' . $lang->get('editor_msg_editing_old_revision') . '</div>';
-          
-          $rev_count = $db->numrows() - 2;
-          $row = $db->fetchrow();
-          $undo_info = array(
-            'old_author'     => $row['oldrev_author'],
-            'current_author' => $row['currentrev_author'],
-            'undo_count'     => max($rev_count, 1),
-            'last_rev_id'    => $revid
-          );
+          echo '<div class="error-box">' . htmlspecialchars($result['error']) . '</div>';
         }
         else
         {
-          $revid = 0;
+          echo '<div class="info-box">' . $lang->get('comment_msg_comment_posted') . '</div>';
         }
+        
+        echo PageUtils::comments_html($paths->page_id, $paths->namespace);
+        break;
+      case 'editcomment':
+        if(!isset($_GET['id']) || ( isset($_GET['id']) && !preg_match('#^([0-9]+)$#', $_GET['id']) )) { echo '<p>Invalid comment ID</p>'; break; }
+        $q = $db->sql_query('SELECT subject,comment_data,comment_id FROM '.table_prefix.'comments WHERE comment_id='.$_GET['id']);
+        if(!$q) $db->_die('The comment data could not be selected.');
+        $row = $db->fetchrow();
         $db->free_result();
-      }
-      echo '
-        <form action="'.makeUrl($paths->page, 'do=edit').'" method="post" enctype="multipart/form-data">
-        <br />
-        <textarea name="page_text" rows="20" cols="60" style="width: 97%;">'.$text.'</textarea><br />
-        <br />
-        ';
-      $edsumm = ( $revid > 0 ) ? $lang->get('editor_reversion_edit_summary', $undo_info) : $edsumm;
-      echo $lang->get('editor_lbl_edit_summary') . ' <input name="edit_summary" type="text" size="40" value="' . htmlspecialchars($edsumm) . '" /><br /><label><input type="checkbox" name="minor" /> ' . $lang->get('editor_lbl_minor_edit_field') . '</label><br />';
+        $row['subject'] = str_replace('\'', '&#039;', $row['subject']);
+        echo '<form action="'.makeUrl($paths->page, 'do=comments&amp;sub=savecomment').'" method="post">';
+        echo "<br /><div class='tblholder'><table border='0' width='100%' cellspacing='1' cellpadding='4'>
+                <tr><td class='row1'>" . $lang->get('comment_postform_field_subject') . "</td><td class='row1'><input type='text' name='subj' value='{$row['subject']}' /></td></tr>
+                <tr><td class='row2'>" . $lang->get('comment_postform_field_comment') . "</td><td class='row2'><textarea rows='10' cols='40' style='width: 98%;' name='text'>{$row['comment_data']}</textarea></td></tr>
+                <tr><td class='row1' colspan='2' class='row1' style='text-align: center;'><input type='hidden' name='id' value='{$row['comment_id']}' /><input type='submit' value='" . $lang->get('etc_save_changes') . "' /></td></tr>
+              </table></div>";
+        echo '</form>';
+        break;
+      case 'savecomment':
+        if(empty($_POST['subj']) || empty($_POST['text'])) { echo '<p>Invalid request</p>'; break; }
+        $r = PageUtils::savecomment_neater($paths->page_id, $paths->namespace, $_POST['subj'], $_POST['text'], (int)$_POST['id']);
+        if($r != 'good') { echo "<pre>$r</pre>"; break; }
+        echo PageUtils::comments_html($paths->page_id, $paths->namespace);
+        break;
+      case 'deletecomment':
+        if(!empty($_GET['id']))
+        {
+          PageUtils::deletecomment_neater($paths->page_id, $paths->namespace, (int)$_GET['id']);
+        }
+        echo PageUtils::comments_html($paths->page_id, $paths->namespace);
+        break;
+    }
+    $output->footer();
+    break;
+  case 'edit':
+    if(isset($_POST['_cancel']))
+    {
+      redirect(makeUrl($paths->page), '', '', 0);
+      break;
+    }
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    if(isset($_POST['_save']))
+    {
+      $captcha_valid = true;
       if ( !$session->user_logged_in && getConfig('guest_edit_require_captcha') == '1' )
       {
-        echo '<br /><table border="0"><tr><td>';
-        echo '<b>' . $lang->get('editor_lbl_field_captcha') . '</b><br />'
-             . '<br />'
-             . $lang->get('editor_msg_captcha_pleaseenter') . '<br /><br />'
-             . $lang->get('editor_msg_captcha_blind');
-        echo '</td><td>';
-        $hash = $session->make_captcha();
-        echo '<img src="' . makeUrlNS('Special', "Captcha/$hash") . '" onclick="this.src+=\'/a\'" style="cursor: pointer;" /><br />';
-        echo '<input type="hidden" name="captcha_id" value="' . $hash . '" />';
-        echo $lang->get('editor_lbl_field_captcha_code') . ' <input type="text" name="captcha_code" value="" size="9" />';
-        echo '</td></tr></table>';
+        $captcha_valid = false;
+        if ( isset($_POST['captcha_id']) && isset($_POST['captcha_code']) )
+        {
+          $hash_correct = strtolower($session->get_captcha($_POST['captcha_id']));
+          $hash_input   = strtolower($_POST['captcha_code']);
+          if ( $hash_input === $hash_correct )
+            $captcha_valid = true;
+        }
       }
-      echo '<br />
-          <input type="submit" name="_save"    value="' . $lang->get('editor_btn_save') . '" style="font-weight: bold;" />
-          <input type="submit" name="_preview" value="' . $lang->get('editor_btn_preview') . '" />
-          <input type="submit" name="_revert"  value="' . $lang->get('editor_btn_revert') . '" />
-          <input type="submit" name="_cancel"  value="' . $lang->get('editor_btn_cancel') . '" />
-        </form>
-      ';
-      if ( getConfig('wiki_edit_notice', '0') == '1' )
+      if ( $captcha_valid )
       {
-        $notice = getConfig('wiki_edit_notice_text');
-        echo RenderMan::render($notice);
+        $e = PageUtils::savepage($paths->page_id, $paths->namespace, $_POST['page_text'], $_POST['edit_summary'], isset($_POST['minor']));
+        if ( $e == 'good' )
+        {
+          redirect(makeUrl($paths->page), $lang->get('editor_msg_save_success_title'), $lang->get('editor_msg_save_success_body'), 3);
+        }
       }
-      $template->footer();
-      break;
-    case 'viewsource':
-      $template->header();
-      $text = RenderMan::getPage($paths->page_id, $paths->namespace, 0, false, false, false, false);
+    }
+    $template->header();
+    if ( isset($captcha_valid) )
+    {
+      echo '<div class="usermessage">' . $lang->get('editor_err_captcha_wrong') . '</div>';
+    }
+    if(isset($_POST['_preview']))
+    {
+      $text = $_POST['page_text'];
+      $edsumm = $_POST['edit_summary'];
+      echo PageUtils::genPreview($_POST['page_text']);
       $text = htmlspecialchars($text);
-      echo '
-        <form action="'.makeUrl($paths->page, 'do=edit').'" method="post">
-        <br />
-        <textarea readonly="readonly" name="page_text" rows="20" cols="60" style="width: 97%;">'.$text.'</textarea>';
-      echo '<br />
-          <input type="submit" name="_cancel" value="' . $lang->get('editor_btn_closeviewer') . '" />
-        </form>
-      ';
-      $template->footer();
-      break;
-    case 'history':
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      $hist = PageUtils::histlist($paths->page_id, $paths->namespace);
-      $template->header();
-      echo $hist;
-      $template->footer();
-      break;
-    case 'rollback':
-      $id = (isset($_GET['id'])) ? $_GET['id'] : false;
-      if(!$id || !ctype_digit($id)) die_friendly('Invalid action ID', '<p>The URL parameter "id" is not an integer. Exiting to prevent nasties like SQL injection, etc.</p>');
+      $revid = 0;
+    }
+    else
+    {
+      $revid = ( isset($_GET['revid']) ) ? intval($_GET['revid']) : 0;
+      $page = new PageProcessor($paths->page_id, $paths->namespace, $revid);
+      $text = $page->fetch_source();
+      $edsumm = '';
+      // $text = RenderMan::getPage($paths->cpage['urlname_nons'], $paths->namespace, 0, false, false, false, false);
+    }
+    if ( $revid > 0 )
+    {
+      $time = $page->revision_time;
+      // Retrieve information about this revision and the current one
+      $q = $db->sql_query('SELECT l1.author AS currentrev_author, l2.author AS oldrev_author FROM ' . table_prefix . 'logs AS l1
+LEFT JOIN ' . table_prefix . 'logs AS l2
+  ON ( l2.log_id = ' . $revid . '
+       AND l2.log_type  = \'page\'
+       AND l2.action    = \'edit\'
+       AND l2.page_id   = \'' . $db->escape($paths->page_id) . '\'
+       AND l2.namespace = \'' . $db->escape($paths->namespace) . '\'
+       AND l1.is_draft != 1
+      )
+WHERE l1.log_type  = \'page\'
+  AND l1.action    = \'edit\'
+  AND l1.page_id   = \'' . $db->escape($paths->page_id) . '\'
+  AND l1.namespace = \'' . $db->escape($paths->namespace) . '\'
+  AND l1.time_id > ' . $time . '
+  AND l1.is_draft != 1
+ORDER BY l1.time_id DESC;');
+      if ( !$q )
+        $db->die_json();
       
-      $id = intval($id);
-      
-      $page = new PageProcessor($paths->page_id, $paths->namespace);
-      $result = $page->rollback_log_entry($id);
-      
-      if ( $result['success'] )
+      if ( $db->numrows() > 0 )
       {
-        $result = $lang->get("page_msg_rb_success_{$result['action']}", array('dateline' => $result['dateline']));
+        echo '<div class="usermessage">' . $lang->get('editor_msg_editing_old_revision') . '</div>';
+        
+        $rev_count = $db->numrows() - 2;
+        $row = $db->fetchrow();
+        $undo_info = array(
+          'old_author'     => $row['oldrev_author'],
+          'current_author' => $row['currentrev_author'],
+          'undo_count'     => max($rev_count, 1),
+          'last_rev_id'    => $revid
+        );
       }
       else
       {
-        $result = $lang->get("page_err_{$result['error']}", array('action' => @$result['action']));
+        $revid = 0;
       }
-      
-      $template->header();
-      echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a></p>';
-      $template->footer();
-      break;
-    case 'catedit':
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      if(isset($_POST['__enanoSaveButton']))
-      {
-        unset($_POST['__enanoSaveButton']);
-        $val = PageUtils::catsave($paths->page_id, $paths->namespace, $_POST);
-        if($val == 'GOOD')
-        {
-          header('Location: '.makeUrl($paths->page)); echo '<html><head><title>Redirecting...</title></head><body>If you haven\'t been redirected yet, <a href="'.makeUrl($paths->page).'">click here</a>.'; break;
-        } else {
-          die_friendly('Error saving category information', '<p>'.$val.'</p>');
-        }
-      }
-      elseif(isset($_POST['__enanoCatCancel']))
+      $db->free_result();
+    }
+    echo '
+      <form action="'.makeUrl($paths->page, 'do=edit').'" method="post" enctype="multipart/form-data">
+      <br />
+      <textarea name="page_text" rows="20" cols="60" style="width: 97%;">'.$text.'</textarea><br />
+      <br />
+      ';
+    $edsumm = ( $revid > 0 ) ? $lang->get('editor_reversion_edit_summary', $undo_info) : $edsumm;
+    echo $lang->get('editor_lbl_edit_summary') . ' <input name="edit_summary" type="text" size="40" value="' . htmlspecialchars($edsumm) . '" /><br /><label><input type="checkbox" name="minor" /> ' . $lang->get('editor_lbl_minor_edit_field') . '</label><br />';
+    if ( !$session->user_logged_in && getConfig('guest_edit_require_captcha') == '1' )
+    {
+      echo '<br /><table border="0"><tr><td>';
+      echo '<b>' . $lang->get('editor_lbl_field_captcha') . '</b><br />'
+           . '<br />'
+           . $lang->get('editor_msg_captcha_pleaseenter') . '<br /><br />'
+           . $lang->get('editor_msg_captcha_blind');
+      echo '</td><td>';
+      $hash = $session->make_captcha();
+      echo '<img src="' . makeUrlNS('Special', "Captcha/$hash") . '" onclick="this.src+=\'/a\'" style="cursor: pointer;" /><br />';
+      echo '<input type="hidden" name="captcha_id" value="' . $hash . '" />';
+      echo $lang->get('editor_lbl_field_captcha_code') . ' <input type="text" name="captcha_code" value="" size="9" />';
+      echo '</td></tr></table>';
+    }
+    echo '<br />
+        <input type="submit" name="_save"    value="' . $lang->get('editor_btn_save') . '" style="font-weight: bold;" />
+        <input type="submit" name="_preview" value="' . $lang->get('editor_btn_preview') . '" />
+        <input type="submit" name="_revert"  value="' . $lang->get('editor_btn_revert') . '" />
+        <input type="submit" name="_cancel"  value="' . $lang->get('editor_btn_cancel') . '" />
+      </form>
+    ';
+    if ( getConfig('wiki_edit_notice', '0') == '1' )
+    {
+      $notice = getConfig('wiki_edit_notice_text');
+      echo RenderMan::render($notice);
+    }
+    $template->footer();
+    break;
+  case 'viewsource':
+    $template->header();
+    $text = RenderMan::getPage($paths->page_id, $paths->namespace, 0, false, false, false, false);
+    $text = htmlspecialchars($text);
+    echo '
+      <form action="'.makeUrl($paths->page, 'do=edit').'" method="post">
+      <br />
+      <textarea readonly="readonly" name="page_text" rows="20" cols="60" style="width: 97%;">'.$text.'</textarea>';
+    echo '<br />
+        <input type="submit" name="_cancel" value="' . $lang->get('editor_btn_closeviewer') . '" />
+      </form>
+    ';
+    $template->footer();
+    break;
+  case 'history':
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    $hist = PageUtils::histlist($paths->page_id, $paths->namespace);
+    $template->header();
+    echo $hist;
+    $template->footer();
+    break;
+  case 'rollback':
+    $id = (isset($_GET['id'])) ? $_GET['id'] : false;
+    if(!$id || !ctype_digit($id)) die_friendly('Invalid action ID', '<p>The URL parameter "id" is not an integer. Exiting to prevent nasties like SQL injection, etc.</p>');
+    
+    $id = intval($id);
+    
+    $page = new PageProcessor($paths->page_id, $paths->namespace);
+    $result = $page->rollback_log_entry($id);
+    
+    if ( $result['success'] )
+    {
+      $result = $lang->get("page_msg_rb_success_{$result['action']}", array('dateline' => $result['dateline']));
+    }
+    else
+    {
+      $result = $lang->get("page_err_{$result['error']}", array('action' => @$result['action']));
+    }
+    
+    $template->header();
+    echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a></p>';
+    $template->footer();
+    break;
+  case 'catedit':
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    if(isset($_POST['__enanoSaveButton']))
+    {
+      unset($_POST['__enanoSaveButton']);
+      $val = PageUtils::catsave($paths->page_id, $paths->namespace, $_POST);
+      if($val == 'GOOD')
       {
         header('Location: '.makeUrl($paths->page)); echo '<html><head><title>Redirecting...</title></head><body>If you haven\'t been redirected yet, <a href="'.makeUrl($paths->page).'">click here</a>.'; break;
+      } else {
+        die_friendly('Error saving category information', '<p>'.$val.'</p>');
       }
-      $template->header();
-      $c = PageUtils::catedit_raw($paths->page_id, $paths->namespace);
-      echo $c[1];
-      $template->footer();
-      break;
-    case 'moreoptions':
-      $template->header();
-      echo '<div class="menu_nojs" style="width: 150px; padding: 0;"><ul style="display: block;"><li><div class="label">' . $lang->get('ajax_lbl_moreoptions_nojs') . '</div><div style="clear: both;"></div></li>'.$template->toolbar_menu.'</ul></div>';
-      $template->footer();
-      break;
-    case 'protect':
-      if ( !$session->sid_super )
+    }
+    elseif(isset($_POST['__enanoCatCancel']))
+    {
+      header('Location: '.makeUrl($paths->page)); echo '<html><head><title>Redirecting...</title></head><body>If you haven\'t been redirected yet, <a href="'.makeUrl($paths->page).'">click here</a>.'; break;
+    }
+    $template->header();
+    $c = PageUtils::catedit_raw($paths->page_id, $paths->namespace);
+    echo $c[1];
+    $template->footer();
+    break;
+  case 'moreoptions':
+    $template->header();
+    echo '<div class="menu_nojs" style="width: 150px; padding: 0;"><ul style="display: block;"><li><div class="label">' . $lang->get('ajax_lbl_moreoptions_nojs') . '</div><div style="clear: both;"></div></li>'.$template->toolbar_menu.'</ul></div>';
+    $template->footer();
+    break;
+  case 'protect':
+    if ( !$session->sid_super )
+    {
+      redirect(makeUrlNS('Special', "Login/{$paths->page}", 'target_do=protect&level=' . $session->user_level, false), $lang->get('etc_access_denied_short'), $lang->get('etc_access_denied_need_reauth'), 0);
+    }
+    
+    if ( isset($_POST['level']) && isset($_POST['reason']) )
+    {
+      $level = intval($_POST['level']);
+      if ( !in_array($level, array(PROTECT_FULL, PROTECT_SEMI, PROTECT_NONE)) )
       {
-        redirect(makeUrlNS('Special', "Login/{$paths->page}", 'target_do=protect&level=' . $session->user_level, false), $lang->get('etc_access_denied_short'), $lang->get('etc_access_denied_need_reauth'), 0);
+        $errors[] = 'bad level';
+      }
+      $reason = trim($_POST['reason']);
+      if ( empty($reason) )
+      {
+        $errors[] = $lang->get('onpage_protect_err_need_reason');
       }
       
-      if ( isset($_POST['level']) && isset($_POST['reason']) )
+      $page = new PageProcessor($paths->page_id, $paths->namespace);
+      $result = $page->protect_page($level, $reason);
+      if ( $result['success'] )
+      {
+        redirect(makeUrl($paths->page), $lang->get('page_protect_lbl_success_title'), $lang->get('page_protect_lbl_success_body', array('page_link' => makeUrl($paths->page, false, true))), 3);
+      }
+      else
       {
-        $level = intval($_POST['level']);
-        if ( !in_array($level, array(PROTECT_FULL, PROTECT_SEMI, PROTECT_NONE)) )
-        {
-          $errors[] = 'bad level';
-        }
-        $reason = trim($_POST['reason']);
-        if ( empty($reason) )
-        {
-          $errors[] = $lang->get('onpage_protect_err_need_reason');
-        }
-        
-        $page = new PageProcessor($paths->page_id, $paths->namespace);
-        $result = $page->protect_page($level, $reason);
-        if ( $result['success'] )
-        {
-          redirect(makeUrl($paths->page), $lang->get('page_protect_lbl_success_title'), $lang->get('page_protect_lbl_success_body', array('page_link' => makeUrl($paths->page, false, true))), 3);
-        }
-        else
-        {
-          $errors[] = $lang->get('page_err_' . $result['error']);
-        }
+        $errors[] = $lang->get('page_err_' . $result['error']);
       }
-      $template->header();
+    }
+    $template->header();
+    ?>
+    <form action="<?php echo makeUrl($paths->page, 'do=protect'); ?>" method="post">
+      <h3><?php echo $lang->get('onpage_protect_heading'); ?></h3>
+      <p><?php echo $lang->get('onpage_protect_msg_select_level'); ?></p>
+      
+      <?php
+      if ( !empty($errors) )
+      {
+        echo '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
+      }
       ?>
-      <form action="<?php echo makeUrl($paths->page, 'do=protect'); ?>" method="post">
-        <h3><?php echo $lang->get('onpage_protect_heading'); ?></h3>
-        <p><?php echo $lang->get('onpage_protect_msg_select_level'); ?></p>
-        
-        <?php
-        if ( !empty($errors) )
-        {
-          echo '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
-        }
-        ?>
-        
-        <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
-          <label>
-            <input type="radio" name="level" value="<?php echo PROTECT_FULL; ?>" />
-            <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 0, 0); ?>
-            <?php echo $lang->get('onpage_protect_btn_full'); ?>
-          </label>
-        </div>
-        <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
-          <?php echo $lang->get('onpage_protect_btn_full_hint'); ?>
-        </div>
-        
-        <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
-          <label>
-            <input type="radio" name="level" value="<?php echo PROTECT_SEMI; ?>" />
-            <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 22, 0); ?>
-            <?php echo $lang->get('onpage_protect_btn_semi'); ?>
-          </label>
-        </div>
-        <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
-          <?php echo $lang->get('onpage_protect_btn_semi_hint'); ?>
-        </div>
-        
-        <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
-          <label>
-            <input type="radio" name="level" value="<?php echo PROTECT_NONE; ?>" />
-            <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 44, 0); ?>
-            <?php echo $lang->get('onpage_protect_btn_none'); ?>
-          </label>
-        </div>
-        <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
-          <?php echo $lang->get('onpage_protect_btn_none_hint'); ?>
-        </div>
-        
-        <table style="margin-left: 1em;" cellspacing="10">
-          <tr>
-            <td valign="top">
-              <?php echo $lang->get('onpage_protect_lbl_reason'); ?>
-            </td>
-            <td>
-              <input type="text" name="reason" size="40" /><br />
-              <small><?php echo $lang->get('onpage_protect_lbl_reason_hint'); ?></small>
-            </td>
-          </tr>
-        </table>
-                              
-        <p>
-          <input type="submit" value="<?php echo htmlspecialchars($lang->get('page_protect_btn_submit')) ?>" style="font-weight: bold;" />
-          <a class="abutton" href="<?php echo makeUrl($paths->page, false, true); ?>"><?php echo $lang->get('etc_cancel'); ?></a>
-        </p> 
+      
+      <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
+        <label>
+          <input type="radio" name="level" value="<?php echo PROTECT_FULL; ?>" />
+          <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 0, 0); ?>
+          <?php echo $lang->get('onpage_protect_btn_full'); ?>
+        </label>
+      </div>
+      <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
+        <?php echo $lang->get('onpage_protect_btn_full_hint'); ?>
+      </div>
+      
+      <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
+        <label>
+          <input type="radio" name="level" value="<?php echo PROTECT_SEMI; ?>" />
+          <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 22, 0); ?>
+          <?php echo $lang->get('onpage_protect_btn_semi'); ?>
+        </label>
+      </div>
+      <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
+        <?php echo $lang->get('onpage_protect_btn_semi_hint'); ?>
+      </div>
+      
+      <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
+        <label>
+          <input type="radio" name="level" value="<?php echo PROTECT_NONE; ?>" />
+          <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 44, 0); ?>
+          <?php echo $lang->get('onpage_protect_btn_none'); ?>
+        </label>
+      </div>
+      <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
+        <?php echo $lang->get('onpage_protect_btn_none_hint'); ?>
+      </div>
+      
+      <table style="margin-left: 1em;" cellspacing="10">
+        <tr>
+          <td valign="top">
+            <?php echo $lang->get('onpage_protect_lbl_reason'); ?>
+          </td>
+          <td>
+            <input type="text" name="reason" size="40" /><br />
+            <small><?php echo $lang->get('onpage_protect_lbl_reason_hint'); ?></small>
+          </td>
+        </tr>
+      </table>
+                            
+      <p>
+        <input type="submit" value="<?php echo htmlspecialchars($lang->get('page_protect_btn_submit')) ?>" style="font-weight: bold;" />
+        <a class="abutton" href="<?php echo makeUrl($paths->page, false, true); ?>"><?php echo $lang->get('etc_cancel'); ?></a>
+      </p> 
+    </form>
+    <?php
+    $template->footer();
+    break;
+  case 'rename':
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    if(!empty($_POST['newname']))
+    {
+      $r = PageUtils::rename($paths->page_id, $paths->namespace, $_POST['newname']);
+      die_friendly($lang->get('page_rename_success_title'), '<p>'.nl2br($r).' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>');
+    }
+    $template->header();
+    ?>
+    <form action="<?php echo makeUrl($paths->page, 'do=rename'); ?>" method="post">
+      <?php if(isset($_POST['newname'])) echo '<p style="color: red;">' . $lang->get('page_rename_err_need_name') . '</p>'; ?>
+      <p><?php echo $lang->get('page_rename_lbl'); ?></p>
+      <p><input type="text" name="newname" size="40" /></p>
+      <p><input type="submit" value="<?php echo htmlspecialchars($lang->get('page_rename_btn_submit')); ?>" style="font-weight: bold;" /></p> 
+    </form>
+    <?php
+    $template->footer();    
+    break;
+  case 'flushlogs':
+    if(!$session->get_permissions('clear_logs'))
+    {
+      die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
+    }
+    if ( !$session->sid_super )
+    {
+      redirect(makeUrlNS('Special', "Login/{$paths->page}", 'target_do=flushlogs&level=' . $session->user_level, false), $lang->get('etc_access_denied_short'), $lang->get('etc_access_denied_need_reauth'), 0);
+    }
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    if(isset($_POST['_downthejohn']))
+    {
+      $template->header();
+        $result = PageUtils::flushlogs($paths->page_id, $paths->namespace);
+        echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>';
+      $template->footer();
+      break;
+    }
+    $template->header();
+      ?>
+      <form action="<?php echo makeUrl($paths->page, 'do=flushlogs'); ?>" method="post">
+         <?php echo $lang->get('page_flushlogs_warning_stern'); ?>
+         <p><input type="submit" name="_downthejohn" value="<?php echo htmlspecialchars($lang->get('page_flushlogs_btn_submit')); ?>" style="color: red; font-weight: bold;" /></p>
       </form>
       <?php
+    $template->footer();
+    break;
+  case 'delvote':
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    if(isset($_POST['_ballotbox']))
+    {
+      $template->header();
+      $result = PageUtils::delvote($paths->page_id, $paths->namespace);
+      echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>';
       $template->footer();
       break;
-    case 'rename':
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      if(!empty($_POST['newname']))
-      {
-        $r = PageUtils::rename($paths->page_id, $paths->namespace, $_POST['newname']);
-        die_friendly($lang->get('page_rename_success_title'), '<p>'.nl2br($r).' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>');
-      }
-      $template->header();
+    }
+    $template->header();
       ?>
-      <form action="<?php echo makeUrl($paths->page, 'do=rename'); ?>" method="post">
-        <?php if(isset($_POST['newname'])) echo '<p style="color: red;">' . $lang->get('page_rename_err_need_name') . '</p>'; ?>
-        <p><?php echo $lang->get('page_rename_lbl'); ?></p>
-        <p><input type="text" name="newname" size="40" /></p>
-        <p><input type="submit" value="<?php echo htmlspecialchars($lang->get('page_rename_btn_submit')); ?>" style="font-weight: bold;" /></p> 
+      <form action="<?php echo makeUrl($paths->page, 'do=delvote'); ?>" method="post">
+         <?php
+           echo $lang->get('page_delvote_warning_stern');
+           echo '<p>';
+           switch($paths->cpage['delvotes'])
+           {
+             case 0:  echo $lang->get('page_delvote_count_zero'); break;
+             case 1:  echo $lang->get('page_delvote_count_one'); break;
+             default: echo $lang->get('page_delvote_count_plural', array('delvotes' => $paths->cpage['delvotes'])); break;
+           }
+           echo '</p>';
+         ?>
+         <p><input type="submit" name="_ballotbox" value="<?php echo htmlspecialchars($lang->get('page_delvote_btn_submit')); ?>" /></p>
       </form>
       <?php
-      $template->footer();    
+    $template->footer();
+    break;
+  case 'resetvotes':
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    if(!$session->get_permissions('vote_reset'))
+    {
+      die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
+    }
+    if(isset($_POST['_youmaylivealittlelonger']))
+    {
+      $template->header();
+        $result = PageUtils::resetdelvotes($paths->page_id, $paths->namespace);
+        echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>';
+      $template->footer();
       break;
-    case 'flushlogs':
-      if(!$session->get_permissions('clear_logs'))
-      {
-        die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
-      }
-      if ( !$session->sid_super )
-      {
-        redirect(makeUrlNS('Special', "Login/{$paths->page}", 'target_do=flushlogs&level=' . $session->user_level, false), $lang->get('etc_access_denied_short'), $lang->get('etc_access_denied_need_reauth'), 0);
-      }
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      if(isset($_POST['_downthejohn']))
+    }
+    $template->header();
+      ?>
+      <form action="<?php echo makeUrl($paths->page, 'do=resetvotes'); ?>" method="post">
+        <p><?php echo $lang->get('ajax_delvote_reset_confirm'); ?></p>
+        <p><input type="submit" name="_youmaylivealittlelonger" value="<?php echo htmlspecialchars($lang->get('page_delvote_reset_btn_submit')); ?>" /></p>
+      </form>
+      <?php
+    $template->footer();
+    break;
+  case 'deletepage':
+    if(!$session->get_permissions('delete_page'))
+    {
+      die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
+    }
+    if ( !$session->sid_super )
+    {
+      redirect(makeUrlNS('Special', "Login/{$paths->page}", 'target_do=deletepage&level=' . $session->user_level, false), $lang->get('etc_access_denied_short'), $lang->get('etc_access_denied_need_reauth'), 0);
+    }
+    
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    if(isset($_POST['_adiossucker']))
+    {
+      $reason = ( isset($_POST['reason']) ) ? $_POST['reason'] : false;
+      if ( empty($reason) )
+        $error = $lang->get('ajax_delete_prompt_reason');
+      else
       {
         $template->header();
-          $result = PageUtils::flushlogs($paths->page_id, $paths->namespace);
+          $result = PageUtils::deletepage($paths->page_id, $paths->namespace, $reason);
           echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>';
         $template->footer();
         break;
       }
-      $template->header();
-        ?>
-        <form action="<?php echo makeUrl($paths->page, 'do=flushlogs'); ?>" method="post">
-           <?php echo $lang->get('page_flushlogs_warning_stern'); ?>
-           <p><input type="submit" name="_downthejohn" value="<?php echo htmlspecialchars($lang->get('page_flushlogs_btn_submit')); ?>" style="color: red; font-weight: bold;" /></p>
-        </form>
-        <?php
-      $template->footer();
-      break;
-    case 'delvote':
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      if(isset($_POST['_ballotbox']))
+    }
+    $template->header();
+      ?>
+      <form action="<?php echo makeUrl($paths->page, 'do=deletepage'); ?>" method="post">
+         <?php echo $lang->get('page_delete_warning_stern'); ?>
+         <?php if ( isset($error) ) echo "<p>$error</p>"; ?>
+         <p><?php echo $lang->get('page_delete_lbl_reason'); ?> <input type="text" name="reason" size="50" /></p>
+         <p><input type="submit" name="_adiossucker" value="<?php echo htmlspecialchars($lang->get('page_delete_btn_submit')); ?>" style="color: red; font-weight: bold;" /></p>
+      </form>
+      <?php
+    $template->footer();
+    break;
+  case 'setwikimode':
+    if(!$session->get_permissions('set_wiki_mode'))
+    {
+      die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
+    }
+    if ( isset($_POST['finish']) )
+    {
+      $level = intval($_POST['level']);
+      if ( !in_array($level, array(0, 1, 2) ) )
       {
-        $template->header();
-        $result = PageUtils::delvote($paths->page_id, $paths->namespace);
-        echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>';
-        $template->footer();
-        break;
+        die_friendly('Invalid request', '<p>Level not specified</p>');
       }
-      $template->header();
-        ?>
-        <form action="<?php echo makeUrl($paths->page, 'do=delvote'); ?>" method="post">
-           <?php
-             echo $lang->get('page_delvote_warning_stern');
-             echo '<p>';
-             switch($paths->cpage['delvotes'])
-             {
-               case 0:  echo $lang->get('page_delvote_count_zero'); break;
-               case 1:  echo $lang->get('page_delvote_count_one'); break;
-               default: echo $lang->get('page_delvote_count_plural', array('delvotes' => $paths->cpage['delvotes'])); break;
-             }
-             echo '</p>';
-           ?>
-           <p><input type="submit" name="_ballotbox" value="<?php echo htmlspecialchars($lang->get('page_delvote_btn_submit')); ?>" /></p>
-        </form>
-        <?php
-      $template->footer();
-      break;
-    case 'resetvotes':
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      if(!$session->get_permissions('vote_reset'))
-      {
-        die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
-      }
-      if(isset($_POST['_youmaylivealittlelonger']))
-      {
-        $template->header();
-          $result = PageUtils::resetdelvotes($paths->page_id, $paths->namespace);
-          echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>';
-        $template->footer();
-        break;
-      }
+      $q = $db->sql_query('UPDATE '.table_prefix.'pages SET wiki_mode=' . $level . ' WHERE urlname=\'' . $db->escape($paths->page_id) . '\' AND namespace=\'' . $paths->namespace . '\';');
+      if ( !$q )
+        $db->_die();
+      redirect(makeUrl($paths->page), htmlspecialchars($paths->cpage['name']), $lang->get('page_wikimode_success_redirect'), 2);
+    }
+    else
+    {
       $template->header();
-        ?>
-        <form action="<?php echo makeUrl($paths->page, 'do=resetvotes'); ?>" method="post">
-          <p><?php echo $lang->get('ajax_delvote_reset_confirm'); ?></p>
-          <p><input type="submit" name="_youmaylivealittlelonger" value="<?php echo htmlspecialchars($lang->get('page_delvote_reset_btn_submit')); ?>" /></p>
-        </form>
-        <?php
-      $template->footer();
-      break;
-    case 'deletepage':
-      if(!$session->get_permissions('delete_page'))
-      {
-        die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
-      }
-      if ( !$session->sid_super )
-      {
-        redirect(makeUrlNS('Special', "Login/{$paths->page}", 'target_do=deletepage&level=' . $session->user_level, false), $lang->get('etc_access_denied_short'), $lang->get('etc_access_denied_need_reauth'), 0);
-      }
-      
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      if(isset($_POST['_adiossucker']))
-      {
-        $reason = ( isset($_POST['reason']) ) ? $_POST['reason'] : false;
-        if ( empty($reason) )
-          $error = $lang->get('ajax_delete_prompt_reason');
-        else
-        {
-          $template->header();
-            $result = PageUtils::deletepage($paths->page_id, $paths->namespace, $reason);
-            echo '<p>'.$result.' <a href="'.makeUrl($paths->page).'">' . $lang->get('etc_return_to_page') . '</a>.</p>';
-          $template->footer();
-          break;
-        }
-      }
-      $template->header();
-        ?>
-        <form action="<?php echo makeUrl($paths->page, 'do=deletepage'); ?>" method="post">
-           <?php echo $lang->get('page_delete_warning_stern'); ?>
-           <?php if ( isset($error) ) echo "<p>$error</p>"; ?>
-           <p><?php echo $lang->get('page_delete_lbl_reason'); ?> <input type="text" name="reason" size="50" /></p>
-           <p><input type="submit" name="_adiossucker" value="<?php echo htmlspecialchars($lang->get('page_delete_btn_submit')); ?>" style="color: red; font-weight: bold;" /></p>
-        </form>
-        <?php
-      $template->footer();
-      break;
-    case 'setwikimode':
-      if(!$session->get_permissions('set_wiki_mode'))
-      {
-        die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
-      }
-      if ( isset($_POST['finish']) )
-      {
-        $level = intval($_POST['level']);
+      if(!isset($_GET['level']) || ( isset($_GET['level']) && !preg_match('#^([0-9])$#', $_GET['level']))) die_friendly('Invalid request', '<p>Level not specified</p>');
+        $level = intval($_GET['level']);
         if ( !in_array($level, array(0, 1, 2) ) )
         {
           die_friendly('Invalid request', '<p>Level not specified</p>');
         }
-        $q = $db->sql_query('UPDATE '.table_prefix.'pages SET wiki_mode=' . $level . ' WHERE urlname=\'' . $db->escape($paths->page_id) . '\' AND namespace=\'' . $paths->namespace . '\';');
-        if ( !$q )
-          $db->_die();
-        redirect(makeUrl($paths->page), htmlspecialchars($paths->cpage['name']), $lang->get('page_wikimode_success_redirect'), 2);
-      }
-      else
-      {
-        $template->header();
-        if(!isset($_GET['level']) || ( isset($_GET['level']) && !preg_match('#^([0-9])$#', $_GET['level']))) die_friendly('Invalid request', '<p>Level not specified</p>');
-          $level = intval($_GET['level']);
-          if ( !in_array($level, array(0, 1, 2) ) )
-          {
-            die_friendly('Invalid request', '<p>Level not specified</p>');
-          }
-        echo '<form action="' . makeUrl($paths->page, 'do=setwikimode', true) . '" method="post">';
-        echo '<input type="hidden" name="finish" value="foo" />';
-        echo '<input type="hidden" name="level" value="' . $level . '" />';
-        $level_txt = ( $level == 0 ) ? 'page_wikimode_level_off' : ( ( $level == 1 ) ? 'page_wikimode_level_on' : 'page_wikimode_level_global' );
-        $blurb = ( $level == 0 || ( $level == 2 && getConfig('wiki_mode') != '1' ) ) ? 'page_wikimode_blurb_disable' : 'page_wikimode_blurb_enable';
-        ?>
-        <h3><?php echo $lang->get('page_wikimode_heading'); ?></h3>
-        <p><?php echo $lang->get($level_txt) . ' ' . $lang->get($blurb); ?></p>
-        <p><?php echo $lang->get('page_wikimode_warning'); ?></p>
-        <p><input type="submit" value="<?php echo htmlspecialchars($lang->get('page_wikimode_btn_submit')); ?>" /></p>
-        <?php
-        echo '</form>';
-        $template->footer();
-      }
+      echo '<form action="' . makeUrl($paths->page, 'do=setwikimode', true) . '" method="post">';
+      echo '<input type="hidden" name="finish" value="foo" />';
+      echo '<input type="hidden" name="level" value="' . $level . '" />';
+      $level_txt = ( $level == 0 ) ? 'page_wikimode_level_off' : ( ( $level == 1 ) ? 'page_wikimode_level_on' : 'page_wikimode_level_global' );
+      $blurb = ( $level == 0 || ( $level == 2 && getConfig('wiki_mode') != '1' ) ) ? 'page_wikimode_blurb_disable' : 'page_wikimode_blurb_enable';
+      ?>
+      <h3><?php echo $lang->get('page_wikimode_heading'); ?></h3>
+      <p><?php echo $lang->get($level_txt) . ' ' . $lang->get($blurb); ?></p>
+      <p><?php echo $lang->get('page_wikimode_warning'); ?></p>
+      <p><input type="submit" value="<?php echo htmlspecialchars($lang->get('page_wikimode_btn_submit')); ?>" /></p>
+      <?php
+      echo '</form>';
+      $template->footer();
+    }
+    break;
+  case 'diff':
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    require_once(ENANO_ROOT.'/includes/diff.php');
+    $template->header();
+    $id1 = ( isset($_GET['diff1']) ) ? (int)$_GET['diff1'] : false;
+    $id2 = ( isset($_GET['diff2']) ) ? (int)$_GET['diff2'] : false;
+    if ( !$id1 || !$id2 )
+    {
+      echo '<p>Invalid request.</p>';
+      $template->footer();
       break;
-    case 'diff':
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      require_once(ENANO_ROOT.'/includes/diff.php');
-      $template->header();
-      $id1 = ( isset($_GET['diff1']) ) ? (int)$_GET['diff1'] : false;
-      $id2 = ( isset($_GET['diff2']) ) ? (int)$_GET['diff2'] : false;
-      if ( !$id1 || !$id2 )
-      {
-        echo '<p>Invalid request.</p>';
-        $template->footer();
-        break;
-      }
-      if ( !ctype_digit($_GET['diff1']) || !ctype_digit($_GET['diff1']) )
-      {
-        echo '<p>SQL injection attempt</p>';
-        $template->footer();
-        break;
-      }
-      echo PageUtils::pagediff($paths->page_id, $paths->namespace, $id1, $id2);
+    }
+    if ( !ctype_digit($_GET['diff1']) || !ctype_digit($_GET['diff1']) )
+    {
+      echo '<p>SQL injection attempt</p>';
       $template->footer();
       break;
-    case 'detag':
-      if ( $session->user_level < USER_LEVEL_ADMIN )
-      {
-        die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
-      }
-      if ( $paths->page_exists )
-      {
-        die_friendly($lang->get('etc_invalid_request_short'), '<p>' . $lang->get('page_detag_err_page_exists') . '</p>');
-      }
-      $q = $db->sql_query('DELETE FROM '.table_prefix.'tags WHERE page_id=\'' . $db->escape($paths->page_id) . '\' AND namespace=\'' . $paths->namespace . '\';');
-      if ( !$q )
-        $db->_die('Detag query, index.php:'.__LINE__);
-      die_friendly($lang->get('page_detag_success_title'), '<p>' . $lang->get('page_detag_success_body') . '</p>');
-      break;
-    case 'aclmanager':
-      if ( !$session->sid_super )
-      {
-        redirect(makeUrlNS('Special', "Login/{$paths->page}", 'target_do=aclmanager&level=' . $session->user_level, false), $lang->get('etc_access_denied_short'), $lang->get('etc_access_denied_need_reauth'), 0);
-      }
-      
-      require_once(ENANO_ROOT.'/includes/pageutils.php');
-      $data = ( isset($_POST['data']) ) ? $_POST['data'] : Array('mode' => 'listgroups');
-      PageUtils::aclmanager($data);
-      break;
-    case 'sql_report':
-      $rev_id = ( (isset($_GET['oldid'])) ? intval($_GET['oldid']) : 0 );
-      $page = new PageProcessor( $paths->page_id, $paths->namespace, $rev_id );
-      $page->send_headers = true;
-      $pagepass = ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '';
-      $page->password = $pagepass;
-      $page->send(true);
-      ob_end_clean();
-      ob_start();
-      $db->sql_report();
-      break;
+    }
+    echo PageUtils::pagediff($paths->page_id, $paths->namespace, $id1, $id2);
+    $template->footer();
+    break;
+  case 'detag':
+    if ( $session->user_level < USER_LEVEL_ADMIN )
+    {
+      die_friendly($lang->get('etc_access_denied_short'), '<p>' . $lang->get('etc_access_denied') . '</p>');
+    }
+    if ( $paths->page_exists )
+    {
+      die_friendly($lang->get('etc_invalid_request_short'), '<p>' . $lang->get('page_detag_err_page_exists') . '</p>');
+    }
+    $q = $db->sql_query('DELETE FROM '.table_prefix.'tags WHERE page_id=\'' . $db->escape($paths->page_id) . '\' AND namespace=\'' . $paths->namespace . '\';');
+    if ( !$q )
+      $db->_die('Detag query, index.php:'.__LINE__);
+    die_friendly($lang->get('page_detag_success_title'), '<p>' . $lang->get('page_detag_success_body') . '</p>');
+    break;
+  case 'aclmanager':
+    if ( !$session->sid_super )
+    {
+      redirect(makeUrlNS('Special', "Login/{$paths->page}", 'target_do=aclmanager&level=' . $session->user_level, false), $lang->get('etc_access_denied_short'), $lang->get('etc_access_denied_need_reauth'), 0);
+    }
+    
+    require_once(ENANO_ROOT.'/includes/pageutils.php');
+    $data = ( isset($_POST['data']) ) ? $_POST['data'] : Array('mode' => 'listgroups');
+    PageUtils::aclmanager($data);
+    break;
+  case 'sql_report':
+    $rev_id = ( (isset($_GET['oldid'])) ? intval($_GET['oldid']) : 0 );
+    $page = new PageProcessor( $paths->page_id, $paths->namespace, $rev_id );
+    $page->send_headers = true;
+    $pagepass = ( isset($_REQUEST['pagepass']) ) ? sha1($_REQUEST['pagepass']) : '';
+    $page->password = $pagepass;
+    $page->send(true);
+    ob_end_clean();
+    ob_start();
+    $db->sql_report();
+    break;
+}
+
+// Generate an ETag
+/*
+// format: first 10 digits of SHA1 of page name, user id in hex, user and auth levels, page timestamp in hex
+$etag = substr(sha1($paths->namespace . ':' . $paths->page_id), 0, 10) . '-' .
+        "u{$session->user_id}l{$session->user_level}a{$session->auth_level}-" .
+        dechex($page_timestamp);
+        
+if ( isset($_SERVER['HTTP_IF_NONE_MATCH']) )
+{
+  if ( "\"$etag\"" == $_SERVER['HTTP_IF_NONE_MATCH'] )
+  {
+    header('HTTP/1.1 304 Not Modified');
+    exit();
   }
-  
-  // Generate an ETag
-  /*
-  // format: first 10 digits of SHA1 of page name, user id in hex, user and auth levels, page timestamp in hex
-  $etag = substr(sha1($paths->namespace . ':' . $paths->page_id), 0, 10) . '-' .
-          "u{$session->user_id}l{$session->user_level}a{$session->auth_level}-" .
-          dechex($page_timestamp);
+}
           
-  if ( isset($_SERVER['HTTP_IF_NONE_MATCH']) )
-  {
-    if ( "\"$etag\"" == $_SERVER['HTTP_IF_NONE_MATCH'] )
-    {
-      header('HTTP/1.1 304 Not Modified');
-      exit();
-    }
-  }
-            
-  header("ETag: \"$etag\"");
-  */
-  
-  $db->close();  
-  gzip_output();
-  
-  @ob_end_flush();
+header("ETag: \"$etag\"");
+*/
+
+$db->close();  
+gzip_output();
+
+@ob_end_flush();
   
 ?>
--- a/install/includes/cli-core.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/cli-core.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * cli-core.php - CLI installation wizard/core
  *
--- a/install/includes/common.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/common.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * common.php - Installer common functions
  *
@@ -16,7 +15,7 @@
 
 // Our version number. This needs to be changed for any custom releases.
 $installer_version = array(
-  'version' => '1.1.6',
+  'version' => '1.1.7',
   'type' => 'beta'
   // If type is set to "rc", "beta", or "alpha", optionally another version number can be issued with the key 'sub':
   // 'sub' => '3' will produce Enano 1.1.1a3 / Enano 1.1.1 alpha 3
--- a/install/includes/libenanoinstall.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/libenanoinstall.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * libenanoinstall.php - Installation payload backend
  *
--- a/install/includes/libenanoinstallcli.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/libenanoinstallcli.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * libenanoinstallcli.php - Installer frontend logic, CLI version
  *
--- a/install/includes/payload.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/payload.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * payload.php - Installer payload (the installation logic)
  *
@@ -425,7 +424,7 @@
   global $db, $session, $paths, $template, $plugins; // Common objects
   global $installer_version;
   
-  $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') . '\', \'' . $db->escape($_POST['username']) . '\', \'' . $db->escape(enano_version()) . '\', \'' . $db->escape($_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(ED_DATE | ED_TIME) . '\', \'' . $db->escape($_POST['username']) . '\', \'' . $db->escape(enano_version()) . '\', \'' . $db->escape($_SERVER['REMOTE_ADDR']) . '\');');
   if ( !$q )
   {
     echo '<p><tt>MySQL return: ' . $db->sql_error() . '</tt></p>';
--- a/install/includes/stages/confirm.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/confirm.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * confirm.php - Installer installation summary/confirmation stage
  *
--- a/install/includes/stages/database.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/database.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * database.php - Installer database driver selection stage
  *
--- a/install/includes/stages/database_mysql.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/database_mysql.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * database_mysql.php - Installer database info page, MySQL
  *
--- a/install/includes/stages/database_post.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/database_post.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * database_post.php - Database installation, stage 1
  *
--- a/install/includes/stages/database_postgresql.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/database_postgresql.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * database_postgresql.php - Installer database info page, PostgreSQL
  *
--- a/install/includes/stages/finish.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/finish.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * finish.php - Installer finalization stage
  *
--- a/install/includes/stages/install.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/install.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * install.php - Installer payload stage
  *
--- a/install/includes/stages/license.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/license.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * license.php - Installer license-agreement stage
  *
--- a/install/includes/stages/login.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/login.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * login.php - Installer login information stage
  *
--- a/install/includes/stages/sysreqs.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/sysreqs.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * sysreqs.php - Installer system-requirements page
  *
--- a/install/includes/stages/website.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/stages/website.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * website.php - Installer website-settings stage
  *
--- a/install/includes/ui.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/includes/ui.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * ui.php - User interface for installations and upgrades
  *
--- a/install/index.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/index.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * welcome.php - Portal to upgrade, readme, and install pages
  *
--- a/install/install-cli.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/install-cli.php	Tue Aug 25 01:43:40 2009 -0400
@@ -3,8 +3,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * install-cli.php - CLI installation frontend stub
  *
--- a/install/install.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/install.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * install.php - Main installation interface
  *
--- a/install/readme.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/readme.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * install.php - Main installation interface
  *
--- a/install/schemas/mysql_stage2.sql	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/schemas/mysql_stage2.sql	Tue Aug 25 01:43:40 2009 -0400
@@ -135,6 +135,8 @@
   user_hobbies text,
   email_public tinyint(1) NOT NULL DEFAULT 0,
   disable_js_fx tinyint(1) NOT NULL DEFAULT 0,
+  date_format varchar(32) NOT NULL DEFAULT 'F d, Y',
+  time_format varchar(32) NOT NULL DEFAULT 'G:i',
   PRIMARY KEY ( user_id ) 
 ) CHARACTER SET `utf8` COLLATE `utf8_bin`;
 
--- a/install/schemas/postgresql_stage2.sql	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/schemas/postgresql_stage2.sql	Tue Aug 25 01:43:40 2009 -0400
@@ -136,6 +136,8 @@
   user_hobbies text,
   email_public smallint NOT NULL DEFAULT 0,
   disable_js_fx smallint NOT NULL DEFAULT 0,
+  date_format varchar(32) NOT NULL DEFAULT 'F d, Y',
+  time_format varchar(32) NOT NULL DEFAULT 'G:i',
   PRIMARY KEY ( user_id ) 
 );
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/install/schemas/upgrade/1.1.6-1.1.7-mysql.sql	Tue Aug 25 01:43:40 2009 -0400
@@ -0,0 +1,2 @@
+ALTER TABLE {{TABLE_PREFIX}}users_extra ADD COLUMN date_format varchar(32) NOT NULL DEFAULT 'F d, Y';
+ALTER TABLE {{TABLE_PREFIX}}users_extra ADD COLUMN time_format varchar(32) NOT NULL DEFAULT 'G:i';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/install/schemas/upgrade/1.1.6-1.1.7-postgresql.sql	Tue Aug 25 01:43:40 2009 -0400
@@ -0,0 +1,2 @@
+ALTER TABLE {{TABLE_PREFIX}}users_extra ADD COLUMN date_format varchar(32) NOT NULL DEFAULT 'F d, Y';
+ALTER TABLE {{TABLE_PREFIX}}users_extra ADD COLUMN time_format varchar(32) NOT NULL DEFAULT 'G:i';
--- a/install/upgrade.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/install/upgrade.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * Installation package
  * upgrade.php - Upgrade interface
  *
@@ -19,7 +18,7 @@
 // The list of versions in THIS AND PREVIOUS branches, in chronological order.
 $enano_versions = array();
 $enano_versions['1.0'] = array('1.0', '1.0.1', '1.0.2b1', '1.0.2', '1.0.3', '1.0.4', '1.0.5', '1.0.6');
-$enano_versions['1.1'] = array('1.1.1', '1.1.2', '1.1.3', '1.1.4', '1.1.5', '1.1.6');
+$enano_versions['1.1'] = array('1.1.1', '1.1.2', '1.1.3', '1.1.4', '1.1.5', '1.1.6', '1.1.7');
 
 // If true, this will do a full langimport instead of only adding new strings.
 // Will probably be left on, but some change probably needs to be made to mark
@@ -108,6 +107,9 @@
 
 if ( !$session->user_logged_in || ( $session->user_logged_in && $session->auth_level < USER_LEVEL_ADMIN ) )
 {
+  // if we're not logged in, destroy any existing session keys in the browser
+  @setcookie('sid', '', time() - 86400);
+  
   $ui->set_visible_stage($stg_login);
   if ( isset($_POST['do_login']) )
   {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/language/english/install/default-tutorial/Basic_administration.txt	Tue Aug 25 01:43:40 2009 -0400
@@ -0,0 +1,66 @@
+The <acronym title="Administration Control Panel">ACP</acronym> is where you can go to manage things most users can't, such as website configuration, security settings, users, and plugins. This tutorial page covers the basic parts of the administration panel.
+
+To get started, open this link in a new browser window or tab: [[Special:Administration|Administration panel]]. You'll probably be asked to enter your password again; if prompted, please do so.
+
+== Layout of the ACP ==
+
+Enano's administration panel combines design elements from several other web applications with our own bits of design. It emphasizes familiarity and tries to be as self-explanatory as possible. We accomplish this by using lots of text and, except when such a design would be limiting, working with the same 2-column layout in every page.
+
+=== RTFD (Read The Friendly Descriptions) ===
+
+Except for completely self-explanatory basic options, all controls have descriptions of what exactly they do, in smaller text just below the label. This layout lets you scan quickly for what you're looking for, but puts help a glance away when you need it.
+
+== Applets ==
+
+There are 20 applets that make up Enano's administration panel. This might seem intimidating, but applets are sorted by category in Enano 1.2, so it's easy to find what you're looking for.
+
+'''Administration panel home:''' This shows you basic information about your website. Here you can find statistics, version information, active alerts, and instructions for getting support for Enano.
+'''General configuration:''' Here is where basic parameters of your site can be viewed and changed. There are a lot of settings here that can affect your site's security and permissions, so read everything twice on here.
+'''File uploads:''' Specific options related to Enano's file uploading feature.
+'''Allowed file types:''' Configure which file extensions may be uploaded through the [[Special:UploadFile|Upload File]] page.
+'''Manage pages:''' Batch control of pages, plus specific administrator options like moving pages to a new URL.
+'''Edit page content:''' Merely a front-end for finding and editing pages. This was included in Enano 1.0, so we left it in just in case you're still looking for this button here.
+'''Manage page groups:''' Group pages together, so that you can assign the same set of permissions to multiple pages at once.
+'''Manage themes:''' Install themes, change the default theme, and view or change permissions.
+'''Manage plugins:''' Install, remove, upgrade, and enable or disable installed plugins. This is also where you can see the list of system plugins (plugins that run basic functions) that come bundled with Enano.
+'''Backup database:''' Download a copy of your database that can be restored if something ever goes wrong with your website. This is only available on Enano installations based on MySQL.
+'''Language manager:''' View and change languages your site uses. You can also edit individual strings to customize your site.
+'''Cache settings:''' Check the status of individual caches. Caching lets Enano save some generated values so that pages can be produced faster.
+'''Manage users:''' Edit or delete user accounts on your website. Here you can reset passwords, activate or deactivate accounts, and a lot more.
+'''Edit user groups:''' Create, edit, and delete user groups. User groups let you place any number of users within one common category, so you can assign permissions, username colors (ranks) and more to lots of users at the same time.
+'''COPPA support:''' Enable or disable Enano's support for COPPA, a United States law that requires websites with a target audience under the age of 13 to seek parental consent before allowing new members to participate.
+'''Mass e-mail:''' Send out an e-mail to everybody on your website, or to a certain user group.
+'''User ranks and titles:''' Assign different visual properties to user titles. In addition to changing the color and basic formatting, you can enter custom CSS rules.
+'''Security log:''' See a list of things done on your site that pertain to security. You can see successful and failed attempts to log in, information on actions taken with plugins, changing of sensitive settings, and more.
+'''Ban control:''' Ban (or unban) people by username, IP address or e-mail address from your website.
+'''Log out of admin panel:''' Tell Enano that you're finished working with the admin panel and wish to discard your privileged state, so that a password is required to use the administration panel again. You should always use this when you're finished using the ACP.
+
+== Getting started ==
+
+OK, you should have, in a separate browser window or tab, the ACP home page now. On the left you should see a tree menu with several different categories of applets. Click each one to open it, so that you can see everything. Also take the time now to click "Turn on keep-alive", since you'll be switching back and forth between your admin panel and this tutorial a lot.
+
+The right side is where the current ACP page is loaded. In this case, it should be the Administration Dashboard, also available through the "Administration panel home" link at the top of the menu. You should see a table with statistics about your website and, if you scroll down a bit, an alert or two. Finally, you can see your fresh new security log showing the date, time, and source IP address of your Enano installation as well as a pair of light-blue boxes with links to Enano documentation and support.
+
+Look to the far right: you'll see a light blue bar with an arrow peeking out. If you click that, you'll see your site's sidebar, so that you can navigate around from the admin panel. We usually keep this hidden because it makes space a bit limited on non-widescreen displays.
+
+Let's take a shot at some configuration. Click on "General configuration" in the navigation tree. Scroll down a little bit and look for something you'd like to change - we usually like to start by turning on approval of comments and visual confirmation when guests post to cut down on comment spam. If you can send e-mail from your server, try also setting account activation to "User." Save your changes by scrolling all the way to the bottom and clicking "Save Changes."
+
+Did you catch that? Not too hard. That's how just about all the forms in Enano work.
+
+== Install a plug-in ==
+
+Now we're ready for something a little more advanced. Let's start off with a relatively basic plugin: [http://enanocms.org/plugin/ajim2 AjIM2].
+
+Start off by downloading the plugin as instructed on the page. Unzip the file and upload the files to your webserver the same way you uploaded Enano. Make sure you put both the "AjIM2.0.php" file and the "ajim" folder under Enano's "plugins" folder.
+
+Now go to Manage Plugins in your ACP tab. You should see an entry for "AjIM 2.0". Click on it and watch the table cell expand. You'll see a description of the plugin as well as information like its author, version, and enanocms.org plugin page URL. Off to the right you'll see a button labeled "Install." Click it and confirm the installation when prompted. If all goes well, you'll see the page refresh and the entry for AjIM will now be green. Congratulations! You just installed your first plugin.
+
+Since AjIM adds a sidebar block, let's also go in and enable that. Expand the sidebar by clicking the light blue bar on the right side of the admin panel window and click "Edit the Sidebar." Then click "Create a new block." Select "Plugin block" from the drop-down box, then enter the name of the new block and which sidebar you want it on. Finally select "AjIM Shoutbox" from the last drop-down box and click Create new block. You'll see a message that says "The item was added" and the new AjIM Shoutbox block at the bottom of the sidebar you selected. Drag the gray handle at the top of the block to rearrange it, if you want. That's it - AjIM is installed and enabled on your site.
+
+Most plugins are easy to install but need just a little help to become fully integrated with your site. For example, if you install [http://enanocms.org/plugin/snapr Snapr] or [http://enanocms.org/plugin/newsboy Newsboy], you might want to edit your Navigation sidebar block to add a link or change your main page. Plugins are totally flexible in this regard, so experiment - a plugin often drives the main feature of an Enano site.
+
+== That's it! ==
+
+Now you're familiar with the administration control panel. We've accomplished a knowledge of Enano's basic features and familiarized ourselves with its interface. Now it's time to explore some more advanced features.
+
+[[Moderation|Next step: Moderation, security, and access controls &raquo;]]
--- a/language/english/install/default-tutorial/Creating_and_editing_pages.txt	Tue Aug 25 01:43:11 2009 -0400
+++ b/language/english/install/default-tutorial/Creating_and_editing_pages.txt	Tue Aug 25 01:43:40 2009 -0400
@@ -1,7 +1,67 @@
-OK, I lied. The beta doesn't have a tutorial.
+At its heart, Enano is a wiki. Why is this special? Because content is at the heart of the Enano design, not an afterthought. In Enano, editing - like most other tasks - is done right on the page. The page is updated live so you can see your changes right away. You can edit a page simply by clicking the "Edit this page" button on the shiny black toolbar. Create a page simply by editing it - the first time you save it, it will be created automatically.
+
+=== Your first edit ===
+
+Let's try some basic editing now. Click the "edit this page" button you see on the textual toolbar at the top of this page. Type between the two HTML comments (&lt;!-- like this --&gt;) you see in the text box (you might have to scroll down a bit). Click "Save Changes" - you should see what you typed show up right away!
+
+==== User-entered text ====
+
+<!-- Put your own text below this line! -->
+
+<!-- Put your own text above this line! -->
+
+=== Create your first page ===
+
+Now let's try creating a page. Open [[My first page|this link]] in a new browser tab or window so that you can keep these instructions available. Click the same "edit this page" button and type some text. What you typed should be visible on the page now!
 
-=== Oh noes! What am I to do? ===
+=== Add some flair ===
+
+Have you noticed the way links and headings look on this page? They are embedded using a very simple language called ''wikitext''. You can use wikitext to organize and format your page, and to link to other pages. Linking to other pages is what makes a wiki, a wiki.
+
+To use bold text:
+
+<code><nowiki>'''Your text here'''</nowiki></code>
+
+To use italic text:
+
+<code><nowiki>''Your text here''</nowiki></code>
+
+Create a link:
+
+<code><nowiki>[[Page title]]</nowiki></code>
+
+Create a link, but using your own text:
 
-For now, use the [http://enanocms.org/download?series=1.0 stable releases] of Enano if you don't feel comfortable. Also read the [http://docs.enanocms.org/ documentation] - it won't give you a tutorial ''per se'', but it will explain how to run an Enano website. If you're stuck, try our [http://forum.enanocms.org/ support forums] or see [http://enanocms.org/Support other support options].
+<code><nowiki>[[Page title|Your text here]]</nowiki></code>
+
+Create a large heading:
+
+<code><nowiki>== Your text here ==</nowiki></code>
+
+Create a medium heading:
+
+<code><nowiki>=== Your text here ===</nowiki></code>
+
+Create a small heading:
+
+<code><nowiki>==== Your text here ====</nowiki></code>
+
+Link to an external site:
 
-<div class="error-box">Remember that this is a beta release of Enano. We don't provide official support for problems, but we will fix bugs and take suggestions. Take this into account when you post for help - it will make getting an answer more likely!</div>
+<code><nowiki>[http://www.example.com/ Your text here]</nowiki></code>
+
+== Visual editing ==
+
+If you prefer to design your documents in a more graphical way, click the <a href="#" onclick="return false;" class="abutton abutton_blue image"><img width="16" height="16" src="images/spacer.gif" style="background-image: url(images/editor/sprite.png); background-repeat: no-repeat; background-position: -112px 0px;" /> Convert to HTML</a> button in the editor. Enano includes [http://tinymce.moxiecode.com/ TinyMCE], a widely-used graphical editor for the web.
+
+== Moving up from Enano 1.0? ==
+
+Good news: You don't have to learn anything new to use Enano 1.2's formatting syntax or editor. We've improved the interface of the editor a lot though. Enano 1.2 also has new features like auto-saving and the ability to detect when someone else saves the page while you're working on it. Another new feature is a guard against automatically closing out the editor, so it's much harder to lose a page you're working on.
+
+The biggest change to page editing in Enano 1.2 is the way the renderer behaves when you use TinyMCE to edit the page. We made this process a lot smarter so the wikitext engine doesn't try to apply formatting that should already be done by TinyMCE. This means, however, that you can't use certain bits of wikitext syntax - such as bold, italics, headings and tables - that are already covered through TinyMCE features.
+
+== All done! ==
+
+That's it! Now you know how to write pages with Enano. Let's move on and learn how to do some basic administration of your new website.
+
+[[Basic_administration|Next step: Basic administation &raquo;]]
--- a/language/english/user.json	Tue Aug 25 01:43:11 2009 -0400
+++ b/language/english/user.json	Tue Aug 25 01:43:40 2009 -0400
@@ -317,6 +317,8 @@
       publicinfo_field_changetheme_title: 'Change theme:',
       publicinfo_field_changetheme_hint: 'If you don\'t like the look of the site, need a visual break, or are just curious, we might have some different themes for you to try out!',
       publicinfo_field_changetheme: 'Change my theme...',
+      publicinfo_field_dateformat: 'Date format:',
+      publicinfo_field_timeformat: 'Time format:',
       publicinfo_field_timezone: 'Time zone:',
       publicinfo_field_timezone_hint: 'Select the time zone you live in and when Daylight Savings Time occurs, if at all.',
       publicinfo_field_dst: 'Daylight saving time:',
@@ -357,7 +359,7 @@
       avatar_lbl_url_desc: 'This must start with the <tt>http://</tt> prefix and must be a valid URL. The image will be copied from the existing URL to this server - dynamic avatars are not supported.',
       avatar_lbl_file: 'Upload file:',
       avatar_lbl_file_desc: 'Your browser needs to support file uploads for this option to work.',
-      avatar_limits: 'The image cannot be more than %config.avatar_max_size% bytes in size. The maximum dimensions are %config.avatar_max_width% &#215; %config.avatar_max_height% pixels. Allowed formats are PNG, GIF, and JPEG.',
+      avatar_limits: 'The maximum file size is %config.avatar_max_size% bytes, and maximum dimensions are %config.avatar_max_width% &#215; %config.avatar_max_height% pixels; we\'ll try resizing it if necessary. Allowed formats are PNG, GIF, and JPEG.',
       avatar_delete_success: 'Your avatar has been deleted.',
       avatar_bad_write: 'Either the remote server had trouble finding the image, or your image exceeded the allowed file size.',
       avatar_bad_filetype: 'The file you selected is invalid. You must choose a file in PNG, JPEG, or GIF format.',
@@ -367,6 +369,7 @@
       avatar_move_failed: 'Your image was accepted, but there was a problem moving the image file to the correct location.',
       avatar_upload_success: 'Your avatar has been updated.',
       avatar_file_too_large: 'The image you uploaded exceeds the maximum file size allowed for avatars on this site.',
+      avatar_invalid_url: 'The URL you entered to your avatar image is not valid. Please enter another URL and try again.',
       avatar_gravatar_success: 'Your Gravatar will now be used as your avatar on this site.',
       avatar_gravatar_rating_g: 'The highest allowed rating for your Gravatar image is <b>G</b>. Images must be suitable for display on all websites with any audience type.',
       avatar_gravatar_rating_pg: 'The highest allowed rating for your Gravatar image is <b>PG</b>. Rude gestures, lesser swear words, mild violence, and mildly provocatively dressed individuals are permitted.',
--- a/plugins/PrivateMessages.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/PrivateMessages.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -83,7 +82,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 enano_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(ED_DATE | ED_TIME, $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'] != '' )
           {
@@ -259,7 +258,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 " . 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 ;-)
+        $text = "\n\n\nOn " . enano_date(ED_DATE | ED_TIME, $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) )
@@ -637,7 +636,7 @@
               {
                 echo '</b>';
               }
-              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>';
+              echo '</a></td><td class="'.$cls.'">'.enano_date(ED_DATE | ED_TIME, $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	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialAdmin.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -1482,7 +1481,7 @@
     $filename = 'enano_backup_' . enano_date('ymd') . '.sql' . $aesext;
     ob_start();
     // Spew some headers
-    $headdate = enano_date('F d, Y \a\t h:i a');
+    $headdate = enano_date(ED_DATE | ED_TIME);
     echo <<<HEADER
 -- Enano CMS SQL backup
 -- Generated on {$headdate} by {$session->username}
@@ -1494,7 +1493,7 @@
     $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)) . '\')');
+    $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(ED_DATE | ED_TIME).'\', \''.$db->escape($session->username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', \'' . $db->escape(implode(', ', $tables)) . '\')');
     if ( !$e )
       $db->_die();
     
@@ -2227,26 +2226,22 @@
         <td width="100%" valign="top">
           <div class="pad" id="ajaxPageContainer">
           <?php
-          if(isset($_GET['module'])) 
+          if ( isset($_GET['module']) ) 
           {
-            // Look for a namespace prefix in the urlname, and assign a different namespace, if necessary
-            $k = array_keys($paths->nslist);
-            for ( $i = 0; $i < sizeof($paths->nslist); $i++ )
+            list($module) = explode('/', $_GET['module']);
+            list($page_id, $namespace) = RenderMan::strToPageID($module);
+            if ( $namespace != 'Admin' )
             {
-              $ln = strlen( $paths->nslist[ $k[ $i ] ] );
-              if ( substr($_GET['module'], 0, $ln) == $paths->nslist[$k[$i]] )
-              {
-                $ns = $k[$i];
-                $nm = substr($_GET['module'], $ln, strlen($_GET['module']));
-              }
+              echo '<div class="error-box">Module must be in the Admin namespace</div>';
             }
-            $fname = 'page_'.$ns.'_'.$nm;
-            $s = strpos($fname, '?noheaders');
-            if($s) $fname = substr($fname, 0, $s);
-            $paths->cpage['module'] = $_GET['module'];
-            if ( function_exists($fname) && $_GET['module'] != $paths->nslist['Special'] . 'Administration' )
+            else
             {
-              call_user_func($fname);
+              $paths->fullpage = $_GET['module'];
+              $paths->cpage['module'] = $_GET['module'];
+              $page = new PageProcessor($page_id, $namespace);
+              $page->send_headers = false;
+              $page->send();
+              $paths->fullpage = $paths->page;
             }
           } 
           else 
@@ -2603,7 +2598,7 @@
           }
           if(isset($_GET['ajax']))
           {
-            ob_end_clean();
+            @ob_end_clean();
             die('GOOD');
           }
           break;
--- a/plugins/SpecialCSS.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialCSS.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/SpecialGroups.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialGroups.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,7 +12,6 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
  * Copyright (C) 2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -377,7 +376,7 @@
       foreach ( $pending as $member )
       {
         
-        $date = enano_date('F d, Y', $member['reg_time']);
+        $date = enano_date(ED_DATE, $member['reg_time']);
         $cls = ( $cls == 'row2' ) ? 'row1' : 'row2';
         $addy = $email->encryptEmail($member['email']);
         
@@ -423,7 +422,7 @@
       if ( $member['is_mod'] != 1 )
         break;
       
-      $date = enano_date('F d, Y', $member['reg_time']);
+      $date = enano_date(ED_DATE, $member['reg_time']);
       $cls = ( $cls == 'row2' ) ? 'row1' : 'row2';
       $addy = $email->encryptEmail($member['email']);
       
@@ -447,7 +446,7 @@
       if ( $member['is_mod'] == 1 )
         continue;
       
-      $date = enano_date('F d, Y', $member['reg_time']);
+      $date = enano_date(ED_DATE, $member['reg_time']);
       $cls = ( $cls == 'row2' ) ? 'row1' : 'row2';
       $addy = $email->encryptEmail($member['email']);
       
--- a/plugins/SpecialLog.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialLog.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/SpecialPageFuncs.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialPageFuncs.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -641,7 +640,7 @@
           if ( !$q )
             $db->die_json();
           
-          while ( $row = $db->fetchrow() )
+          while ( $row = $db->fetchrow($q) )
           {
             $key = array(
               'name' => $row['username'],
--- a/plugins/SpecialSearch.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialSearch.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/SpecialUpdownload.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialUpdownload.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * SpecialUpdownload.php - handles uploading and downloading of user-uploaded files - possibly the most rigorously security-enforcing script in all of Enano, although sessions.php comes in a close second
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -128,13 +127,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.', \''.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.'logs(time_id,date_string,log_type,action,author,page_id,namespace) VALUES('.$utime.', \''.enano_date(ED_DATE | ED_TIME).'\', \'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.', \''.enano_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(ED_DATE | ED_TIME).'\', \'page\', \'reupload\', \''.$session->username.'\', \''.$filename.'\', \''.'File'.'\', \''.$comments.'\');')) $db->_die('The page log could not be updated.');
     }
     $cache->purge('page_meta');
     die_friendly($lang->get('upload_success_title'), '<p>' . $lang->get('upload_success_body', array('file_link' => makeUrlNS('File', $filename))) . '</p>');
--- a/plugins/SpecialUserFuncs.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialUserFuncs.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -406,6 +405,10 @@
           echo '<input type="hidden" name="get_fwd" value="' . $get_string . '" />';
         }
       }
+      else if ( isset($_POST['get_fwd']) )
+      {
+        echo '<input type="hidden" name="get_fwd" value="' . htmlspecialchars($_POST['get_fwd']) . '" />';
+      }
       ?>
     </form>
     <?php
@@ -422,6 +425,7 @@
   global $lang;
   require_once( ENANO_ROOT . '/includes/math.php' );
   
+  $paths->fullpage = $GLOBALS['title'];
   if ( $paths->getParam(0) === 'action.json' )
   {
     if ( !isset($_POST['r']) )
@@ -1838,47 +1842,8 @@
   
   public static function format_date($time)
   {
-    global $lang;
-    // 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 = enano_date($formatstring);
-    // Yesterday's date
-    $yesterday = enano_date($formatstring, (time() - (24*60*60)));
-    // Date on the input
-    $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 = enano_date($formatstring, (time() - $offset));
-      // so does the input timestamp match the date from $i days ago?
-      if ( $then == $days_ago )
-      {
-        // yes, return $i
-        return $lang->get('userfuncs_ml_date_daysago', array('days_ago' => $i));
-      }
-    }
-    // either yesterday, today, or before 6 days ago
-    switch($then)
-    {
-      case $today:
-        return $lang->get('userfuncs_ml_date_today');
-      case $yesterday:
-        return $lang->get('userfuncs_ml_date_yesterday');
-      default:
-        return $then;
-    }
-    //     .--.
-    //    |o_o |
-    //    |!_/ |
-    //   //   \ \
-    //  (|     | )
-    // /'\_   _/`\
-    // \___)=(___/
-    return 'Linux rocks!';
+    // merged into enano_date() :)
+    return enano_date(ED_DATE, $time);
   }
   function reg_time($time, $row)
   {
--- a/plugins/SpecialUserPrefs.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/SpecialUserPrefs.php	Tue Aug 25 01:43:40 2009 -0400
@@ -12,8 +12,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute it and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -185,6 +184,10 @@
   
   switch ( $section )
   {
+    case 'Avatar':
+      $template->preload_js('jquery');
+      $template->preload_js('jquery-ui');
+      break;
     case 'EmailPassword':
       // Require elevated privileges (well sortof)
       if ( $session->auth_level < USER_LEVEL_CHPREF )
@@ -306,6 +309,10 @@
       $template->tpl_strings['PAGE_NAME'] = $lang->get('usercp_signature_title');
       break;
     case 'Profile':
+    case 'Home':
+      if ( isset($_POST['submit']) )
+        csrf_request_confirm();
+      
       $template->tpl_strings['PAGE_NAME'] = $lang->get('usercp_publicinfo_title');
       break;
   }
@@ -454,6 +461,9 @@
         $hobbies = htmlspecialchars($_POST['hobbies']);
         $hobbies = $db->escape($hobbies);
         
+        $date_format = $db->escape(htmlspecialchars($_POST['date_format']));
+        $time_format = $db->escape(htmlspecialchars($_POST['time_format']));
+        
         $email_public = ( isset($_POST['email_public']) ) ? '1' : '0';
         $disable_js_fx = ( isset($_POST['disable_js_fx']) ) ? '1' : '0';
         
@@ -483,6 +493,8 @@
         $session->user_extra['user_job'] = $occupation;
         $session->user_extra['user_hobbies'] = $hobbies;
         $session->user_extra['email_public'] = intval($email_public);
+        $session->date_format = $date_format;
+        $session->time_format = $time_format;
         
         // user title
         $user_title_col = '';
@@ -536,7 +548,8 @@
         
         $q = $db->sql_query('UPDATE '.table_prefix."users_extra SET user_aim='$imaddr_aim',user_yahoo='$imaddr_yahoo',user_msn='$imaddr_msn',
                                user_xmpp='$imaddr_xmpp',user_homepage='$homepage',user_location='$location',user_job='$occupation',
-                               user_hobbies='$hobbies',email_public=$email_public,disable_js_fx=$disable_js_fx
+                               user_hobbies='$hobbies',email_public=$email_public,disable_js_fx=$disable_js_fx,date_format='$date_format',
+                               time_format='$time_format'
                                WHERE user_id=$session->user_id;");
         
         if ( !$q )
@@ -632,6 +645,34 @@
             <td class="row1"><?php echo $lang->get('usercp_publicinfo_field_changetheme_hint'); ?> <a href="<?php echo makeUrlNS('Special', 'ChangeStyle/' . $paths->page); ?>" onclick="ajaxChangeStyle(); return false;"><?php echo $lang->get('usercp_publicinfo_field_changetheme'); ?></a></td>
           </tr>
           <tr>
+            <td class="row2"><?php echo $lang->get('usercp_publicinfo_field_dateformat'); ?></td>
+            <td class="row1">
+            <select name="date_format">
+              <?php
+              foreach ( array(DATE_1, DATE_2, DATE_3, DATE_4) as $format )
+              {
+                $selected = $format === $session->date_format ? ' selected="selected"' : '';
+                echo '<option value="' . $format . '"' . $selected . '>' . enano_date($format) . '</option>';
+              }
+              ?>
+            </select>
+            </td>
+          </tr>
+          <tr>
+            <td class="row2"><?php echo $lang->get('usercp_publicinfo_field_timeformat'); ?></td>
+            <td class="row1">
+            <select name="time_format">
+              <?php
+              foreach ( array(TIME_12_NS, TIME_12_S, TIME_24_NS, TIME_24_S) as $format )
+              {
+                $selected = $format === $session->time_format ? ' selected="selected"' : '';
+                echo '<option value="' . $format . '"' . $selected . '>' . enano_date($format) . '</option>';
+              }
+              ?>
+            </select>
+            </td>
+          </tr>
+          <tr>
             <td class="row3" colspan="2"><?php echo $lang->get('usercp_publicinfo_field_timezone'); ?> <?php echo $tz_select; ?><br /><small><?php echo $lang->get('usercp_publicinfo_field_timezone_hint'); ?></small></td>
           </tr>
           <tr>
@@ -745,6 +786,8 @@
         </table>
       </div>
       <?php
+      // CSRF protection
+      echo '<input type="hidden" name="cstok" value="' . $session->csrf_token . '" />';
       echo '</form>';
       break;
     case 'Avatar':
@@ -754,197 +797,18 @@
         break;
       }
       
-      // Determine current avatar
-      $q = $db->sql_query('SELECT user_has_avatar, avatar_type FROM ' . table_prefix . 'users WHERE user_id = ' . $session->user_id . ';');
-      if ( !$q )
-        $db->_die('Avatar CP selecting user\'s avatar data');
-      
-      list($has_avi, $avi_type) = $db->fetchrow_num();
-      
       if ( isset($_POST['submit']) )
       {
-        $action = ( isset($_POST['avatar_action']) ) ? $_POST['avatar_action'] : 'keep';
-        $avi_path = ENANO_ROOT . '/' . getConfig('avatar_directory') . '/' . $session->user_id . '.' . $avi_type;
-        switch($action)
-        {
-          case 'keep':
-          default:
-            break;
-          case 'remove':
-            if ( $has_avi )
-            {
-              // First switch the avatar off
-              $q = $db->sql_query('UPDATE ' . table_prefix . 'users SET user_has_avatar = 0 WHERE user_id = ' . $session->user_id . ';');
-              if ( !$q )
-                $db->_die('Avatar CP switching user avatar off');
-              
-              if ( @unlink($avi_path) )
-              {
-                echo '<div class="info-box">' . $lang->get('usercp_avatar_delete_success') . '</div>';
-              }
-              $has_avi = 0;
-            }
-            break;
-          case 'set_http':
-          case 'set_file':
-            // Hackish way to preserve the UNIX philosophy of reusing as much code as possible
-            if ( $action == 'set_http' )
-            {
-              // Check if this action is enabled
-              if ( getConfig('avatar_upload_http', 1) !== 1 )
-              {
-                // non-localized, only appears on hack attempt
-                echo '<div class="error-box">Uploads over HTTP are disabled.</div>';
-                break;
-              }
-              // Download the file
-              require_once( ENANO_ROOT . '/includes/http.php' );
-              
-              if ( !preg_match('/^http:\/\/([a-z0-9-\.]+)(:([0-9]+))?\/(.+)$/', $_POST['avatar_http_url'], $match) )
-              {
-                echo '<div class="error-box">' . $lang->get('usercp_avatar_invalid_url') . '</div>';
-                break;
-              }
-              
-              $hostname = $match[1];
-              $uri = '/' . $match[4];
-              $port = ( $match[3] ) ? intval($match[3]) : 80;
-              $max_size = intval(getConfig('avatar_max_size'));
-              
-              // Get temporary file
-              $tempfile = tempnam(false, "enanoavatar_{$session->user_id}");
-              if ( !$tempfile )
-                echo '<div class="error-box">Error getting temp file.</div>';
-              
-              @unlink($tempfile);
-              $request = new Request_HTTP($hostname, $uri, 'GET', $port);
-              $result = $request->write_response_to_file($tempfile, 50, $max_size);
-              if ( !$result || $request->response_code != HTTP_OK )
-              {
-                @unlink($tempfile);
-                echo '<div class="error-box">' . $lang->get('usercp_avatar_bad_write') . '</div>';
-                break;
-              }
-              
-              // Response written. Proceed to validation...
-            }
-            else
-            {
-              // Check if this action is enabled
-              if ( getConfig('avatar_upload_file', 1) !== 1 )
-              {
-                // non-localized, only appears on hack attempt
-                echo '<div class="error-box">Uploads from the browser are disabled.</div>';
-                break;
-              }
-              
-              $max_size = intval(getConfig('avatar_max_size'));
-              
-              $file =& $_FILES['avatar_file'];
-              $tempfile =& $file['tmp_name'];
-              if ( filesize($tempfile) > $max_size )
-              {
-                @unlink($tempfile);
-                echo '<div class="error-box">' . $lang->get('usercp_avatar_file_too_large') . '</div>';
-                break;
-              }
-            }
-            $file_type = get_image_filetype($tempfile);
-            if ( !$file_type )
-            {
-              unlink($tempfile);
-              echo '<div class="error-box">' . $lang->get('usercp_avatar_bad_filetype') . '</div>';
-              break;
-            }
-            
-            $avi_path_new = ENANO_ROOT . '/' . getConfig('avatar_directory') . '/' . $session->user_id . '.' . $file_type;
-            
-            // The file type is good - validate dimensions and animation
-            switch($file_type)
-            {
-              case 'png':
-                $is_animated = is_png_animated($tempfile);
-                $dimensions = png_get_dimensions($tempfile);
-                break;
-              case 'gif':
-                $is_animated = is_gif_animated($tempfile);
-                $dimensions = gif_get_dimensions($tempfile);
-                break;
-              case 'jpg':
-                $is_animated = false;
-                $dimensions = jpg_get_dimensions($tempfile);
-                break;
-              default:
-                echo '<div class="error-box">API mismatch</div>';
-                break 2;
-            }
-            // Did we get invalid size data? If so the image is probably corrupt.
-            if ( !$dimensions )
-            {
-              @unlink($tempfile);
-              echo '<div class="error-box">' . $lang->get('usercp_avatar_corrupt_image') . '</div>';
-              break;
-            }
-            // Is the image animated?
-            if ( $is_animated && getConfig('avatar_enable_anim') !== '1' )
-            {
-              @unlink($tempfile);
-              echo '<div class="error-box">' . $lang->get('usercp_avatar_disallowed_animation') . '</div>';
-              break;
-            }
-            // Check image dimensions
-            list($image_x, $image_y) = $dimensions;
-            $max_x = intval(getConfig('avatar_max_width'));
-            $max_y = intval(getConfig('avatar_max_height'));
-            if ( $image_x > $max_x || $image_y > $max_y )
-            {
-              @unlink($tempfile);
-              echo '<div class="error-box">' . $lang->get('usercp_avatar_too_large') . '</div>';
-              break;
-            }
-            // All good!
-            @unlink($avi_path);
-            if ( rename($tempfile, $avi_path_new) )
-            {
-              $q = $db->sql_query('UPDATE ' . table_prefix . "users SET user_has_avatar = 1, avatar_type = '$file_type' WHERE user_id = {$session->user_id};");
-              if ( !$q )
-                $db->_die('Avatar CP updating users table after successful avatar upload');
-              $has_avi = 1;
-              $avi_type = $file_type;
-              echo '<div class="info-box">' . $lang->get('usercp_avatar_upload_success') . '</div>';
-            }
-            else
-            {
-              echo '<div class="error-box">' . $lang->get('usercp_avatar_move_failed') . '</div>';
-            }
-            break;
-          case 'set_gravatar':
-            // set avatar to use Gravatar
-            // make sure we're allowed to do this
-            if ( getConfig('avatar_upload_gravatar') != '1' )
-            {
-              // access denied
-              break;
-            }
-            // first, remove old image
-            if ( $has_avi )
-            {
-              // First switch the avatar off
-              $q = $db->sql_query('UPDATE ' . table_prefix . 'users SET user_has_avatar = 0 WHERE user_id = ' . $session->user_id . ';');
-              if ( !$q )
-                $db->_die('Avatar CP switching user avatar off');
-              
-              @unlink($avi_path);
-            }
-            // set to gravatar mode
-            $q = $db->sql_query('UPDATE ' . table_prefix . 'users SET user_has_avatar = 1, avatar_type = \'grv\' WHERE user_id = ' . $session->user_id . ';');
-            if ( !$q )
-              $db->_die('Avatar CP switching user avatar off');
-              
-            $has_avi = 1;
-            echo '<div class="info-box">' . $lang->get('usercp_avatar_gravatar_success') . '</div>';
-            break;
-        }
+        list($has_avi, $avi_type) = avatar_post($session->user_id);
+      }
+      else
+      {
+        // Determine current avatar
+        $q = $db->sql_query('SELECT user_has_avatar, avatar_type FROM ' . table_prefix . 'users WHERE user_id = ' . $session->user_id . ';');
+        if ( !$q )
+          $db->_die('Avatar CP selecting user\'s avatar data');
+        
+        list($has_avi, $avi_type) = $db->fetchrow_num();
       }
       
       ?>
@@ -952,28 +816,17 @@
       
         function avatar_select_field(elParent)
         {
+          $('td#avatar_upload_btns > div:visible').hide('blind');
           switch(elParent.value)
           {
-            case 'keep':
-            case 'remove':
-              $('avatar_upload_http').object.style.display = 'none';
-              $('avatar_upload_file').object.style.display = 'none';
-              $('avatar_upload_gravatar').object.style.display = 'none';
-              break;
             case 'set_http':
-              $('avatar_upload_http').object.style.display = 'block';
-              $('avatar_upload_file').object.style.display = 'none';
-              $('avatar_upload_gravatar').object.style.display = 'none';
+              $('#avatar_upload_http').show('blind');
               break;
             case 'set_file':
-              $('avatar_upload_http').object.style.display = 'none';
-              $('avatar_upload_file').object.style.display = 'block';
-              $('avatar_upload_gravatar').object.style.display = 'none';
+              $('#avatar_upload_file').show('blind');
               break;
             case 'set_gravatar':
-              $('avatar_upload_gravatar').object.style.display = 'block';
-              $('avatar_upload_http').object.style.display = 'none';
-              $('avatar_upload_file').object.style.display = 'none';
+              $('#avatar_upload_gravatar').show('blind');
               break;
           }
         }
@@ -991,7 +844,7 @@
             </tr>';
             
       echo '<tr>
-              <td class="row2" style="width: 50%;">
+              <td class="row2" style="width: 150px;">
                 ' . $lang->get('usercp_avatar_label_current') . '
               </td>
               <td class="row1" style="text-align: center;">';
@@ -1012,7 +865,7 @@
                 <td class="row2">
                   ' . $lang->get('usercp_avatar_lbl_change') . '
                 </td>
-                <td class="row1">
+                <td class="row1" id="avatar_upload_btns">
                   <label><input type="radio" name="avatar_action" value="keep" onclick="avatar_select_field(this);" checked="checked" /> ' . $lang->get('usercp_avatar_lbl_keep') . '</label><br />
                   <label><input type="radio" name="avatar_action" value="remove" onclick="avatar_select_field(this);" /> ' . $lang->get('usercp_avatar_lbl_remove') . '</label><br />';
       if ( getConfig('avatar_upload_http') == '1' )
@@ -1023,10 +876,6 @@
                     <small>' . $lang->get('usercp_avatar_lbl_url_desc') . ' ' . $lang->get('usercp_avatar_limits') . '</small>
                   </div>';
       }
-      else
-      {
-        echo '    <div id="avatar_upload_http" style="display: none;"></div>';
-      }
       if ( getConfig('avatar_upload_file') == '1' )
       {
         echo '    <label><input type="radio" name="avatar_action" value="set_file" onclick="avatar_select_field(this);" /> ' . $lang->get('usercp_avatar_lbl_set_file') . '</label><br />
@@ -1035,10 +884,6 @@
                     <small>' . $lang->get('usercp_avatar_lbl_file_desc') . ' ' . $lang->get('usercp_avatar_limits') . '</small>
                   </div>';
       }
-      else
-      {
-        echo '    <div id="avatar_upload_file" style="display: none;"></div>';
-      }
       if ( getConfig('avatar_upload_gravatar') == '1' )
       {
         $rating_images = array('g' => '0', 'pg' => '1', 'r' => '2', 'x' => '3');
@@ -1053,10 +898,6 @@
                     ' . $lang->get("usercp_avatar_gravatar_rating_$max_rating") . '
                   </div>';
       }
-      else
-      {
-        echo '    <div id="avatar_upload_gravatar" style="display: none;"></div>';
-      }
       echo '    </td>
               </tr>';
               
@@ -1089,4 +930,237 @@
   $template->footer();
 }
 
+// Avatar POST processor
+function avatar_post($user_id, $quiet = false)
+{
+  global $db, $session, $paths, $template, $plugins; // Common objects
+  global $lang;
+  
+  $had_a_boo_boo = true;
+  
+  // Determine current avatar
+  $q = $db->sql_query('SELECT user_has_avatar, avatar_type FROM ' . table_prefix . 'users WHERE user_id = ' . $session->user_id . ';');
+  if ( !$q )
+    $db->_die('Avatar CP selecting user\'s avatar data');
+  
+  list($has_avi, $avi_type) = $db->fetchrow_num();
+  
+  $action = ( isset($_POST['avatar_action']) ) ? $_POST['avatar_action'] : 'keep';
+  $avi_path = ENANO_ROOT . '/' . getConfig('avatar_directory') . '/' . $user_id . '.' . $avi_type;
+  switch($action)
+  {
+    case 'keep':
+    default:
+      $had_a_boo_boo = false;
+      break;
+    case 'remove':
+      if ( $has_avi )
+      {
+        // First switch the avatar off
+        $q = $db->sql_query('UPDATE ' . table_prefix . 'users SET user_has_avatar = 0 WHERE user_id = ' . $user_id . ';');
+        if ( !$q )
+          $db->_die('Avatar CP switching user avatar off');
+        
+        if ( @unlink($avi_path) )
+        {
+          $quiet || print '<div class="info-box">' . $lang->get('usercp_avatar_delete_success') . '</div>';
+        }
+        $has_avi = 0;
+      }
+      $had_a_boo_boo = false;
+      break;
+    case 'set_http':
+    case 'set_file':
+      // Hackish way to preserve the UNIX philosophy of reusing as much code as possible
+      if ( $action == 'set_http' )
+      {
+        // Check if this action is enabled
+        if ( getConfig('avatar_upload_http', 1) !== 1 )
+        {
+          // non-localized, only appears on hack attempt
+          echo '<div class="error-box">Uploads over HTTP are disabled.</div>';
+          break;
+        }
+        // Download the file
+        require_once( ENANO_ROOT . '/includes/http.php' );
+        
+        if ( !preg_match('/^http:\/\/((?:[a-z0-9-\.]+|\[[a-f0-9:]+\]))(:([0-9]+))?\/(.+)$/', $_POST['avatar_http_url'], $match) )
+        {
+          echo '<div class="error-box">' . $lang->get('usercp_avatar_invalid_url') . '</div>';
+          break;
+        }
+        
+        $hostname = $match[1];
+        $uri = '/' . $match[4];
+        $port = ( $match[3] ) ? intval($match[3]) : 80;
+        $max_size = intval(getConfig('avatar_max_size'));
+        
+        // Get temporary file
+        $tempfile = tempnam(false, "enanoavatar_{$user_id}");
+        if ( !$tempfile )
+          echo '<div class="error-box">Error getting temp file.</div>';
+        
+        @unlink($tempfile);
+        $request = new Request_HTTP($hostname, $uri, 'GET', $port);
+        // max download size: 2MB, keeps things reasonable
+        // note: we'll try to scale the image down before checking filesize
+        $result = $request->write_response_to_file($tempfile, 1160, 2097152);
+        if ( !$result || $request->response_code != HTTP_OK )
+        {
+          @unlink($tempfile);
+          echo '<div class="error-box">' . $lang->get('usercp_avatar_bad_write') . '</div>';
+          break;
+        }
+        
+        // Response written. Proceed to validation...
+      }
+      else
+      {
+        // Check if this action is enabled
+        if ( getConfig('avatar_upload_file', 1) !== 1 )
+        {
+          // non-localized, only appears on hack attempt
+          echo '<div class="error-box">Uploads from the browser are disabled.</div>';
+          break;
+        }
+        
+        $max_size = intval(getConfig('avatar_max_size'));
+        
+        $file =& $_FILES['avatar_file'];
+        $tempfile =& $file['tmp_name'];
+      }
+      $file_type = get_image_filetype($tempfile);
+      if ( !$file_type )
+      {
+        @unlink($tempfile);
+        echo '<div class="error-box">' . $lang->get('usercp_avatar_bad_filetype') . '</div>';
+        break;
+      }
+      
+      $avi_path_new = ENANO_ROOT . '/' . getConfig('avatar_directory') . '/' . $user_id . '.' . $file_type;
+      
+      // The file type is good - validate dimensions and animation
+      switch($file_type)
+      {
+        case 'png':
+          $is_animated = is_png_animated($tempfile);
+          $dimensions = png_get_dimensions($tempfile);
+          break;
+        case 'gif':
+          $is_animated = is_gif_animated($tempfile);
+          $dimensions = gif_get_dimensions($tempfile);
+          break;
+        case 'jpg':
+          $is_animated = false;
+          $dimensions = jpg_get_dimensions($tempfile);
+          break;
+        default:
+          echo '<div class="error-box">API mismatch</div>';
+          break 2;
+      }
+      // Did we get invalid size data? If so the image is probably corrupt.
+      if ( !$dimensions )
+      {
+        @unlink($tempfile);
+        echo '<div class="error-box">' . $lang->get('usercp_avatar_corrupt_image') . '</div>';
+        break;
+      }
+      // Is the image animated?
+      if ( $is_animated && getConfig('avatar_enable_anim', 0) !== 1 )
+      {
+        @unlink($tempfile);
+        echo '<div class="error-box">' . $lang->get('usercp_avatar_disallowed_animation') . '</div>';
+        break;
+      }
+      // Check image dimensions
+      list($image_x, $image_y) = $dimensions;
+      $max_x = intval(getConfig('avatar_max_width'));
+      $max_y = intval(getConfig('avatar_max_height'));
+      if ( $image_x > $max_x || $image_y > $max_y )
+      {
+        // try to scale the image
+        try
+        {
+          @rename($tempfile, "$tempfile-unscaled.$file_type");
+          $scale_result = scale_image("$tempfile-unscaled.$file_type", "$tempfile.$file_type", $max_x, $max_y, true);
+          if ( $scale_result )
+          {
+            if ( !(@unlink("$tempfile-unscaled.$file_type") && @rename("$tempfile.$file_type", $tempfile)) )
+            {
+              // scale failed
+              @unlink("$tempfile-scale.$file_type");
+              echo '<div class="error-box">Rename failure: ' . $lang->get('usercp_avatar_too_large') . '</div>';
+              break;
+            }
+          }
+          else
+          {
+            @unlink($tempfile);
+            @unlink("$tempfile-unscaled.$file_type");
+            echo '<div class="error-box">Scale failure: ' . $lang->get('usercp_avatar_too_large') . '</div>';
+            break;
+          }
+        }
+        catch ( Exception $e )
+        {
+          // If we get here, the scaling process most definitely failed.
+          echo '<div class="error-box">EXCEPTION: ' . $lang->get('usercp_avatar_too_large') . '</div>';
+          break;
+        }
+      }
+      // Check file size last, so that the scale operation is considered
+      if ( filesize($tempfile) > $max_size )
+      {
+        @unlink($tempfile);
+        echo '<div class="error-box">' . $lang->get('usercp_avatar_file_too_large') . '</div>';
+        break;
+      }
+      // All good!
+      @unlink($avi_path);
+      if ( rename($tempfile, $avi_path_new) )
+      {
+        $q = $db->sql_query('UPDATE ' . table_prefix . "users SET user_has_avatar = 1, avatar_type = '$file_type' WHERE user_id = {$user_id};");
+        if ( !$q )
+          $db->_die('Avatar CP updating users table after successful avatar upload');
+        $has_avi = 1;
+        $avi_type = $file_type;
+        $quiet || print '<div class="info-box">' . $lang->get('usercp_avatar_upload_success') . '</div>';
+      }
+      else
+      {
+        echo '<div class="error-box">' . $lang->get('usercp_avatar_move_failed') . '</div>';
+      }
+      $had_a_boo_boo = false;
+      break;
+    case 'set_gravatar':
+      // set avatar to use Gravatar
+      // make sure we're allowed to do this
+      if ( getConfig('avatar_upload_gravatar') != '1' )
+      {
+        // access denied
+        break;
+      }
+      // first, remove old image
+      if ( $has_avi )
+      {
+        // First switch the avatar off
+        $q = $db->sql_query('UPDATE ' . table_prefix . 'users SET user_has_avatar = 0 WHERE user_id = ' . $user_id . ';');
+        if ( !$q )
+          $db->_die('Avatar CP switching user avatar off');
+        
+        @unlink($avi_path);
+      }
+      // set to gravatar mode
+      $q = $db->sql_query('UPDATE ' . table_prefix . 'users SET user_has_avatar = 1, avatar_type = \'grv\' WHERE user_id = ' . $user_id . ';');
+      if ( !$q )
+        $db->_die('Avatar CP switching user avatar off');
+        
+      $has_avi = 1;
+      $quiet || print '<div class="info-box">' . $lang->get('usercp_avatar_gravatar_success') . '</div>';
+      $had_a_boo_boo = false;
+      break;
+  }
+  return array($has_avi, $avi_type, $had_a_boo_boo);
+}
+
 ?>
--- a/plugins/admin/CacheManager.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/CacheManager.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/GroupManager.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/GroupManager.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/Home.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/Home.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/LangManager.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/LangManager.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/PageEditor.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/PageEditor.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/PageGroups.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/PageGroups.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/PageManager.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/PageManager.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/PluginManager.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/PluginManager.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/SecurityLog.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/SecurityLog.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -176,7 +175,7 @@
     case "u_to_mod"        : $return .= $lang->get('acpsl_entry_u_to_mod'         , array('username' => $r['page_text'])); break;
     case "view_comment_ip" : $return .= $lang->get('acpsl_entry_view_comment_ip'  , array('username' => htmlspecialchars($r['page_text']))); break;
   }
-  $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="' . $lang->get('acpsl_tip_reverse_dns') . '">'.$r['edit_summary'].'</td></tr>';
+  $return .= '</td><td class="'.$cls.'">'.enano_date(ED_DATE | ED_TIME, $r['time_id']).'</td><td class="'.$cls.'">'.$r['author'].'</td><td class="'.$cls.'" style="cursor: pointer;" onclick="ajaxReverseDNS(this);" title="' . $lang->get('acpsl_tip_reverse_dns') . '">'.$r['edit_summary'].'</td></tr>';
   return $return;
 }
 
--- a/plugins/admin/ThemeManager.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/ThemeManager.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/plugins/admin/UserManager.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/UserManager.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
@@ -60,6 +59,24 @@
       if ( !$q )
         $db->_die();
       echo '<div class="info-box">' . $lang->get('acpum_msg_delete_success') . '</div>';
+      
+      // deleting own account?
+      if ( $user_id === $session->user_id )
+      {
+        // cute little hack to boot them out of the admin panel
+        echo '<script type="text/javascript">
+          addOnloadHook(function()
+          {
+            setTimeout(function()
+            {
+              eraseCookie("sid");
+              ENANO_SID = false;
+              auth_level = USER_LEVEL_MEMBER;
+              window.location = makeUrlNS("Special", "Login");
+            }, 3000);
+          });
+        </script>';
+      }
     }
     else
     {
@@ -89,7 +106,7 @@
         $real_name = $_POST['real_name'];
       }
       
-      $signature = RenderMan::preprocess_text($_POST['signature'], true, true);
+      $signature = RenderMan::preprocess_text($_POST['signature'], true, false);
       
       $user_level = intval($_POST['user_level']);
       if ( $user_level < USER_LEVEL_MEMBER || $user_level > USER_LEVEL_ADMIN )
@@ -129,7 +146,10 @@
         $homepage = '';
       }
       
-      if ( count($errors) < 1 )
+      // true for quiet operation
+      list(, , $avatar_post_fail) = avatar_post($user_id, true);
+      
+      if ( count($errors) < 1 && !$avatar_post_fail )
       {
         $q = $db->sql_query('SELECT u.user_level, u.user_has_avatar, u.avatar_type FROM '.table_prefix.'users AS u WHERE u.user_id = ' . $user_id . ';');
         if ( !$q )
@@ -177,167 +197,6 @@
           $to_update_users['activation_key'] = sha1($session->dss_rand());
         }
         
-        // Avatar validation
-        $action = ( isset($_POST['avatar_action']) ) ? $_POST['avatar_action'] : 'keep';
-        $avi_path = ENANO_ROOT . '/' . getConfig('avatar_directory') . '/' . $user_id . '.' . $avi_type;
-        switch($action)
-        {
-          case 'keep':
-          default:
-            break;
-          case 'remove':
-            if ( $has_avi )
-            {
-              // First switch the avatar off
-              $to_update_users['user_has_avatar'] = '0';
-              @unlink($avi_path);
-            }
-            break;
-          case 'set_http':
-          case 'set_file':
-            // Hackish way to preserve the UNIX philosophy of reusing as much code as possible
-            if ( $action == 'set_http' )
-            {
-              // Check if this action is enabled
-              if ( getConfig('avatar_upload_http', 1) !== 1 )
-              {
-                // non-localized, only appears on hack attempt
-                $errors[] = 'Uploads over HTTP are disabled.';
-                break;
-              }
-              // Download the file
-              require_once( ENANO_ROOT . '/includes/http.php' );
-              
-              if ( !preg_match('/^http:\/\/([a-z0-9-\.]+)(:([0-9]+))?\/(.+)$/', $_POST['avatar_http_url'], $match) )
-              {
-                $errors[] = $lang->get('usercp_avatar_invalid_url');
-                break;
-              }
-              
-              $hostname = $match[1];
-              $uri = '/' . $match[4];
-              $port = ( $match[3] ) ? intval($match[3]) : 80;
-              $max_size = intval(getConfig('avatar_max_size'));
-              
-              // Get temporary file
-              $tempfile = tempnam(false, "enanoavatar_{$user_id}");
-              if ( !$tempfile )
-                $errors[] = 'Error getting temp file.';
-              
-              @unlink($tempfile);
-              $request = new Request_HTTP($hostname, $uri, 'GET', $port);
-              $result = $request->write_response_to_file($tempfile, 50, $max_size);
-              if ( !$result || $request->response_code != HTTP_OK )
-              {
-                @unlink($tempfile);
-                $errors[] = $lang->get('usercp_avatar_bad_write');
-                break;
-              }
-              
-              // Response written. Proceed to validation...
-            }
-            else
-            {
-              // Check if this action is enabled
-              if ( getConfig('avatar_upload_file', 1) !== 1 )
-              {
-                // non-localized, only appears on hack attempt
-                $errors[] = 'Uploads from the browser are disabled.';
-                break;
-              }
-              
-              $max_size = intval(getConfig('avatar_max_size'));
-              
-              $file =& $_FILES['avatar_file'];
-              $tempfile =& $file['tmp_name'];
-              if ( filesize($tempfile) > $max_size )
-              {
-                @unlink($tempfile);
-                $errors[] = $lang->get('usercp_avatar_file_too_large');
-                break;
-              }
-            }
-            $file_type = get_image_filetype($tempfile);
-            if ( !$file_type )
-            {
-              unlink($tempfile);
-              $errors[] = $lang->get('usercp_avatar_bad_filetype');
-              break;
-            }
-            
-            $avi_path_new = ENANO_ROOT . '/' . getConfig('avatar_directory') . '/' . $user_id . '.' . $file_type;
-            
-            // The file type is good - validate dimensions and animation
-            switch($file_type)
-            {
-              case 'png':
-                $is_animated = is_png_animated($tempfile);
-                $dimensions = png_get_dimensions($tempfile);
-                break;
-              case 'gif':
-                $is_animated = is_gif_animated($tempfile);
-                $dimensions = gif_get_dimensions($tempfile);
-                break;
-              case 'jpg':
-                $is_animated = false;
-                $dimensions = jpg_get_dimensions($tempfile);
-                break;
-              default:
-                $errors[] = 'API mismatch';
-                break 2;
-            }
-            // Did we get invalid size data? If so the image is probably corrupt.
-            if ( !$dimensions )
-            {
-              @unlink($tempfile);
-              $errors[] = $lang->get('usercp_avatar_corrupt_image');
-              break;
-            }
-            // Is the image animated?
-            if ( $is_animated && getConfig('avatar_enable_anim') !== '1' )
-            {
-              @unlink($tempfile);
-              $errors[] = $lang->get('usercp_avatar_disallowed_animation');
-              break;
-            }
-            // Check image dimensions
-            list($image_x, $image_y) = $dimensions;
-            $max_x = intval(getConfig('avatar_max_width'));
-            $max_y = intval(getConfig('avatar_max_height'));
-            if ( $image_x > $max_x || $image_y > $max_y )
-            {
-              @unlink($tempfile);
-              $errors[] = $lang->get('usercp_avatar_too_large');
-              break;
-            }
-            // All good!
-            @unlink($avi_path);
-            if ( rename($tempfile, $avi_path_new) )
-            {
-              $to_update_users['user_has_avatar'] = '1';
-              $to_update_users['avatar_type'] = $file_type;
-            }
-            else
-            {
-              // move failed - turn avatar off
-              $to_update_users['user_has_avatar'] = '0';
-            }
-            break;
-          case 'set_gravatar':
-            // set avatar to use Gravatar
-            // first, remove old image
-            if ( $has_avi )
-            {
-              @unlink($avi_path);
-            }
-            // set to gravatar mode
-            $to_update_users['user_has_avatar'] = '1';
-            $to_update_users['avatar_type'] = 'grv';
-            
-            $has_avi = 1;
-            break;
-        }
-        
         if ( count($errors) < 1 )
         {
           $to_update_users_extra = array();
@@ -423,14 +282,17 @@
       }
     }
     
-    if ( count($errors) > 0 )
+    if ( count($errors) > 0 || @$avatar_post_fail )
     {
-      echo '<div class="error-box">
-              <b>' . $lang->get('acpum_err_validation_fail') . '</b>
-              <ul>
-                <li>' . implode("</li>\n        <li>", $errors) . '</li>
-              </ul>
-            </div>';
+      if ( count($errors) > 0 )
+      {
+        echo '<div class="error-box">
+                <b>' . $lang->get('acpum_err_validation_fail') . '</b>
+                <ul>
+                  <li>' . implode("</li>\n        <li>", $errors) . '</li>
+                </ul>
+              </div>';
+      }
       $form = new Admin_UserManager_SmartForm();
       $form->user_id = $user_id;
       $form->username = $username;
@@ -466,7 +328,7 @@
     # END VALIDATION
     #
   }
-  else if ( isset($_POST['action']['go']) || ( isset($_GET['src']) && $_GET['src'] == 'get' ) )
+  else if ( isset($_POST['action']['go']) || ( isset($_GET['src']) && $_GET['src'] == 'get' ) || ($pathsuser = $paths->getParam(0)) )
   {
     if ( isset($_GET['user']) )
     {
@@ -480,6 +342,10 @@
     {
       $username =& $_POST['username'];
     }
+    else if ( $pathsuser )
+    {
+      $username = str_replace('_', ' ', dirtify_page_id($pathsuser));
+    }
     else
     {
       echo 'No username provided';
@@ -680,7 +546,7 @@
         else $cls = 'row2';
         $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.'">'.enano_date(ED_DATE | ED_TIME, $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>
@@ -1091,32 +957,21 @@
                   <td class="row2">
                     {lang:acpum_avatar_lbl_change}
                   </td>
-                  <td class="row1">
+                  <td class="row1" id="avatar_upload_btns_{UUID}">
                     <script type="text/javascript">
                       function admincp_users_avatar_set_{UUID}(elParent)
                       {
+                        $('td#avatar_upload_btns_{UUID} > div:visible').hide('blind');
                         switch(elParent.value)
                         {
-                          case 'keep':
-                          case 'remove':
-                            \$dynano('avatar_upload_http_{UUID}').object.style.display = 'none';
-                            \$dynano('avatar_upload_file_{UUID}').object.style.display = 'none';
-                            \$dynano('avatar_upload_gravatar_{UUID}').object.style.display = 'none';
-                            break;
                           case 'set_http':
-                            \$dynano('avatar_upload_http_{UUID}').object.style.display = 'block';
-                            \$dynano('avatar_upload_file_{UUID}').object.style.display = 'none';
-                            \$dynano('avatar_upload_gravatar_{UUID}').object.style.display = 'none';
+                            $('#avatar_upload_http_{UUID}').show('blind');
                             break;
                           case 'set_file':
-                            \$dynano('avatar_upload_http_{UUID}').object.style.display = 'none';
-                            \$dynano('avatar_upload_file_{UUID}').object.style.display = 'block';
-                            \$dynano('avatar_upload_gravatar_{UUID}').object.style.display = 'none';
+                            $('#avatar_upload_file_{UUID}').show('blind');
                             break;
                           case 'set_gravatar':
-                            \$dynano('avatar_upload_gravatar_{UUID}').object.style.display = 'block';
-                            \$dynano('avatar_upload_http_{UUID}').object.style.display = 'none';
-                            \$dynano('avatar_upload_file_{UUID}').object.style.display = 'none';
+                            $('#avatar_upload_gravatar_{UUID}').show('blind');
                             break;
                         }
                       }
--- a/plugins/admin/UserRanks.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/plugins/admin/UserRanks.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
--- a/themes/enanium/css/babygrand.css	Tue Aug 25 01:43:11 2009 -0400
+++ b/themes/enanium/css/babygrand.css	Tue Aug 25 01:43:40 2009 -0400
@@ -74,6 +74,15 @@
   margin: 100px auto 0 auto;
 }
 
+a.header-placeholder {
+  display: block;
+  width: 60%;
+  min-width: 500px;
+  position: absolute;
+  top: 0;
+  left: 0;
+}
+
 div#header h1 {
   margin: 0;
   font-weight: normal;
@@ -137,6 +146,7 @@
 
 ul.useropts li:hover > a {
   padding: 2px 12px 4px 12px;
+  color: #b9d0e3;
 }
 
 ul.useropts li.logout:hover > a {
--- a/themes/enanium/header.tpl	Tue Aug 25 01:43:11 2009 -0400
+++ b/themes/enanium/header.tpl	Tue Aug 25 01:43:40 2009 -0400
@@ -24,6 +24,7 @@
       
       if ( is_object($paths) && $head = $paths->sysMsg('SiteHeader') )
       {
+        echo '<a class="header-placeholder" href="' . makeUrl(get_main_page()) . '">&nbsp;</a>';
         echo $head;
       }
       else