More preliminary l10n work; userpage portal style basics implemented
authorDan
Tue, 26 Jun 2007 20:48:44 -0400
changeset 22 d0314575e2f0
parent 21 663fcf528726
child 23 320acf077276
More preliminary l10n work; userpage portal style basics implemented
TODO
ajax.php
includes/clientside/static/dropdown.js
includes/functions.php
includes/pageprocess.php
includes/template.php
plugins/PrivateMessages.php
plugins/SpecialAdmin.php
plugins/SpecialPageFuncs.php
themes/admin/css/default.css
themes/oxygen/elements.tpl
themes/oxygen/footer.tpl
themes/oxygen/header.tpl
--- a/TODO	Tue Jun 26 17:28:18 2007 -0400
+++ b/TODO	Tue Jun 26 20:48:44 2007 -0400
@@ -17,7 +17,7 @@
 [x] Possibly add these fields: AIM, Yahoo, MSN, XMPP messenger icons, then homepage, location, occupation, hobbies, allow public e-mail display
     [ ] Put it in a user_extra table and have an option to enable or disable these fields in the admin panel
     [Y] Delay until RC3 or Banshee?
-    [ ] When added, put a box on the user page that shows the information
+    [x] When added, put a box on the user page that shows the information
 [x] Fix "this page" bug in ACL editor
     [x] The problem itself got fixed BUT there seem to be deeper problems related to scope selection
         This needs to be FIXED and WORKING PERFECTLY in Banshee!
--- a/ajax.php	Tue Jun 26 17:28:18 2007 -0400
+++ b/ajax.php	Tue Jun 26 20:48:44 2007 -0400
@@ -123,6 +123,10 @@
       $c = 0;
       $u = Array();
       $n = Array();
+      
+      $name = sanitize_page_id($name);
+      $name = str_replace('_', ' ', $name);
+      
       for($i=0;$i<sizeof($paths->pages)/2;$i++)
       {
         if( ( 
--- a/includes/clientside/static/dropdown.js	Tue Jun 26 17:28:18 2007 -0400
+++ b/includes/clientside/static/dropdown.js	Tue Jun 26 20:48:44 2007 -0400
@@ -191,7 +191,14 @@
   {
     a.className = '';
     
-    slideIn(ul);
+    if ( jBox_slide_enable )
+    {
+      slideIn(ul);
+    }
+    else
+    {
+      ul.style.display = 'none';
+    }
     
   }
   
--- a/includes/functions.php	Tue Jun 26 17:28:18 2007 -0400
+++ b/includes/functions.php	Tue Jun 26 20:48:44 2007 -0400
@@ -11,63 +11,148 @@
  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
  */
- 
-function getConfig($n) {
+
+/**
+ * Fetch a value from the site configuration.
+ * @param string The identifier of the value ("site_name" etc.)
+ * @return string Configuration value, or bool(false) if the value is not set
+ */
+
+function getConfig($n)
+{
   global $enano_config;
-  if(isset($enano_config[$n])) return $enano_config[$n];
-  else                         return false;
+  if ( isset( $enano_config[ $n ] ) )
+  {
+    return $enano_config[$n];
+  }
+  else
+  {
+    return false;
+  }
 }
 
-function setConfig($n, $v) {
+/**
+ * Update or change a configuration value.
+ * @param string The identifier of the value ("site_name" etc.)
+ * @param string The new value
+ * @return null
+ */
+
+function setConfig($n, $v)
+{
+  
   global $enano_config, $db;
   $enano_config[$n] = $v;
   $v = $db->escape($v);
-  $e=$db->sql_query('DELETE FROM '.table_prefix.'config WHERE config_name=\''.$n.'\';');
-  if(!$e) $db->_die('Error during generic setConfig() call row deletion.');
-  $e=$db->sql_query('INSERT INTO '.table_prefix.'config(config_name, config_value) VALUES(\''.$n.'\', \''.$v.'\')');
-  if(!$e) $db->_die('Error during generic setConfig() call row insertion.');
+  
+  $e = $db->sql_query('DELETE FROM '.table_prefix.'config WHERE config_name=\''.$n.'\';');
+  if ( !$e )
+  {
+    $db->_die('Error during generic setConfig() call row deletion.');
+  }
+  
+  $e = $db->sql_query('INSERT INTO '.table_prefix.'config(config_name, config_value) VALUES(\''.$n.'\', \''.$v.'\')');
+  if ( !$e )
+  {
+    $db->_die('Error during generic setConfig() call row insertion.');
+  }
 }
 
+/**
+ * Create a URI for an internal link.
+ * @param string The full identifier of the page to link to (Special:Administration)
+ * @param string The GET query string to append
+ * @param bool   If true, perform htmlspecialchars() on the return value to make it HTML-safe
+ * @return string
+ */
+
 function makeUrl($t, $query = false, $escape = false)
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
   $flags = '';
   $sep = urlSeparator;
-  if(isset($_GET['printable'])) { $flags .= $sep.'printable'; $sep = '&'; }
-  if(isset($_GET['theme'])) { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
-  if(isset($_GET['style'])) { $flags .= $sep.'style='.$session->style; $sep = '&'; }
+  if ( isset($_GET['printable'] ) )
+  {
+    $flags .= $sep . 'printable=yes';
+    $sep = '&';
+  }
+  if ( isset($_GET['theme'] ) )
+  {
+    $flags .= $sep . 'theme='.$session->theme;
+    $sep = '&';
+  }
+  if ( isset($_GET['style'] ) ) {
+    $flags .= $sep . 'style='.$session->style; 
+    $sep = '&';
+  }
+  
   $url = $session->append_sid(contentPath.$t.$flags);
   if($query)
   {
     $sep = strstr($url, '?') ? '&' : '?';
     $url = $url . $sep . $query;
   }
+  
   return ($escape) ? htmlspecialchars($url) : $url;
 }
 
+/**
+ * Create a URI for an internal link, and be namespace-friendly. Watch out for this one because it's different from most other Enano functions, in that the namespace is the first parameter.
+ * @param string The namespace ID
+ * @param string The page ID
+ * @param string The GET query string to append
+ * @param bool   If true, perform htmlspecialchars() on the return value to make it HTML-safe
+ * @return string
+ */
+
 function makeUrlNS($n, $t, $query = false, $escape = false)
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
   $flags = '';
-  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator;
-  else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
-  if(isset($_GET['printable'])) { $flags .= $sep.'printable';              $sep = '&'; }
-  if(isset($_GET['theme']))     { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
-  if(isset($_GET['style']))     { $flags .= $sep.'style='.$session->style; $sep = '&'; }
   
   if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
   {
-    $url = contentPath.$paths->nslist[$n].$t.$flags;
+    $sep = urlSeparator;
   }
   else
   {
-    $url = contentPath.$n.':'.$t.$flags;
+    $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
+  }
+  if ( isset( $_GET['printable'] ) ) {
+    $flags .= $sep . 'printable';
+    $sep = '&';
+  }
+  if ( isset( $_GET['theme'] ) ) 
+  {
+    $flags .= $sep . 'theme='.$session->theme;
+    $sep = '&';
+  }
+  if ( isset( $_GET['style'] ) )
+  {
+    $flags .= $sep . 'style='.$session->style;
+    $sep = '&';
+  }
+  
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
+  {
+    $url = contentPath . $paths->nslist[$n] . $t . $flags;
+  }
+  else
+  {
+    // If the path manager hasn't been initted yet, take an educated guess at what the URI should be
+    $url = contentPath . $n . ':' . $t . $flags;
   }
   
   if($query)
   {
-    if(strstr($url, '?')) $sep =  '&';
-    else $sep = '?';
+    if(strstr($url, '?')) 
+    {
+      $sep =  '&';
+    }
+    else
+    {
+      $sep = '?';
+    }
     $url = $url . $sep . $query . $flags;
   }
   
@@ -79,25 +164,62 @@
   return ($escape) ? htmlspecialchars($url) : $url;
 }
 
+/**
+ * Create a URI for an internal link, be namespace-friendly, and add http://hostname/scriptpath to the beginning if possible. Watch out for this one because it's different from most other Enano functions, in that the namespace is the first parameter.
+ * @param string The namespace ID
+ * @param string The page ID
+ * @param string The GET query string to append
+ * @param bool   If true, perform htmlspecialchars() on the return value to make it HTML-safe
+ * @return string
+ */
+
 function makeUrlComplete($n, $t, $query = false, $escape = false)
 {
   global $db, $session, $paths, $template, $plugins; // Common objects
   $flags = '';
-  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $sep = urlSeparator;
-  else $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
-  if(isset($_GET['printable'])) { $flags .= $sep.'printable';              $sep = '&'; }
-  if(isset($_GET['theme']))     { $flags .= $sep.'theme='.$session->theme; $sep = '&'; }
-  if(isset($_GET['style']))     { $flags .= $sep.'style='.$session->style; $sep = '&'; }
-  if(defined('ENANO_BASE_CLASSES_INITIALIZED')) $url = $session->append_sid(contentPath.$paths->nslist[$n].$t.$flags);
-  else $url = contentPath.$n.':'.$t.$flags;
+  
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
+  {
+    $sep = urlSeparator;
+  }
+  else
+  {
+    $sep = (strstr($_SERVER['REQUEST_URI'], '?')) ? '&' : '?';
+  }
+  if ( isset( $_GET['printable'] ) ) {
+    $flags .= $sep . 'printable';
+    $sep = '&';
+  }
+  if ( isset( $_GET['theme'] ) ) 
+  {
+    $flags .= $sep . 'theme='.$session->theme;
+    $sep = '&';
+  }
+  if ( isset( $_GET['style'] ) )
+  {
+    $flags .= $sep . 'style='.$session->style;
+    $sep = '&';
+  }
+  
+  if(defined('ENANO_BASE_CLASSES_INITIALIZED'))
+  {
+    $url = $session->append_sid(contentPath . $paths->nslist[$n] . $t . $flags);
+  }
+  else
+  {
+    // If the path manager hasn't been initted yet, take an educated guess at what the URI should be
+    $url = contentPath . $n . ':' . $t . $flags;
+  }
   if($query)
   {
     if(strstr($url, '?')) $sep =  '&';
     else $sep = '?';
     $url = $url . $sep . $query . $flags;
   }
+  
   $baseprot = 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://' . $_SERVER['HTTP_HOST'];
   $url = $baseprot . $url;
+  
   return ($escape) ? htmlspecialchars($url) : $url;
 }
 
@@ -141,14 +263,38 @@
 
 // Removed wikiFormat() from here, replaced with RenderMan::render
 
+/**
+ * Tell me if the page exists or not.
+ * @param string the full page ID (Special:Administration) of the page to check for
+ * @return bool True if the page exists, false otherwise
+ */
+
 function isPage($p) {
   global $db, $session, $paths, $template, $plugins; // Common objects
-  if(isset($paths->pages[$p])) return true;
-  $d = RenderMan::strToPageID($p);
-  if($d[1] != 'Special' && $d[1] != 'Template' && $d[1] != 'Admin') return false;
-  $a = explode('/', $p);
-  if(isset($paths->pages[$a[0]])) return true;
-  else return false;
+  
+  // Try the easy way first ;-)
+  if ( isset( $paths->pages[ $p ] ) )
+  {
+    return true;
+  }
+  
+  // Special case for Special, Template, and Admin pages that can't have slashes in their URIs
+  $ns_test = RenderMan::strToPageID( $p );
+  
+  if($ns_test[1] != 'Special' && $ns_test[1] != 'Template' && $ns_test[1] != 'Admin')
+  {
+    return false;
+  }
+  
+  $particles = explode('/', $p);
+  if ( isset ( $paths->pages[ $particles[ 0 ] ] ) )
+  {
+    return true;
+  }
+  else
+  {
+    return false;
+  }
 }
 
 function arrayItemUp($arr, $keyname) {
--- a/includes/pageprocess.php	Tue Jun 26 17:28:18 2007 -0400
+++ b/includes/pageprocess.php	Tue Jun 26 20:48:44 2007 -0400
@@ -464,15 +464,17 @@
       $page_name = ( isset($paths->pages[$this->page_id]) ) ? $paths->pages[$this->page_id]['name'] : $this->page_id;
     }
     
-    if ( $page_name == str_replace('_', ' ', $this->page_id) || $page_name == $paths->nslist['User'] . str_replace('_', ' ', $this->page_id) )
+    $target_username = strtr($page_name, 
+      Array(
+        '_' => ' ',
+        '<' => '&lt;',
+        '>' => '&gt;'
+        ));
+    
+    $target_username = preg_replace('/^' . preg_quote($paths->nslist['User']) . '/', '', $target_username);
+    
+    if ( ( $page_name == str_replace('_', ' ', $this->page_id) || $page_name == $paths->nslist['User'] . str_replace('_', ' ', $this->page_id) ) || !$this->page_exists )
     {
-      $target_username = strtr($page_name, 
-        Array(
-          '_' => ' ',
-          '<' => '&lt;',
-          '>' => '&gt;'
-          ));
-      $target_username = preg_replace('/^' . preg_quote($paths->nslist['User']) . '/', '', $target_username);
       $page_name = "$target_username's user page";
     }
     else
@@ -483,27 +485,155 @@
     
     $template->tpl_strings['PAGE_NAME'] = htmlspecialchars($page_name);
     
+    $q = $db->sql_query('SELECT u.username, u.user_id AS authoritative_uid, u.real_name, u.email, u.reg_time, x.*, COUNT(c.comment_id) AS n_comments
+                           FROM '.table_prefix.'users u
+                           LEFT JOIN '.table_prefix.'users_extra AS x
+                             ON ( u.user_id = x.user_id OR x.user_id IS NULL ) 
+                           LEFT JOIN '.table_prefix.'comments AS c
+                             ON ( ( c.user_id=u.user_id AND c.approved=1 ) OR ( c.comment_id IS NULL AND c.approved IS NULL ) )
+                           WHERE u.username=\'' . $db->escape($target_username) . '\'
+                           GROUP BY u.user_id;');
+    if ( !$q )
+      $db->_die();
+    
+    $user_exists = true;
+    
+    if ( $db->numrows() < 1 )
+    {
+      $user_exists = false;
+    }
+    else
+    {
+      $userdata = $db->fetchrow();
+      if ( $userdata['authoritative_uid'] == 1 )
+      {
+        // Hide data for anonymous user
+        $user_exists = false;
+        unset($userdata);
+      }
+    }
+    
     $this->header();
     
     // if ( $send_headers )
     // {
-      display_page_headers();
+    //  display_page_headers();
     // }
    
     // Start left sidebar: basic user info, latest comments
     
+    if ( $user_exists ):
+    
     echo '<table border="0" cellspacing="4" cellpadding="0" style="width: 100%;">';
-    echo '<tr><td style="width: 150px;">';
+    echo '<tr><td style="width: 150px;" valign="top">';
     
     echo '<div class="tblholder">
             <table border="0" cellspacing="1" cellpadding="4">';
     
+    //
     // Main part of sidebar
+    //
+    
+    // Basic user info
+    
+    echo '<tr><th class="subhead">All about ' . htmlspecialchars($target_username) . '</th></tr>';
+    echo '<tr><td class="row3">Joined: ' . date('F d, Y h:i a', $userdata['reg_time']) . '</td></tr>';
+    echo '<tr><td class="row1">Total comments: ' . $userdata['n_comments'] . '</td></tr>';
+    
+    if ( !empty($userdata['real_name']) )
+    {
+      echo '<tr><td class="row3">Real name: ' . htmlspecialchars($userdata['real_name']) . '</td></tr>';
+    }
+    
+    // Comments
+    
+    echo '<tr><th class="subhead">' . htmlspecialchars($target_username) . '\'s latest comments</th></tr>';
+    $q = $db->sql_query('SELECT page_id, namespace, subject, time FROM '.table_prefix.'comments WHERE name=\'' . $db->escape($target_username) . '\' AND approved=1 ORDER BY time DESC LIMIT 5;');
+    if ( !$q )
+      $db->_die();
+    
+    $comments = Array();
+    $no_comments = false;
+    
+    if ( $row = $db->fetchrow() )
+    {
+      do 
+      {
+        $row['time'] = date('F d, Y', $row['time']);
+        $comments[] = $row;
+      }
+      while ( $row = $db->fetchrow() );
+    }
+    else
+    {
+      $no_comments = true;
+    }
+    
+    echo '<tr><td class="row3">';
+    echo '<div style="border: 1px solid #000000; padding: 0px; margin: 0; max-height: 200px; clip: rect(0px,auto,auto,0px); overflow: auto; background-color: transparent;" class="tblholder">';
+    
+    echo '<table border="0" cellspacing="1" cellpadding="4">';
+    $class = 'row1';
+    
+    $tpl = '<tr>
+              <td class="{CLASS}">
+                <a href="{PAGE_LINK}" <!-- BEGINNOT page_exists -->class="wikilink-nonexistent"<!-- END page_exists -->>{PAGE}</a><br />
+                <small>Posted {DATE}<br /></small>
+                <b><a href="{COMMENT_LINK}">{SUBJECT}</a></b>
+              </td>
+            </tr>';
+    $parser = $template->makeParserText($tpl);
+    
+    if ( count($comments) > 0 )
+    {
+      foreach ( $comments as $comment )
+      {
+        $c_page_id = $paths->nslist[ $comment['namespace'] ] . sanitize_page_id($comment['page_id']);
+        if ( isset($paths->pages[ $c_page_id ]) )
+        {
+          $parser->assign_bool(array(
+            'page_exists' => true
+            ));
+          $page_title = $paths->pages[ $c_page_id ]['name'];
+        }
+        else
+        {
+          $parser->assign_bool(array(
+            'page_exists' => false
+            ));
+          $page_title = htmlspecialchars(dirtify_page_id($c_page_id));
+        }
+        $parser->assign_vars(array(
+            'CLASS' => $class,
+            'PAGE_LINK' => makeUrlNS($comment['namespace'], sanitize_page_id($comment['page_id'])),
+            'PAGE' => $page_title,
+            'SUBJECT' => $comment['subject'],
+            'DATE' => $comment['time'],
+            'COMMENT_LINK' => makeUrlNS($comment['namespace'], sanitize_page_id($comment['page_id']), 'do=comments', true)
+          ));
+        $class = ( $class == 'row3' ) ? 'row1' : 'row3';
+        echo $parser->run();
+      }
+    }
+    else
+    {
+      echo '<tr><td class="' . $class . '">This user has not posted any comments.</td></tr>';
+    }
+    echo '</table>';
+    
+    echo '</div>';
+    echo '</td></tr>';
             
     echo '  </table>
           </div>';
     
-    echo '</td><td>';
+    echo '</td><td valign="top" style="padding: 0 10px;">';
+    
+    else:
+    
+    // Nothing for now
+    
+    endif;
     
     // User's own content
     
@@ -516,26 +646,108 @@
     }
     else
     {
-      $this->err_page_not_existent();
+      $this->err_page_not_existent(true);
     }
     
     // Right sidebar
     
-    echo '</td><td style="width: 150px;">';
+    if ( $user_exists ):
+    
+    echo '</td><td style="width: 150px;" valign="top">';
     
     echo '<div class="tblholder">
             <table border="0" cellspacing="1" cellpadding="4">';
     
+    //
     // Main part of sidebar
-            
+    //
+    
+    // Contact information
+    
+    echo '<tr><th class="subhead">Get in touch</th></tr>';
+    
+    $class = 'row3';
+    
+    if ( $userdata['email_public'] == 1 )
+    {
+      $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+      global $email;
+      $email_link = $email->encryptEmail($userdata['email']);
+      echo '<tr><td class="'.$class.'">E-mail address: ' . $email_link . '</td></tr>';
+    }
+    
+    $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+    if ( $session->user_logged_in )
+    {
+      echo '<tr><td class="'.$class.'">Send ' . htmlspecialchars($target_username) . ' a <a href="' . makeUrlNS('Special', 'PrivateMessages/Compose/to/' . $this->page_id, false, true) . '">Private Message</a>!</td></tr>';
+    }
+    else
+    {
+      echo '<tr><td class="'.$class.'">You could send ' . htmlspecialchars($target_username) . ' a private message if you were <a href="' . makeUrlNS('Special', 'Login/' . $paths->nslist[$this->namespace] . $this->page_id) . '">logged in</a>.</td></tr>';
+    }
+    
+    if ( !empty($userdata['user_aim']) )
+    {
+      $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+      echo '<tr><td class="'.$class.'">AIM: ' . htmlspecialchars($userdata['user_aim']) . '</td></tr>';
+    }
+    
+    if ( !empty($userdata['user_yahoo']) )
+    {
+      $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+      echo '<tr><td class="'.$class.'">Yahoo! IM: ' . htmlspecialchars($userdata['user_yahoo']) . '</td></tr>';
+    }
+    
+    if ( !empty($userdata['user_msn']) )
+    {
+      $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+      $email_link = $email->encryptEmail($userdata['user_msn']);
+      echo '<tr><td class="'.$class.'">WLM: ' . $email_link . '</td></tr>';
+    }
+    
+    if ( !empty($userdata['user_xmpp']) )
+    {
+      $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+      $email_link = $email->encryptEmail($userdata['user_xmpp']);
+      echo '<tr><td class="'.$class.'">XMPP/Jabber: ' . $email_link . '</td></tr>';
+    }
+    
+    // Real life
+    
+    echo '<tr><th class="subhead">' . htmlspecialchars($target_username) . ' in real life</th></tr>';
+    
+    if ( !empty($userdata['user_location']) )
+    {
+      $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+      echo '<tr><td class="'.$class.'">Location: ' . htmlspecialchars($userdata['user_location']) . '</td></tr>';
+    }
+    
+    if ( !empty($userdata['user_job']) )
+    {
+      $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+      echo '<tr><td class="'.$class.'">Job/occupation: ' . htmlspecialchars($userdata['user_job']) . '</td></tr>';
+    }
+    
+    if ( !empty($userdata['user_hobbies']) )
+    {
+      $class = ( $class == 'row1' ) ? 'row3' : 'row1';
+      echo '<tr><td class="'.$class.'">Enjoys: ' . htmlspecialchars($userdata['user_hobbies']) . '</td></tr>';
+    }
+    
     echo '  </table>
           </div>';
           
     echo '</tr></table>';
     
+    else:
+    
+    echo '<p>Additional information: user "' . htmlspecialchars($target_username) . '" does not exist.</p>';
+    
+    endif;
+    
     // if ( $send_headers )
     // {
-      display_page_footers();
+    //  display_page_footers();
     // }
     
     $this->send_headers = $send_headers;
@@ -601,14 +813,22 @@
    * @access private
    */
    
-  function err_page_not_existent()
+  function err_page_not_existent($userpage = false)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
     
     $this->header();
     header('HTTP/1.1 404 Not Found');
-    echo '<h3>There is no page with this title yet.</h3>
-           <p>You have requested a page that doesn\'t exist yet.';
+    if ( $userpage )
+    {
+      echo '<h3>There is no page with this title yet.</h3>
+             <p>This user has not created his or her user page yet.';
+    }
+    else
+    {
+      echo '<h3>There is no page with this title yet.</h3>
+             <p>You have requested a page that doesn\'t exist yet.';
+    }
     if ( $session->get_permissions('create_page') )
     {
       echo ' You can <a href="'.makeUrlNS($this->namespace, $this->page_id, 'do=edit', true).'" onclick="ajaxEditor(); return false;">create this page</a>, or return to the <a href="'.makeUrl(getConfig('main_page')).'">homepage</a>.';
--- a/includes/template.php	Tue Jun 26 17:28:18 2007 -0400
+++ b/includes/template.php	Tue Jun 26 20:48:44 2007 -0400
@@ -647,11 +647,13 @@
     $urlname_clean = str_replace('\'', '\\\'', str_replace('\\', '\\\\', dirtify_page_id($paths->fullpage)));
     $urlname_clean = strtr( $urlname_clean, array( '<' => '&lt;', '>' => '&gt;' ) );
     
+    $urlname_jssafe = sanitize_page_id($paths->fullpage);
+    
     // Generate the dynamic javascript vars
     $js_dynamic = '    <script type="text/javascript">// <![CDATA[
       // This section defines some basic and very important variables that are used later in the static Javascript library.
       // SKIN DEVELOPERS: The template variable for this code block is {JS_DYNAMIC_VARS}. This MUST be inserted BEFORE the tag that links to the main Javascript lib.
-      var title=\''. $urlname_clean .'\';
+      var title=\''. $urlname_jssafe .'\';
       var page_exists='. ( ( $paths->page_exists) ? 'true' : 'false' ) .';
       var scriptPath=\''. scriptPath .'\';
       var contentPath=\''.contentPath.'\';
--- a/plugins/PrivateMessages.php	Tue Jun 26 17:28:18 2007 -0400
+++ b/plugins/PrivateMessages.php	Tue Jun 26 20:48:44 2007 -0400
@@ -180,7 +180,7 @@
         
         $to = $r['message_from'];
       } else {
-        if($argv[1]=='to' && $argv[2]) $to = $argv[2];
+        if(( $argv[1]=='to' || $argv[1]=='To' ) && $argv[2]) $to = $argv[2];
         else $to = '';
         $text = '';
         $subj = '';
--- a/plugins/SpecialAdmin.php	Tue Jun 26 17:28:18 2007 -0400
+++ b/plugins/SpecialAdmin.php	Tue Jun 26 20:48:44 2007 -0400
@@ -863,14 +863,16 @@
     }
     else
     {
+      $disabled = ( $r['user_id'] == $session->user_id ) ? ' disabled="disabled" ' : '';
       echo('
       <h3>Edit User Info</h3>
       <form action="'.makeUrl($paths->nslist['Special'].'Administration', 'module='.$paths->cpage['module']).'" method="post">
         <table border="0" style="margin-left: 0.2in;">   
           <tr><td>Username:</td><td><input type="text" name="new_username" value="'.$r['username'].'" /></td></tr>
-          <tr><td>New Password:</td><td><input type="password" name="new_pass" /></td></tr>
-          <tr><td>E-mail:</td><td><input type="text" name="email" value="'.$r['email'].'" /></td></tr>
-          <tr><td>Real Name:</td><td><input type="text" name="real_name" value="'.$r['real_name'].'" /></td></tr>
+          <tr><td>New Password:</td><td><input ' . $disabled . ' type="password" name="new_pass" /></td></tr>
+          <tr><td>E-mail:</td><td><input ' . $disabled . ' type="text" name="email" value="'.$r['email'].'" /></td></tr>
+          <tr><td>Real Name:</td><td><input ' . $disabled . ' type="text" name="real_name" value="'.$r['real_name'].'" /></td></tr>
+          ' . ( ( !empty($disabled) ) ? '<tr><td colspan="2"><small>To change your e-mail address, password, or real name, please use the user control panel.</small></td></tr>' : '' ) . '
           <tr><td>User level:</td><td><select name="level"><option '); if($r['user_level']==USER_LEVEL_CHPREF) echo('SELECTED'); echo(' value="'.USER_LEVEL_CHPREF.'">Regular User</option><option '); if($r['user_level']==USER_LEVEL_MOD) echo('SELECTED'); echo(' value="'.USER_LEVEL_MOD.'">Moderator</option><option '); if($r['user_level']==USER_LEVEL_ADMIN) echo('SELECTED'); echo(' value="'.USER_LEVEL_ADMIN.'">Administrator</option></select></td></tr>
           <tr><td>Delete user:</td><td><input type="hidden" name="go" /><input type="hidden" name="username" value="'.$r['username'].'" /><input onclick="return confirm(\'This is your last warning.\n\nAre you sure you want to delete this user account? Even if you delete this user account, the username will be shown in page edit history, comments, and other areas of the site.\n\nDeleting a user account CANNOT BE UNDONE and should only be done in extreme circumstances.\n\nIf the user has violated the site policy, deleting the account will not prevent him from using the site, for that you need to add a new ban rule.\n\nContinue deleting this user account?\')" type="submit" name="deleteme" value="Delete this user" style="color: red;" /> <label><input type="checkbox" name="delete_conf" /> I\'m absolutely sure</label>
           <tr><td align="center" colspan="2">
@@ -890,19 +892,33 @@
     {
       // Get the current session information so the user doesn't get logged out
       $aes = new AESCrypt();
-      $sk = md5($session->sid_super);
+      $sk = md5(strrev($session->sid_super));
       $qb = $db->sql_query('SELECT session_key,salt,auth_level,source_ip,time FROM '.table_prefix.'session_keys WHERE session_key=\''.$sk.'\' AND user_id='.$session->user_id.' AND auth_level='.USER_LEVEL_ADMIN);
-      if(!$qb) die('Error selecting session key info block B: '.$db->get_error());
-      if($db->numrows($qb) < 1) die('Error: cannot read admin session info block B, aborting table clear process');
+      if ( !$qb )
+      {
+        die('Error selecting session key info block B: '.$db->get_error());
+      }
+      if ( $db->numrows($qb) < 1 )
+      {
+        die('Error: cannot read admin session info block B, aborting table clear process');
+      }
       $qa = $db->sql_query('SELECT session_key,salt,auth_level,source_ip,time FROM '.table_prefix.'session_keys WHERE session_key=\''.md5($session->sid).'\' AND user_id='.$session->user_id.' AND auth_level='.USER_LEVEL_MEMBER);
-      if(!$qa) die('Error selecting session key info block A: '.$db->get_error());
-      if($db->numrows($qa) < 1) die('Error: cannot read user session info block A, aborting table clear process');
+      if ( !$qa )
+      {
+        die('Error selecting session key info block A: '.$db->get_error());
+      }
+      if ( $db->numrows($qa) < 1 )
+      {
+        die('Error: cannot read user session info block A, aborting table clear process');
+      }
       $ra = mysql_fetch_object($qa);
       $rb = mysql_fetch_object($qb);
       $db->free_result($qa);
       $db->free_result($qb);
+      
       $db->sql_query('DELETE FROM '.table_prefix.'session_keys;');
       $db->sql_query('INSERT INTO '.table_prefix.'session_keys( session_key,salt,user_id,auth_level,source_ip,time ) VALUES( \''.$ra->session_key.'\', \''.$ra->salt.'\', \''.$session->user_id.'\', \''.$ra->auth_level.'\', \''.$ra->source_ip.'\', '.$ra->time.' ),( \''.$rb->session_key.'\', \''.$rb->salt.'\', \''.$session->user_id.'\', \''.$rb->auth_level.'\', \''.$rb->source_ip.'\', '.$rb->time.' )');
+      
       echo('
         <div class="info-box">The session key table has been cleared. Your database should be a little bit smaller now.</div>
       ');
@@ -1386,55 +1402,80 @@
     $cpage = $paths->pages[$paths->nslist[$_POST['namespace']].$_POST['old_page_id']];
     if(isset($_POST['submit']))
     {
-      // Create a list of things to update
-      $page_info = Array(
-          'name'=>$_POST['name'],
-          'urlname'=>$_POST['page_id'],
-          'namespace'=>$_POST['namespace'],
-          'special'=>isset($_POST['special']) ? '1' : '0',
-          'visible'=>isset($_POST['visible']) ? '1' : '0',
-          'comments_on'=>isset($_POST['comments_on']) ? '1' : '0',
-          'protected'=>isset($_POST['protected']) ? '1' : '0'
-        );
-      // Build the query
-      $q = 'UPDATE '.table_prefix.'pages SET ';
-      $k = array_keys($page_info);
-      foreach($k as $c)
-      {
-        $q .= $c.'=\''.$db->escape($page_info[$c]).'\',';
-      }
-      $q = substr($q, 0, strlen($q)-1);
-      // Build the WHERE statements
-      $q .= ' WHERE ';
-      $k = array_keys($cpage);
-      foreach($k as $c)
+      switch(true)
       {
-        if($c != 'urlname_nons' && $c != 'urlname' && $c != 'really_protected') $q .= $c.'=\''.$cpage[$c].'\' AND ';
-        elseif($c == 'urlname') $q .= $c.'=\''.$cpage['urlname_nons'].'\' AND ';
+        case true:
+          // Create a list of things to update
+          $page_info = Array(
+              'name'=>$_POST['name'],
+              'urlname'=>sanitize_page_id($_POST['page_id']),
+              'namespace'=>$_POST['namespace'],
+              'special'=>isset($_POST['special']) ? '1' : '0',
+              'visible'=>isset($_POST['visible']) ? '1' : '0',
+              'comments_on'=>isset($_POST['comments_on']) ? '1' : '0',
+              'protected'=>isset($_POST['protected']) ? '1' : '0'
+            );
+          
+          $updating_urlname_or_namespace = ( $page_info['namespace'] != $cpage['namespace'] || $page_info['urlname'] != $cpage['urlname'] );
+          
+          if ( !isset($paths->nslist[ $page_info['namespace'] ]) )
+          {
+            echo '<div class="error-box">The namespace you selected is not properly registered.</div>';
+            break;
+          }
+          if ( isset($paths->pages[ $paths->nslist[$page_info['namespace']] . $page_info[ 'urlname' ] ]) && $updating_urlname_or_namespace )
+          {
+            echo '<div class="error-box">There is already a page that exists with that URL string and namespace.</div>';
+            break;
+          }
+          // Build the query
+          $q = 'UPDATE '.table_prefix.'pages SET ';
+          $k = array_keys($page_info);
+          foreach($k as $c)
+          {
+            $q .= $c.'=\''.$db->escape($page_info[$c]).'\',';
+          }
+          $q = substr($q, 0, strlen($q)-1);
+          // Build the WHERE statements
+          $q .= ' WHERE ';
+          $k = array_keys($cpage);
+          foreach($k as $c)
+          {
+            if($c != 'urlname_nons' && $c != 'urlname' && $c != 'really_protected')
+            {
+              $q .= $c.'=\''.$db->escape($cpage[$c]).'\' AND ';
+            }
+            else if($c == 'urlname')
+            {
+              $q .= $c.'=\''.$db->escape($cpage['urlname_nons']).'\' AND ';
+            }
+          }
+          // Trim off the last " AND " and append a semicolon
+          $q = substr($q, 0, strlen($q)-5) . ';';
+          // Send the completed query to MySQL
+          $e = $db->sql_query($q);
+          if(!$e) $db->_die('The page data could not be updated.');
+          // Update any additional tables
+          $q = Array(
+            'UPDATE '.table_prefix.'categories SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
+            'UPDATE '.table_prefix.'comments   SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
+            'UPDATE '.table_prefix.'logs       SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
+            'UPDATE '.table_prefix.'page_text  SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
+            );
+          foreach($q as $cq)
+          {
+            $e = $db->sql_query($cq);
+            if(!$e) $db->_die('Some of the additional tables containing page information could not be updated.');
+          }
+          // Update $cpage
+          $cpage = $page_info;
+          $cpage['urlname_nons'] = $cpage['urlname'];
+          $cpage['urlname'] = $paths->nslist[$cpage['namespace']].$cpage['urlname'];
+          $_POST['old_page_id'] = $page_info['urlname'];
+          $_POST['old_namespace'] = $page_info['namespace'];
+          echo '<div class="info-box">Your changes have been saved.</div>';
+          break;
       }
-      $q = substr($q, 0, strlen($q)-5) . ';';
-      // Send the completed query to MySQL
-      $e = $db->sql_query($q);
-      if(!$e) $db->_die('The page data could not be updated.');
-      // Update any additional tables
-      $q = Array(
-        'UPDATE '.table_prefix.'categories SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'UPDATE '.table_prefix.'comments   SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'UPDATE '.table_prefix.'logs       SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        'UPDATE '.table_prefix.'page_text  SET page_id=\''.$page_info['urlname'].'\',namespace=\''.$page_info['namespace'].'\' WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
-        );
-      foreach($q as $cq)
-      {
-        $e = $db->sql_query($cq);
-        if(!$e) $db->_die('Some of the additional tables containing page information could not be updated.');
-      }
-      // Update $cpage
-      $cpage = $page_info;
-      $cpage['urlname_nons'] = $cpage['urlname'];
-      $cpage['urlname'] = $paths->nslist[$cpage['namespace']].$cpage['urlname'];
-      $_POST['old_page_id'] = $page_info['urlname'];
-      $_POST['old_namespace'] = $page_info['namespace'];
-      echo '<div class="info-box">Your changes have been saved.</div>';
     } elseif(isset($_POST['delete'])) {
       $q = Array(
         'DELETE FROM '.table_prefix.'categories WHERE page_id=\'' . $db->escape($_POST['old_page_id']) . '\' AND namespace=\'' . $db->escape($_POST['old_namespace']) . '\';',
@@ -1460,7 +1501,7 @@
      <table border="0">
        <tr><td>Namespace:</td><td><select name="namespace"><?php $nm = array_keys($paths->nslist); foreach($nm as $ns) { if($ns != 'Special' && $ns != 'Admin') { echo '<option '; if($_POST['namespace']==$ns) echo 'selected="selected" '; echo 'value="'.$ns.'">'; if($paths->nslist[$ns] == '') echo '[No prefix]'; else echo $paths->nslist[$ns]; echo '</option>'; } } ?></select></td></tr>
        <tr><td>Page title:</td><td><input type="text" name="name" value="<?php echo $cpage['name']; ?>" /></td></tr>
-       <tr><td>Page URL string:<br /><small>No spaces, and don't enter the namespace prefix (e.g. User:).<br />Changing this value is usually not a good idea, especially for templates and project pages.</small></td><td><input type="text" name="page_id" value="<?php echo $cpage['urlname_nons']; ?>" /></td></tr>
+       <tr><td>Page URL string:<br /><small>No spaces, and don't enter the namespace prefix (e.g. User:).<br />Changing this value is usually not a good idea, especially for templates and project pages.</small></td><td><input type="text" name="page_id" value="<?php echo htmlspecialchars(dirtify_page_id($cpage['urlname_nons'])); ?>" /></td></tr>
        <tr><td></td><td><input <?php if($cpage['comments_on']) echo 'checked="checked"'; ?> name="comments_on" type="checkbox" id="cmt" />  <label for="cmt">Enable comments for this page</label></td></tr>
        <tr><td></td><td><input <?php if($cpage['special']) echo 'checked="checked"'; ?> name="special" type="checkbox" id="spc" />  <label for="spc">Bypass the template engine for this page</label><br /><small>This option enables you to use your own HTML headers and other code. It is recommended that only advanced users enable this feature. As with other Enano pages, you may use PHP code in your pages, meaning you can use Enano's API on the page.</small></td></tr>
        <tr><td></td><td><input <?php if($cpage['visible']) echo 'checked="checked"'; ?> name="visible" type="checkbox" id="vis" />  <label for="vis">Allow this page to be shown in page lists</label><br /><small>Unchecking this checkbox prevents the page for being indexed for searching. The index is rebuilt each time a page is saved, and you can force an index rebuild by going to the page <?php echo $paths->nslist['Special']; ?>SearchRebuild.</small></td></tr>
--- a/plugins/SpecialPageFuncs.php	Tue Jun 26 17:28:18 2007 -0400
+++ b/plugins/SpecialPageFuncs.php	Tue Jun 26 20:48:44 2007 -0400
@@ -62,7 +62,8 @@
 
 // function names are IMPORTANT!!! The name pattern is: page_<namespace ID>_<page URLname, without namespace>
 
-function page_Special_CreatePage() {
+function page_Special_CreatePage()
+{
   global $db, $session, $paths, $template, $plugins; // Common objects
   if ( isset($_POST['do']) )
   {
@@ -88,7 +89,7 @@
       exit;
     }
     $name = $db->escape(str_replace('_', ' ', $p));
-    $urlname = $db->escape(str_replace(' ', '_', $p));
+    $urlname = str_replace(' ', '_', $p);
     $namespace = $_POST['namespace'];
     if ( $namespace == 'Special' || ( $namespace == 'System' && $session->user_level < USER_LEVEL_ADMIN ) || $namespace == 'Admin')
     {
@@ -119,6 +120,9 @@
       $db->_die('An SQL injection attempt was caught at '.dirname(__FILE__).':'.__LINE__.'.');
     }
     
+    $urlname = sanitize_page_id($urlname);
+    $urlname = $db->escape($urlname);
+    
     $perms = $session->fetch_page_acl($urlname, $namespace);
     if ( !$perms->get_permissions('create_page') )
       die_friendly('Error creating page', '<p>An access control rule is preventing you from creating pages.</p>');
@@ -140,7 +144,7 @@
       $db->_die('The page text entry could not be inserted.');
     }
     
-    header('Location: '.makeUrl($paths->nslist[$_POST['namespace']].$p));
+    header('Location: '.makeUrlNS($_POST['namespace'], sanitize_page_id($p)));
     exit;
   }
   $template->header();
--- a/themes/admin/css/default.css	Tue Jun 26 17:28:18 2007 -0400
+++ b/themes/admin/css/default.css	Tue Jun 26 20:48:44 2007 -0400
@@ -161,3 +161,10 @@
   padding: 3px;
 }
 
+input:disabled {
+  border-color: #666666 !important;
+  background-image: none !important;
+  background-color: #DDD !important;
+  color: #888;
+}
+
--- a/themes/oxygen/elements.tpl	Tue Jun 26 17:28:18 2007 -0400
+++ b/themes/oxygen/elements.tpl	Tue Jun 26 20:48:44 2007 -0400
@@ -19,7 +19,7 @@
             <table border="0" width="100%" cellspacing="0" cellpadding="0" style="font-size: 1px;">
               <tr>
                 <td style="margin: 0; padding: 0; height: 12px;"> <img alt=" " src="{SCRIPTPATH}/themes/oxygen/images/{STYLE_ID}/border-menu-l.gif" width="12" height="12" /> </td>
-                <td style="margin: 0; padding: 0; height: 12px;" class="recttoptop"></td>
+                <td style="margin: 0; padding: 0; height: 12px;" class="recttoptop" onclick="var id = this.parentNode.parentNode.parentNode.parentNode.parentNode.id; var side = id.substr(0, id.indexOf('-')); collapseSidebar(side);"></td>
                 <td style="margin: 0; padding: 0; height: 12px;"> <img alt=" " src="{SCRIPTPATH}/themes/oxygen/images/{STYLE_ID}/border-menu-r.gif" width="12" height="12" /> </td>
               </tr>
             </table>
--- a/themes/oxygen/footer.tpl	Tue Jun 26 17:28:18 2007 -0400
+++ b/themes/oxygen/footer.tpl	Tue Jun 26 20:48:44 2007 -0400
@@ -43,23 +43,6 @@
      <p>If you can see this text, it means that your browser does not support Cascading Style Sheets (CSS). CSS is a fundemental aspect of XHTML, and as a result it is becoming very widely adopted by websites, including this one. You should consider switching to a more modern web browser, such as Mozilla Firefox or Opera 9.</p>
      <p>Because of this, there are a few minor issues that you may experience while browsing this site, not the least of which is some visual elements below that would normally be hidden in most browsers. Please excuse these minor inconveniences.</p>
     </div>
-    <div id="root1" class="jswindow" style="display: none;">
-      <div id="tb1" class="titlebar">Confirm Logout</div>
-      <div class="content" id="cn1">
-        <form action="{CONTENTPATH}Special:Logout" method="get">
-          <div style="text-align: center">
-            <h3>Are you sure you want to log out?</h3>
-            <input type="submit" value="Log out" style="font-weight: bold;" />  <input type="button" onclick="jws.closeWin('root1');" value="Cancel" />
-          </div>
-        </form>
-      </div>  
-    </div>
-    <div id="root2" class="jswindow" style="display: none;">
-      <div id="tb2" class="titlebar">Change style</div>
-      <div class="content" id="cn2">
-        
-      </div>
-    </div>
     <div id="root3" class="jswindow" style="display: none;">
       <div id="tb3" class="titlebar">Wiki formatting help</div>
       <div class="content" id="cn3">
--- a/themes/oxygen/header.tpl	Tue Jun 26 17:28:18 2007 -0400
+++ b/themes/oxygen/header.tpl	Tue Jun 26 20:48:44 2007 -0400
@@ -43,6 +43,14 @@
       }
       */
       
+      addOnloadHook(function() {
+          if(typeof readCookie == 'function')
+          {
+            if(readCookie('left_sidebar') =='collapsed') collapseSidebar('left');
+            if(readCookie('right_sidebar')=='collapsed') collapseSidebar('right');
+          }
+        });
+      
       function ajaxRenameInline()
       {
         // This trick is _so_ vBulletin...