diff -ruN 3.24.src/action.php 3.31.src/action.php
--- 3.24.src/action.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/action.php	2007-10-22 19:36:04.000000000 -0500
@@ -1,35 +1,35 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)  
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 
 /**
-  * File containing actions that can be performed by visitors of the site,
-  * like adding comments, etc...
+ * File containing actions that can be performed by visitors of the site,
+ * like adding comments, etc...
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: action.php,v 1.15.2.1 2005/08/15 10:51:08 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: action.php 1194 2007-09-05 05:49:25Z kimitake $
+ */
 
 $CONF = array();
-include('./config.php');			// common functions
+require('./config.php');
+
+// common functions
 include_once($DIR_LIBS . 'ACTION.php');
 
 $action = requestVar('action');
-
 $a =& new ACTION();
 $errorInfo = $a->doAction($action);
 
-if ($errorInfo)
-{
-	doError($errorInfo['message'], new SKIN($errorInfo['skinid']));	
+if ($errorInfo) {
+	doError($errorInfo['message'], new SKIN($errorInfo['skinid']) );
 }
 
 ?>
\ No newline at end of file
diff -ruN 3.24.src/atom.php 3.31.src/atom.php
--- 3.24.src/atom.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/atom.php	2007-10-22 19:36:04.000000000 -0500
@@ -1,24 +1,23 @@
 <?php
-
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 
 /**
-  * Nucleus Atom Syndication
+ * Nucleus Atom Syndication
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: atom.php,v 1.4.2.1 2005/08/15 10:51:08 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: atom.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 
-header("Pragma: no-cache");
+header('Pragma: no-cache');
 
 $CONF = array();
 $CONF['Self'] = 'atom.php';
@@ -30,23 +29,23 @@
 	ob_start();
 		selectSkin('feeds/atom');
 		selector();
-	$feed = ob_get_contents();
+		$feed = ob_get_contents();
 	ob_end_clean();
-	
+
 	// create ETAG (hash of feed)
 	// (HTTP_IF_NONE_MATCH has quotes around it)
-	$eTag = '"'.md5($feed).'"';
-	header('Etag: '.$eTag);
-	
+	$eTag = '"' . md5($feed) . '"';
+	header('Etag: ' . $eTag);
+
 	// compare Etag to what we got
-	if ($eTag == serverVar('HTTP_IF_NONE_MATCH')) {	
-		header("HTTP/1.0 304 Not Modified");
+	if ($eTag == serverVar('HTTP_IF_NONE_MATCH') ) {
+		header('HTTP/1.0 304 Not Modified');
 		header('Content-Length: 0');
 	} else {
 		// dump feed
 		echo $feed;
 	}
-		
+
 }
 
-?>
+?>
\ No newline at end of file
diff -ruN 3.24.src/benchmark.inc 3.31.src/benchmark.inc
--- 3.24.src/benchmark.inc	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/benchmark.inc	2007-10-22 19:36:04.000000000 -0500
@@ -0,0 +1,17 @@
+<?php
+
+if (!function_exists('getmtime'))
+{
+  function getmtime()
+  {
+    $a = explode (' ',microtime());
+    return(double) $a[0] + $a[1];
+  }
+}
+
+// For benchmarking
+global $StartTime, $SQLQCount;
+$StartTime = getmtime();
+$SQLCount = 0;
+
+?>
diff -ruN 3.24.src/config.php 3.31.src/config.php
--- 3.24.src/config.php	2006-07-27 13:48:45.000000000 -0500
+++ 3.31.src/config.php	2008-01-17 10:45:09.000000000 -0600
@@ -4,26 +4,26 @@
 // and basic functions that every page can use
 
 // mySQL connection information
-$MYSQL_HOST     = '[% mysql.ncls.sqlhost %]';
-$MYSQL_USER     = '[% mysql_user %]';
+$MYSQL_HOST = '[% mysql.ncls.sqlhost %]';
+$MYSQL_USER = '[% mysql_user %]';
 $MYSQL_PASSWORD = '[% mysql_pass %]';
 $MYSQL_DATABASE = '[% ncls %]';
-$MYSQL_PREFIX   = '[% table_prefix %]_';
+$MYSQL_PREFIX = '[% table_prefix %]_';
 
 // main nucleus directory
 $DIR_NUCLEUS = '[% installdir %]/nucleus/';
 
 // media dir
-$DIR_MEDIA   = '[% installdir %]/media/';
+$DIR_MEDIA = '[% installdir %]/media/';
 
 // extra skin files for imported skins
-$DIR_SKINS   = '[% installdir %]/skins/';
+$DIR_SKINS = '[% installdir %]/skins/';
 
 // these dirs are normally subdirs of the nucleus dir, but
 // you can redefine them if you wish
 $DIR_PLUGINS = $DIR_NUCLEUS . 'plugins/';
-$DIR_LANG    = $DIR_NUCLEUS . 'language/';
-$DIR_LIBS    = $DIR_NUCLEUS . 'libs/';
+$DIR_LANG = $DIR_NUCLEUS . 'language/';
+$DIR_LIBS = $DIR_NUCLEUS . 'libs/';
 
 if (!@file_exists($DIR_LIBS . 'globalfunctions.php')) {
 	echo "Configuration error, please run the install script or modify config.php";
diff -ruN 3.24.src/createaccount.html 3.31.src/createaccount.html
--- 3.24.src/createaccount.html	2003-02-05 19:24:12.000000000 -0600
+++ 3.31.src/createaccount.html	2007-10-22 19:36:04.000000000 -0500
@@ -1,39 +1,16 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html>
 <head>
+	<meta http-equiv="Refresh" content="5;url=createaccount.php">
 	<title>Create Member Account</title>
 	<style type="text/css">@import url(nucleus/styles/manual.css);</style>
 </head>
 <body>
 	<h1>Create Account</h1>
 
-	<form method="post" action="action.php">
-
-	<div>
-	<input type="hidden" name="action" value="createaccount" />
-		Login Name: 
-		<br />
-		<input name="name" size="20" /> <small>(only a-z, 0-9)</small>
-		<br />
-		<br />		
-		Real Name: 
-		<br />
-		<input name="realname" size="40" />
-		<br />
-		<br />		
-		Email:
-		<br />
-		<input name="email" size="40" /> <small>(must be valid, since password will be sent over there)</small>
-		<br />
-		<br />		
-		URL: 
-		<br />
-		<input name="url" size="60" />
-		<br />
-		<br />
-		<input type="submit" value="Create Account" />
-	</div>
-
-	</form>
+	<p>Sorry, the URL of the Create Account Form has changed.</p>
+	<p>If you are not redirected automatically please use this link: <a href="createaccount.php">Create Member Account</a>.</p>
+	<p>Thank you. :-)</p>
+	
 </body>
-</html>
\ No newline at end of file
+</html>
diff -ruN 3.24.src/createaccount.php 3.31.src/createaccount.php
--- 3.24.src/createaccount.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/createaccount.php	2007-10-22 19:36:04.000000000 -0500
@@ -0,0 +1,128 @@
+<?php
+	include "./config.php";
+	include $DIR_LIBS."ACTION.php";
+	
+	if (isset ($_POST['showform'])&&$_POST['showform']==1) {
+		$showform = 1;
+	}
+	else {
+		$showform = 0;
+	}
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+	<title>Create Member Account</title>
+	<style type="text/css">@import url(nucleus/styles/manual.css);</style>
+</head>
+<body>
+
+	<h1>Create Account</h1>
+
+<?php
+	// show form only if Visitors are allowed to create a Member Account
+	if ($CONF['AllowMemberCreate']==1) { 
+		// if the form is shown the first time no POST data 
+		// will be added as value for the input fields
+		if ($showform==0) {
+?>
+
+	<form method="post" action="createaccount.php">
+
+	<div>
+	<input type="hidden" name="showform" value="1" />
+	<input type="hidden" name="action" value="createaccount" />
+	
+		Login Name (required): 
+		<br />
+		<input name="name" size="20" /> <small>(only a-z, 0-9)</small>
+		<br />
+		<br />		
+		Real Name (required): 
+		<br />
+		<input name="realname" size="40" />
+		<br />
+		<br />		
+		Email (required):
+		<br />
+		<input name="email" size="40" /> <small>(must be valid, because an activation link will be sent over there)</small>
+		<br />
+		<br />		
+		URL: 
+		<br />
+		<input name="url" size="60" />
+		<br />
+		<?php
+		// add a Captcha challenge or something else
+		global $manager;
+		$manager->notify('FormExtra', array('type' => 'membermailform-notloggedin'));
+		?>
+		<br />
+		<br />						
+		<input type="submit" value="Create Account" />
+	</div>
+
+	</form>
+<?php
+		} // close if showfrom ...
+		else {
+		// after the from is sent it will be validated
+		// POST data will be added as value to treat the user with care (;-))
+	
+		$a = new ACTION();
+
+		// if createAccount fails it returns an error message 
+		$message = $a->createAccount();
+
+		echo '<span style="font-weight:bold; color:red;">'.$message.'</span><br /><br />'; 
+?>
+	
+		<form method="post" action="createaccount.php">
+
+	<div>
+	<input type="hidden" name="showform" value="1" />
+	<input type="hidden" name="action" value="createaccount" />
+	
+		Login Name (required): 
+		<br />
+		<input name="name" size="20" <?php if(isset($_POST['name'])){echo 'value="'.$_POST['name'].'"';}?>/> <small>(only a-z, 0-9)</small>
+		<br />
+		<br />		
+		Real Name (required): 
+		<br />
+		<input name="realname" size="40" <?php if(isset($_POST['realname'])){echo 'value="'.$_POST['realname'].'"';}?>/>
+		<br />
+		<br />		
+		Email (required):
+		<br />
+		<input name="email" size="40" <?php if(isset($_POST['email'])){echo 'value="'.$_POST['email'].'"';}?>/> <small>(must be valid, because an activation link will be sent over there)</small>
+		<br />
+		<br />		
+		URL: 
+		<br />
+		<input name="url" size="60" <?php if(isset($_POST['url'])){echo 'value="'.$_POST['url'].'"';}?>/>
+		<br />
+		<?php
+		// add a Captcha challenge or something else
+		global $manager;
+		$manager->notify('FormExtra', array('type' => 'membermailform-notloggedin'));
+		?>
+		<br />
+		<br />
+		<input type="submit" value="Create Account" />
+	</div>
+
+	</form>
+<?php
+		}	// close else showform ...
+
+}
+else { 
+	echo 'Visitors are not allowed to create a Member Account.<br /><br />';
+	echo 'Please contact the website administrator for more information.';
+}
+?>
+	
+	
+</body>
+</html>
\ No newline at end of file
diff -ruN 3.24.src/extra/fancyurls/fancyurls.config.php 3.31.src/extra/fancyurls/fancyurls.config.php
--- 3.24.src/extra/fancyurls/fancyurls.config.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/extra/fancyurls/fancyurls.config.php	2007-10-22 19:35:52.000000000 -0500
@@ -50,10 +50,11 @@
     	If you want to change these, you'll also need to rename the stub files 
     	and update the contents of the .htaccess file accordingly
     */
-    $CONF['ItemKey'] = 'item';
-    $CONF['ArchiveKey'] = 'archive';
-    $CONF['ArchivesKey'] = 'archives';
-    $CONF['MemberKey'] = 'member';
-    $CONF['BlogKey'] = 'blog';
-    $CONF['CategoryKey'] = 'category';	
+    $CONF['ItemKey']        = 'item';
+    $CONF['ArchiveKey']     = 'archive';
+    $CONF['ArchivesKey']    = 'archives';
+    $CONF['MemberKey']      = 'member';
+    $CONF['BlogKey']        = 'blog';
+    $CONF['CategoryKey']    = 'category';
+    $CONF['SpecialskinKey'] = 'special';
 ?>
\ No newline at end of file
diff -ruN 3.24.src/extra/fancyurls/.htaccess 3.31.src/extra/fancyurls/.htaccess
--- 3.24.src/extra/fancyurls/.htaccess	2002-11-27 18:30:26.000000000 -0600
+++ 3.31.src/extra/fancyurls/.htaccess	2007-10-22 19:35:52.000000000 -0500
@@ -15,4 +15,7 @@
 </FilesMatch>
 <FilesMatch "^blog$">
     ForceType application/x-httpd-php
-</FilesMatch>
\ No newline at end of file
+</FilesMatch>
+<FilesMatch "^special$">
+    ForceType application/x-httpd-php
+</FilesMatch>
diff -ruN 3.24.src/extra/fancyurls/special 3.31.src/extra/fancyurls/special
--- 3.24.src/extra/fancyurls/special	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/extra/fancyurls/special	2007-10-22 19:35:52.000000000 -0500
@@ -0,0 +1,17 @@
+<?php
+
+include('./fancyurls.config.php');
+include('./config.php');
+
+if (!requestVar('special'))
+{
+       $data = explode("/",serverVar('PATH_INFO'));
+       if (count($data) > 1)
+       {
+               $_REQUEST['special'] = $data[1];
+       }
+}
+
+selector();
+
+?>
\ No newline at end of file
diff -ruN 3.24.src/extra/fancyurls-2/.htaccess 3.31.src/extra/fancyurls-2/.htaccess
--- 3.24.src/extra/fancyurls-2/.htaccess	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/extra/fancyurls-2/.htaccess	2007-10-22 19:35:52.000000000 -0500
@@ -0,0 +1,6 @@
+<IfModule mod_rewrite.c>
+	RewriteEngine on
+	RewriteCond %{REQUEST_FILENAME} !-f
+	RewriteCond %{REQUEST_FILENAME} !-d
+	RewriteRule ^(.*)$ index.php?virtualpath=$1 [L,QSA]
+</IfModule>
diff -ruN 3.24.src/index.php 3.31.src/index.php
--- 3.24.src/index.php	2003-07-22 20:04:40.000000000 -0500
+++ 3.31.src/index.php	2007-10-22 19:36:04.000000000 -0500
@@ -1,4 +1,7 @@
 <?php
+//setup for benchmarking
+include('./benchmark.inc');
+
 // This file will generate and return the main page of the site
 $CONF = array();
 $CONF['Self'] = 'index.php';
diff -ruN 3.24.src/install.php 3.31.src/install.php
--- 3.24.src/install.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/install.php	2007-10-22 19:36:04.000000000 -0500
@@ -0,0 +1,1075 @@
+<?php
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ * This script will install the Nucleus tables in your SQL-database, and initialize the data in
+ * those tables.
+ *
+ * Below is a friendly way of letting users on non-php systems know that Nucleus won't run there.
+ * ?><div style="font-size: xx-large;">If you see this text in your browser when you open <i>install.php</i>, your web server is not able to run PHP-scripts, and therefor Nucleus will not be able to run there. </div><div style="display: none"><?php
+ */
+
+/**
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: install.php 1184 2007-07-15 22:43:46Z kaigreve $
+ */
+
+/*
+	This part of the install.php code allows for customization of the install process.
+	When distributing plugins or skins together with a Nucleus installation, the
+	configuration below will instruct to install them
+
+	-- Start Of Configurable Part --
+*/
+
+// array with names of plugins to install. Plugin files must be present in the nucleus/plugin/
+// directory.
+//
+// example:
+//     array('NP_TrackBack', 'NP_MemberGoodies')
+$aConfPlugsToInstall = array('NP_SkinFiles');
+
+
+// array with skins to install. skins must be present under the skins/ directory with
+// a subdirectory having the same name that contains a skinbackup.xml file
+//
+// example:
+//     array('base','rsd')
+$aConfSkinsToImport = array('default');
+
+/*
+	-- End Of Configurable Part --
+*/
+
+// don't give warnings for uninitialized vars
+error_reporting(E_ERROR | E_WARNING | E_PARSE);
+
+// make sure there's no unnecessary escaping:
+set_magic_quotes_runtime(0);
+
+// if there are some plugins or skins to import, do not include vars
+// in globalfunctions.php again... so set a flag
+if ((count($aConfPlugsToInstall) > 0) || (count($aConfSkinsToImport) > 0) ) {
+	global $CONF;
+	$CONF['installscript'] = 1;
+}
+
+if (phpversion() >= '4.1.0') {
+	include_once('nucleus/libs/vars4.1.0.php');
+} else {
+	include_once('nucleus/libs/vars4.0.6.php');
+}
+
+include_once('nucleus/libs/mysql.php');
+
+// check if mysql support is installed
+	if (!function_exists('mysql_query') ) {
+		_doError('Your PHP version does not have support for MySQL :(');
+	}
+
+	if (postVar('action') == 'go') {
+		doInstall();
+	} else {
+		showInstallForm();
+	}
+
+	exit;
+
+function showInstallForm() {
+	// 0. pre check if all necessary files exist
+	doCheckFiles();
+
+	?>
+	<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+	<html xmlns="http://www.w3.org/1999/xhtml">
+	<head>
+		<title>Nucleus Install</title>
+		<style type="text/css"><!--
+			@import url('nucleus/documentation/styles/manual.css');
+		--></style>
+		<script type="text/javascript"><!--
+			var submitcount = 0;
+
+			// function to make sure the submit button only gets pressed once
+			function checkSubmit() {
+				if (submitcount == 0) {
+					submitcount++;
+					return true;
+				} else {
+					return false;
+				}
+			}
+		--></script>
+	</head>
+	<body>
+		<div style="text-align:center"><img src="./nucleus/styles/logo.gif" /></div> <!-- Nucleus logo -->
+		<form method="post" action="install.php">
+
+		<h1>Install Nucleus</h1>
+
+		<p>This script will help you to install Nucleus. It will set up your MySQL database tables and provide you with the information you need to enter in <i>config.php</i>. In order to do all this, you need to enter some information.</p>
+
+		<p>All fields are mandatory. Optional information can be set from the Nucleus admin-area when installation is completed.</p>
+
+		<h1>PHP &amp; MySQL Versions</h1>
+
+		<p>Below are the version numbers of the PHP interpreter and the MySQL server on your webhost. When reporting problems on the Nucleus Support Forum, please include this information.</p>
+
+		<ul>
+			<li>PHP:
+
+<?php
+	echo phpversion();
+	$minVersion = '4.0.6';
+
+	if (phpversion() < $minVersion) {
+		echo ' <span class="warning">WARNING: Nucleus requires at least version ', $minVersion, '</span>';
+	}
+?>
+
+			</li>
+			<li>MySQL:
+
+<?php
+	// note: this piece of code is taken from phpMyAdmin
+	$result = @mysql_query('SELECT VERSION() AS version');
+
+	if ($result != FALSE && @mysql_num_rows($result) > 0) {
+		$row = mysql_fetch_array($result);
+		$match = explode('.', $row['version']);
+	} else {
+		$result = @mysql_query('SHOW VARIABLES LIKE \'version\'');
+
+		if ($result != FALSE && @mysql_num_rows($result) > 0) {
+			$row = mysql_fetch_row($result);
+			$match = explode('.', $row[1]);
+		} else {
+			$match[0] = '?';
+			$match[1] = '?';
+			$match[2] = '?';
+		}
+	}
+
+	if (!isset($match) || !isset($match[0]) ) {
+		$match[0] = 3;
+	}
+
+	if (!isset($match[1]) ) {
+		$match[1] = 21;
+	}
+
+	if (!isset($match[2]) ) {
+		$match[2] = 0;
+	}
+
+	if ($match[0] != '?') {
+		$match[0] = intval($match[0]);
+		$match[1] = intval($match[1]);
+	}
+
+	$mysqlVersion = implode($match, '.');
+	$minVersion = '3.23';
+
+	echo $mysqlVersion;
+
+	if ($mysqlVersion < $minVersion) {
+		echo ' <span class="warning">WARNING: Nucleus requires at least version ', $minVersion, '</span>';
+	}
+?>
+
+			</li>
+		</ul>
+
+<?php
+	// tell people how they can have their config file filled out automatically
+	if (@file_exists('config.php') && @!is_writable('config.php') ) {
+?>
+
+		<h1>Automatic <i>config.php</i> Update</h1>
+
+		<p>If you want Nucleus to automatically update the <em>config.php</em> file, you'll need to make it writable. You can do this by changing the file permissions to <strong>666</strong>. After Nucleus is successfully installed, you can change the permissions back to <strong>444</strong> (<a href="nucleus/documentation/tips.html#filepermissions">Quick guide on how to change file permissions</a>).</p>
+
+		<p>If you choose not to make your file writable (or are unable to do so): don't worry. The installation process will provide you with the contents of the <em>config.php</em> file so you can upload it yourself.</p>
+
+<?php } ?>
+
+		<h1>MySQL login data</h1>
+
+		<p>Enter your MySQL data below. This install script needs it to be able to create and fill your database tables. Afterwards, you'll also need to fill it out in <i>config.php</i>.</p>
+
+		<p>If you don't know this information, contact your system administrator for more info. Often, the hostname will be 'localhost'. If Nucleus found a 'default MySQL host' in the PHP settings of your server, this host is already listed in the 'hostname' field. There's no guarantee that this information is correct, though.</p>
+
+		<fieldset>
+			<legend>General Database Settings</legend>
+			<table>
+				<tr>
+					<td>Hostname:</td>
+					<td><input name="mySQL_host" value="<?php echo htmlspecialchars(@ini_get('mysql.default_host') )?>" /></td>
+				</tr>
+				<tr>
+					<td>Username:</td>
+					<td><input name="mySQL_user" /></td>
+				</tr>
+				<tr>
+					<td>Password:</td>
+					<td><input name="mySQL_password" type="password" /></td>
+				</tr>
+				<tr>
+					<td>Database:</td>
+					<td><input name="mySQL_database" /> (<input name="mySQL_create" value="1" type="checkbox" id="mySQL_create"><label for="mySQL_create" />needs to be created</label>)</td>
+				</tr>
+			</table>
+		</fieldset>
+
+		<fieldset>
+			<legend>Advanced Database Settings</legend>
+			<table>
+				<tr>
+					<td><input name="mySQL_usePrefix" value="1" type="checkbox" id="mySQL_usePrefix"><label for="mySQL_usePrefix" />Use table prefix:</label></td>
+					<td><input name="mySQL_tablePrefix" value="" /></td>
+				</tr>
+			</table>
+
+			<p>Unless you're installing multiple Nucleus installations in one single database and know what you're doing, <strong>you really shouldn't change this</strong>.</p>
+			<p>All database tables generated by Nucleus will start with this prefix.</p>
+		</fieldset>
+
+		<h1>Directories and URLs</h1>
+
+		<p>This install script has attempted to find out the directories and URLs in which Nucleus is installed. Please check the values below and correct if necessary. The URLs and file paths should end with a slash.</p>
+
+<?php
+
+	// no need to this all! dirname(__FILE__) is all we need -- moraes
+	/*
+	// discover full path
+	$fullPath = serverVar('PATH_TRANSLATED');
+
+	if ($fullPath == '') {
+		$fullPath = serverVar('SCRIPT_FILENAME');
+	}
+
+	$basePath = str_replace('install.php', '', $fullPath);
+	$basePath = replaceDoubleBackslash($basePath);
+	$basePath = replaceDoubleBackslash($basePath);
+
+	// add slash at end if necessary
+	if (!endsWithSlash($basePath) ) {
+		$basePath .= '/';
+	}
+	*/
+
+	$basePath = dirname(__FILE__) . '/';
+?>
+
+		<fieldset>
+			<legend>URLs and directories</legend>
+			<table>
+				<tr>
+					<td>Site <strong>URL</strong>:</td>
+					<td><input name="IndexURL" size="60" value="<?php
+						$url = 'http://' . serverVar('HTTP_HOST') . serverVar('PHP_SELF');
+						$url = str_replace('install.php', '', $url);
+						$url = replaceDoubleBackslash($url);
+
+						// add slash at end if necessary
+						if (!endsWithSlash($url) ) {
+							$url .= '/';
+						}
+
+						echo $url; ?>" /></td>
+				</tr>
+				<tr>
+					<td>Admin-area <strong>URL</strong>:</td>
+					<td><input name="AdminURL" size="60" value="<?php
+						if ($url) {
+							echo $url, 'nucleus/';
+						} ?>" /></td>
+				</tr>
+				<tr>
+					<td>Admin-area <strong>path</strong>:</td>
+					<td><input name="AdminPath" size="60" value="<?php
+						if($basePath) {
+							echo $basePath, 'nucleus/';
+						} ?>" /></td>
+				</tr>
+				<tr>
+					<td>Media files <strong>URL</strong>:</td>
+					<td><input name="MediaURL" size="60" value="<?php
+						if ($url) {
+							echo $url, 'media/';
+						} ?>" /></td>
+				</tr>
+				<tr>
+					<td>Media directory <strong>path</strong>:</td>
+					<td><input name="MediaPath" size="60" value="<?php
+						if ($basePath) {
+							echo $basePath, 'media/';
+						} ?>" /></td>
+				</tr>
+				<tr>
+					<td>Extra skin files <strong>URL</strong>:</td>
+					<td><input name="SkinsURL" size="60" value="<?php
+						if ($url) {
+							echo $url, 'skins/';
+						} ?>" />
+						<br />(used by imported skins)
+					</td>
+				</tr>
+				<tr>
+					<td>Extra skin files directory <strong>path</strong>:</td>
+					<td><input name="SkinsPath" size="60" value="<?php
+						if ($basePath) {
+							echo $basePath, 'skins/';
+						} ?>" />
+						<br />(this is where imported skins can place their extra files)
+					</td>
+				</tr>
+				<tr>
+					<td>Plugin files <strong>URL</strong>:</td>
+					<td><input name="PluginURL" size="60" value="<?php
+						if ($url) {
+							echo $url, 'nucleus/plugins/';
+						} ?>" /></td>
+				</tr>
+				<tr>
+					<td>Action <strong>URL</strong>:</td>
+					<td><input name="ActionURL" size="60" value="<?php
+						if ($url) {
+							echo $url, 'action.php';
+						} ?>" />
+						<br />(absolute location of the <tt>action.php</tt> file)
+					</td>
+				</tr>
+			</table>
+		</fieldset>
+
+		<p class="note"><strong>Note: Use absolute paths</strong> instead of relative paths. Usually, an absolute path will start with something like <tt>/home/username/public_html/</tt>. On Unix systems (most servers), paths should start with a slash. If you have trouble filling out this information, you should ask your administrator what to fill out.</p>
+
+		<h1>Administrator User</h1>
+
+		<p>Below, you need to enter some information to create the first user of your site.</p>
+
+		<fieldset>
+			<legend>Administrator User</legend>
+			<table>
+				<tr>
+					<td>Display Name:</td>
+					<td><input name="User_name" value="" /> <small>(allowed characters: a-z and 0-9, spaces allowed inside)</small></td>
+				</tr>
+				<tr>
+					<td>Real Name:</td>
+					<td><input name="User_realname" value="" /></td>
+				</tr>
+				<tr>
+					<td>Password:</td>
+					<td><input name="User_password" type="password" value="" /></td>
+				</tr>
+				<tr>
+					<td>Password Again:</td>
+					<td><input name="User_password2" type="password" value="" /></td>
+				</tr>
+				<tr>
+					<td>E-mail Address:</td>
+					<td><input name="User_email" value="" /> <small>(needs to be a valid e-mail address)</small></td>
+				</tr>
+			</table>
+		</fieldset>
+
+		<h1>Weblog data</h1>
+
+		<p>Below, you need to enter some information to create a default weblog. The name of this weblog will also be used as name for your site</p>
+
+		<fieldset>
+			<legend>Weblog Data</legend>
+			<table>
+				<tr>
+					<td>Blog Name:</td>
+					<td><input name="Blog_name" size="60" value="My Nucleus CMS" /></td>
+				</tr>
+				<tr>
+					<td>Blog Short Name:</td>
+					<td><input name="Blog_shortname" value="mynucleuscms" /> <small>(allowed characters: a-z and 0-9, no spaces allowed)</small></td>
+				</tr>
+			</table>
+		</fieldset>
+
+		<h1>Submit</h1>
+
+		<p>Verify the data above, and click the button below to set up your database tables and initial data. This can take a while, so have patience. <strong>ONLY CLICK THE BUTTON ONCE !</strong></p>
+
+		<p><input name="action" value="go" type="hidden" /> <input type="submit" value="Install Nucleus" onclick="return checkSubmit();" /></p>
+
+		</form>
+	</body>
+</html>
+
+<?php }
+
+function tableName($unPrefixed) {
+	global $mysql_usePrefix, $mysql_prefix;
+
+	if ($mysql_usePrefix == 1) {
+		return $mysql_prefix . $unPrefixed;
+	} else {
+		return $unPrefixed;
+	}
+}
+
+function doInstall() {
+	global $mysql_usePrefix, $mysql_prefix;
+
+	// 0. put all POST-vars into vars
+	$mysql_host = postVar('mySQL_host');
+	$mysql_user = postVar('mySQL_user');
+	$mysql_password = postVar('mySQL_password');
+	$mysql_database = postVar('mySQL_database');
+	$mysql_create = postVar('mySQL_create');
+	$mysql_usePrefix = postVar('mySQL_usePrefix');
+	$mysql_prefix = postVar('mySQL_tablePrefix');
+	$config_indexurl = postVar('IndexURL');
+	$config_adminurl = postVar('AdminURL');
+	$config_adminpath = postVar('AdminPath');
+	$config_mediaurl = postVar('MediaURL');
+	$config_skinsurl = postVar('SkinsURL');
+	$config_pluginurl = postVar('PluginURL');
+	$config_actionurl = postVar('ActionURL');
+	$config_mediapath = postVar('MediaPath');
+	$config_skinspath = postVar('SkinsPath');
+	$user_name = postVar('User_name');
+	$user_realname = postVar('User_realname');
+	$user_password = postVar('User_password');
+	$user_password2 = postVar('User_password2');
+	$user_email = postVar('User_email');
+	$blog_name = postVar('Blog_name');
+	$blog_shortname = postVar('Blog_shortname');
+	$config_adminemail = $user_email;
+	$config_sitename = $blog_name;
+
+	$config_indexurl = replaceDoubleBackslash($config_indexurl);
+	$config_adminurl = replaceDoubleBackslash($config_adminurl);
+	$config_mediaurl = replaceDoubleBackslash($config_mediaurl);
+	$config_skinsurl = replaceDoubleBackslash($config_skinsurl);
+	$config_pluginurl = replaceDoubleBackslash($config_pluginurl);
+	$config_actionurl = replaceDoubleBackslash($config_actionurl);
+	$config_adminpath = replaceDoubleBackslash($config_adminpath);
+	$config_skinspath = replaceDoubleBackslash($config_skinspath);
+
+	// 1. check all the data
+	$errors = array();
+
+	if (!$mysql_database) {
+		array_push($errors, 'mySQL database name missing');
+	}
+
+	if (($mysql_usePrefix == 1) && (strlen($mysql_prefix) == 0) ) {
+		array_push($errors, 'mySQL prefix was selected, but prefix is empty');
+	}
+
+	if (($mysql_usePrefix == 1) && (!eregi('^[a-zA-Z0-9_]+$', $mysql_prefix) ) ) {
+		array_push($errors, 'mySQL prefix should only contain characters from the ranges A-Z, a-z, 0-9 or underscores');
+	}
+
+	// TODO: add action.php check
+	if (!endsWithSlash($config_indexurl) || !endsWithSlash($config_adminurl) || !endsWithSlash($config_mediaurl) || !endsWithSlash($config_pluginurl) || !endsWithSlash($config_skinsurl) ) {
+		array_push($errors, 'One of the URLs does not end with a slash, or action url does not end with \'action.php\'');
+	}
+
+	if (!endsWithSlash($config_adminpath) ) {
+		array_push($errors, 'The path of the administration area does not end with a slash');
+	}
+
+	if (!endsWithSlash($config_mediapath) ) {
+		array_push($errors, 'The media path does not end with a slash');
+	}
+
+	if (!endsWithSlash($config_skinspath) ) {
+		array_push($errors, 'The skins path does not end with a slash');
+	}
+
+	if (!is_dir($config_adminpath) ) {
+		array_push($errors, 'The path of the administration area does not exist on your server');
+	}
+
+	if (!_isValidMailAddress($user_email) ) {
+		array_push($errors, 'Invalid e-mail address given for user');
+	}
+
+	if (!_isValidDisplayName($user_name) ) {
+		array_push($errors, 'User name is not a valid display name (allowed chars: a-zA-Z0-9 and spaces)');
+	}
+
+	if (!$user_password || !$user_password2) {
+		array_push($errors, 'User password is empty');
+	}
+
+	if ($user_password != $user_password2) {
+		array_push($errors, 'User password do not match');
+	}
+
+	if (!_isValidShortName($blog_shortname) ) {
+		array_push($errors, 'Invalid short name given for blog (allowed chars: a-z0-9, no spaces)');
+	}
+
+	if (sizeof($errors) > 0) {
+		showErrorMessages($errors);
+	}
+
+	// 2. try to log in to mySQL
+	global $MYSQL_CONN;
+	$MYSQL_CONN = @mysql_connect($mysql_host, $mysql_user, $mysql_password);
+
+	if ($MYSQL_CONN == false) {
+		_doError('Could not connect to mySQL server: ' . mysql_error() );
+	}
+
+	// 3. try to create database (if needed)
+	if ($mysql_create == 1) {
+		mysql_query('CREATE DATABASE ' . $mysql_database) or _doError('Could not create database. Make sure you have the rights to do so. SQL error was: ' . mysql_error() );
+	}
+
+	// 4. try to select database
+	mysql_select_db($mysql_database) or _doError('Could not select database. Make sure it exists');
+
+	// 5. execute queries
+	$filename = 'install.sql';
+	$fd = fopen($filename, 'r');
+	$queries = fread($fd, filesize($filename) );
+	fclose($fd);
+
+	$queries = split("(;\n|;\r)", $queries);
+
+	$aTableNames = array(
+		'nucleus_actionlog',
+		'nucleus_ban',
+		'nucleus_blog',
+		'nucleus_category',
+		'nucleus_comment',
+		'nucleus_config',
+		'nucleus_item',
+		'nucleus_karma',
+		'nucleus_member',
+		'nucleus_plugin',
+		'nucleus_skin',
+		'nucleus_template',
+		'nucleus_team',
+		'nucleus_activation',
+		'nucleus_tickets'
+		);
+// these are unneeded (one of the replacements above takes care of them)
+//			'nucleus_plugin_event',
+//			'nucleus_plugin_option',
+//			'nucleus_plugin_option_desc',
+//			'nucleus_skin_desc',
+//			'nucleus_template_desc',
+
+	$aTableNamesPrefixed = array(
+		$mysql_prefix . 'nucleus_actionlog',
+		$mysql_prefix . 'nucleus_ban',
+		$mysql_prefix . 'nucleus_blog',
+		$mysql_prefix . 'nucleus_category',
+		$mysql_prefix . 'nucleus_comment',
+		$mysql_prefix . 'nucleus_config',
+		$mysql_prefix . 'nucleus_item',
+		$mysql_prefix . 'nucleus_karma',
+		$mysql_prefix . 'nucleus_member',
+		$mysql_prefix . 'nucleus_plugin',
+		$mysql_prefix . 'nucleus_skin',
+		$mysql_prefix . 'nucleus_template',
+		$mysql_prefix . 'nucleus_team',
+		$mysql_prefix . 'nucleus_activation',
+		$mysql_prefix . 'nucleus_tickets'
+		);
+// these are unneeded (one of the replacements above takes care of them)
+//			$mysql_prefix . 'nucleus_plugin_event',
+//			$mysql_prefix . 'nucleus_plugin_option',
+//			$mysql_prefix . 'nucleus_plugin_option_desc',
+//			$mysql_prefix . 'nucleus_skin_desc',
+//			$mysql_prefix . 'nucleus_template_desc',
+
+	$count = count($queries);
+
+	for ($idx = 0; $idx < $count; $idx++) {
+		$query = trim($queries[$idx]);
+		// echo "QUERY = <small>" . htmlspecialchars($query) . "</small><p>";
+
+		if ($query) {
+
+			if ($mysql_usePrefix == 1) {
+					$query = str_replace($aTableNames, $aTableNamesPrefixed, $query);
+			}
+
+			mysql_query($query) or _doError('Error while executing query (<small>' . htmlspecialchars($query) . '</small>): ' . mysql_error() );
+		}
+	}
+
+	// 6. update global settings
+	updateConfig('IndexURL', $config_indexurl);
+	updateConfig('AdminURL', $config_adminurl);
+	updateConfig('MediaURL', $config_mediaurl);
+	updateConfig('SkinsURL', $config_skinsurl);
+	updateConfig('PluginURL', $config_pluginurl);
+	updateConfig('ActionURL', $config_actionurl);
+	updateConfig('AdminEmail', $config_adminemail);
+	updateConfig('SiteName', $config_sitename);
+
+	// 7. update GOD member
+	$query = 'UPDATE ' . tableName('nucleus_member')
+			. " SET mname='" . addslashes($user_name) . "',"
+			. " mrealname='" . addslashes($user_realname) . "',"
+			. " mpassword='" . md5(addslashes($user_password) ) . "',"
+			. " murl='" . addslashes($config_indexurl) . "',"
+			. " memail='" . addslashes($user_email) . "',"
+			. " madmin=1, mcanlogin=1"
+			. " WHERE mnumber=1";
+
+	mysql_query($query) or _doError('Error while setting member settings: ' . mysql_error() );
+
+	// 8. update weblog settings
+	$query = 'UPDATE ' . tableName('nucleus_blog')
+			. " SET bname='" . addslashes($blog_name) . "',"
+			. " bshortname='" . addslashes($blog_shortname) . "',"
+			. " burl='" . addslashes($config_indexurl) . "'"
+			. " WHERE bnumber=1";
+
+	mysql_query($query) or _doError('Error while setting weblog settings: ' . mysql_error() );
+
+	// 9. update item date
+	$query = 'UPDATE ' . tableName('nucleus_item')
+			. " SET itime='" . date('Y-m-d H:i:s', time() ) ."'"
+			. " WHERE inumber=1";
+
+	mysql_query($query) or _doError('Error with query: ' . mysql_error() );
+
+	global $aConfPlugsToInstall, $aConfSkinsToImport;
+	$aSkinErrors = array();
+	$aPlugErrors = array();
+
+	if ((count($aConfPlugsToInstall) > 0) || (count($aConfSkinsToImport) > 0) ) {
+		// 10. set global variables
+		global $MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD, $MYSQL_DATABASE, $MYSQL_PREFIX;
+
+		$MYSQL_HOST = $mysql_host;
+		$MYSQL_USER = $mysql_user;
+		$MYSQL_PASSWORD = $mysql_password;
+		$MYSQL_DATABASE = $mysql_database;
+		$MYSQL_PREFIX = ($mysql_usePrefix == 1)?$mysql_prefix:'';
+
+		global $DIR_NUCLEUS, $DIR_MEDIA, $DIR_SKINS, $DIR_PLUGINS, $DIR_LANG, $DIR_LIBS;
+
+		$DIR_NUCLEUS = $config_adminpath;
+		$DIR_MEDIA = $config_mediapath;
+		$DIR_SKINS = $config_skinspath;
+		$DIR_PLUGINS = $DIR_NUCLEUS . 'plugins/';
+		$DIR_LANG = $DIR_NUCLEUS . 'language/';
+		$DIR_LIBS = $DIR_NUCLEUS . 'libs/';
+
+		// close database connection (needs to be closed if we want to include globalfunctions.php)
+		mysql_close();
+
+		$manager = '';
+		include_once($DIR_LIBS . 'globalfunctions.php');
+
+		// 11. install custom skins
+		$aSkinErrors = installCustomSkins($manager);
+
+		// 12. install custom plugins
+		$aPlugErrors = installCustomPlugs($manager);
+	}
+
+	// 12. Write config file ourselves (if possible)
+	$bConfigWritten = 0;
+
+	if (@file_exists('config.php') && is_writable('config.php') && $fp = @fopen('config.php', 'w') ) {
+		$config_data = '<' . '?php' . "\n\n";
+		//$config_data .= "\n"; (extraneous, just added extra \n to previous line
+		$config_data .= "	// mySQL connection information\n";
+		$config_data .= "	\$MYSQL_HOST = '" . $mysql_host . "';\n";
+		$config_data .= "	\$MYSQL_USER = '" . $mysql_user . "';\n";
+		$config_data .= "	\$MYSQL_PASSWORD = '" . $mysql_password . "';\n";
+		$config_data .= "	\$MYSQL_DATABASE = '" . $mysql_database . "';\n";
+		$config_data .= "	\$MYSQL_PREFIX = '" . (($mysql_usePrefix == 1)?$mysql_prefix:'') . "';\n";
+		$config_data .= "\n";
+		$config_data .= "	// main nucleus directory\n";
+		$config_data .= "	\$DIR_NUCLEUS = '" . $config_adminpath . "';\n";
+		$config_data .= "\n";
+		$config_data .= "	// path to media dir\n";
+		$config_data .= "	\$DIR_MEDIA = '" . $config_mediapath . "';\n";
+		$config_data .= "\n";
+		$config_data .= "	// extra skin files for imported skins\n";
+		$config_data .= "	\$DIR_SKINS = '" . $config_skinspath . "';\n";
+		$config_data .= "\n";
+		$config_data .= "	// these dirs are normally sub dirs of the nucleus dir, but \n";
+		$config_data .= "	// you can redefine them if you wish\n";
+		$config_data .= "	\$DIR_PLUGINS = \$DIR_NUCLEUS . 'plugins/';\n";
+		$config_data .= "	\$DIR_LANG = \$DIR_NUCLEUS . 'language/';\n";
+		$config_data .= "	\$DIR_LIBS = \$DIR_NUCLEUS . 'libs/';\n";
+		$config_data .= "\n";
+		$config_data .= "	// include libs\n";
+		$config_data .= "	include(\$DIR_LIBS.'globalfunctions.php');\n";
+		$config_data .= "?" . ">";
+
+		$result = @fputs($fp, $config_data, strlen($config_data) );
+		fclose($fp);
+
+		if ($result) {
+			$bConfigWritten = 1;
+		}
+	}
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Nucleus Install</title>
+	<style>@import url('nucleus/styles/manual.css');</style>
+</head>
+<body>
+	<div style='text-align:center'><img src='./nucleus/styles/logo.gif' /></div> <!-- Nucleus logo -->
+
+<?php
+	$aAllErrors = array_merge($aSkinErrors, $aPlugErrors);
+
+	if (count($aAllErrors) > 0) {
+		echo '<h1>Skin/Plugin Install errors</h1>';
+		echo '<ul><li>' . implode('</li><li>', $aAllErrors) . '</li></ul>';
+	}
+
+	if (!$bConfigWritten) { ?>
+		<h1>Installation Almost Complete!</h1>
+
+		<p>The database tables have been initialized successfully. What still needs to be done is to change the contents of <i>config.php</i>. Below is how it should look like (the mysql password is masked, so you'll have to fill that out yourself)</p>
+
+		<pre><code>&lt;?php
+	// mySQL connection information
+	$MYSQL_HOST = '<b><?php echo $mysql_host?></b>';
+	$MYSQL_USER = '<b><?php echo $mysql_user?></b>';
+	$MYSQL_PASSWORD = '<i><b>xxxxxxxxxxx</b></i>';
+	$MYSQL_DATABASE = '<b><?php echo $mysql_database?></b>';
+	$MYSQL_PREFIX = '<b><?php echo ($mysql_usePrefix == 1)?$mysql_prefix:''?></b>';
+
+	// main nucleus directory
+	$DIR_NUCLEUS = '<b><?php echo $config_adminpath?></b>';
+
+	// path to media dir
+	$DIR_MEDIA = '<b><?php echo $config_mediapath?></b>';
+
+	// extra skin files for imported skins
+	$DIR_SKINS = '<b><?php echo $config_skinspath?></b>';
+
+	// these dirs are normally sub dirs of the nucleus dir, but
+	// you can redefine them if you wish
+	$DIR_PLUGINS = $DIR_NUCLEUS . 'plugins/';
+	$DIR_LANG = $DIR_NUCLEUS . 'language/';
+	$DIR_LIBS = $DIR_NUCLEUS . 'libs/';
+
+	// include libs
+	include($DIR_LIBS.'globalfunctions.php');
+?&gt;</code></pre>
+
+	<p>After you changed the file on your computer, upload it to your web server using FTP. Make sure you use ASCII mode to send over the files.</p>
+
+	<div class="note">
+		<b>Note:</b> Make sure that you have no spaces at the beginning or end of the <i>config.php</i> file. These would cause errors to happen when performing certain actions.<br />
+		Thus, the first character of config.php should be "&lt;", and the last character should be "&gt;".
+	</div>
+
+<?php } else { ?>
+
+	<h1>Installation complete!</h1>
+
+	<p>Nucleus has been installed, and your <code>config.php</code> has been updated for you.</p>
+
+	<p>Don't forget to change the permissions on <code>config.php</code> back to 444 for security (<a href="nucleus/documentation/tips.html#filepermissions">Quick guide on how to change file permissions</a>).</p>
+
+<?php } ?>
+
+	<h1>Fight against Spam</h1>
+	
+	<p>Nucleus CMS allows every visitor to write comments in blogs. So there is a high risk that spammers abuse this function. We recommend that you protect your blog with one of the following methods:</p>
+
+	<ul>
+		<li>If you don't want comments you can disable them individually for each blog: Go to the hompage of the Admin area and choose <b>Your Weblog > Settings > Comments enabled > No</b>.</li>
+		<li>Install one of serveral plugins that help to avoid spam comments: <a href="http://faq.nucleuscms.org/item/45">How can I stop comment and trackback spam?</a> (you could bookmark this page to read it later).</li>
+	</ul>
+	
+	<h1>Delete your install files</h1>
+
+	<p>Files you should delete from your web server:</p>
+
+	<ul>
+		<li><b>install.sql</b>: file containing table structures</li>
+		<li><b>install.php</b>: this file</li>
+	</ul>
+
+	<p>If you don't delete these files, you won't be able to open the admin area</p>
+
+	<h1>Visit your web site</h1>
+
+	<p>Your web site is now ready to use.
+		<ul>
+			<li><a href="<?php echo $config_adminurl?>">Login to the admin area to configure your site</a></li>
+			<li><a href="<?php echo $config_indexurl?>">Visit your site now</a></li>
+		</ul>
+	</p>
+
+</body>
+</html>
+
+<?php
+}
+
+function installCustomPlugs(&$manager) {
+	global $aConfPlugsToInstall, $DIR_LIBS;
+
+	$aErrors = array();
+
+	if (count($aConfPlugsToInstall) == 0) {
+		return $aErrors;
+	}
+
+	$res = sql_query('SELECT * FROM ' . sql_table('plugin') );
+	$numCurrent = mysql_num_rows($res);
+
+	foreach ($aConfPlugsToInstall as $plugName) {
+		// do this before calling getPlugin (in case the plugin id is used there)
+		$query = 'INSERT INTO ' . sql_table('plugin') . ' (porder, pfile) VALUES (' . (++$numCurrent) . ', "' . addslashes($plugName) . '")';
+		sql_query($query);
+
+		// get and install the plugin
+		$plugin =& $manager->getPlugin($plugName);
+
+		if (!$plugin) {
+			sql_query('DELETE FROM ' . sql_table('plugin') . ' WHERE pfile=\'' . addslashes($plugName) . '\'');
+			$numCurrent--;
+			array_push($aErrors, 'Unable to install plugin ' . $plugName);
+			continue;
+		}
+
+		$plugin->install();
+	}
+
+	// SYNC PLUGIN EVENT LIST
+	sql_query('DELETE FROM ' . sql_table('plugin_event') );
+
+	// loop over all installed plugins
+	$res = sql_query('SELECT pid, pfile FROM ' . sql_table('plugin') );
+
+	while($o = mysql_fetch_object($res) ) {
+		$pid = $o->pid;
+		$plug =& $manager->getPlugin($o->pfile);
+
+		if ($plug) {
+			$eventList = $plug->getEventList();
+
+			foreach ($eventList as $eventName) {
+				sql_query('INSERT INTO ' . sql_table('plugin_event') . ' (pid, event) VALUES (' . $pid . ', \'' . $eventName . '\')');
+			}
+		}
+	}
+
+	return $aErrors;
+}
+
+function installCustomSkins(&$manager) {
+	global $aConfSkinsToImport, $DIR_LIBS, $DIR_SKINS;
+
+	$aErrors = array();
+
+	if (count($aConfSkinsToImport) == 0) {
+		return $aErrors;
+	}
+
+	// load skinie class
+	include_once($DIR_LIBS . 'skinie.php');
+
+	$importer = new SKINIMPORT();
+
+	foreach ($aConfSkinsToImport as $skinName) {
+		$importer->reset();
+		$skinFile = $DIR_SKINS . $skinName . '/skinbackup.xml';
+
+		if (!@file_exists($skinFile) ) {
+			array_push($aErrors, 'Unable to import ' . $skinFile . ' : file does not exist');
+			continue;
+		}
+
+		$error = $importer->readFile($skinFile);
+
+		if ($error) {
+			array_push($aErrors, 'Unable to import ' . $skinName . ' : ' . $error);
+			continue;
+		}
+
+		$error = $importer->writeToDatabase(1);
+
+		if ($error) {
+			array_push($aErrors, 'Unable to import ' . $skinName . ' : ' . $error);
+			continue;
+		}
+	}
+
+	return $aErrors;
+}
+
+// give an error if one or more nucleus are not accessible
+function doCheckFiles() {
+	$missingfiles = array();
+	$files = array(
+		'install.sql',
+		'index.php',
+		'action.php',
+		'nucleus/index.php',
+		'nucleus/libs/globalfunctions.php',
+		'nucleus/libs/ADMIN.php',
+		'nucleus/libs/BLOG.php',
+		'nucleus/libs/COMMENT.php',
+		'nucleus/libs/COMMENTS.php',
+		'nucleus/libs/ITEM.php',
+		'nucleus/libs/MEMBER.php',
+		'nucleus/libs/SKIN.php',
+		'nucleus/libs/TEMPLATE.php',
+		'nucleus/libs/MEDIA.php',
+		'nucleus/libs/ACTIONLOG.php',
+		'nucleus/media.php'
+		);
+
+	$count = count($files);
+
+	for ($i = 0; $i < $count; $i++) {
+		if (!is_readable($files[$i]) ) {
+			array_push($missingfiles, 'File <b>' . $files[$i] . '</b> is missing or not readable.');
+		}
+	}
+
+// The above code replaces several if statements of the form:
+
+//	if (!is_readable('install.sql') ) {
+//		array_push($missingfiles, 'File <b>install.sql</b> is missing or not readable');
+//	}
+
+	if (count($missingfiles) > 0) {
+		showErrorMessages($missingfiles);
+	}
+}
+
+function updateConfig($name, $val) {
+	$name = addslashes($name);
+	$val = trim(addslashes($val) );
+
+	$query = 'UPDATE ' . tableName('nucleus_config')
+			. " SET value='$val'"
+			. " WHERE name='$name'";
+
+	mysql_query($query) or _doError('Query error while trying to update config: ' . mysql_error() );
+	return mysql_insert_id();
+}
+
+function replaceDoubleBackslash($input) {
+	return str_replace('\\', '/', $input);
+}
+
+function endsWithSlash($s) {
+	return (strrpos($s, '/') == strlen($s) - 1);
+}
+
+/**
+ * Checks if email address is valid
+ */
+function _isValidMailAddress($address) {
+	if (preg_match("/^[a-zA-Z0-9\._-]+@+[A-Za-z0-9\._-]+\.+[A-Za-z]{2,4}$/", $address) ) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+// returns true if the given string is a valid shortname
+// (to check short blog names and nicknames)
+// logic: starts and ends with a non space, can contain spaces in between
+//        min 2 chars
+function _isValidShortName($name) {
+	if (eregi("^[a-z0-9]+$", $name) ) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+
+
+// returns true if the given string is a valid display name
+// (to check nicknames)
+function _isValidDisplayName($name) {
+	if (eregi("^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$", $name) ) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+function _doError($msg) {
+	?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Nucleus Install</title>
+	<style>@import url('nucleus/styles/manual.css');</style>
+</head>
+<body>
+	<div style='text-align:center'><img src='./nucleus/styles/logo.gif' /></div> <!-- Nucleus logo -->
+	<h1>Error!</h1>
+
+	<p>Error message was: "<?php echo $msg?>";</p>
+
+	<p><a href="install.php" onclick="history.back();return false;">Go Back</a></p>
+</body>
+</html>
+
+<?php
+	exit;
+}
+
+function showErrorMessages($errors) {
+	?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>Nucleus Install</title>
+	<style>@import url('nucleus/styles/manual.css');</style>
+</head>
+<body>
+	<div style='text-align:center'><img src='./nucleus/styles/logo.gif' /></div> <!-- Nucleus logo -->
+	<h1>Errors!</h1>
+
+	<p>Errors were found:</p>
+
+	<ul>
+
+<?php
+	while($msg = array_shift($errors) ) {
+		echo '<li>', $msg, '</li>';
+	}
+?>
+
+	</ul>
+
+	<p><a href="install.php" onclick="history.back();return false;">Go Back</a></p>
+</body>
+</html>
+
+<?php
+	exit;
+}
+
+/* for the non-php systems that decide to show the contents:
+?></div><?php	*/
+
+?>
diff -ruN 3.24.src/install.sql 3.31.src/install.sql
--- 3.24.src/install.sql	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/install.sql	2008-01-17 10:01:12.000000000 -0600
@@ -0,0 +1,309 @@
+CREATE TABLE `nucleus_actionlog` (
+  `timestamp` datetime NOT NULL default '0000-00-00 00:00:00',
+  `message` varchar(255) NOT NULL default ''
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_activation` (
+  `vkey` varchar(40) NOT NULL default '',
+  `vtime` datetime NOT NULL default '0000-00-00 00:00:00',
+  `vmember` int(11) NOT NULL default '0',
+  `vtype` varchar(15) NOT NULL default '',
+  `vextra` varchar(128) NOT NULL default '',
+  PRIMARY KEY  (`vkey`)
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_ban` (
+  `iprange` varchar(15) NOT NULL default '',
+  `reason` varchar(255) NOT NULL default '',
+  `blogid` int(11) NOT NULL default '0'
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_blog` (
+  `bnumber` int(11) NOT NULL auto_increment,
+  `bname` varchar(60) NOT NULL default '',
+  `bshortname` varchar(15) NOT NULL default '',
+  `bdesc` varchar(200) default NULL,
+  `bcomments` tinyint(2) NOT NULL default '1',
+  `bmaxcomments` int(11) NOT NULL default '0',
+  `btimeoffset` decimal(3,1) NOT NULL default '0.0',
+  `bnotify` varchar(60) default NULL,
+  `burl` varchar(100) default NULL,
+  `bupdate` varchar(60) default NULL,
+  `bdefskin` int(11) NOT NULL default '1',
+  `bpublic` tinyint(2) NOT NULL default '1',
+  `bsendping` tinyint(2) NOT NULL default '0',
+  `bconvertbreaks` tinyint(2) NOT NULL default '1',
+  `bdefcat` int(11) default NULL,
+  `bnotifytype` int(11) NOT NULL default '15',
+  `ballowpast` tinyint(2) NOT NULL default '0',
+  `bincludesearch` tinyint(2) NOT NULL default '0',
+  `breqemail` TINYINT( 2 ) DEFAULT '0' NOT NULL,
+  `bfuturepost` TINYINT(2) DEFAULT '0' NOT NULL,
+  PRIMARY KEY  (`bnumber`),
+  UNIQUE KEY `bnumber` (`bnumber`),
+  UNIQUE KEY `bshortname` (`bshortname`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_blog` VALUES (1, 'My Nucleus CMS', 'mynucleuscms', '', 1, 0, 0.0, '', 'http://localhost:8080/nucleus/', '', 5, 1, 0, 1, 1, 1, 1, 0, 0, 0);
+
+CREATE TABLE `nucleus_category` (
+  `catid` int(11) NOT NULL auto_increment,
+  `cblog` int(11) NOT NULL default '0',
+  `cname` varchar(200) default NULL,
+  `cdesc` varchar(200) default NULL,
+  PRIMARY KEY  (`catid`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_category` VALUES (1, 1, 'General', 'Items that do not fit in other categories');
+
+CREATE TABLE `nucleus_comment` (
+  `cnumber` int(11) NOT NULL auto_increment,
+  `cbody` text NOT NULL,
+  `cuser` varchar(40) default NULL,
+  `cmail` varchar(100) default NULL,
+  `cemail` VARCHAR( 100 ),
+  `cmember` int(11) default NULL,
+  `citem` int(11) NOT NULL default '0',
+  `ctime` datetime NOT NULL default '0000-00-00 00:00:00',
+  `chost` varchar(60) default NULL,
+  `cip` varchar(15) NOT NULL default '',
+  `cblog` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`cnumber`),
+  UNIQUE KEY `cnumber` (`cnumber`),
+  KEY `citem` (`citem`),
+  FULLTEXT KEY `cbody` (`cbody`)
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_config` (
+  `name` varchar(20) NOT NULL default '',
+  `value` varchar(128) default NULL,
+  PRIMARY KEY  (`name`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_config` VALUES ('DefaultBlog', '1');
+INSERT INTO `nucleus_config` VALUES ('AdminEmail', 'example@example.org');
+INSERT INTO `nucleus_config` VALUES ('IndexURL', 'http://localhost:8080/nucleus/');
+INSERT INTO `nucleus_config` VALUES ('Language', 'english');
+INSERT INTO `nucleus_config` VALUES ('SessionCookie', '');
+INSERT INTO `nucleus_config` VALUES ('AllowMemberCreate', '');
+INSERT INTO `nucleus_config` VALUES ('AllowMemberMail', '1');
+INSERT INTO `nucleus_config` VALUES ('SiteName', 'My Nucleus CMS');
+INSERT INTO `nucleus_config` VALUES ('AdminURL', 'http://localhost:8080/nucleus/nucleus/');
+INSERT INTO `nucleus_config` VALUES ('NewMemberCanLogon', '1');
+INSERT INTO `nucleus_config` VALUES ('DisableSite', '');
+INSERT INTO `nucleus_config` VALUES ('DisableSiteURL', 'http://www.this-page-intentionally-left-blank.org/');
+INSERT INTO `nucleus_config` VALUES ('LastVisit', '');
+INSERT INTO `nucleus_config` VALUES ('MediaURL', 'http://localhost:8080/nucleus/media/');
+INSERT INTO `nucleus_config` VALUES ('AllowedTypes', 'jpg,jpeg,gif,mpg,mpeg,avi,mov,mp3,swf,png');
+INSERT INTO `nucleus_config` VALUES ('AllowLoginEdit', '');
+INSERT INTO `nucleus_config` VALUES ('AllowUpload', '1');
+INSERT INTO `nucleus_config` VALUES ('DisableJsTools', '2');
+INSERT INTO `nucleus_config` VALUES ('CookiePath', '/');
+INSERT INTO `nucleus_config` VALUES ('CookieDomain', '');
+INSERT INTO `nucleus_config` VALUES ('CookieSecure', '');
+INSERT INTO `nucleus_config` VALUES ('CookiePrefix', '');
+INSERT INTO `nucleus_config` VALUES ('MediaPrefix', '1');
+INSERT INTO `nucleus_config` VALUES ('MaxUploadSize', '1048576');
+INSERT INTO `nucleus_config` VALUES ('NonmemberMail', '');
+INSERT INTO `nucleus_config` VALUES ('PluginURL', 'http://localhost:8080/nucleus/nucleus/plugins/');
+INSERT INTO `nucleus_config` VALUES ('ProtectMemNames', '1');
+INSERT INTO `nucleus_config` VALUES ('BaseSkin', '5');
+INSERT INTO `nucleus_config` VALUES ('SkinsURL', 'http://localhost:8080/nucleus/skins/');
+INSERT INTO `nucleus_config` VALUES ('ActionURL', 'http://localhost:8080/nucleus/action.php');
+INSERT INTO `nucleus_config` VALUES ('URLMode', 'normal');
+INSERT INTO `nucleus_config` VALUES ('DatabaseVersion', '330');
+
+CREATE TABLE `nucleus_item` (
+  `inumber` int(11) NOT NULL auto_increment,
+  `ititle` varchar(160) default NULL,
+  `ibody` text NOT NULL,
+  `imore` text,
+  `iblog` int(11) NOT NULL default '0',
+  `iauthor` int(11) NOT NULL default '0',
+  `itime` datetime NOT NULL default '0000-00-00 00:00:00',
+  `iclosed` tinyint(2) NOT NULL default '0',
+  `idraft` tinyint(2) NOT NULL default '0',
+  `ikarmapos` int(11) NOT NULL default '0',
+  `icat` int(11) default NULL,
+  `ikarmaneg` int(11) NOT NULL default '0',
+  `iposted` tinyint(2) NOT NULL default '1',
+  PRIMARY KEY  (`inumber`),
+  UNIQUE KEY `inumber` (`inumber`),
+  KEY `itime` (`itime`),
+  FULLTEXT KEY `ibody` (`ibody`,`ititle`,`imore`)
+) TYPE=MyISAM PACK_KEYS=0;
+
+INSERT INTO `nucleus_item` VALUES (1, 'Welcome to Nucleus CMS v3.3', 'This is the first post on your Nucleus CMS. Nucleus offers you the building blocks you need to create a web presence. Whether you want to create a personal blog, a family page, or an online business site, Nucleus CMS can help you achieve your goals.<br />
+<br />
+We\'ve loaded this first entry with links and information to get you started. Though you can delete this entry, it will eventually scroll off the main page as you add content to your site. Add your comments while you learn to work with Nucleus CMS, or bookmark this page so you can come back to it when you need to.', '<b>Home - <a href=\"http://nucleuscms.org/\" title=\"Nucleus CMS home\">nucleuscms.org</a></b><br />
+Welcome to the world of Nucleus CMS. In 2001 a set of PHP scripts were let loose on the open Internet. Those scripts, which took user-generated data and used it to dynamically create html pages, contained the ideas and the algorithms that are the core of today’s Nucleus CMS. Though Nucleus CMS 3.3 is far more flexible and powerful than the scripts from which it emerged, it still expresses the values that guided its birth: flexibility, security, and computational elegance.<br />
+<br />
+Thanks to an international community of sophisticated developers and designers, Nucleus CMS remains simple enough for anyone to learn, and expandable enough to allow you to build almost any website you can imagine. Nucleus CMS lets you integrate text, images, and user comments in a seamless package that will make your web presence as serious, professional, personal, or fun as you want it to be. We hope you enjoy its power.<br />
+<br />
+<b>Documentation - <a href=\"http://docs.nucleuscms.org/\" title=\"Nucleus CMS Documentation\">docs.nucleuscms.org</a></b><br />
+The install process places a <a href=\"nucleus/documentation/\">user</a> and a <a href=\"nucleus/documentation/devdocs/\">developer</a> documentation on your web server. Pop-up <a href=\"/nucleus/documentation/help.html\">help</a> is available throughout the administration area to assist you in maintaining and customizing your site. When in the Nucleus CMS admin area, click on this symbol <img src=\"nucleus/documentation/icon-help.gif\" width=\"15\" height=\"15\" alt=\"help icon\" /> for context-sensitive help. You can also read this documentation online under <a href=\"http://docs.nucleuscms.org/\" title=\"Nucleus CMS Documentation\">docs.nucleuscms.org</a>.<br />
+<br />
+<b>Frequently Asked Questions - <a nicetitle=\"Nucleus CMS FAQ\" href=\"http://faq.nucleuscms.org/\">faq.nucleuscms.org</a></b><br />
+If you need more information about managing, extending or troubleshooting your Nucleus CMS the Nucleus FAQ is the first place to search information. Over 170 frequently asked questions are answered from experienced Nucleus users.<br />
+<br />
+<b>Support - <a href=\"http://forum.nucleuscms.org/\" title=\"Nucleus CMS Support Forum\">forum.nucleuscms.org</a></b><br />
+Should you require assistance, please don\'t hesitate to <a href=\"http://forum.nucleuscms.org/faq.php\">join</a> the 6,800+ registered users on our forums. With its built-in search capability of the 73,000+ posted articles, your answers are just a few clicks away. Remember: almost any question you think of has already been asked on the forums, and almost anything you want to do with Nucleus has been tried and explained there. Be sure to check them out.<br />
+<br />
+<b>Demonstration - <a href=\"http://demo.nucleuscms.org/\" title=\"Nucleus CMS Demonstration\">demo.nucleuscms.org</a></b><br />
+Want to play around, test changes or tell a friend or relative about Nucleus CMS? Visit our live <a href=\"http://demo.nucleuscms.org/\">demo site</a>.<br />
+<br />
+<b>Skins - <a href=\"http://skins.nucleuscms.org/\" title=\"Nucleus CMS Skins\">skins.nucleuscms.org</a></b><br />
+The combination of multi-weblogs and skins/templates make for a powerful duo in personalizing your site or designing one for a friend, relative or business client. Import new skins to change the look of your website, or create your own skins and share them with the Nucleus community! Help designing or modifying skins is only a few clicks away in the Nucleus forums.<br />
+<br />
+<b>Plugins - <a href=\"http://plugins.nucleuscms.org/\" title=\"Nucleus plugins\">plugins.nucleuscms.org</a></b><br />
+Looking to add some extra functionality to the base Nucleus CMS package? Our <a href=\"http://wiki.nucleuscms.org/plugin\">plugin repository</a> gives you plenty of ways to extend and expand what Nucleus CMS can do; your imagination and creativity are the only limit on how Nucleus CMS can work for you.<br />
+<br />
+<b>Development - <a href=\"http://dev.nucleuscms.org/\" title=\"Nucleus Development\">dev.nucleuscms.org</a></b><br />
+If you need more information about the Nucleus development you can find Informations in the developer documents at <a href=\"http://dev.nucleuscms.org/\" title=\"Nucleus Development\">dev.nucleuscms.org</a> or in the <a href=\"http://forum.nucleuscms.org/\">Support Forum</a>. Sourceforge.net graciously hosts our <a href=\"http://sourceforge.net/projects/nucleuscms/\">Open Source project page</a> which contains our software downloads and CVS repository.<br />
+<br />
+<b>Donators</b><br />
+We would like to thank these <a href=\"http://nucleuscms.org/donators.php\">nice people</a> for their <a href=\"http://nucleuscms.org/donate.php\">support</a>. <em>Thanks all!</em><br />
+<br />
+<b>Vote for Nucleus CMS</b><br />
+Like Nucleus CMS? Vote for us at <a href=\"http://www.hotscripts.com/Detailed/13368.html?RID=nucleus@demuynck.org\">HotScripts</a> and <a href=\"http://www.opensourcecms.com/index.php?option=content&task=view&id=145\">opensourceCMS</a>.<br />
+<br />
+<b>License</b><br />
+When we speak of free software, we are referring to freedom, not price. Our <a href=\"http://www.gnu.org/licenses/gpl.html\">General Public Licenses</a> are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.', 1, 1, '2005-08-15 11:04:26', 0, 0, 0, 1, 0, 1);
+
+CREATE TABLE `nucleus_karma` (
+  `itemid` int(11) NOT NULL default '0',
+  `ip` char(15) NOT NULL default ''
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_member` (
+  `mnumber` int(11) NOT NULL auto_increment,
+  `mname` varchar(16) NOT NULL default '',
+  `mrealname` varchar(60) default NULL,
+  `mpassword` varchar(40) NOT NULL default '',
+  `memail` varchar(60) default NULL,
+  `murl` varchar(100) default NULL,
+  `mnotes` varchar(100) default NULL,
+  `madmin` tinyint(2) NOT NULL default '0',
+  `mcanlogin` tinyint(2) NOT NULL default '1',
+  `mcookiekey` varchar(40) default NULL,
+  `deflang` varchar(20) NOT NULL default '',
+  PRIMARY KEY  (`mnumber`),
+  UNIQUE KEY `mname` (`mname`),
+  UNIQUE KEY `mnumber` (`mnumber`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_member` VALUES (1, 'example', 'example', '1a79a4d60de6718e8e5b326e338ae533', 'example@example.org', 'http://localhost:8080/nucleus/', '', 1, 1, 'd767aefc60415859570d64c649257f19', '');
+
+CREATE TABLE `nucleus_plugin` (
+  `pid` int(11) NOT NULL auto_increment,
+  `pfile` varchar(40) NOT NULL default '',
+  `porder` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`pid`),
+  KEY `pid` (`pid`),
+  KEY `porder` (`porder`)
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_plugin_event` (
+  `pid` int(11) NOT NULL default '0',
+  `event` varchar(40) default NULL,
+  KEY `pid` (`pid`)
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_plugin_option` (
+  `ovalue` text NOT NULL,
+  `oid` int(11) NOT NULL auto_increment,
+  `ocontextid` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`oid`,`ocontextid`)
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_plugin_option_desc` (
+  `oid` int(11) NOT NULL auto_increment,
+  `opid` int(11) NOT NULL default '0',
+  `oname` varchar(20) NOT NULL default '',
+  `ocontext` varchar(20) NOT NULL default '',
+  `odesc` varchar(255) default NULL,
+  `otype` varchar(20) default NULL,
+  `odef` text,
+  `oextra` text,
+  PRIMARY KEY  (`opid`,`oname`,`ocontext`),
+  UNIQUE KEY `oid` (`oid`)
+) TYPE=MyISAM;
+
+CREATE TABLE `nucleus_skin` (
+  `sdesc` int(11) NOT NULL default '0',
+  `stype` varchar(20) NOT NULL default '',
+  `scontent` text NOT NULL,
+  PRIMARY KEY  (`sdesc`,`stype`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_skin` VALUES (2, 'index', '<?xml version=\"1.0\" encoding=\"<%charset%>\"?>\n\n<feed xml:lang=\"en-us\" xmlns=\"http://www.w3.org/2005/Atom\">\n    <title><%blogsetting(name)%></title>\n    <id><%blogsetting(url)%>:<%blogsetting(id)%></id>\n\n    <link rel=\"alternate\" type=\"text/html\" href=\"<%blogsetting(url)%>\" />\n    <link rel=\"self\" type=\"application/atom+xml\" href=\"<%blogsetting(url)%><%self%>\" />\n    <generator uri=\"http://nucleuscms.org/\"><%version%></generator>\n    <updated><%blog(feeds/atom/modified,1)%></updated>\n\n    <%blog(feeds/atom/entries,10)%>\n</feed>');
+INSERT INTO `nucleus_skin` VALUES (4, 'index', '<?xml version="1.0"?>\r\n<rsd version="1.0">\r\n <service>\r\n  <engineName><%version%></engineName>\r\n  <engineLink>http://nucleuscms.org/</engineLink>\r\n  <homepageLink><%sitevar(url)%></homepageLink>\r\n  <apis>\r\n   <api name="MetaWeblog" preferred="true" apiLink="<%adminurl%>xmlrpc/server.php" blogID="<%blogsetting(id)%>">\r\n    <docs>http://nucleuscms.org/documentation/devdocs/xmlrpc.html</docs>\r\n   </api>\r\n   <api name="Blogger" preferred="false" apiLink="<%adminurl%>xmlrpc/server.php" blogID="<%blogsetting(id)%>">\r\n    <docs>http://nucleuscms.org/documentation/devdocs/xmlrpc.html</docs>\r\n   </api>\r\n  </apis>\r\n </service>\r\n</rsd>');
+INSERT INTO `nucleus_skin` VALUES (3, 'index', '<?xml version="1.0" encoding="<%charset%>"?>\r\n<rss version="2.0">\r\n  <channel>\r\n    <title><%blogsetting(name)%></title>\r\n    <link><%blogsetting(url)%></link>\r\n    <description><%blogsetting(desc)%></description>\r\n    <language>en-us</language>           \r\n    <generator><%version%></generator>\r\n    <copyright>�</copyright>             \r\n    <category>Weblog</category>\r\n    <docs>http://backend.userland.com/rss</docs>\r\n    <image>\r\n      <url><%blogsetting(url)%>/nucleus/nucleus2.gif</url>\r\n      <title><%blogsetting(name)%></title>\r\n      <link><%blogsetting(url)%></link>\r\n    </image>\r\n    <%blog(feeds/rss20,10)%>\r\n  </channel>\r\n</rss>');
+
+CREATE TABLE `nucleus_skin_desc` (
+  `sdnumber` int(11) NOT NULL auto_increment,
+  `sdname` varchar(20) NOT NULL default '',
+  `sddesc` varchar(200) default NULL,
+  `sdtype` varchar(40) NOT NULL default 'text/html',
+  `sdincmode` varchar(10) NOT NULL default 'normal',
+  `sdincpref` varchar(50) NOT NULL default '',
+  PRIMARY KEY  (`sdnumber`),
+  UNIQUE KEY `sdname` (`sdname`),
+  UNIQUE KEY `sdnumber` (`sdnumber`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_skin_desc` VALUES (2, 'feeds/atom', 'Atom 1.0 weblog syndication', 'application/atom+xml', 'normal', '');
+INSERT INTO `nucleus_skin_desc` VALUES (3, 'feeds/rss20', 'RSS 2.0 syndication of weblogs', 'text/xml', 'normal', '');
+INSERT INTO `nucleus_skin_desc` VALUES (4, 'xml/rsd', 'RSD (Really Simple Discovery) information for weblog clients', 'text/xml', 'normal', '');
+INSERT INTO `nucleus_skin_desc` VALUES (5, 'default', 'Nucleus CMS default skin', 'text/html', 'skindir', 'default/');
+
+CREATE TABLE `nucleus_team` (
+  `tmember` int(11) NOT NULL default '0',
+  `tblog` int(11) NOT NULL default '0',
+  `tadmin` tinyint(2) NOT NULL default '0',
+  PRIMARY KEY  (`tmember`,`tblog`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_team` VALUES (1, 1, 1);
+
+CREATE TABLE `nucleus_template` (
+  `tdesc` int(11) NOT NULL default '0',
+  `tpartname` varchar(20) NOT NULL default '',
+  `tcontent` text NOT NULL,
+  PRIMARY KEY  (`tdesc`,`tpartname`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_template` VALUES (3, 'ITEM', '<item>\r\n <title><%title(xml)%></title>\r\n <link><%blogurl%>index.php?itemid=<%itemid%></link>\r\n<description><![CDATA[<%body%><%more%>]]></description>\r\n <category><%category%></category>\r\n<comments><%blogurl%>index.php?itemid=<%itemid%></comments>\r\n <pubDate><%date(rfc822)%></pubDate>\r\n</item>');
+INSERT INTO `nucleus_template` VALUES (3, 'EDITLINK', '<a href="<%editlink%>" onclick="<%editpopupcode%>">edit</a>');
+INSERT INTO `nucleus_template` VALUES (3, 'FORMAT_DATE', '%x');
+INSERT INTO `nucleus_template` VALUES (3, 'FORMAT_TIME', '%X');
+INSERT INTO `nucleus_template` VALUES (4, 'ITEM', '<%date(utc)%>');
+INSERT INTO `nucleus_template` VALUES (5, 'ITEM', '<entry>\n <title type=\"html\"><![CDATA[<%title%>]]></title>\n <link rel=\"alternate\" type=\"text/html\" href=\"<%blogurl%>index.php?itemid=<%itemid%>\" />\n <author>\n  <name><%author%></name>\n </author>\n <updated><%date(utc)%></updated>\n <published><%date(iso8601)%></published>\n <content type=\"html\"><![CDATA[<%body%><%more%>]]></content>\n <id><%blogurl%>:<%blogid%>:<%itemid%></id>\n</entry>');
+INSERT INTO `nucleus_template` VALUES (5, 'POPUP_CODE', '<%media%>');
+INSERT INTO `nucleus_template` VALUES (5, 'IMAGE_CODE', '<%image%>');
+INSERT INTO `nucleus_template` VALUES (5, 'MEDIA_CODE', '<%media%>');
+INSERT INTO `nucleus_template` VALUES (3, 'POPUP_CODE', '<%image%>');
+INSERT INTO `nucleus_template` VALUES (3, 'MEDIA_CODE', '<%media%>');
+INSERT INTO `nucleus_template` VALUES (3, 'IMAGE_CODE', '<%media%>');
+
+CREATE TABLE `nucleus_template_desc` (
+  `tdnumber` int(11) NOT NULL auto_increment,
+  `tdname` varchar(20) NOT NULL default '',
+  `tddesc` varchar(200) default NULL,
+  PRIMARY KEY  (`tdnumber`),
+  UNIQUE KEY `tdnumber` (`tdnumber`),
+  UNIQUE KEY `tdname` (`tdname`)
+) TYPE=MyISAM;
+
+INSERT INTO `nucleus_template_desc` VALUES (4, 'feeds/atom/modified', 'Atom feeds: Inserts last modification date');
+INSERT INTO `nucleus_template_desc` VALUES (5, 'feeds/atom/entries', 'Atom feeds: Feed items');
+INSERT INTO `nucleus_template_desc` VALUES (3, 'feeds/rss20', 'Used for RSS 2.0 syndication of your blog');
+INSERT INTO `nucleus_template_desc` VALUES (8, 'default/index', 'Nucleus CMS default index template');
+INSERT INTO `nucleus_template_desc` VALUES (9, 'default/item', 'Nucleus CMS default item template');
+
+CREATE TABLE `nucleus_tickets` (
+  `ticket` varchar(40) NOT NULL default '',
+  `ctime` datetime NOT NULL default '0000-00-00 00:00:00',
+  `member` int(11) NOT NULL default '0',
+  PRIMARY KEY  (`ticket`,`member`)
+) TYPE=MyISAM;
diff -ruN 3.24.src/nucleus/bookmarklet.php 3.31.src/nucleus/bookmarklet.php
--- 3.24.src/nucleus/bookmarklet.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/bookmarklet.php	2007-10-22 19:36:04.000000000 -0500
@@ -1,28 +1,28 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * This script allows adding items to Nucleus through bookmarklets. The member must be logged in
-  * in order to use this.
-  *
+ * This script allows adding items to Nucleus through bookmarklets. The member must be logged in
+ * in order to use this.
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: bookmarklet.php,v 1.16.2.1 2005/08/15 10:51:08 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: bookmarklet.php 1130 2007-03-13 14:42:38Z ehui $
+ */
 
 // bookmarklet is part of admin area (might need XML-RPC)
 $CONF = array();
 $CONF['UsingAdminArea'] = 1;
 
-// include all classes and config data 
+// include all classes and config data
 include('../config.php');
 
 $action = requestVar('action');
@@ -32,118 +32,136 @@
 	exit;
 }
 
-if (!$member->isLoggedIn()) {
+if (!$member->isLoggedIn() ) {
 	bm_loginAndPassThrough();
 	exit;
 }
 
 // on successfull login
-if (($action == 'login') && ($member->isLoggedIn()))
+if ( ($action == 'login') && ($member->isLoggedIn() ) ) {
 	$action = requestVar('nextaction');
-if ($action == '')
+}
+
+if ($action == '') {
 	$action = 'add';
-	
-sendContentType('application/xhtml+xml', 'bookmarklet-'.$action);	
+}
+
+sendContentType('application/xhtml+xml', 'bookmarklet-' . $action);
 
 // check ticket
 $action = strtolower($action);
 $aActionsNotToCheck = array('login', 'add', 'edit');
-if (!in_array($action, $aActionsNotToCheck))
-{
-	if (!$manager->checkTicket())
+
+if (!in_array($action, $aActionsNotToCheck) ) {
+
+	if (!$manager->checkTicket() ) {
 		bm_doError(_ERROR_BADTICKET);
-} 
+	}
 
+}
 
 // find out what to do
 switch ($action) {
+	// adds the item for real
 	case 'additem':
-		bm_doAddItem();		// adds the item for real
+		bm_doAddItem();
 		break;
+
+	// shows the edit item form
 	case 'edit':
-		bm_doEditForm();	// shows the edit item form
+		bm_doEditForm();
 		break;
-	case 'edititem':		// edits the item for real
+
+	// edits the item for real
+	case 'edititem':
 		bm_doEditItem();
 		break;
-	case 'login':			// on login, 'action' gets changed to 'nextaction'
+
+	// on login, 'action' gets changed to 'nextaction'
+	case 'login':
 		bm_doError('Something went wrong');
 		break;
+
+	// shows the fill in form
 	case 'add':
 	default:
-		bm_doShowForm();	// shows the fill in form
+		bm_doShowForm();
 		break;
 }
-	
+
 function bm_doAddItem() {
 	global $member, $manager, $CONF;
-	
+
 	$manager->loadClass('ITEM');
 	$result = ITEM::createFromRequest();
-	
-	if ($result['status'] == 'error')
+
+	if ($result['status'] == 'error') {
 		bm_doError($result['message']);
+	}
 
 	$blogid = getBlogIDFromItemID($result['itemid']);
 	$blog =& $manager->getBlog($blogid);
-	
+
 	if ($result['status'] == 'newcategory') {
-		$message = 'Item was added, and a new category was created. <a href="index.php?action=categoryedit&amp;blogid='.$blogid.'&amp;catid='.$result['catid'].'" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); window.open(this.href); return false;" title="Opens in new window">Click here to edit the name and description of the category.</a>';
+		$message = 'Item was added, and a new category was created. <a href="index.php?action=categoryedit&amp;blogid=' . $blogid . '&amp;catid=' . $result['catid'] . '" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); window.open(this.href); return false;" title="Opens in new window">Click here to edit the name and description of the category.</a>';
 		$extrahead = '';
-	} elseif ((postVar('actiontype') == 'addnow') && $blog->pingUserland()) {
+	} elseif ( (postVar('actiontype') == 'addnow') && $blog->sendPing() ) {
 		$message = 'Item was added successfully. Now pinging weblogs.com. Please hold on... (can take a while)';
-		$pingUrl = $manager->addTicketToUrl($CONF['AdminURL'] . 'index.php?action=sendping&blogid=' . intval($blogid));
-		$extrahead = '<meta http-equiv="refresh" content="1; url=' . htmlspecialchars($pingUrl). '" />';
+		$pingUrl = $manager->addTicketToUrl($CONF['AdminURL'] . 'index.php?action=sendping&blogid=' . intval($blogid) );
+		$extrahead = '<meta http-equiv="refresh" content="1; url=' . htmlspecialchars($pingUrl) . '" />';
 	} else {
 		$message = _ITEM_ADDED;
 		$extrahead = '';
 	}
-	
+
 	bm_message(_ITEM_ADDED, _ITEM_ADDED, $message,$extrahead);
 }
 
 function bm_doEditItem() {
 	global $member, $manager, $CONF;
-	
-	$itemid 	= intRequestVar('itemid');
-	$catid 		= postVar('catid');
-	
+
+	$itemid = intRequestVar('itemid');
+	$catid = postVar('catid');
+
 	// only allow if user is allowed to alter item
-	if (!$member->canUpdateItem($itemid, $catid))
+	if (!$member->canUpdateItem($itemid, $catid) ) {
 		bm_doError(_ERROR_DISALLOWED);
+	}
 
-	$body 		= postVar('body');
-	$title 		= postVar('title');
-	$more 		= postVar('more');
-	$closed 	= intPostVar('closed');
+	$body = postVar('body');
+	$title = postVar('title');
+	$more = postVar('more');
+	$closed = intPostVar('closed');
 	$actiontype = postVar('actiontype');
-	
+	$draftid = intPostVar('draftid');
+
 	// redirect to admin area on delete (has delete confirmation)
 	if ($actiontype == 'delete') {
-		redirect('index.php?action=itemdelete&itemid='.$itemid);
-		exit;	
+		redirect('index.php?action=itemdelete&itemid=' . $itemid);
+		exit;
 	}
-	
+
 	// create new category if needed (only on edit/changedate)
-	if (strstr($catid,'newcat')) {
-		// get blogid 
-		list($blogid) = sscanf($catid,"newcat-%d");
+	if (strstr($catid,'newcat') ) {
+		// get blogid
+		list($blogid) = sscanf($catid, "newcat-%d");
 
 		// create
 		$blog =& $manager->getBlog($blogid);
 		$catid = $blog->createNewCategory();
 
 		// show error when sth goes wrong
-		if (!$catid) 
+		if (!$catid) {
 			bm_doError('Could not create new category');
-	} 
+		}
+	}
 
 	// only edit action is allowed for bookmarklet edit
 	switch ($actiontype) {
 		case 'changedate':
 			$publish = 1;
 			$wasdraft = 0;
-			$timestamp = mktime(postVar('hour'), postVar('minutes'), 0, postVar('month'), postVar('day'), postVar('year'));
+			$timestamp = mktime(postVar('hour'), postVar('minutes'), 0, postVar('month'), postVar('day'), postVar('year') );
 			break;
 		case 'edit':
 			$publish = 1;
@@ -153,15 +171,20 @@
 		default:
 			bm_doError('Something went wrong');
 	}
-	
+
 	// update item for real
 	ITEM::update($itemid, $catid, $title, $body, $more, $closed, $wasdraft, $publish, $timestamp);
-	
+
+	if ($draftid > 0) {
+		ITEM::delete($draftid);
+	}
+
 	// show success message
-	if ($catid != intPostVar('catid'))
-		bm_message(_ITEM_UPDATED, _ITEM_UPDATED, 'Item was added, and a new category was created. <a href="index.php?action=categoryedit&amp;blogid='.$blog->getID().'&amp;catid='.$catid.'" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); window.open(this.href); return false;" title="Opens in new window">Click here to edit the name and description of the category.</a>', '');
-	else
+	if ($catid != intPostVar('catid') ) {
+		bm_message(_ITEM_UPDATED, _ITEM_UPDATED, 'Item was added, and a new category was created. <a href="index.php?action=categoryedit&amp;blogid=' . $blog->getID() . '&amp;catid=' . $catid . '" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); window.open(this.href); return false;" title="Opens in new window">Click here to edit the name and description of the category.</a>', '');
+	} else {
 		bm_message(_ITEM_UPDATED, _ITEM_UPDATED, _ITEM_UPDATED, '');
+	}
 }
 
 function bm_loginAndPassThrough() {
@@ -170,7 +193,7 @@
 	$log_text = requestVar('logtext');
 	$log_link = requestVar('loglink');
 	$log_linktitle = requestVar('loglinktitle');
-	
+
 	?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 	<html xmlns="http://www.w3.org/1999/xhtml">
@@ -179,24 +202,24 @@
 		<?php bm_style(); ?>
 	</head>
 	<body>
-	<h1><?php echo _LOGIN_PLEASE?></h1>
-	
+	<h1><?php echo _LOGIN_PLEASE ?></h1>
+
 	<form method="post" action="bookmarklet.php">
 	<p>
 		<input name="action" value="login" type="hidden" />
-		<input name="blogid" value="<?php echo  htmlspecialchars($blogid) ?>" type="hidden" />
-		<input name="logtext" value="<?php echo  htmlspecialchars($log_text) ?>" type="hidden" />
-		<input name="loglink" value="<?php echo  htmlspecialchars($log_link) ?>" type="hidden" />
-		<input name="loglinktitle" value="<?php echo  htmlspecialchars($log_linktitle) ?>" type="hidden" />
-		<?php echo _LOGINFORM_NAME?>:
+		<input name="blogid" value="<?php echo htmlspecialchars($blogid); ?>" type="hidden" />
+		<input name="logtext" value="<?php echo htmlspecialchars($log_text); ?>" type="hidden" />
+		<input name="loglink" value="<?php echo htmlspecialchars($log_link); ?>" type="hidden" />
+		<input name="loglinktitle" value="<?php echo htmlspecialchars($log_linktitle); ?>" type="hidden" />
+		<?php echo _LOGINFORM_NAME ?>:
 		<br /><input name="login" />
-		<br /><?php echo _LOGINFORM_PWD?>:
+		<br /><?php echo _LOGINFORM_PWD ?>:
 		<br /><input name="password" type="password" />
 		<br /><br />
-		<br /><input type="submit" value="<?php echo _LOGIN?>" />
+		<br /><input type="submit" value="<?php echo _LOGIN ?>" />
 	</p>
 	</form>
-	<p><a href="bookmarklet.php" onclick="window.close();"><?php echo _POPUP_CLOSE?></a></p>
+	<p><a href="bookmarklet.php" onclick="window.close();"><?php echo _POPUP_CLOSE ?></a></p>
 	</body>
 	</html>
 	<?php
@@ -204,62 +227,70 @@
 
 function bm_doShowForm() {
 	global $member;
-	
+
 	$blogid = intRequestVar('blogid');
 	$log_text = trim(requestVar('logtext'));
 	$log_link = requestVar('loglink');
 	$log_linktitle = requestVar('loglinktitle');
-	
-	if (!BLOG::existsID($blogid))
+
+	if (!BLOG::existsID($blogid) ) {
 		bm_doError(_ERROR_NOSUCHBLOG);
+	}
 
-	if (!$member->isTeamMember($blogid))
+	if (!$member->isTeamMember($blogid) ) {
 		bm_doError(_ERROR_NOTONTEAM);
-	
+	}
+
 	$logje = '';
-	if ($log_text)
-		$logje .= '<blockquote><div>"' . htmlspecialchars($log_text) .'"</div></blockquote>' . "\n";
-	if (!$log_linktitle)
+
+	if ($log_text) {
+		$logje .= '<blockquote><div>"' . htmlspecialchars($log_text) . '"</div></blockquote>' . "\n";
+	}
+
+	if (!$log_linktitle) {
 		$log_linktitle = $log_link;
-	if ($log_link) 
-		$logje .= '<a href="'. htmlspecialchars($log_link) . '">'. htmlspecialchars($log_linktitle).'</a>';
-		
+	}
+
+	if ($log_link) {
+		$logje .= '<a href="' . htmlspecialchars($log_link) . '">' . htmlspecialchars($log_linktitle) . '</a>';
+	}
 
 	$item['body'] = $logje;
 	$item['title'] = htmlspecialchars($log_linktitle);
 
 	$factory = new PAGEFACTORY($blogid);
-	$factory->createAddForm('bookmarklet',$item);
+	$factory->createAddForm('bookmarklet', $item);
 }
 
 function bm_doEditForm() {
 	global $member, $manager;
-	
+
 	$itemid = intRequestVar('itemid');
-	
-	if (!$manager->existsItem($itemid, 0, 0)) 
+
+	if (!$manager->existsItem($itemid, 0, 0) ) {
 		bm_doError(_ERROR_NOSUCHITEM);
-		
-	if (!$member->canAlterItem($itemid))
+	}
+
+	if (!$member->canAlterItem($itemid) ) {
 		bm_doError(_ERROR_DISALLOWED);
-		
-	$item =& $manager->getItem($itemid,1,1);
-	$blog =& $manager->getBlog(getBlogIDFromItemID($itemid));
-	
-	$manager->notify('PrepareItemForEdit', array('item' => &$item));
+	}
+
+	$item =& $manager->getItem($itemid, 1, 1);
+	$blog =& $manager->getBlog(getBlogIDFromItemID($itemid) );
 
-	if ($blog->convertBreaks()) {
+	$manager->notify('PrepareItemForEdit', array('item' => &$item) );
+
+	if ($blog->convertBreaks() ) {
 		$item['body'] = removeBreaks($item['body']);
 		$item['more'] = removeBreaks($item['more']);
 	}
 
-	$formfactory = new PAGEFACTORY($blog->getID());
-	$formfactory->createEditForm('bookmarklet',$item);		
-
+	$formfactory = new PAGEFACTORY($blog->getID() );
+	$formfactory->createEditForm('bookmarklet', $item);
 }
 
 function bm_doError($msg) {
-	bm_message(_ERROR,_ERRORMSG,$msg);
+	bm_message(_ERROR, _ERRORMSG, $msg);
 	die;
 }
 
@@ -268,36 +299,37 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 	<html xmlns="http://www.w3.org/1999/xhtml">
 	<head>
-		<title><?php echo  $title ?></title>
+		<title><?php echo $title ?></title>
 		<?php bm_style(); ?>
-		<?php echo $extrahead?>
+		<?php echo $extrahead; ?>
 	</head>
 	<body>
-	<h1><?php echo  $head ?></h1>
-	<p><?php echo  $msg ?></p>
-	<p><a href="bookmarklet.php" onclick="window.close();"><?php echo _POPUP_CLOSE?></a></p>
+	<h1><?php echo $head; ?></h1>
+	<p><?php echo $msg; ?></p>
+	<p><a href="bookmarklet.php" onclick="window.close();"><?php echo _POPUP_CLOSE ?></a></p>
 	</body>
 	</html>
-	
-	<?php }
+
+	<?php
+}
 
 function bm_style() {
 	echo '<link rel="stylesheet" type="text/css" href="styles/bookmarklet.css" />';
-	echo '<link rel="stylesheet" type="text/css" href="styles/addedit.css" />';	
+	echo '<link rel="stylesheet" type="text/css" href="styles/addedit.css" />';
 }
 
 function bm_doContextMenuCode() {
 	global $CONF;
 	?>
 <script type="text/javascript" defer="defer">
-doc=external.menuArguments.document;
-lt=escape(doc.selection.createRange().text);
-loglink=escape(external.menuArguments.location.href);
-loglinktitle=escape(doc.title);
-wingm=window.open('<?php echo $CONF['AdminURL']?>bookmarklet.php?blogid=<?php echo intGetVar('blogid')?>&logtext='+lt+'&loglink='+loglink+'&loglinktitle='+loglinktitle,'nucleusbm','scrollbars=yes,width=600,height=500,left=10,top=10,status=yes,resizable=yes');
+doc = external.menuArguments.document;
+lt = escape(doc.selection.createRange().text);
+loglink = escape(external.menuArguments.location.href);
+loglinktitle = escape(doc.title);
+wingm = window.open('<?php echo $CONF['AdminURL']?>bookmarklet.php?blogid=<?php echo intGetVar('blogid')?>&logtext=' + lt + '&loglink=' + loglink + '&loglinktitle=' + loglinktitle, 'nucleusbm', 'scrollbars=yes,width=600,height=500,left=10,top=10,status=yes,resizable=yes');
 wingm.focus();
-</script>	
+</script>
 	<?php
 }
 
-?>
\ No newline at end of file
+?>
diff -ruN 3.24.src/nucleus/documentation/devdocs/custominstall.html 3.31.src/nucleus/documentation/devdocs/custominstall.html
--- 3.24.src/nucleus/documentation/devdocs/custominstall.html	2004-08-05 09:50:50.000000000 -0500
+++ 3.31.src/nucleus/documentation/devdocs/custominstall.html	2007-10-22 19:36:02.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: custominstall.html,v 1.3 2004/08/05 07:50:50 dekarma Exp $ -->
+	<!-- $Id: custominstall.html 756 2005-08-11 20:28:57Z ehui $ -->
 	<title>Nucleus - Custom Install Scripts</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 </head>
diff -ruN 3.24.src/nucleus/documentation/devdocs/index.html 3.31.src/nucleus/documentation/devdocs/index.html
--- 3.24.src/nucleus/documentation/devdocs/index.html	2004-08-05 09:50:50.000000000 -0500
+++ 3.31.src/nucleus/documentation/devdocs/index.html	2007-10-22 19:36:02.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: index.html,v 1.5 2004/08/05 07:50:50 dekarma Exp $ -->
+	<!-- $Id: index.html 756 2005-08-11 20:28:57Z ehui $ -->
 	<title>Nucleus - Development Documentation</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 </head>
diff -ruN 3.24.src/nucleus/documentation/devdocs/plugins.html 3.31.src/nucleus/documentation/devdocs/plugins.html
--- 3.24.src/nucleus/documentation/devdocs/plugins.html	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/documentation/devdocs/plugins.html	2007-10-22 19:36:02.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: plugins.html,v 1.35.2.1 2005/08/15 10:51:08 dekarma Exp $ -->
+	<!-- $Id: plugins.html 1177 2007-06-22 12:37:32Z kaigreve $ -->
 	<title>Nucleus - Plugin API</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 	<style type="text/css">
@@ -30,7 +30,7 @@
 
 <div class="heading">
 Plugin API
-<i>July 27, 2005</i>
+<i>June 16, 2007</i>
 </div>
 
 <div class="note"><strong>Notes:</strong>
@@ -664,6 +664,8 @@
 		<td><dl>
 			<dt class="ref">comment</dt>
 			<dd>comment data (associative array)</dd>
+			<dt class="ref">spamcheck</dt>
+			<dd>the resulting datastructure of the previously called <code>SpamCheck</code> event (associative array)</dd>
 		</dl></td>
 	</tr>
 	<tr>
@@ -674,6 +676,8 @@
 			<dd>comment data (associative array)</dd>
 			<dt class="ref">commentid</dt>
 			<dd>comment ID</dd>
+			<dt class="ref">spamcheck</dt>
+			<dd>the resulting datastructure of the previously called <code>SpamCheck</code> event (associative array)</dd>
 		</dl></td>
 	</tr>
 	<tr>
@@ -1404,10 +1408,86 @@
 			<dd>When the plugin wants to stop the handling of the form, it needs to fill out a non-empty error string message in this <code>error</code> field. This error message will then be presented to the user.</dd>
 			<dt class="ref">comment</dt>
 			<dd>On <code>comment</code>-type forms, contains an associative array with the comment data.</dd>
+			<dt class="ref">spamcheck</dt>
+			<dd>On <code>comment</code>-type forms, the resulting datastructure of the previously called <code>SpamCheck</code> event (associative array)</dd>
 			<dt class="ro obj">member</dt>
 			<dd>On <code>activation</code>-type forms, contains information about the member being activated.</dd>
 		</dl></td>
 	</tr>
+	<tr>
+		<td>ParseURL</td>
+		<td>(v3.22) Called before an URL is resolved from the Nucleus Core. This event allows Plugins to interpret URLs.</td>
+		<td><dl>
+			<dt class="ro">type</dt>
+			<dd>Type of the page, e.g. item, blog, ...</dd>
+			<dt class="ro">info</dt>
+			<dd>The full URL which should be resolved (the name is derived from the old fashion variable <code>pathinfo</code>).</dd>
+			<dt class="ref">complete</dt>
+			<dd>Should be set to <b>true</b> if the plugin has resolved the URL and to <b>false</b> if the plugin hasn't resolved the URL.</dd>
+		</dl></td>
+	</tr>
+	<tr>
+		<td>GenerateURL</td>
+		<td>(v3.22) Called before an URL is output on the page. Allows plugins to rewrite the output URLs and offer an own URL logic.</td>
+		<td><dl>
+			<dt class="ro">type</dt>
+			<dd>Type of the page, e.g. item, blog, ...</dd>
+			<dt class="ro">params</dt>
+			<dd>Parameters which should be added to the URL.</dd>
+			<dt class="ref">completed</dt>
+			<dd>Should be set to <b>true</b> if the plugin returns an URL and to <b>false</b> if the plugin don't returns an URL.</dd>
+			<dt class="ref">url</dt>
+			<dd>The URL itself which should be output from Nucleus.</dd>
+		</dl></td>
+	</tr>
+	<tr>
+		<td>SpamCheck</td>
+		<td>(v3.3) Called when a new comment is added. This event allows anti-spam plugins to mark this comment as spam. A complete descriptions of the <code>SpamCheck</code> event can be found in a seperate document: <a href='http://wakka.xiffy.nl/spamcheck_api'>SpamCheck API 2.0</a>.</td>
+		<td><dl>
+			<dt class="ref">spamcheck</dt>
+			<dd>The spamcheck datastructure</dd>
+		</dl></td>
+	</tr>
+	<tr>
+		<td>PreMediaUpload</td>
+		<td>(v3.3) Before an uploaded media file is written to the media directory.</td>
+		<td><dl>
+			<dt class="ref">collection</dt>
+			<dd>The collection where the uploaded file should be saved.</dd>
+			<dt class="ro">uploadfile</dt>
+			<dd>The temporary name of the uploaded file.</dd>
+			<dt class="ref">filename</dt>
+			<dd>The filename under which the file should be saved.</dd>
+		</dl></td>
+	</tr>
+	<tr>
+		<td>PostMediaUpload</td>
+		<td>(v3.3) After an uploaded is written to the media directory.</td>
+		<td><dl>
+			<dt class="ro">collection</dt>
+			<dd>The collection to which the uploaded file has been added.</dd>
+			<dt class="ro">mediadir</dt>
+			<dd>The media directory to which the uploaded file has been written.</dd>
+			<dt class="ro">filename</dt>
+			<dd>The filename under which the file has been saved.</dd>
+		</dl></td>
+	</tr>
+	<tr>
+		<td>SendPing</td>
+		<td>(v3.3) Called when a new item is added and the blog is configured to send ping (need NP_Ping installed). This event is used by NP_Ping to ping various weblog listing service (i.e. pingomatic.com)</td>
+		<td><dl>
+			<dt class="ref">blogid</dt>
+			<dd>ID of the blog</dd>
+		</dl></td>
+	</tr>
+	<tr>
+		<td>JustPosted</td>
+		<td>(v3.3) Called when a future post appears on the blog the first time. The event is trigger after a skin parse is completed</td>
+		<td><dl>
+			<dt class="ref">blogid</dt>
+			<dd>ID of the blog</dd>
+		</dl></td>
+	</tr>
 <!--
 	<tr>
 		<td></td>
diff -ruN 3.24.src/nucleus/documentation/devdocs/sqltables.html 3.31.src/nucleus/documentation/devdocs/sqltables.html
--- 3.24.src/nucleus/documentation/devdocs/sqltables.html	2005-03-05 13:19:30.000000000 -0600
+++ 3.31.src/nucleus/documentation/devdocs/sqltables.html	2007-10-22 19:36:02.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: sqltables.html,v 1.9 2005/03/05 13:19:30 dekarma Exp $ -->
+	<!-- $Id: sqltables.html 1177 2007-06-22 12:37:32Z kaigreve $ -->
 	<title>Nucleus - SQL Table Structure</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 	<style type="text/css">
@@ -52,7 +52,7 @@
 
 <div class="heading">
 SQL Table Reference
-<i>March 5, 2005</i>
+<i>March 13, 2007</i>
 </div>
 
 <h1>Introduction</h1>
@@ -232,7 +232,7 @@
 	<td class="notnull toremove">bsendping</td>
 	<td>tinyint(2)</td>
 	<td>'0'</td>
-	<td>Send a ping to weblogs.com on update? (1=true/0=false)</td>
+	<td>Send a ping to various weblog listing services on update? (1=true/0=false) This option is only visible when NP_Ping plugin is installed</td>
 
 </tr><tr>
 	<td class="notnull toremove">bconvertbreaks</td>
@@ -1216,4 +1216,4 @@
 
 
 </body>
-</html>
\ No newline at end of file
+</html>
diff -ruN 3.24.src/nucleus/documentation/devdocs/xmlrpc.html 3.31.src/nucleus/documentation/devdocs/xmlrpc.html
--- 3.24.src/nucleus/documentation/devdocs/xmlrpc.html	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/documentation/devdocs/xmlrpc.html	2007-10-22 19:36:02.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: xmlrpc.html,v 1.8.2.1 2005/08/15 10:51:08 dekarma Exp $ -->
+	<!-- $Id: xmlrpc.html 777 2005-08-21 18:08:04Z dekarma $ -->
 	<title>Nucleus - XML-RPC Interface</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 </head>
diff -ruN 3.24.src/nucleus/documentation/help.html 3.31.src/nucleus/documentation/help.html
--- 3.24.src/nucleus/documentation/help.html	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/documentation/help.html	2007-10-22 19:36:04.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: help.html,v 1.28.2.1 2005/08/15 10:51:08 dekarma Exp $ -->
+	<!-- $Id: help.html 1175 2007-06-16 22:14:16Z kaigreve $ -->
 
 	<title>Nucleus Admin Help</title>
 	<style type="text/css">
@@ -1224,10 +1224,10 @@
 
 </div>
 
-<div class="page"><a name="pinguserland"></a>
-<h1>Ping Weblogs.com</h1>
+<div class="page"><a name="sendping"></a>
+<h1>Ping weblog listing services</h1>
 <p>
-When updating your weblog, you can choose to send an update notification (ping) to <a href="http://www.weblogs.com/" onclick="window.open(this.href);return false;" class="out">weblogs.com</a>. This website provides a list of recently updated weblogs to everyone who requests it. Lots of websites are using this data, so you might receive some extra hits when enabling the ping.
+When updating your weblog, you can choose to send an update notification (ping) to various weblog listing services. They provides a list of recently updated weblogs to everyone who requests it. Lots of websites are using this data, so you might receive some extra hits when enabling the ping.
 </p>
 <p class="note"><strong>Note:</strong> For this feature to work correctly, you need to fill out both the weblog URL and the weblog name in the blogsettings.
 </p>
@@ -1464,6 +1464,41 @@
 
 </div>
 
+<div class="page">
+<a name="skinvar-bloglist"></a>
+<h1>Skinvar: bloglist</h1>
+
+<p>
+Shows a list of all blogs that are defined in your Nucles CMS.
+</p>
+
+<h2>Arguments</h2>
+<p>
+	Required:
+	<ul>
+		<li><strong>template</strong>: name of the template to use</li>
+	</ul>
+	Optional:
+	<ul>
+		<li><strong>bnametype</strong>: whether the Blog Name (<code>name</code>) or the Short Blog Name (<code>shortname</code>) of the Blog is used. Default setting is the Blog name (<code>name</code>).</li>
+	</ul>
+</p>
+
+<h2>Skintypes</h2>
+
+<p>
+all
+</p>
+
+<h2>Examples</h2>
+
+<pre>
+&lt;%bloglist(default/index)%&gt;
+&lt;%bloglist(default/index,name)%&gt; 
+&lt;%bloglist(default/index,shortname)%&gt;
+</pre>
+
+</div>
 
 
 
diff -ruN 3.24.src/nucleus/documentation/history.html 3.31.src/nucleus/documentation/history.html
--- 3.24.src/nucleus/documentation/history.html	2006-05-23 19:40:10.000000000 -0500
+++ 3.31.src/nucleus/documentation/history.html	2007-10-22 19:36:04.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: history.html,v 1.187.2.5 2005/08/21 08:35:29 dekarma Exp $ -->
+	<!-- $Id: history.html 1213 2007-10-22 17:21:23Z kaigreve $ -->
 	<title>Nucleus - History</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 </head>
@@ -15,6 +15,64 @@
 
 <ul>
 	<li>
+		<b>Nucleus v3.31 (October 22, 2007)</b>
+		<ul>
+			<li>ADDED: add <code>createaccount.html</code> with a redirect to <code>createaccount.php</code> for backward compatibility with the old location of the form</li>
+			<li>CHANGED: protect the 'create account form' against abuse: show the form only if needed and add FormExtra (e.g. Captcha) and ValidateForm (to validate input) events (ftruscot and kaigreve)</li>
+			<li>FIXED: bug in upgrade script (admun)</li>
+			<li>CHANGED: update xmlrpc client to version 2.2, this version supports PHP 5.2.x (kimitake)</li>
+			<li>CHANGED: use require instead of include for the file inclusion (kimitake)</li>
+			<li>CHANGED: rollback benchmark default skin (admun)</li>
+			<li>FIXED: possible security problem in NP_Ping (admun)</li>
+		</ul>
+	</li>
+	<li>
+		<b>Nucleus v3.3 (August 7, 2007)</b>
+		<ul>
+			<li>ADDED: NP_Ping sends ping for future post via JustPosted event (admun)</li>
+			<li>ADDED: JustPosted event (admun)</li>
+			<li>ADDED: move weblogs.com ping function into plugin (admun)</li>
+			<li>ADDED: Serveral changes and fixes from Nucleus Japan (details in the log files of the <a href="http://sourceforge.net/svn/?group_id=66479">Nucleus repository</a> at sourceforge.net)</li>
+			<li>ADDED: Sanitize parameters such as $_GET and $_SERVER['REQUEST_URI'] etc. to avoid XSS (from Nucleus Japan)</li>
+			<li>ADDED: (<a href="http://nucleus-jp.sourceforge.jp/tracker/?do=details&id=45">#45</a>  from the Japanese Tracker): include code from NP_0TicketForPlugin in the core (Changes from Nucleus Japan)
+			<li>ADDED: new events for Media upload: PreMediaUpload and PostMediaUpload (kaigreve)</li>
+			<li>ADDED: new skinvar bloglist (kaigreve)</li>
+			<li>ADDED: new method for URL rewriting with the global variable virtualpath, new .htaccess file can be found in the folder extra/fancyurl-2, more information <a href="http://forum.nucleuscms.org/viewtopic.php?t=12241">here</a> (kaigreve and Legolas)</li>
+			<li>FIXED: allow + in email address, see <a href="http://forum.nucleuscms.org/viewtopic.php?t=14207">here</a> (wgroleau)</li>
+			<li>FIXED: XHTML compliance in default skin (admun)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=80&amp;do=details">#80</a>): Atom 1.0 support (rakaz)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=129&amp;do=details">#129</a>): Plugin API: SpamCheck event called from core. (rakaz)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=128&amp;do=details">#128</a>): Don't show DISALLOWED(XXXX) errors (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=127&amp;do=details">#127</a>): parse_commentform: double-escaped URLs (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=121&amp;do=details">#121</a>): backup fails when <code>$plugin-&gt;getTableList()</code> doesn't return an array (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=118&amp;do=details">#118</a>): Errors in default skin (legolas)</li>
+			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=119&amp;do=details">#119</a>): Added optional includeMode/includePrefix parameters to <code>parseFile()</code> (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=115&amp;do=details">#115</a>): Redundant database queries on member table (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=114&amp;do=details">#114</a>): Magic quotes not correctly undone when <code>magic_quotes_sybase</code> enabled (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=104&amp;do=details">#104</a>): Return to blogsettings - link missing on edit category</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=107&amp;do=details">#107</a>): Better path detection in install.php (dekarma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=106&amp;do=details">#106</a>): Make 'Log Out' link under Comment box work with Fancy URLs (Wendy Smoak)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=99&amp;do=details">#99</a>): Use workaround when the only installed MySQL PHP extension is mysqli (dekarma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=98&amp;do=details">#98</a>): More "Fatal error: Only variables can be passed by reference" occurrences on some installations (pete)</li>
+			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=23&amp;do=details">#23</a>): adding email/url + email field display in blog comment list (admun)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=12">#12</a>): item id and timestamp were not sent along with <code>GenerateURL</code> event when <code>itemlink</code> called from commentvars (karma)</li>
+			<li>CHANGED: Now using XML-RPC for PHP (phpxmlrpc) v1.2.1</li>
+			<li>FIXED: (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=97">#97</a>): file uploads didn't check <code>$_FILES['file']['error']</code> codes. (dekarma)</li>
+			<li>CHANGED: Update user instruction for Blogger conversion tool</li>
+			<li>ADDED: When an e-mail is provided in the comment-form it is validated. (TeRanEX)</li>
+			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?id=23&amp;do=details">#23</a>): Splitted the URL &amp; E-mail field in comments. (gRegor, ketsugi, Red Dalek, TeRanEX)</li>
+			<li>ADDED: (bug 817364): delete member enhancement (admun)</li>
+			<li>ADDED: Auto save draft (Legolas)</li>
+			<li>ADDED: Custom skin parts (tutorio)</li>
+		</ul>
+	</li>
+	<li>
+		<b>Nucleus v3.24 (November 11, 2006)</b>
+		<ul>
+			<li>FIXED: XSS issue (reported by <a href="http://www.jpcert.or.jp/">JPCERT/CC</a>).</li>
+		</ul>
+	</li>
+	<li>
 		<b>Nucleus v3.23 (May 23, 2006)</b>
 		<ul>
 			<li>FIXED: Remote code execution vulnerability (reported by rgod).</li>
@@ -25,32 +83,32 @@
 		<ul>
 			<li>FIXED: Major security vulnerability in the phpxmlrpc library.</li>
 			<li>FIXED: New NP_SkinFiles version, fixing a minor security issue. (rakaz)</li>
-			<li>CHANGED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=17">#17</a>): An errormessage is now displayed when logon through loginform failed. (karma)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=91">#91</a>): Initialize variables in MEMBER class (andrew)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=90">#90</a>): there was no plugin callback on member edits when the email address changed (andrew)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=90">#90</a>): when editing members other than yourself, you shouldn't be logged out (andrew)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=85">#85</a>): If both <code>itemid</code> and <code>catid</code> are specified in the URL, ignore <code>catid</code> if it doesn't match <code>itemid</code> (karma)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=49">#49</a>): 'name clashes' warning on skin import no longer displayed when no clashes detected (karma)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=67">#67</a>): Add resilency to upgrade scripts (Frankenstein)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=88">#88</a>): PHP5.1: "Fatal error: Only variables can be passed by reference" (karma)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=87">#87</a>): Translate &amp; -> &amp;amp; when links added via toolbar (karma)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=42">#42</a>): <code>formatDate</code> didn't always use the correct timezone (karma)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=43">#43</a>): Only load user language file when logged in (karma).</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=76">#76</a>): Disabling site blocked admin menu access (karma).</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=57">#57</a>): PostRegister event not fired from inside admin area.</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=58">#58</a>): images and popups were not in feeds. (karma)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=33">#33</a>): add item form invalid ticket error (admun)</li>
+			<li>CHANGED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=17">#17</a>): An errormessage is now displayed when logon through loginform failed. (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=91">#91</a>): Initialize variables in MEMBER class (andrew)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=90">#90</a>): there was no plugin callback on member edits when the email address changed (andrew)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=90">#90</a>): when editing members other than yourself, you shouldn't be logged out (andrew)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=85">#85</a>): If both <code>itemid</code> and <code>catid</code> are specified in the URL, ignore <code>catid</code> if it doesn't match <code>itemid</code> (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=49">#49</a>): 'name clashes' warning on skin import no longer displayed when no clashes detected (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=67">#67</a>): Add resilency to upgrade scripts (Frankenstein)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=88">#88</a>): PHP5.1: "Fatal error: Only variables can be passed by reference" (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=87">#87</a>): Translate &amp; -> &amp;amp; when links added via toolbar (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=42">#42</a>): <code>formatDate</code> didn't always use the correct timezone (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=43">#43</a>): Only load user language file when logged in (karma).</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=76">#76</a>): Disabling site blocked admin menu access (karma).</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=57">#57</a>): PostRegister event not fired from inside admin area.</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=58">#58</a>): images and popups were not in feeds. (karma)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=33">#33</a>): add item form invalid ticket error (admun)</li>
 			<li>FIXED: Most buttons of the toolbar reset the scroll position of the textarea to the top in Firefox (leonbloy)</li>
-			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=64">#64</a>): Applications that use the metaweblogAPI, such as Ecto can now also access and edit the extended body (rakaz)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=63">#63</a>): _getArrayVal() always returned first element of array (rakaz)</li>
+			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=64">#64</a>): Applications that use the metaweblogAPI, such as Ecto can now also access and edit the extended body (rakaz)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=63">#63</a>): _getArrayVal() always returned first element of array (rakaz)</li>
 			<li>ADDED: add InitSkinParse event (rakaz)</li>
-			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=38">#38</a>): added alternative output for &lt;%title%&gt;, &lt;%itemtitle%&gt;, &lt;%previtemtitle%&gt; and &lt;%nextitemtitle%&gt; (rakaz)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=51">#51</a>): removed hardcoded charset declaration from the RSS 2 skin (rakaz)</li>
-			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=55">#55</a>): add &lt;%skinvar%&gt; variable that corresponds with _CHARSET (rakaz)</li>
-			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=24">#24</a>): add PostUpdateItem event (admun)</li>
-			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=48">#48</a>):  &lt;%if(nextitem)%&gt; and &lt;%nextlink%&gt; didn't use the timezone offset. (<a href="http://forum.nucleuscms.org/viewtopic.php?t=6371">Basic</a>)</li>
-			<li>FIXED: "ADMIN.php line 5270" fatal error when plugin filename and plugin classname mismtach (Frankenstein)</li>
-			<li>CHANGED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&id=16">#16</a>): Event <code>PreSkinItem</code> can now modify the skin contents; <code>PreComment</code> now knows the ItemID. (<a href="http://forum.nucleuscms.org/viewtopic.php?t=6266">suggested</a> by Andy)</li>
+			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=38">#38</a>): added alternative output for &lt;%title%&gt;, &lt;%itemtitle%&gt;, &lt;%previtemtitle%&gt; and &lt;%nextitemtitle%&gt; (rakaz)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=51">#51</a>): removed hardcoded charset declaration from the RSS 2 skin (rakaz)</li>
+			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=55">#55</a>): add &lt;%skinvar%&gt; variable that corresponds with _CHARSET (rakaz)</li>
+			<li>ADDED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=24">#24</a>): add PostUpdateItem event (admun)</li>
+			<li>FIXED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=48">#48</a>):  &lt;%if(nextitem)%&gt; and &lt;%nextlink%&gt; didn't use the timezone offset. (<a href="http://forum.nucleuscms.org/viewtopic.php?t=6371">Basic</a>)</li>
+			<li>FIXED: "ADMIN.php line 5270" fatal error when plugin filename and plugin classname mismatch (Frankenstein)</li>
+			<li>CHANGED (<a href="http://dev.nucleuscms.org/tracker/index.php?do=details&amp;id=16">#16</a>): Event <code>PreSkinItem</code> can now modify the skin contents; <code>PreComment</code> now knows the ItemID. (<a href="http://forum.nucleuscms.org/viewtopic.php?t=6266">suggested</a> by Andy)</li>
 		</ul>
 	</li>
 	<li>
diff -ruN 3.24.src/nucleus/documentation/index.html 3.31.src/nucleus/documentation/index.html
--- 3.24.src/nucleus/documentation/index.html	2005-03-05 13:19:30.000000000 -0600
+++ 3.31.src/nucleus/documentation/index.html	2007-10-22 19:36:04.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: index.html,v 1.36 2005/03/05 13:19:29 dekarma Exp $ -->
+	<!-- $Id: index.html 1175 2007-06-16 22:14:16Z kaigreve $ -->
 	<title>Nucleus CMS - Manual</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 </head>
@@ -9,7 +9,7 @@
 
 <div class="heading">
 Nucleus CMS Manual
-<i>(v3.2)</i>
+<i>(v3.3)</i>
 </div>
 
 <div class="note">
@@ -95,7 +95,7 @@
 <p>
 Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
 <br />
-Copyright (C) 2002-2005 The Nucleus Group
+Copyright (C) 2002-2007 The Nucleus Group
 </p>
 
 <p>This program is free software; you can redistribute it and/or
@@ -352,7 +352,7 @@
 </p>
 
 <ul>
-	<li>At the time of release, there are officially supported blog conversion tools available for Nucleus v3.0. We do have a set of code with which you can start, and are providing <a href="http://nucleuscms.org/convert.php">pointers to the import tools created by others</a>.</li>
+	<li>At the time of release, there are officially supported blog conversion tools available for Nucleus v3.3. We do have a set of code with which you can start, and are providing <a href="http://nucleuscms.org/convert.php">pointers to the import tools created by others</a>. A good starting point is also the Nucleus Forum section <a href="http://forum.nucleuscms.org/viewforum.php?f=17">Import Questions</a>. Because all blog system have a different structure it isn't possible to convert each system in another without a possible loss of information. The script authors try to minimize troubles and loss of information.</li>
 	<li>Ctrl + Shift + A shortcut might conflict with ICQ/Trillian</li>
 	<li>When PHP is running in SAFE mode, it's very likely that there will be problems when using the media directory (Nucleus will not be able to automatically detect image sizes, or disallow uploading)</li>
 	<li>Entities can get messed up in the RSS channel (e.g. &amp;amp; becomes &amp;amp;amp;)</li>
@@ -376,9 +376,18 @@
 <h2>Code submissions</h2>
 
 <ul>
-	<li>Jeroen Budts</li>
+	<li>Andy Matsubara</li>
+	<li>Armon Toubman</li>
 	<li>Edmond Hui</li>
-	<li>Appie Verschoor (Fulltext search)</li>
+	<li>gRegor alias gregorlove</li>
+	<li>Kai Greve alias kg</li>
+	<li>Joel Pan alias ketsugi</li>
+	<li>Kimitake</li>
+	<li>Legolas</li>
+	<li>Niels Leenheer alias rakaz</li>
+	<li>Rodrigo Moraes</li>
+	<li>Jeroen Budts</li>
+	<li>Appie Verschoor alias xiffy (Fulltext search)</li>
 	<li>Many others... (check the <a href="history.html">history</a>)</li>
 </ul>
 
diff -ruN 3.24.src/nucleus/documentation/skins.html 3.31.src/nucleus/documentation/skins.html
--- 3.24.src/nucleus/documentation/skins.html	2004-08-05 09:50:50.000000000 -0500
+++ 3.31.src/nucleus/documentation/skins.html	2007-10-22 19:36:04.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: skins.html,v 1.6 2004/08/05 07:50:50 dekarma Exp $ -->
+	<!-- $Id: skins.html 756 2005-08-11 20:28:57Z ehui $ -->
 	<title>Nucleus - Skins and Templates</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 </head>
diff -ruN 3.24.src/nucleus/documentation/tips.html 3.31.src/nucleus/documentation/tips.html
--- 3.24.src/nucleus/documentation/tips.html	2004-08-05 09:50:50.000000000 -0500
+++ 3.31.src/nucleus/documentation/tips.html	2007-10-22 19:36:04.000000000 -0500
@@ -3,13 +3,14 @@
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: tips.html,v 1.9 2004/08/05 07:50:50 dekarma Exp $ -->
+	<!-- $Id: tips.html 1207 2007-10-04 23:14:09Z kaigreve $ -->
 	<title>Nucleus - Tips and suggestions</title>
 	<link rel="stylesheet" type="text/css" href="styles/manual.css" />
 </head>
 <body>
 
 <div class="heading">
+<a name="top" />
 Tips &amp; Suggestions
 </div>
 
@@ -31,17 +32,18 @@
 		<ul>
 			<li><a href="#searchengines-fancyurls">Fancy URLs</a></li>
 			<li><a href="#searchengines-rewrite">mod_rewrite</a></li>
+			<li><a href="#fancyurls-2">Fancy URLs 2</a></li>
 		</ul>
 	</li>
 	<li><a href="#filepermissions">How to set file/dir permissions?</a></li>
 	<li><a href="#backups">How to restore backups</a></li>
 	<li><a href="#newblog">How to create a new weblogs</a></li>
 	<li><a href="#xhtml">XHTML support</a></li>
+	<li><a href="#specialskinpart">How to create a Special skin part</a></li>
 <!--
 	<li><a href="#"></a></li>
 	<li><a href="#"></a></li>
 	<li><a href="#"></a></li>
-	<li><a href="#"></a></li>
 -->
 </ul>
 
@@ -69,10 +71,11 @@
 <ol>
 	<li><a href="#searchengines-fancyurls">Fancy URLs</a></li>
 	<li><a href="#searchengines-rewrite">mod_rewrite</a></li>
+	<li><a href="#fancyurls-2">Fancy URLs 2</a></li>
 </ol>
 
-<a name="searchengines-fancyurls"></a>
-<h2>Fancy URLs</h2>
+
+<h2><a name="searchengines-fancyurls"></a>Fancy URLs</h2>
 
 <p>Nucleus v2.0 has a new option in the global settings 'URL mode'. Setting it to 'Fancy URL' mode, and performing the steps below, will make your URLs look like <code>http://example.org/item/1234</code> instead of <code>http://example.org/index.php?itemid=1234</code>. Search engines like these URLs better.</p>
 
@@ -90,8 +93,8 @@
 <p>When it doesn't work (e.g. you receive an Internal Server Error): bad luck... Remove the files again (don't forget the hidden file <code>.htaccess</code>) and reset the Fancy URLs setting in the admin area.</p>
 
 
-<a name="searchengines-rewrite"></a>
-<h2>mod_rewrite</h2>
+
+<h2><a name="searchengines-rewrite"></a>mod_rewrite</h2>
 
 <p>
 This second possible solution will only work on servers running Apache, and when you have the right to do so. What we will do is 'disguise' the archives as regular HTML pages
@@ -125,6 +128,20 @@
 </p>
 
 
+<h2><a name="fancyurls-2"></a>Fancy URLs 2</h2>
+
+<p>Nucleus CMS version 3.3 offers an easier way to enable the basic Fancy URLs. There are only three steps necessary to install this solution:</p>
+
+<ol><li>Copy or move the <code>.htaccess</code> file from <code>extra/fancyurl-2</code> to the root directory of your Nucleus CMS installation.</li>
+<li>Edit the <code>index.php</code> file which you can find in your root directory. Change value of the <code>CONF['Self']</code> from the  default value (<code>'index.php'</code>) to the URL that points to your root directory, for example:<br />
+<pre>CONF['Self'] = 'http://yourdomain.com/yourNucleusDirectory';</pre>
+Don't use a slash at the end.<br /></li>
+<li>Enable the 'Fancy URLs' in the Nucleus admin area, you can find this setting under <em>Management &gt; Configuration</em>.</li></ol>
+
+<p>Everything done.</p>
+
+<p>If you want to use rewritten URLs like <code>item/this-is-a-title</code> you can find plugin solutions for it in the Nucleus Plugin Wiki, for example <a href="http://wakka.xiffy.nl/fancierurl2">NP_FancierURL2</a>.</p>
+
 <h1>How to set file/dir permissions <a name="filepermissions" href="#top" class="toplink"><img src="icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
 
 <p>
@@ -276,5 +293,59 @@
 
 
 
+
+
+
+
+
+
+
+
+<h1>How to create a Special skin part <a name="specialskinpart" href="#top" class="toplink"><img src="icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
+
+<p>1. Enter the Nucleus admin area and go to Skins management page (<strong>Layout>Skins</strong>). Find your skin and click the Edit link in the right column.</p>
+
+<p>2. Under the list of skin parts there is a sections called Special skin parts. In the field type the name of your special skin part and then click the Create button. (I'm using the name 'About' for my example). You then get a Edit skin part form, just like for any other skin part, that you can add content, skin variables or anything else. If you want to make it look like the rest of your site, you can copy the contents of the Main Index skinpart here and replace the <code>&lt;%body(...)%&gt;</code> skin variable with the contents of the static page.<br />
+<br />
+For example, using the default skin, the contents of the About skin part would look something like this:</p>
+<pre><code>&lt;%parsedinclude(head.inc)%&gt;
+
+&lt;!-- page header --&gt;
+&lt;%parsedinclude(header.inc)%&gt;
+
+&lt;!-- page content --&gt;
+&lt;div id="container"&gt;
+&lt;div class="content"&gt;
+This site is run by a group of friends who all enjoy hiking. Together we have
+hiked a total of over 4000 miles though out the US, Canada and Europe. Here we
+share our experiences and our experience. Though we are serious hikers, we
+believe hiking should first be fun for everybody.
+&lt;br /&gt;&lt;br /&gt;
+To join our community, please register here: (...link to registration page...)
+&lt;br /&gt;&lt;br /&gt;
+... insert links to images of hiking fun...
+&lt;/div&gt;
+&lt;/div&gt;
+
+&lt;!-- page menu --&gt;
+&lt;h2 class="hidden"&gt;Sidebar&lt;/h2&gt;
+&lt;div id="sidebarcontainer"&gt;
+&lt;%parsedinclude(sidebar.inc)%&gt;
+&lt;/div&gt;
+
+&lt;!-- page footer --&gt;
+&lt;%parsedinclude(footer.inc)%&gt;</code></pre>
+
+<p>3. Now to access this page, you would point your browser (or put a link in your skin somewhere) to </p>
+
+<pre><code>www.yourdomain.tld/index.php?special=About</code></pre>
+
+
+<p>4. You can edit this skin part just as you would any other skin part and most skin variables and plugins will probably work.</p>
+
+<p><strong>Note:</strong> You may want to keep your static content in a file called <code>About.html</code> in the <code>skins/default/</code> directory (if using the default skin) and instead of typing the content of the page in the skin part, just put <code>&lt;%include(About.html)%&gt;</code>. There's almost no restriction on what these pages can contain.</p>
+
+<p>(Tip from  <a href="http://www.iai.com/">ftruscot</a>)</p>
+
 </body>
 </html>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/forgotpassword.html 3.31.src/nucleus/forgotpassword.html
--- 3.24.src/nucleus/forgotpassword.html	2005-03-05 13:19:24.000000000 -0600
+++ 3.31.src/nucleus/forgotpassword.html	2007-10-22 19:36:04.000000000 -0500
@@ -1,7 +1,7 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
-	<!-- $Id: forgotpassword.html,v 1.8 2005/03/05 13:19:24 dekarma Exp $ -->
+	<!-- $Id: forgotpassword.html 1123 2007-02-21 15:20:36Z kimitake $ -->
 	<title>Nucleus - Forgotten Password</title>
 	<style type="text/css">
 	<!--
@@ -10,41 +10,37 @@
 	</style>
 </head>
 <body>
-		<div class="header">
-		<h1>Nucleus</h1>
-		</div>
-		<div id="content">
+	<div class="header">
+	<h1>Nucleus CMS</h1>
+	</div>
+
+	<div id="content">
+
+		<h2>Forgot your password?</h2>
 
-			<h2>Forgot your password?</h2>
+		<p>Enter your username and email address below, and you'll be sent an e-mail with a link where you can choose a new password.</p>
 
+		<form method="post" action="../action.php">
 			<p>
-			Enter your username and email address below, and you'll be sent an e-mail with a link where you can choose a new password.
-			</p>
+				<label for="nucleus_pf_username">Username:</label><br />
+				<input type="text" name="name" id="nucleus_pf_username" /><br />
 
-			<form method="post" action="../action.php"><p>
-				<input name="action" value="forgotpassword" type="hidden" />
-				Name:
-				<br />
-				<input name="name" />
-				<br />
-				E-mail address:
+				<label for="nucleus_pf_email">Email address:</label><br />
+				<input type="text" name="email" id="nucleus_pf_email" /><br />
 				<br />
-				<input name="email" />
-				<br />
-				<br />
-				<input type="submit" value="Send Activation Link" class="transparent" />
-			</p></form>
 
-			<p>
-			If you don't remember your exact username, contact the site administrator.
+				<input type="hidden" name="action" value="forgotpassword" />
+				<input type="submit" value="Send Activation Link" class="transparent" />
 			</p>
+		</form>
 
+		<p>If you don't remember your exact username, contact the site administrator.</p>
 
-			<div class="foot">
-				<a href="http://nucleuscms.org/">Nucleus &copy; 2001-2005 The Nucleus Group</a>
-			</div>
+		<div class="foot">
+			<a href="http://nucleuscms.org/">Nucleus &copy; 2001-2007 The Nucleus Group</a>
+		</div>
 
-		</div><!-- content -->
+	</div>
 
 </body>
-</html>
\ No newline at end of file
+</html>
diff -ruN 3.24.src/nucleus/forms/commentform-loggedin.template 3.31.src/nucleus/forms/commentform-loggedin.template
--- 3.24.src/nucleus/forms/commentform-loggedin.template	2004-08-09 15:15:58.000000000 -0500
+++ 3.31.src/nucleus/forms/commentform-loggedin.template	2007-10-22 19:35:58.000000000 -0500
@@ -1,19 +1,18 @@
 <a id="nucleus_cf"></a>
 <form method="post" action="#nucleus_cf">
-  <div class="commentform">
-  	<%errordiv%>
-  	
-	<input type="hidden" name="action" value="addcomment" />
-	<input type="hidden" name="url" value="<%formdata(destinationurl)%>" />
-	<input type="hidden" name="itemid" value="<%itemid%>" />
-	<label for="nucleus_cf_body"><%text(_COMMENTFORM_COMMENT)%></label>:
-	<br />
-	<textarea name="body" class="formfield" cols="40" rows="10" id="nucleus_cf_body"><%formdata(body)%></textarea>
-	<br />
-	<%text(_COMMENTFORM_YOUARE)%> <%formdata(membername)%>
-	<small>(<a href="?action=logout"><%text(_LOGOUT)%></a>)</small>
-	<br />
-	<input type="submit" value="<%text(_COMMENTFORM_SUBMIT)%>" class="formbutton" />
-	<%callback(FormExtra,commentform-loggedin)%>	
-  </div>
-</form>
\ No newline at end of file
+	<div class="commentform">
+<input type="hidden" name="action" value="addcomment" />
+<input type="hidden" name="url" value="<%formdata(destinationurl)%>" />
+<input type="hidden" name="itemid" value="<%itemid%>" />
+		<%errordiv%>
+		<label for="nucleus_cf_body"><%text(_COMMENTFORM_COMMENT)%></label>
+		<textarea name="body" class="formfield" cols="40" rows="10" id="nucleus_cf_body"><%formdata(body)%></textarea>
+
+		<%text(_COMMENTFORM_YOUARE)%> <%formdata(membername)%>
+		<small>(<a href="<%self%>?action=logout" title="<%text(_LOGOUT)%>"><%text(_LOGOUT)%></a>)</small>
+
+		<input type="submit" alt="<%text(_COMMENTFORM_SUBMIT)%>" value="<%text(_COMMENTFORM_SUBMIT)%>" class="formbutton" />
+
+		<%callback(FormExtra,commentform-loggedin)%>
+	</div>
+</form>
diff -ruN 3.24.src/nucleus/forms/commentform-notloggedin.template 3.31.src/nucleus/forms/commentform-notloggedin.template
--- 3.24.src/nucleus/forms/commentform-notloggedin.template	2004-08-09 15:15:58.000000000 -0500
+++ 3.31.src/nucleus/forms/commentform-notloggedin.template	2007-10-22 19:36:00.000000000 -0500
@@ -1,25 +1,28 @@
 <a id="nucleus_cf"></a>
-<form method="post" action="#nucleus_cf"> 
-  <div class="commentform">
+<form method="post" action="#nucleus_cf">
+	<div class="commentform">
+<input type="hidden" name="action" value="addcomment" />
+<input type="hidden" name="url" value="<%formdata(destinationurl)%>" />
+<input type="hidden" name="itemid" value="<%itemid%>" />
+		<%errordiv%>
 
-  	<%errordiv%>
+		<label for="nucleus_cf_body"><%text(_COMMENTFORM_COMMENT)%></label>
+		<textarea name="body" class="formfield" cols="40" rows="10" id="nucleus_cf_body"><%formdata(body)%></textarea>
 
-	<input type="hidden" name="action" value="addcomment" />
-	<input type="hidden" name="url" value="<%formdata(destinationurl)%>" />
-	<input type="hidden" name="itemid" value="<%itemid%>" />
-	<label for="nucleus_cf_body"><%text(_COMMENTFORM_COMMENT)%></label>:
-	<br />
-	<textarea name="body" class="formfield" cols="40" rows="10" id="nucleus_cf_body"><%formdata(body)%></textarea>
-	<br />
-	<label for="nucleus_cf_name"><%text(_COMMENTFORM_NAME)%></label>: <input name="user" size="40" maxlength="40" value="<%formdata(user)%>" class="formfield" id="nucleus_cf_name" />
-	<br />
-	<label for="nucleus_cf_mail"><%text(_COMMENTFORM_MAIL)%></label>: <input name="userid" size="40" maxlength="60" value="<%formdata(userid)%>" class="formfield" id="nucleus_cf_mail" />
-
-	<%callback(FormExtra,commentform-notloggedin)%>	
-	
-	<br />
-	<input type="checkbox" value="1" name="remember" id="nucleus_cf_remember" <%formdata(rememberchecked)%> /><label for="nucleus_cf_remember"><%text(_COMMENTFORM_REMEMBER)%></label>
-	<br />
-	<input type="submit" value="<%text(_COMMENTFORM_SUBMIT)%>" class="formbutton" />
-  </div>
-</form>
\ No newline at end of file
+		<label for="nucleus_cf_name"><%text(_COMMENTFORM_NAME)%></label>
+		<input name="user" size="40" maxlength="40" value="<%formdata(user)%>" class="formfield" id="nucleus_cf_name" />
+
+		<label for="nucleus_cf_mail"><%text(_COMMENTFORM_MAIL)%></label>
+		<input name="userid" size="40" maxlength="60" value="<%formdata(userid)%>" class="formfield" id="nucleus_cf_mail" />
+
+		<label for="nucleus_cf_email"><%text(_COMMENTFORM_EMAIL)%></label>
+		<input name="email" size="40" maxlength="100" value="<%formdata(email)%>" class="formfield" id="nucleus_cf_email" />
+
+		<%callback(FormExtra,commentform-notloggedin)%>
+
+		<input type="checkbox" value="1" name="remember" id="nucleus_cf_remember" <%formdata(rememberchecked)%> />
+		<label for="nucleus_cf_remember"><%text(_COMMENTFORM_REMEMBER)%></label>
+
+		<input type="submit" alt="<%text(_COMMENTFORM_SUBMIT)%>" value="<%text(_COMMENTFORM_SUBMIT)%>" class="formbutton" />
+	</div>
+</form>
diff -ruN 3.24.src/nucleus/forms/loginform-loggedin.template 3.31.src/nucleus/forms/loginform-loggedin.template
--- 3.24.src/nucleus/forms/loginform-loggedin.template	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/forms/loginform-loggedin.template	2007-10-22 19:36:00.000000000 -0500
@@ -1,4 +1,4 @@
 <a id="nucleus_lf"></a>
 <div class="loginform">
-	<%text(_LOGINFORM_YOUARE)%> <%formdata(membername)%> ! (<a href="<%self%>?action=logout"><%text(_LOGOUT)%></a>)
+	<%text(_LOGINFORM_YOUARE)%> <%formdata(membername)%> ! (<a href="<%self%>?action=logout" title="<%text(_LOGOUT)%>"><%text(_LOGOUT)%></a>)
 </div>
diff -ruN 3.24.src/nucleus/forms/loginform-notloggedin.template 3.31.src/nucleus/forms/loginform-notloggedin.template
--- 3.24.src/nucleus/forms/loginform-notloggedin.template	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/forms/loginform-notloggedin.template	2007-10-22 19:36:00.000000000 -0500
@@ -1,16 +1,18 @@
 <a id="nucleus_lf"></a>
 <form method="post" action="#nucleus_lf">
-  <div class="loginform">
-  
-  	<%errordiv%>
-  
-	<input type="hidden" name="action" value="login" />
-	<label for="nucleus_lf_name" accesskey="l"><%text(_LOGINFORM_NAME)%></label>: <input id="nucleus_lf_name" name="login" size="10" value="" class="formfield" />
-	<br />
-	<label for="nucleus_lf_pwd"><%text(_LOGINFORM_PWD)%></label>: <input id="nucleus_lf_pwd" name="password" size="10" type="password" value="" class="formfield" />
-	<br />
-	<input type="submit" value="<%text(_LOGIN)%>" class="formbutton" />
-	<br />
-	<input type="checkbox" value="1" name="shared" id="nucleus_lf_shared" /><label for="nucleus_lf_shared"><%text(_LOGINFORM_SHARED)%></label>
-  </div>
-</form>
\ No newline at end of file
+	<div class="loginform">
+<input type="hidden" name="action" value="login" />
+		<%errordiv%>
+
+		<label for="nucleus_lf_name" accesskey="l"><%text(_LOGINFORM_NAME)%></label>
+		<input id="nucleus_lf_name" name="login" size="10" value="" class="formfield" />
+
+		<label for="nucleus_lf_pwd"><%text(_LOGINFORM_PWD)%></label>
+		<input id="nucleus_lf_pwd" name="password" size="10" type="password" value="" class="formfield" />
+
+		<input type="checkbox" value="1" name="shared" id="nucleus_lf_shared" />
+		<label for="nucleus_lf_shared"><%text(_LOGINFORM_SHARED)%></label>
+
+		<input type="submit" alt="<%text(_LOGIN)%>" value="<%text(_LOGIN)%>" class="formbutton" />
+	</div>
+</form>
diff -ruN 3.24.src/nucleus/forms/membermailform-loggedin.template 3.31.src/nucleus/forms/membermailform-loggedin.template
--- 3.24.src/nucleus/forms/membermailform-loggedin.template	2004-08-09 15:15:58.000000000 -0500
+++ 3.31.src/nucleus/forms/membermailform-loggedin.template	2007-10-22 19:36:00.000000000 -0500
@@ -1,19 +1,15 @@
 <a id="nucleus_mf"></a>
 <form method="post" action="#nucleus_mf">
-  <div class="mailform">
-  	<%errordiv%>
-  
-	<input type="hidden" name="memberid" value="<%formdata(memberid)%>" />
-	<input type="hidden" name="action" value="sendmessage" />
+	<div class="mailform">
+<input type="hidden" name="memberid" value="<%formdata(memberid)%>" />
+<input type="hidden" name="action" value="sendmessage" />
+<input type="hidden" name="url" value="<%formdata(url)%>" />
+		<%errordiv%>
 
-	<input type="hidden" name="url" value="<%formdata(url)%>" />
+		<textarea alt="<%text(_MMAIL_MAIL)%>" name="message" class="formfield" rows="<%formdata(rows)%>" cols="<%formdata(cols)%>"><%formdata(message)%></textarea>
 
-	<textarea name="message" class="formfield" rows="<%formdata(rows)%>" cols="<%formdata(cols)%>"><%formdata(message)%></textarea>
+		<%callback(FormExtra,membermailform-loggedin)%>
 
-	<%callback(FormExtra,membermailform-loggedin)%>	
-	
-	<br />
-	<input type="submit" value="<%text(_MEMBERMAIL_SUBMIT)%>" class="formbutton" />
-	
-  </div>
-</form>		
+		<input type="submit" alt="<%text(_MEMBERMAIL_SUBMIT)%>" value="<%text(_MEMBERMAIL_SUBMIT)%>" class="formbutton" />
+	</div>
+</form>
diff -ruN 3.24.src/nucleus/forms/membermailform-notloggedin.template 3.31.src/nucleus/forms/membermailform-notloggedin.template
--- 3.24.src/nucleus/forms/membermailform-notloggedin.template	2004-08-09 15:15:58.000000000 -0500
+++ 3.31.src/nucleus/forms/membermailform-notloggedin.template	2007-10-22 19:35:58.000000000 -0500
@@ -1,20 +1,18 @@
 <a id="nucleus_mf"></a>
 <form method="post" action="#nucleus_mf">
-  <div class="mailform">
-  	<%errordiv%>
-  	
-	<input type="hidden" name="memberid" value="<%formdata(memberid)%>" />
-	<input type="hidden" name="action" value="sendmessage" />
+	<div class="mailform">
+<input type="hidden" name="memberid" value="<%formdata(memberid)%>" />
+<input type="hidden" name="action" value="sendmessage" />
+<input type="hidden" name="url" value="<%formdata(url)%>" />
+		<%errordiv%>
 
-	<input type="hidden" name="url" value="<%formdata(url)%>" />
+		<textarea alt="<%text(_MMAIL_MAIL)%>" name="message" class="formfield" rows="<%formdata(rows)%>" cols="<%formdata(cols)%>"><%formdata(message)%></textarea>
 
-	<textarea name="message" class="formfield" rows="<%formdata(rows)%>" cols="<%formdata(cols)%>"><%formdata(message)%></textarea>
-	<br />
-	<%text(_MEMBERMAIL_MAIL)%><input type="text" name="frommail" class="formfield" value="<%formdata(frommail)%>" />
-	
-	<%callback(FormExtra,membermailform-notloggedin)%>	
-	
-	<br />
-	<input type="submit" value="<%text(_MEMBERMAIL_SUBMIT)%>" class="formbutton" />
-  </div>
-</form>		
+		<label for="nucleus_mmf_frommail"><%text(_MEMBERMAIL_MAIL)%></label>
+		<input id="nucleus_mmf_frommail" type="text" name="frommail" class="formfield" value="<%formdata(frommail)%>" />
+
+		<%callback(FormExtra,membermailform-notloggedin)%>
+
+		<input type="submit" alt="<%text(_MEMBERMAIL_SUBMIT)%>" value="<%text(_MEMBERMAIL_SUBMIT)%>" class="formbutton" />
+	</div>
+</form>
diff -ruN 3.24.src/nucleus/forms/nucleusbutton.template 3.31.src/nucleus/forms/nucleusbutton.template
--- 3.24.src/nucleus/forms/nucleusbutton.template	2005-02-26 11:56:18.000000000 -0600
+++ 3.31.src/nucleus/forms/nucleusbutton.template	2007-10-22 19:35:58.000000000 -0500
@@ -1,3 +1,3 @@
 <div class="nucleusbutton">
-<a href="http://nucleuscms.org/"><img src="<%formdata(imgurl)%>" width="<%formdata(imgwidth)%>" height="<%formdata(imgheight)%>" alt="Powered by Nucleus CMS" /></a>
+	<a href="http://nucleuscms.org/"><img src="<%formdata(imgurl)%>" width="<%formdata(imgwidth)%>" height="<%formdata(imgheight)%>" alt="Powered by Nucleus CMS" title="Powered by Nucleus CMS" /></a>
 </div>
diff -ruN 3.24.src/nucleus/forms/searchform.template 3.31.src/nucleus/forms/searchform.template
--- 3.24.src/nucleus/forms/searchform.template	2002-11-16 15:19:42.000000000 -0600
+++ 3.31.src/nucleus/forms/searchform.template	2007-10-22 19:35:58.000000000 -0500
@@ -1,9 +1,8 @@
 <form method="get" action="<%self%>">
-  <div class="searchform">
-	<input name="query" class="formfield" size="10" maxlength="60" accesskey="4" value="<%formdata(query)%>" />
-	<input type="hidden" name="amount" value="0" />
-	<input type="hidden" name="blogid" value="<%formdata(id)%>" />
-	<br />
-	<input type="submit" value="<%text(_SEARCHFORM_SUBMIT)%>" class="formbutton" />
-  </div>
+	<div class="searchform">
+<input type="hidden" name="amount" value="0" />
+<input type="hidden" name="blogid" value="<%formdata(id)%>" />
+		<input name="query" alt="<%text(_SEARCHFORM_QUERY)%>" class="formfield" size="10" maxlength="60" accesskey="4" value="<%formdata(query)%>" />
+		<input type="submit" alt="<%text(_SEARCHFORM_SUBMIT)%>" value="<%text(_SEARCHFORM_SUBMIT)%>" class="formbutton" />
+	</div>
 </form>
diff -ruN 3.24.src/nucleus/index.php 3.31.src/nucleus/index.php
--- 3.24.src/nucleus/index.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/index.php	2007-10-22 19:36:04.000000000 -0500
@@ -1,19 +1,19 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: index.php,v 1.16.2.1 2005/08/15 10:51:08 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: index.php 1176 2007-06-16 22:27:17Z kaigreve $
+ */
 	// we are using admin stuff:
 	$CONF = array();
 	$CONF['UsingAdminArea'] = 1;
@@ -50,10 +50,10 @@
 
 	$bNeedsLogin = false;
 	$bIsActivation = in_array($action, array('activate', 'activatesetpwd'));
-	
-	if ($action == 'logout') 
-		$bNeedsLogin = true;	
-	
+
+	if ($action == 'logout')
+		$bNeedsLogin = true;
+
 	if (!$member->isLoggedIn() && !$bIsActivation)
 		$bNeedsLogin = true;
 
@@ -62,15 +62,15 @@
 		$error = _ERROR_LOGINDISALLOWED;
 		$bNeedsLogin = true;
 	}
-	
+
 	if ($bNeedsLogin)
 	{
 		setOldAction($action);	// see ADMIN::login() (sets old action in POST vars)
 		$action = 'showlogin';
 	}
 
-	sendContentType('application/xhtml+xml', 'admin-' . $action);
-	
+	sendContentType('text/html', 'admin-' . $action);
+
 	$admin = new ADMIN();
 	$admin->action($action);
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/javascript/admin.js 3.31.src/nucleus/javascript/admin.js
--- 3.24.src/nucleus/javascript/admin.js	2004-12-28 16:57:30.000000000 -0600
+++ 3.31.src/nucleus/javascript/admin.js	2007-10-22 19:36:02.000000000 -0500
@@ -1,6 +1,6 @@
 /**
   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
+  * Copyright (C) 2002-2007 The Nucleus Group
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
@@ -10,7 +10,7 @@
   *  
   * Some JavaScript code for the admin area
   *
-  * $Id: admin.js,v 1.4 2004/12/28 16:57:29 dekarma Exp $
+  * $Id: admin.js 1143 2007-05-10 08:39:46Z kimitake $
   */
 
 function help(url) {
@@ -45,4 +45,15 @@
 	}
 	return false;					
 }
+function selectCanLogin(flag) {
+	if (flag) {
+		window.document.memberedit.canlogin[0].checked=true;
 
+		// don't disable canlogin[0], otherwise the value won't be passed.
+//		window.document.memberedit.canlogin[0].disabled=true;
+		window.document.memberedit.canlogin[1].disabled=true;
+	} else {
+		window.document.memberedit.canlogin[0].disabled=false;
+		window.document.memberedit.canlogin[1].disabled=false;
+	}
+}
diff -ruN 3.24.src/nucleus/javascript/bookmarklet.js 3.31.src/nucleus/javascript/bookmarklet.js
--- 3.24.src/nucleus/javascript/bookmarklet.js	2004-12-28 16:57:30.000000000 -0600
+++ 3.31.src/nucleus/javascript/bookmarklet.js	2007-10-22 19:36:02.000000000 -0500
@@ -1,6 +1,6 @@
 /**
   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
+  * Copyright (C) 2002-2007 The Nucleus Group
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
@@ -10,7 +10,7 @@
   *  
   * Some JavaScript code for the bookmarklets
   *
-  * $Id: bookmarklet.js,v 1.5 2004/12/28 16:57:29 dekarma Exp $
+  * $Id: bookmarklet.js 1116 2007-02-03 08:24:29Z kimitake $
   */
 
 /**
diff -ruN 3.24.src/nucleus/javascript/compatibility.js 3.31.src/nucleus/javascript/compatibility.js
--- 3.24.src/nucleus/javascript/compatibility.js	2004-12-28 16:57:30.000000000 -0600
+++ 3.31.src/nucleus/javascript/compatibility.js	2007-10-22 19:36:02.000000000 -0500
@@ -1,6 +1,6 @@
 /**
   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
+  * Copyright (C) 2002-2007 The Nucleus Group
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
@@ -18,7 +18,7 @@
   *
   * That's basically it :)
   *
-  * $Id: compatibility.js,v 1.4 2004/12/28 16:57:29 dekarma Exp $
+  * $Id: compatibility.js 1116 2007-02-03 08:24:29Z kimitake $
   */
 
 // to get the script working when page is sent as application/xhtml+xml
diff -ruN 3.24.src/nucleus/javascript/edit.js 3.31.src/nucleus/javascript/edit.js
--- 3.24.src/nucleus/javascript/edit.js	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/javascript/edit.js	2007-10-22 19:36:02.000000000 -0500
@@ -1,6 +1,6 @@
 /**
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
+  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+  * Copyright (C) 2002-2007 The Nucleus Group
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
@@ -11,7 +11,7 @@
   * This file contains functions to allow adding items from inside the weblog.
   * Also contains code to avoid submitting form data twice.
   *
-  * $Id: edit.js,v 1.9.2.1 2005/08/15 10:51:08 dekarma Exp $
+  * $Id: edit.js 1116 2007-02-03 08:24:29Z kimitake $
   */
 
 var nucleusConvertBreaks = true;
@@ -27,17 +27,17 @@
 function preview(id, value) {
 	elem = document.getElementById(id);
 	if (!elem) return;
-	
-	var preview = nucleusConvertBreaks ? str_replace("\n","<br />",value)+"&nbsp;" : value+"&nbsp;";
-	
+
+	var preview = nucleusConvertBreaks ? str_replace("\n","<br />",value)+"&#160;" : value+"&#160;";
+
 	// expand the media commands (without explicit collection)
 	preview = preview.replace(/\<\%image\(([^\/\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<img src='"+nucleusMediaURL+nucleusAuthorId+"/$1' width='$2' height='$3' alt=\"$4\" />");
-	
+
 	// expand the media commands (with collection)
 	preview = preview.replace(/\<\%image\(([^\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<img src='"+nucleusMediaURL+"$1' width='$2' height='$3' alt=\"$4\" />");
 	preview = preview.replace(/\<\%popup\(([^\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<a href='' onclick='if (event &amp;&amp; event.preventDefault) event.preventDefault(); alert(\"popup image\"); return false;' title='popup'>$4</a>");
-	preview = preview.replace(/\<\%media\(([^\|]*)\|([^)]*)\)\%\>/g,"<a href='' title='media link'>$2</a>");	
-	
+	preview = preview.replace(/\<\%media\(([^\|]*)\|([^)]*)\)\%\>/g,"<a href='' title='media link'>$2</a>");
+
 	elem.innerHTML = preview;
 }
 
@@ -50,7 +50,7 @@
 	document.getElementById('edit').style.display = newval;
 
 	if (newval == "block")
-		updAllPreviews();	
+		updAllPreviews();
 }
 
 function updAllPreviews() {
@@ -69,7 +69,7 @@
 function updPreview(id) {
 	// don't update when preview is hidden
 	if (!isEditVisible()) return;
-	
+
 	var inputField = document.getElementById('input' + id);
 	if (!inputField) return;
 	preview('prev' + id, inputField.value);
@@ -86,7 +86,7 @@
 
 function shortCuts() {
 	if (!event || (event.ctrlKey != true)) return;
-	
+
 	switch (event.keyCode) {
 		case 1:
 			ahrefThis(); break; // ctrl-shift-a
@@ -96,7 +96,7 @@
 			italicThis(); break; // ctrl-shift-i
 		case 13:
 			addMedia(); break; // ctrl-shift-m
-		default: 
+		default:
 			return;
 	}
 	return;
@@ -119,17 +119,17 @@
 		strSelection = document.selection.createRange().text;
 	else
 		strSelection = '';
-		
+
 	strHref = prompt("Create a link to:","http://");
 	if (strHref == null) return;
-	
+
 	var textpre = "<a href=\"" + strHref.replace(/&/g,'&amp;') + "\">";
 	insertAroundCaret(textpre, "</a>");
 }
 
 function execAndUpdate(action) {
 	lastSelected.caretPos.execCommand(action);
-	updAllPreviews();	
+	updAllPreviews();
 }
 
 
@@ -137,12 +137,12 @@
 
 // Add media to new item
 function addMedia() {
-	
+
 	var mediapopup = window.open(nucleusMediaPopupURL + 'media.php','name',
 		'status=yes,toolbar=no,scrollbars=yes,resizable=yes,width=500,height=450,top=0,left=0');
 
 	return;
-} 
+}
 
 
 function setMediaPopupURL(url) {
@@ -155,7 +155,7 @@
 	} else {
 		text = getCaretText();
 	}
-	
+
 	// add collection name when not private collection (or editing a message that's not your)
 	var fullName;
 	if (isNaN(collection) || (nucleusAuthorId != collection)) {
@@ -163,8 +163,8 @@
 	} else {
 		fullName = filename;
 	}
-		
-	
+
+
 	var replaceBy;
 	switch(type) {
 		case 'popup':
@@ -174,9 +174,9 @@
 		default:
 			replaceBy = '<%image(' +  fullName + '|'+width+'|'+height+'|' + text +')%>';
 	}
-	
+
 	insertAtCaret(replaceBy);
-	updAllPreviews();	
+	updAllPreviews();
 
 }
 
@@ -187,19 +187,19 @@
 	} else {
 		text = getCaretText();
 	}
-	
+
 	// add collection name when not private collection (or editing a message that's not your)
 	var fullName;
 	if (isNaN(collection) || (nucleusAuthorId != collection)) {
 		fullName = collection + '/' + filename;
 	} else {
 		fullName = filename;
-	}	
-	
+	}
+
 	var replaceBy = '<%media(' +  fullName + '|' + text +')%>';
-	
+
 	insertAtCaret(replaceBy);
-	updAllPreviews();	
+	updAllPreviews();
 }
 
 
@@ -224,12 +224,12 @@
 function storeCaret (textEl) {
 
 	// store caret
-	if (textEl.createTextRange) 
+	if (textEl.createTextRange)
 		textEl.caretPos = document.selection.createRange().duplicate();
 
 	// also store lastselectedelement
 	lastSelected = textEl;
-	
+
 	nonie_FormType = textEl.name;
 
 	scrollTop = textEl.scrollTop;
@@ -237,21 +237,21 @@
 
 var lastSelected;
 
-// inserts text at caret (overwriting selection)
+ // inserts text at caret (overwriting selection)
 function insertAtCaret (text) {
 	var textEl = lastSelected;
 	if (textEl && textEl.createTextRange && textEl.caretPos) {
 		var caretPos = textEl.caretPos;
 		caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text;
 	} else if (!document.all && document.getElementById) {
-		mozReplace(document.getElementById('input' + nonie_FormType), text);				
+		mozReplace(document.getElementById('input' + nonie_FormType), text);
 		if(scrollTop>-1) {
 			document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
 		}
 	} else if (textEl) {
 		textEl.value  += text;
 	} else {
-		document.getElementById('input' + nonie_FormType).value += text;		
+		document.getElementById('input' + nonie_FormType).value += text;
 		if(scrollTop>-1) {
 			document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
 		}
@@ -259,15 +259,15 @@
 	updAllPreviews();
 }
 
-// inserts a tag around the selected text
+ // inserts a tag around the selected text
 function insertAroundCaret (textpre, textpost) {
 	var textEl = lastSelected;
-	
+
 	if (textEl && textEl.createTextRange && textEl.caretPos) {
 		var caretPos = textEl.caretPos;
 		caretPos.text = textpre + caretPos.text + textpost;
 	} else if (!document.all && document.getElementById) {
-		mozWrap(document.getElementById('input' + nonie_FormType), textpre, textpost);		
+		mozWrap(document.getElementById('input' + nonie_FormType), textpre, textpost);
 		if(scrollTop>-1) {
 			document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
 		}
diff -ruN 3.24.src/nucleus/javascript/numbercheck.js 3.31.src/nucleus/javascript/numbercheck.js
--- 3.24.src/nucleus/javascript/numbercheck.js	2004-12-28 16:57:30.000000000 -0600
+++ 3.31.src/nucleus/javascript/numbercheck.js	2007-10-22 19:36:02.000000000 -0500
@@ -1,6 +1,6 @@
 /**
   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
+  * Copyright (C) 2002-2007 The Nucleus Group
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
@@ -11,7 +11,7 @@
   * script the check (on the clientside) if a entered value
   * is a valid number and remove the invalid chars
   *
-  * $Id: numbercheck.js,v 1.3 2004/12/28 16:57:29 dekarma Exp $
+  * $Id: numbercheck.js 1116 2007-02-03 08:24:29Z kimitake $
   */
 
 function checkNumeric(f)
diff -ruN 3.24.src/nucleus/javascript/opennew.js 3.31.src/nucleus/javascript/opennew.js
--- 3.24.src/nucleus/javascript/opennew.js	2004-12-28 16:57:30.000000000 -0600
+++ 3.31.src/nucleus/javascript/opennew.js	2007-10-22 19:36:02.000000000 -0500
@@ -1,6 +1,6 @@
 /*
  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
- * Copyright (C) 2002-2005 The Nucleus Group
+ * Copyright (C) 2002-2007 The Nucleus Group
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -8,7 +8,7 @@
  * of the License, or (at your option) any later version.
  * (see nucleus/documentation/index.html#license for more info)
  *
- * $Id: opennew.js,v 1.4 2004/12/28 16:57:29 dekarma Exp $
+ * $Id: opennew.js 1116 2007-02-03 08:24:29Z kimitake $
  *
  * JavaScript to open non-local links in a new window.
  *
diff -ruN 3.24.src/nucleus/javascript/templateEdit.js 3.31.src/nucleus/javascript/templateEdit.js
--- 3.24.src/nucleus/javascript/templateEdit.js	2004-12-28 16:57:30.000000000 -0600
+++ 3.31.src/nucleus/javascript/templateEdit.js	2007-10-22 19:36:02.000000000 -0500
@@ -1,6 +1,6 @@
 /**
   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
+  * Copyright (C) 2002-2007 The Nucleus Group
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
@@ -12,7 +12,7 @@
   *
   * @require compatibility.js
   *
-  * $Id: templateEdit.js,v 1.5 2004/12/28 16:57:29 dekarma Exp $
+  * $Id: templateEdit.js 1116 2007-02-03 08:24:29Z kimitake $
   */
 
 var amountOfFields = 1;
diff -ruN 3.24.src/nucleus/javascript/xmlhttprequest.js 3.31.src/nucleus/javascript/xmlhttprequest.js
--- 3.24.src/nucleus/javascript/xmlhttprequest.js	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/javascript/xmlhttprequest.js	2007-10-22 19:36:02.000000000 -0500
@@ -0,0 +1,183 @@
+/**
+  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
+  * Copyright (C) 2002-2007 The Nucleus Group
+  *
+  * 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.
+  * (see nucleus/documentation/index.html#license for more info)
+  *
+  *
+  * This page contains xmlHTTPRequest functions for:
+  * - AutoSaveDraft
+  *
+  *
+  * Usage:
+  * - Add in the page before the form open tag:
+  *     <script type="text/javascript" src="javascript/xmlhttprequest.js"></script>
+  * - Add in the page behind the form close tag:
+  *     var xmlhttprequest = new Array();
+  *     xmlhttprequest[0] = createHTTPHandler(); // AutoDraft handler
+  *     xmlhttprequest[1] = createHTTPHandler(); // UpdateTicket handler
+  *     var seconds = now(); // Last AutoDraft time
+  *     var checks = 0; // Number of checks since last AutoDraft
+  *     var addform = document.getElementById('addform'); // The form id
+  *     var goal = document.getElementById('lastsaved'); // The html div id where 'Last saved: date time' must come
+  *     var goalurl = 'action.php'; // The PHP file where the content must be posted to (action.php)
+  *     var lastsavedtext = 'Last saved'; // The language variable for 'Last saved'
+  *     var formtype = 'add'; // Add or edit form
+  * - Add to the form tag:
+  *     id="addform"
+  * - Add to the textarea's and text fields:
+  *     onkeyup="doMonitor();"
+  * - Add tot the selectboxes and radio buttons
+  *     onchange="doMonitor();"
+  * - Add to the form:
+  *     <input type="hidden" name="draftid" value="0" />
+  * - Optionally a autosave now button can be add:
+  *     <input type="button" name="autosavenow" value="AutoSave now" onclick="autoSaveDraft();" />
+  *
+  *
+  * $Id: xmlhttprequest.js 1116 2007-02-03 08:24:29Z kimitake $
+  */
+
+/**
+ * Creates the xmlHTTPRequest handler
+ */
+function createHTTPHandler() {
+	var httphandler = false;
+	/*@cc_on @*/
+	/*@if (@_jscript_version >= 5)
+		// JScript gives us Conditional compilation, we can cope with old IE versions.
+		// and security blocked creation of the objects.
+		try {
+			httphandler = new ActiveXObject("Msxml2.XMLHTTP");
+		}
+		catch (e) {
+			try {
+				httphandler = new ActiveXObject("Microsoft.XMLHTTP");
+			}
+			catch (E) {
+				httphandler = false;
+			}
+		}
+	@end @*/
+	if (!httphandler && typeof XMLHttpRequest != 'undefined') {
+		httphandler = new XMLHttpRequest();
+	}
+	return httphandler;
+}
+
+/**
+ * Auto saves as draft
+ */
+function autoSaveDraft() {
+	checks = 0;
+	seconds = now();
+
+	var title = encodeURI(addform.title.value);
+	var body = encodeURI(addform.body.value);
+	var catid = addform.catid.options[addform.catid.selectedIndex].value;
+	var more = encodeURI(addform.more.value);
+	var closed = 0;
+	if (addform.closed[0].checked) {
+		closed = addform.closed[0].value;
+	}
+	else if (addform.closed[1].checked) {
+		closed = addform.closed[1].value;
+	}
+	var ticket = addform.ticket.value;
+
+	var querystring = 'action=autodraft';
+	querystring += '&title=' + title;
+	querystring += '&body=' + body;
+	querystring += '&catid=' + catid;
+	querystring += '&more=' + more;
+	querystring += '&closed=' + closed;
+	querystring += '&ticket=' + ticket;
+	if (formtype == 'edit') {
+		querystring += '&itemid=' + addform.itemid.value;
+		querystring += '&type=edit';
+	}
+	else {
+		querystring += '&blogid=' + addform.blogid.value;
+		querystring += '&type=add';
+	}
+	if (addform.draftid.value > 0) {
+		querystring += '&draftid=' + addform.draftid.value;
+	}
+
+	xmlhttprequest[0].open('POST', goalurl, true);
+	xmlhttprequest[0].onreadystatechange = checkMonitor;
+	xmlhttprequest[0].setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+	xmlhttprequest[0].send(querystring);
+
+	var querystring = 'action=updateticket&ticket=' + ticket;
+
+	xmlhttprequest[1].open('POST', goalurl, true);
+	xmlhttprequest[1].onreadystatechange = updateTicket;
+	xmlhttprequest[1].setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+	xmlhttprequest[1].send(querystring);
+}
+
+/**
+ * Monitors the edits
+ */
+function doMonitor() {
+	if (checks * (now() - seconds) > 120 * 1000 * 50) {
+		autoSaveDraft();
+	}
+	else {
+		checks++;
+	}
+}
+
+/**
+ * Checks the process of the saving
+ */
+function checkMonitor() {
+	if (xmlhttprequest[0].readyState == 4) {
+		if (xmlhttprequest[0].responseText) {
+			if (xmlhttprequest[0].responseText.substr(0, 4) == 'err:') {
+				goal.innerHTML = xmlhttprequest[0].responseText.substr(4) + ' (' + formattedDate() + ')';
+			}
+			else {
+				addform.draftid.value = xmlhttprequest[0].responseText;
+				goal.innerHTML = lastsavedtext + ' ' + formattedDate();
+			}
+		}
+	}
+}
+
+/**
+ * Checks the process of the ticket updating
+ */
+function updateTicket() {
+	if (xmlhttprequest[1].readyState == 4) {
+		if (xmlhttprequest[1].responseText) {
+			if (xmlhttprequest[1].responseText.substr(0, 4) == 'err:') {
+				goal.innerHTML = xmlhttprequest[1].responseText.substr(4) + ' (' + formattedDate() + ')';
+			}
+			else {
+				addform.ticket.value = xmlhttprequest[1].responseText;
+			}
+		}
+	}
+}
+
+/**
+ * Gets now in milliseconds
+ */
+function now() {
+	var now = new Date();
+	return now.getTime();
+}
+
+/**
+ * Gets now in the local dateformat
+ */
+function formattedDate() {
+	var now = new Date();
+	return now.toLocaleDateString() + ' ' + now.toLocaleTimeString();
+}
\ No newline at end of file
diff -ruN 3.24.src/nucleus/language/english.php 3.31.src/nucleus/language/english.php
--- 3.24.src/nucleus/language/english.php	2005-03-01 23:17:46.000000000 -0600
+++ 3.31.src/nucleus/language/english.php	2007-10-22 19:35:58.000000000 -0500
@@ -12,6 +12,27 @@
 // Fully translated language file can be sent to us and will be made
 // available for download (with proper credit to the author, of course)
 
+// START changed/added after 3.3 START
+define('_AUTOSAVEDRAFT',		'Auto save draft');
+define('_AUTOSAVEDRAFT_LASTSAVED',	'Last saved: ');
+define('_AUTOSAVEDRAFT_NOTYETSAVED',	'No saves have been made yet');
+define('_AUTOSAVEDRAFT_NOW',		'Auto save now');
+define('_SKIN_PARTS_SPECIAL',		'Special skin parts');
+define('_ERROR_SKIN_PARTS_SPECIAL_FORMAT',		'You must enter a name that exists only out of lowercase letters and digits');
+define('_ERROR_SKIN_PARTS_SPECIAL_DELETE',		'Can\'t delete this skin part');
+define('_CONFIRMTXT_SKIN_PARTS_SPECIAL',		'Do you really want to delete this special skin part?');
+define('_ERROR_PLUGIN_LOAD',		'Plugin could not be loaded, or does not support certain features that are required for it to run on your Nucleus installation (you might want to check the <a href="?action=actionlog">actionlog</a> for more info)');
+// END changed/added after 3.3 END
+
+// START changed/added after 3.22 START
+define('_SEARCHFORM_QUERY',			'Keywords to search');
+define('_ERROR_EMAIL_REQUIRED',		'Email address is required');
+define('_COMMENTFORM_MAIL',			'Website:');
+define('_COMMENTFORM_EMAIL',		'E-mail:');
+define('_EBLOG_REQUIREDEMAIL',		'Require E-mail address with comments?');
+define('_ERROR_COMMENTS_SPAM',      'Your comment was rejected because it did not pass the spam test');
+// END changed/added after 3.22 END
+
 // START changed/added after 3.15 START
 
 define('_LIST_PLUG_SUBS_NEEDUPDATE','Please use the \'Update Subscription list\'-button to update the plugin\'s subscription list.');
@@ -98,12 +119,12 @@
 define('_QMENU_HOME',				'Home');
 define('_QMENU_ADD',				'Add Item');
 define('_QMENU_ADD_SELECT',			'-- select --');
-define('_QMENU_USER_SETTINGS',		'Settings');
+define('_QMENU_USER_SETTINGS',		'Profile');
 define('_QMENU_USER_ITEMS',			'Items');
 define('_QMENU_USER_COMMENTS',		'Comments');
 define('_QMENU_MANAGE',				'Management');
 define('_QMENU_MANAGE_LOG',			'Action Log');
-define('_QMENU_MANAGE_SETTINGS',	'Global Settings');
+define('_QMENU_MANAGE_SETTINGS',	'Configuration');
 define('_QMENU_MANAGE_MEMBERS',		'Members');
 define('_QMENU_MANAGE_NEWBLOG',		'New Weblog');
 define('_QMENU_MANAGE_BACKUPS',		'Backups');
@@ -445,14 +466,13 @@
 // commentform
 define('_COMMENTFORM_YOUARE',		'You are');
 define('_COMMENTFORM_SUBMIT',		'Add Comment');
-define('_COMMENTFORM_COMMENT',		'Your comment');
-define('_COMMENTFORM_NAME',			'Name');
-define('_COMMENTFORM_MAIL',			'E-mail/HTTP');
+define('_COMMENTFORM_COMMENT',		'Your comment:');
+define('_COMMENTFORM_NAME',			'Name:');
 define('_COMMENTFORM_REMEMBER',		'Remember Me');
 
 // loginform
-define('_LOGINFORM_NAME',			'Username');
-define('_LOGINFORM_PWD',			'Password');
+define('_LOGINFORM_NAME',			'Username:');
+define('_LOGINFORM_PWD',			'Password:');
 define('_LOGINFORM_YOUARE',			'Logged in as');
 define('_LOGINFORM_SHARED',			'Shared Computer');
 
@@ -555,7 +575,7 @@
 define('_ERROR_DUPSHORTBLOGNAME',	'Another blog already has the chosen short name. These names should be unique');
 define('_ERROR_UPDATEFILE',			'Cannot get write access to the update-file. Make sure the file permissions are set ok (try chmodding it to 666). Also note that the location is relative to the admin-area directory, so you might want to use an absolute path (something like /your/path/to/nucleus/)');
 define('_ERROR_DELDEFBLOG',			'Cannot delete the default blog');
-define('_ERROR_DELETEMEMBER',		'This member cannot be deleted, probably because she is the author of items or comments');
+define('_ERROR_DELETEMEMBER',		'This member cannot be deleted, probably because he/she is the author of item(s)');
 define('_ERROR_BADTEMPLATENAME',	'Invalid name for template, use only a-z and 0-9, without spaces');
 define('_ERROR_DUPTEMPLATENAME',	'Another template with this name already exists');
 define('_ERROR_BADSKINNAME',		'Invalid name for skin (only a-z, 0-9 are allowed, no spaces)');
@@ -654,7 +674,7 @@
 define('_EBLOG_NOTIFY_COMMENT',		'New comments');
 define('_EBLOG_NOTIFY_KARMA',		'New karma votes');
 define('_EBLOG_NOTIFY_ITEM',		'New weblog items');
-define('_EBLOG_PING',				'Ping Weblogs.com on update?');
+define('_EBLOG_PING',				'Ping weblog listing service on update?');
 define('_EBLOG_MAXCOMMENTS',		'Max Amount of comments');
 define('_EBLOG_UPDATE',				'Update file');
 define('_EBLOG_OFFSET',				'Time Offset');
diff -ruN 3.24.src/nucleus/language/english-utf8.php 3.31.src/nucleus/language/english-utf8.php
--- 3.24.src/nucleus/language/english-utf8.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/language/english-utf8.php	2007-10-22 19:35:58.000000000 -0500
@@ -0,0 +1,976 @@
+<?php
+// English Nucleus Language File
+// 
+// Author: Wouter Demuynck
+// Nucleus version: v1.0-v3.2
+//
+// Please note: if you want to translate this file to your own language, be aware
+// that in a next Nucleus version, new variables might be added and some other ones
+// might be deleted. Therefor, it's important to list the Nucleus version for which 
+// the file was written in your document.
+//
+// Fully translated language file can be sent to us and will be made
+// available for download (with proper credit to the author, of course)
+
+// START changed/added after 3.3 START
+define('_AUTOSAVEDRAFT',                'Auto save draft');
+define('_AUTOSAVEDRAFT_LASTSAVED',      'Last saved: ');
+define('_AUTOSAVEDRAFT_NOTYETSAVED',    'No saves have been made yet');
+define('_AUTOSAVEDRAFT_NOW',            'Auto save now');
+define('_SKIN_PARTS_SPECIAL',           'Special skin parts');
+define('_ERROR_SKIN_PARTS_SPECIAL_FORMAT',              'You must enter a name that exists only out of lowercase letters and digits');
+define('_ERROR_SKIN_PARTS_SPECIAL_DELETE',              'Can\'t delete this skin part');
+define('_CONFIRMTXT_SKIN_PARTS_SPECIAL',                'Do you really want to delete this special skin part?');
+define('_ERROR_PLUGIN_LOAD',            'Plugin could not be loaded, or does not support certain features that are required for it to run on your
+Nucleus installation (you might want to check the <a href="?action=actionlog">actionlog</a> for more info)');
+// END changed/added after 3.3 END
+
+// START changed/added after 3.22 START
+define('_SEARCHFORM_QUERY',                     'Keywords to search');
+define('_ERROR_EMAIL_REQUIRED',         'Email address is required');
+define('_COMMENTFORM_MAIL',                     'Website:');
+define('_COMMENTFORM_EMAIL',            'E-mail:');
+define('_EBLOG_REQUIREDEMAIL',          'Require E-mail address with comments?');
+define('_ERROR_COMMENTS_SPAM',      'Your comment was rejected because it did not pass the spam test');
+// END changed/added after 3.22 END
+
+// START changed/added after 3.15 START
+
+define('_LIST_PLUG_SUBS_NEEDUPDATE','Please use the \'Update Subscription list\'-button to update the plugin\'s subscription list.');
+define('_LIST_PLUGS_DEP',			'Plugin(s) requires:');
+
+// END changed/added after 3.15
+
+// START changed/added after 3.1 START
+
+// comments list per weblog
+define('_COMMENTS_BLOG',			'All Comments for blog');
+define('_NOCOMMENTS_BLOG',			'No comments were made on items of this blog');
+define('_BLOGLIST_COMMENTS',		'Comments');
+define('_BLOGLIST_TT_COMMENTS',		'A list of all comments made on items of this blog');
+
+
+// for use in archivetype-skinvar
+define('_ARCHIVETYPE_DAY',			'day');
+define('_ARCHIVETYPE_MONTH',		'month');
+
+// tickets (prevents malicious users to trick an admin to perform actions he doesn't want)
+define('_ERROR_BADTICKET',			'Invalid or expired ticket.');
+
+// plugin dependency
+define('_ERROR_INSREQPLUGIN',		'Plugin installation failed, requires ');
+define('_ERROR_DELREQPLUGIN',		'Plugin deletion failed, required by ');
+
+// cookie prefix
+define('_SETTINGS_COOKIEPREFIX',	'Cookie Prefix');
+
+// account activation
+define('_ERROR_NOLOGON_NOACTIVATE',	'Cannot send activation link. You\'re not allowed to log in.');
+define('_ERROR_ACTIVATE',			'Activation key does not exist, is invalid, or has expired.');
+define('_ACTIONLOG_ACTIVATIONLINK', 'Activation link sent');
+define('_MSG_ACTIVATION_SENT',		'An activation link has been sent by e-mail.');
+
+// activation link emails
+define('_ACTIVATE_REGISTER_MAIL',	"Hi <%memberName%>,\n\nYou need to activate your account at <%siteName%> (<%siteUrl%>).\nYou can do this by visiting the link below: \n\n\t<%activationUrl%>\n\nYou have 2 days to do this. After this, the activation link becomes invalid.");
+define('_ACTIVATE_REGISTER_MAILTITLE',	"Activate your '<%memberName%>' account");
+define('_ACTIVATE_REGISTER_TITLE',	'Welcome <%memberName%>');
+define('_ACTIVATE_REGISTER_TEXT',	'You\'re almost there. Please choose a password for your account below.');
+define('_ACTIVATE_FORGOT_MAIL',		"Hi <%memberName%>,\n\nUsing the link below, you can choose a new password for your account at <%siteName%> (<%siteUrl%>) by choosing a new password.\n\n\t<%activationUrl%>\n\nYou have 2 days to do this. After this, the activation link becomes invalid.");
+define('_ACTIVATE_FORGOT_MAILTITLE',"Re-activate your '<%memberName%>' account");
+define('_ACTIVATE_FORGOT_TITLE',	'Welcome <%memberName%>');
+define('_ACTIVATE_FORGOT_TEXT',		'You can choose a new password for your account below:');
+define('_ACTIVATE_CHANGE_MAIL',		"Hi <%memberName%>,\n\nSince your e-mail address has changed, you'll need to re-activate your account at <%siteName%> (<%siteUrl%>).\nYou can do this by visiting the link below: \n\n\t<%activationUrl%>\n\nYou have 2 days to do this. After this, the activation link becomes invalid.");
+define('_ACTIVATE_CHANGE_MAILTITLE',"Re-activate your '<%memberName%>' account");
+define('_ACTIVATE_CHANGE_TITLE',	'Welcome <%memberName%>');
+define('_ACTIVATE_CHANGE_TEXT',		'Your address change has been verified. Thanks!');
+define('_ACTIVATE_SUCCESS_TITLE',	'Activation Succeeded');
+define('_ACTIVATE_SUCCESS_TEXT',	'Your account has been successfully activated.');
+define('_MEMBERS_SETPWD',			'Set Password');
+define('_MEMBERS_SETPWD_BTN',		'Set Password');
+define('_QMENU_ACTIVATE',			'Account Activation');
+define('_QMENU_ACTIVATE_TEXT',		'<p>After you have activated your account, you can start using it by <a href="index.php?action=showlogin">logging in</a>.</p>');
+
+define('_PLUGS_BTN_UPDATE',			'Update subscription list');
+
+// global settings
+define('_SETTINGS_JSTOOLBAR',		'Javascript Toolbar Style');
+define('_SETTINGS_JSTOOLBAR_FULL',	'Full Toolbar (IE)');
+define('_SETTINGS_JSTOOLBAR_SIMPLE','Simple Toolbar (Non-IE)');
+define('_SETTINGS_JSTOOLBAR_NONE',	'Disable Toolbar');
+define('_SETTINGS_URLMODE_HELP',	'(Info: <a href="documentation/tips.html#searchengines-fancyurls">How to activate fancy URLs</a>)');
+
+// extra plugin settings part when editing categories/members/blogs/...
+define('_PLUGINS_EXTRA',			'Extra Plugin Settings');
+
+// itemlist info column keys
+define('_LIST_ITEM_BLOG',			'blog:');
+define('_LIST_ITEM_CAT',			'cat:');
+define('_LIST_ITEM_AUTHOR',			'author:');
+define('_LIST_ITEM_DATE',			'date:');
+define('_LIST_ITEM_TIME',			'time:');
+
+// indication of registered members in comments list
+define('_LIST_COMMENTS_MEMBER', 	'(member)');
+
+// batch operations
+define('_BATCH_WITH_SEL',			'With selected:');
+define('_BATCH_EXEC',				'Execute');
+
+// quickmenu
+define('_QMENU_HOME',				'Home');
+define('_QMENU_ADD',				'Add Item');
+define('_QMENU_ADD_SELECT',			'-- select --');
+define('_QMENU_USER_SETTINGS',		'Settings');
+define('_QMENU_USER_ITEMS',			'Items');
+define('_QMENU_USER_COMMENTS',		'Comments');
+define('_QMENU_MANAGE',				'Management');
+define('_QMENU_MANAGE_LOG',			'Action Log');
+define('_QMENU_MANAGE_SETTINGS',	'Global Settings');
+define('_QMENU_MANAGE_MEMBERS',		'Members');
+define('_QMENU_MANAGE_NEWBLOG',		'New Weblog');
+define('_QMENU_MANAGE_BACKUPS',		'Backups');
+define('_QMENU_MANAGE_PLUGINS',		'Plugins');
+define('_QMENU_LAYOUT',				'Layout');
+define('_QMENU_LAYOUT_SKINS',		'Skins');
+define('_QMENU_LAYOUT_TEMPL',		'Templates');
+define('_QMENU_LAYOUT_IEXPORT',		'Import/Export');
+define('_QMENU_PLUGINS',			'Plugins');
+
+// quickmenu on logon screen
+define('_QMENU_INTRO',				'Introduction');
+define('_QMENU_INTRO_TEXT',			'<p>This is the logon screen for Nucleus CMS, the content management system that\'s being used to maintain this website.</p><p>If you have an account, you can log on and start posting new items.</p>');
+
+// helppages for plugins
+define('_ERROR_PLUGNOHELPFILE',		'The helpfile for this plugin can not be found');
+define('_PLUGS_HELP_TITLE',			'Helppage for plugin');
+define('_LIST_PLUGS_HELP', 			'help');
+
+
+// END changed/started after 3.1
+
+// START changed/added after v2.5beta START
+
+// general settings (security)
+define('_SETTINGS_EXTAUTH',			'Enable External Authentication');
+define('_WARNING_EXTAUTH',			'Warning: Enable only if needed.');
+
+// member profile
+define('_MEMBERS_BYPASS',			'Use External Authentication');
+
+// 'always include in search' blog setting (yes/no) [in v2.5beta, the 'always' part wasn't clear]
+define('_EBLOG_SEARCH',				'<em>Always</em> include in search');
+
+// END changed/added after v2.5beta
+
+// START introduced after v2.0 START
+
+// media library
+define('_MEDIA_VIEW',				'view');
+define('_MEDIA_VIEW_TT',			'View file (opens in new window)');
+define('_MEDIA_FILTER_APPLY',		'Apply Filter');
+define('_MEDIA_FILTER_LABEL',		'Filter: ');
+define('_MEDIA_UPLOAD_TO',			'Upload to...');
+define('_MEDIA_UPLOAD_NEW',			'Upload new file...');
+define('_MEDIA_COLLECTION_SELECT',	'Select');
+define('_MEDIA_COLLECTION_TT',		'Switch to this category');
+define('_MEDIA_COLLECTION_LABEL',	'Current collection: ');
+
+// tooltips on toolbar
+define('_ADD_ALIGNLEFT_TT',			'Align Left');
+define('_ADD_ALIGNRIGHT_TT',		'Align Right');
+define('_ADD_ALIGNCENTER_TT',		'Align Center');
+
+
+// generic upload failure
+define('_ERROR_UPLOADFAILED',		'Upload failed');
+
+// END introduced after v2.0 END
+
+// START introduced after v1.5 START
+
+// posting to the past/edit timestamps
+define('_EBLOG_ALLOWPASTPOSTING',	'Allow posting to the past');
+define('_ADD_CHANGEDATE',			'Update timestamp');
+define('_BMLET_CHANGEDATE',			'Update timestamp');
+
+// skin import/export
+define('_OVERVIEW_SKINIMPORT',		'Skin import/export...');
+
+// skin settings
+define('_PARSER_INCMODE_NORMAL',	'Normal');
+define('_PARSER_INCMODE_SKINDIR',	'Use skin dir');
+define('_SKIN_INCLUDE_MODE',		'Include mode');
+define('_SKIN_INCLUDE_PREFIX',		'Include prefix');
+
+// global settings
+define('_SETTINGS_BASESKIN',		'Base Skin');
+define('_SETTINGS_SKINSURL',		'Skins URL');
+define('_SETTINGS_ACTIONSURL',		'Full URL to action.php');
+
+// category moves (batch)
+define('_ERROR_MOVEDEFCATEGORY',	'Cannot move default category');
+define('_ERROR_MOVETOSELF',			'Cannot move category (destination blog is the same as source blog)');
+define('_MOVECAT_TITLE',			'Select blog to move category to');
+define('_MOVECAT_BTN',				'Move category');
+
+// URLMode setting
+define('_SETTINGS_URLMODE',			'URL Mode');
+define('_SETTINGS_URLMODE_NORMAL',	'Normal');
+define('_SETTINGS_URLMODE_PATHINFO','Fancy');
+
+// Batch operations
+define('_BATCH_NOSELECTION',		'Nothing selected to perform actions on');
+define('_BATCH_ITEMS',				'Batch operation on items');
+define('_BATCH_CATEGORIES',			'Batch operation on categories');
+define('_BATCH_MEMBERS',			'Batch operation on members');
+define('_BATCH_TEAM',				'Batch operation on team members');
+define('_BATCH_COMMENTS',			'Batch operation on comments');
+define('_BATCH_UNKNOWN',			'Unknown batch operation: ');
+define('_BATCH_EXECUTING',			'Executing');
+define('_BATCH_ONCATEGORY',			'on category');
+define('_BATCH_ONITEM',				'on item');
+define('_BATCH_ONCOMMENT',			'on comment');
+define('_BATCH_ONMEMBER',			'on member');
+define('_BATCH_ONTEAM',				'on team member');
+define('_BATCH_SUCCESS',			'Success!');
+define('_BATCH_DONE',				'Done!');
+define('_BATCH_DELETE_CONFIRM',		'Confirm Batch Deletion');
+define('_BATCH_DELETE_CONFIRM_BTN',	'Confirm Batch Deletion');
+define('_BATCH_SELECTALL',			'select all');
+define('_BATCH_DESELECTALL',		'deselect all');
+
+// batch operations: options in dropdowns
+define('_BATCH_ITEM_DELETE',		'Delete');
+define('_BATCH_ITEM_MOVE',			'Move');
+define('_BATCH_MEMBER_DELETE',		'Delete');
+define('_BATCH_MEMBER_SET_ADM',		'Give admin rights');
+define('_BATCH_MEMBER_UNSET_ADM',	'Take away admin rights');
+define('_BATCH_TEAM_DELETE',		'Delete from team');
+define('_BATCH_TEAM_SET_ADM',		'Give admin rights');
+define('_BATCH_TEAM_UNSET_ADM',		'Take away admin rights');
+define('_BATCH_CAT_DELETE',			'Delete');
+define('_BATCH_CAT_MOVE',			'Move to other blog');
+define('_BATCH_COMMENT_DELETE',		'Delete');
+
+// itemlist: Add new item...
+define('_ITEMLIST_ADDNEW',			'Add new item...');
+define('_ADD_PLUGIN_EXTRAS',		'Extra Plugin Options');
+
+// errors
+define('_ERROR_CATCREATEFAIL',		'Could not create new category');
+define('_ERROR_NUCLEUSVERSIONREQ',	'This plugin requires a newer Nucleus version: ');
+
+// backlinks
+define('_BACK_TO_BLOGSETTINGS',		'Back to blogsettings');
+
+// skin import export
+define('_SKINIE_TITLE_IMPORT',		'Import');
+define('_SKINIE_TITLE_EXPORT',		'Export');
+define('_SKINIE_BTN_IMPORT',		'Import');
+define('_SKINIE_BTN_EXPORT',		'Export selected skins/templates');
+define('_SKINIE_LOCAL',				'Import from local file:');
+define('_SKINIE_NOCANDIDATES',		'No candidates for import found in the skins directory');
+define('_SKINIE_FROMURL',			'Import from URL:');
+define('_SKINIE_EXPORT_INTRO',		'Select the skins and templates you want to export below');
+define('_SKINIE_EXPORT_SKINS',		'Skins');
+define('_SKINIE_EXPORT_TEMPLATES',	'Templates');
+define('_SKINIE_EXPORT_EXTRA',		'Extra Info');
+define('_SKINIE_CONFIRM_OVERWRITE',	'Overwrite skins that already exists (see nameclashes)');
+define('_SKINIE_CONFIRM_IMPORT',	'Yes, I want to import this');
+define('_SKINIE_CONFIRM_TITLE',		'About to import skins and templates');
+define('_SKINIE_INFO_SKINS',		'Skins in file:');
+define('_SKINIE_INFO_TEMPLATES',	'Templates in file:');
+define('_SKINIE_INFO_GENERAL',		'Info:');
+define('_SKINIE_INFO_SKINCLASH',	'Skin name clashes:');
+define('_SKINIE_INFO_TEMPLCLASH',	'Template name clashes:');
+define('_SKINIE_INFO_IMPORTEDSKINS','Imported skins:');
+define('_SKINIE_INFO_IMPORTEDTEMPLS','Imported templates:');
+define('_SKINIE_DONE',				'Done Importing');
+
+define('_AND',						'and');
+define('_OR',						'or');
+
+// empty fields on template edit
+define('_EDITTEMPLATE_EMPTY',		'empty field (click to edit)');
+
+// skin overview list
+define('_LIST_SKINS_INCMODE',		'IncludeMode:');
+define('_LIST_SKINS_INCPREFIX',		'IncludePrefix:');
+define('_LIST_SKINS_DEFINED',		'Defined parts:');
+
+// backup
+define('_BACKUPS_TITLE',			'Backup / Restore');
+define('_BACKUP_TITLE',				'Backup');
+define('_BACKUP_INTRO',				'Click the button below to create a backup of your Nucleus database. You\'ll be prompted to save a backup file. Store it in a safe place.');
+define('_BACKUP_ZIP_YES',			'Try to use compression');
+define('_BACKUP_ZIP_NO',			'Do not use compression');
+define('_BACKUP_BTN',				'Create Backup');
+define('_BACKUP_NOTE',				'<b>Note:</b> Only the database contents is stored in the backup. Media files and settings in config.php are thus <b>NOT</b> included in the backup.');
+define('_RESTORE_TITLE',			'Restore');
+define('_RESTORE_NOTE',				'<b>WARNING:</b> Restoring from a backup will <b>ERASE</b> all current Nucleus data in the database! Only do this when you\'re really sure!	<br />	<b>Note:</b> Make sure that the version of Nucleus in which you created the backup should be the same as the version you\'re running right now! It won\'t work otherwise');
+define('_RESTORE_INTRO',			'Select the backup file below (it\'ll be uploaded to the server) and click the "Restore" button to start.');
+define('_RESTORE_IMSURE',			'Yes, I\'m sure I want to do this!');
+define('_RESTORE_BTN',				'Restore From File');
+define('_RESTORE_WARNING',			'(make sure you\'re restoring the correct backup, maybe make a new backup before you start)');
+define('_ERROR_BACKUP_NOTSURE',		'You\'ll need to check the \'I\'m sure\' testbox');
+define('_RESTORE_COMPLETE',			'Restore Complete');
+
+// new item notification
+define('_NOTIFY_NI_MSG',			'A new item has been posted:');
+define('_NOTIFY_NI_TITLE',			'New Item!');
+define('_NOTIFY_KV_MSG',			'Karma vote on item:');
+define('_NOTIFY_KV_TITLE',			'Nucleus karma:');
+define('_NOTIFY_NC_MSG',			'Comment on item:');
+define('_NOTIFY_NC_TITLE',			'Nucleus comment:');
+define('_NOTIFY_USERID',			'User ID:');
+define('_NOTIFY_USER',				'User:');
+define('_NOTIFY_COMMENT',			'Comment:');
+define('_NOTIFY_VOTE',				'Vote:');
+define('_NOTIFY_HOST',				'Host:');
+define('_NOTIFY_IP',				'IP:');
+define('_NOTIFY_MEMBER',			'Member:');
+define('_NOTIFY_TITLE',				'Title:');
+define('_NOTIFY_CONTENTS',			'Contents:');
+
+// member mail message
+define('_MMAIL_MSG',				'A message sent to you by');
+define('_MMAIL_FROMANON',			'an anonymous visitor');
+define('_MMAIL_FROMNUC',			'Posted from a Nucleus weblog at');
+define('_MMAIL_TITLE',				'A message from');
+define('_MMAIL_MAIL',				'Message:');
+
+// END introduced after v1.5 END
+
+
+// START introduced after v1.1 START
+
+// bookmarklet buttons
+define('_BMLET_ADD',				'Add Item');
+define('_BMLET_EDIT',				'Edit Item');
+define('_BMLET_DELETE',				'Delete Item');
+define('_BMLET_BODY',				'Body');
+define('_BMLET_MORE',				'Extended');
+define('_BMLET_OPTIONS',			'Options');
+define('_BMLET_PREVIEW',			'Preview');
+
+// used in bookmarklet
+define('_ITEM_UPDATED',				'Item was updated');
+define('_ITEM_DELETED',				'Item was deleted');
+
+// plugins
+define('_CONFIRMTXT_PLUGIN',		'Are you sure you want to delete the plugin named');
+define('_ERROR_NOSUCHPLUGIN',		'No such plugin');
+define('_ERROR_DUPPLUGIN',			'Sorry, this plugin is already installed');
+define('_ERROR_PLUGFILEERROR',		'No such plugin exists, or the permissions are set incorrectly');
+define('_PLUGS_NOCANDIDATES',		'No plugin candidates found');
+
+define('_PLUGS_TITLE_MANAGE',		'Manage Plugins');
+define('_PLUGS_TITLE_INSTALLED',	'Currently Installed');
+define('_PLUGS_TITLE_UPDATE',		'Update subscription list');
+define('_PLUGS_TEXT_UPDATE',		'Nucleus keeps a cache of the event subscriptions of the plugins. When you upgrade a plugin by replacing it\'s file, you should run this update to make sure that the correct subscriptions are cached');
+define('_PLUGS_TITLE_NEW',			'Install New Plugin');
+define('_PLUGS_ADD_TEXT',			'Below is a list of all the files in your plugins directory, that might be non-installed plugins. Make sure you are <strong>really sure</strong> that it\'s a plugin before adding it.');
+define('_PLUGS_BTN_INSTALL',		'Install Plugin');
+define('_BACKTOOVERVIEW',			'Back to overview');
+
+// editlink
+define('_TEMPLATE_EDITLINK',		'Edit Item Link');
+
+// add left / add right tooltips
+define('_ADD_LEFT_TT',				'Add left box');
+define('_ADD_RIGHT_TT',				'Add right box');
+
+// add/edit item: new category (in dropdown box)
+define('_ADD_NEWCAT',				'New Category...');
+
+// new settings
+define('_SETTINGS_PLUGINURL',		'Plugin URL');
+define('_SETTINGS_MAXUPLOADSIZE',	'Max. upload file size (bytes)');
+define('_SETTINGS_NONMEMBERMSGS',	'Allow non-members to send messages');
+define('_SETTINGS_PROTECTMEMNAMES',	'Protect member names');
+
+// overview screen
+define('_OVERVIEW_PLUGINS',			'Manage Plugins...');
+
+// actionlog
+define('_ACTIONLOG_NEWMEMBER',		'New member registration:');
+
+// membermail (when not logged in)
+define('_MEMBERMAIL_MAIL',			'Your email address:');
+
+// file upload
+define('_ERROR_DISALLOWEDUPLOAD2',	'You do not have admin rights on any of the blogs that have the destination member on the teamlist. Therefor, you\'re not allowed to upload files to this member\'s media directory');
+
+// plugin list
+define('_LISTS_INFO',				'Information');
+define('_LIST_PLUGS_AUTHOR',		'By:');
+define('_LIST_PLUGS_VER',			'Version:');
+define('_LIST_PLUGS_SITE',			'Visit site');
+define('_LIST_PLUGS_DESC',			'Description:');
+define('_LIST_PLUGS_SUBS',			'Subscribes to the following events:');
+define('_LIST_PLUGS_UP',			'move up');
+define('_LIST_PLUGS_DOWN',			'move down');
+define('_LIST_PLUGS_UNINSTALL',		'uninstall');
+define('_LIST_PLUGS_ADMIN',			'admin');
+define('_LIST_PLUGS_OPTIONS',		'edit&nbsp;options');
+
+// plugin option list
+define('_LISTS_VALUE',				'Value');
+
+// plugin options
+define('_ERROR_NOPLUGOPTIONS',		'this plugin does not have any options set');
+define('_PLUGS_BACK',				'Back to Plugin Overview');
+define('_PLUGS_SAVE',				'Save Options');
+define('_PLUGS_OPTIONS_UPDATED',	'Plugin options updated');
+
+define('_OVERVIEW_MANAGEMENT',		'Management');
+define('_OVERVIEW_MANAGE',			'Nucleus management...');
+define('_MANAGE_GENERAL',			'General Management');
+define('_MANAGE_SKINS',				'Skin and Templates');
+define('_MANAGE_EXTRA',				'Extra features');
+
+define('_BACKTOMANAGE',				'Back to Nucleus management');
+
+
+// END introduced after v1.1 END
+
+
+
+
+// charset to use 
+define('_CHARSET',					'UTF-8');
+
+// global stuff
+define('_LOGOUT',					'Log Out');
+define('_LOGIN',					'Log In');
+define('_YES',						'Yes');
+define('_NO',						'No');
+define('_SUBMIT',					'Submit');
+define('_ERROR',					'Error');
+define('_ERRORMSG',					'An error has occurred!');
+define('_BACK',						'Go Back');
+define('_NOTLOGGEDIN',				'Not logged in');
+define('_LOGGEDINAS',				'Logged in as');
+define('_ADMINHOME',				'Admin Home');
+define('_NAME',						'Name');
+define('_BACKHOME',					'Back to Admin Home');
+define('_BADACTION',				'Non existing action requested');
+define('_MESSAGE',					'Message');
+define('_HELP_TT',					'Help!');
+define('_YOURSITE',					'Your site');
+
+
+define('_POPUP_CLOSE',				'Close Window');
+
+define('_LOGIN_PLEASE',				'Please Log in First');
+
+// commentform
+define('_COMMENTFORM_YOUARE',		'You are');
+define('_COMMENTFORM_SUBMIT',		'Add Comment');
+define('_COMMENTFORM_COMMENT',		'Your comment');
+define('_COMMENTFORM_NAME',			'Name');
+define('_COMMENTFORM_MAIL',			'E-mail/HTTP');
+define('_COMMENTFORM_REMEMBER',		'Remember Me');
+
+// loginform
+define('_LOGINFORM_NAME',			'Username');
+define('_LOGINFORM_PWD',			'Password');
+define('_LOGINFORM_YOUARE',			'Logged in as');
+define('_LOGINFORM_SHARED',			'Shared Computer');
+
+// member mailform
+define('_MEMBERMAIL_SUBMIT',		'Send Message');
+
+// search form
+define('_SEARCHFORM_SUBMIT',		'Search');
+
+// add item form
+define('_ADD_ADDTO',				'Add new item to');
+define('_ADD_CREATENEW',			'Create new item');
+define('_ADD_BODY',					'Body');
+define('_ADD_TITLE',				'Title');
+define('_ADD_MORE',					'Extended (optional)');
+define('_ADD_CATEGORY',				'Category');
+define('_ADD_PREVIEW',				'Preview');
+define('_ADD_DISABLE_COMMENTS',		'Disable comments?');
+define('_ADD_DRAFTNFUTURE',			'Draft &amp; Future Items');
+define('_ADD_ADDITEM',				'Add Item');
+define('_ADD_ADDNOW',				'Add Now');
+define('_ADD_ADDLATER',				'Add Later');
+define('_ADD_PLACE_ON',				'Place on');
+define('_ADD_ADDDRAFT',				'Add to drafts');
+define('_ADD_NOPASTDATES',			'(dates and times in the past are NOT valid, the current time will be used in that case)');
+define('_ADD_BOLD_TT',				'Bold');
+define('_ADD_ITALIC_TT',			'Italic');
+define('_ADD_HREF_TT',				'Make Link');
+define('_ADD_MEDIA_TT',				'Add Media');
+define('_ADD_PREVIEW_TT',			'Show/Hide Preview');
+define('_ADD_CUT_TT',				'Cut');
+define('_ADD_COPY_TT',				'Copy');
+define('_ADD_PASTE_TT',				'Paste');
+
+
+// edit item form
+define('_EDIT_ITEM',				'Edit Item');
+define('_EDIT_SUBMIT',				'Edit Item');
+define('_EDIT_ORIG_AUTHOR',			'Original author');
+define('_EDIT_BACKTODRAFTS',		'Add back to drafts');
+define('_EDIT_COMMENTSNOTE',		'(note: disabling comments will _not_ hide previously added comments)');
+
+// used on delete screens
+define('_DELETE_CONFIRM',			'Please confirm deletion');
+define('_DELETE_CONFIRM_BTN',		'Confirm Deletion');
+define('_CONFIRMTXT_ITEM',			'You\'re about to delete the item following item:');
+define('_CONFIRMTXT_COMMENT',		'You\'re about to delete the following comment:');
+define('_CONFIRMTXT_TEAM1',			'You\'re about to delete ');
+define('_CONFIRMTXT_TEAM2',			' from the teamlist for blog ');
+define('_CONFIRMTXT_BLOG',			'The blog you are going to delete is: ');
+define('_WARNINGTXT_BLOGDEL',		'Warning! Deleting a blog will delete ALL items of that blog, and all comments. Please confirm to make clear that you are CERTAIN of what you\'re doing!<br />Also, don\'t interrupt Nucleus while removing your blog.');
+define('_CONFIRMTXT_MEMBER',		'You\'re about to delete the following member profile: ');
+define('_CONFIRMTXT_TEMPLATE',		'You\'re about to delete the template named ');
+define('_CONFIRMTXT_SKIN',			'You\'re about to delete the skin named ');
+define('_CONFIRMTXT_BAN',			'You\'re about to delete the ban for the ip range');
+define('_CONFIRMTXT_CATEGORY',		'You\'re about to delete the category ');
+
+// some status messages
+define('_DELETED_ITEM',				'Item Deleted');
+define('_DELETED_MEMBER',			'Member Deleted');
+define('_DELETED_COMMENT',			'Comment Deleted');
+define('_DELETED_BLOG',				'Blog Deleted');
+define('_DELETED_CATEGORY',			'Category Deleted');
+define('_ITEM_MOVED',				'Item Moved');
+define('_ITEM_ADDED',				'Item Added');
+define('_COMMENT_UPDATED',			'Comment updated');
+define('_SKIN_UPDATED',				'Skin data has been saved');
+define('_TEMPLATE_UPDATED',			'Template data has been saved');
+
+// errors
+define('_ERROR_COMMENT_LONGWORD',	'Please don\'t use words of lengths higher than 90 in your comments');
+define('_ERROR_COMMENT_NOCOMMENT',	'Please enter a comment');
+define('_ERROR_COMMENT_NOUSERNAME',	'Bad username');
+define('_ERROR_COMMENT_TOOLONG',	'Your comments are too long (max. 5000 chars)');
+define('_ERROR_COMMENTS_DISABLED',	'Comments for this blog are currently disabled.');
+define('_ERROR_COMMENTS_NONPUBLIC',	'You must be logged in as a member to add comment to this blog');
+define('_ERROR_COMMENTS_MEMBERNICK','The name you want to use to post comments is in use by a site member. Choose something else.');
+define('_ERROR_SKIN',				'Skin error');
+define('_ERROR_ITEMCLOSED',			'This item is closed, it\'s not possible to add new comments to it or to vote on it');
+define('_ERROR_NOSUCHITEM',			'No such item exists');
+define('_ERROR_NOSUCHBLOG',			'No such blog');
+define('_ERROR_NOSUCHSKIN',			'No such skin');
+define('_ERROR_NOSUCHMEMBER',		'No such member');
+define('_ERROR_NOTONTEAM',			'You\'re not on the teamlist of this weblog.');
+define('_ERROR_BADDESTBLOG',		'Destination blog does not exist');
+define('_ERROR_NOTONDESTTEAM',		'Cannot move item, since you\'re not on the teamlist of the destination blog');
+define('_ERROR_NOEMPTYITEMS',		'Cannot add empty items!');
+define('_ERROR_BADMAILADDRESS',		'Email address is not valid');
+define('_ERROR_BADNOTIFY',			'One or more of the given notify addresses is not a valid email address');
+define('_ERROR_BADNAME',			'Name is not valid (only a-z and 0-9 allowed, no spaces at start/end)');
+define('_ERROR_NICKNAMEINUSE',		'Another member is already using that nickname');
+define('_ERROR_PASSWORDMISMATCH',	'Passwords must match');
+define('_ERROR_PASSWORDTOOSHORT',	'Password should be at least 6 characters');
+define('_ERROR_PASSWORDMISSING',	'Password cannot be empty');
+define('_ERROR_REALNAMEMISSING',	'You must enter a real name');
+define('_ERROR_ATLEASTONEADMIN',	'There should always be at least one super-admin that can login to the admin area.');
+define('_ERROR_ATLEASTONEBLOGADMIN','Performing this action would leave your weblog unmaintainable. Please make sure there is always at least one admin.');
+define('_ERROR_ALREADYONTEAM',		'You can\'t add a member that is already on the team');
+define('_ERROR_BADSHORTBLOGNAME',	'The short blog name should only contain a-z and 0-9, without spaces');
+define('_ERROR_DUPSHORTBLOGNAME',	'Another blog already has the chosen short name. These names should be unique');
+define('_ERROR_UPDATEFILE',			'Cannot get write access to the update-file. Make sure the file permissions are set ok (try chmodding it to 666). Also note that the location is relative to the admin-area directory, so you might want to use an absolute path (something like /your/path/to/nucleus/)');
+define('_ERROR_DELDEFBLOG',			'Cannot delete the default blog');
+define('_ERROR_DELETEMEMBER',		'This member cannot be deleted, probably because she is the author of items or comments');
+define('_ERROR_BADTEMPLATENAME',	'Invalid name for template, use only a-z and 0-9, without spaces');
+define('_ERROR_DUPTEMPLATENAME',	'Another template with this name already exists');
+define('_ERROR_BADSKINNAME',		'Invalid name for skin (only a-z, 0-9 are allowed, no spaces)');
+define('_ERROR_DUPSKINNAME',		'Another skin with this name already exists');
+define('_ERROR_DEFAULTSKIN',		'There must at all times be a skin named "default"');
+define('_ERROR_SKINDEFDELETE',		'Cannot delete skin since it is the default skin for the following weblog: ');
+define('_ERROR_DISALLOWED',			'Sorry, you\'re not allowed to perform this action');
+define('_ERROR_DELETEBAN',			'Error while trying to delete ban (ban does not exist)');
+define('_ERROR_ADDBAN',				'Error while trying to add ban. Ban might not have been added correctly in all your blogs.');
+define('_ERROR_BADACTION',			'Required action does not exist');
+define('_ERROR_MEMBERMAILDISABLED',	'Member to Member mail messages are disabled');
+define('_ERROR_MEMBERCREATEDISABLED','Creation of member accounts is disabled');
+define('_ERROR_INCORRECTEMAIL',		'Incorrect mail address');
+define('_ERROR_VOTEDBEFORE',		'You have already voted for this item');
+define('_ERROR_BANNED1',			'Cannot perform action since you (ip range ');
+define('_ERROR_BANNED2',			') are banned from doing so. The message was: \'');
+define('_ERROR_BANNED3',			'\'');
+define('_ERROR_LOGINNEEDED',		'You must be logged in in order to perform this action');
+define('_ERROR_CONNECT',			'Connect Error');
+define('_ERROR_FILE_TOO_BIG',		'File is too big!');
+define('_ERROR_BADFILETYPE',		'Sorry, this filetype is not allowed');
+define('_ERROR_BADREQUEST',			'Bad upload request');
+define('_ERROR_DISALLOWEDUPLOAD',	'You are not on any weblogs teamlist. Hence, you are not allowed to upload files');
+define('_ERROR_BADPERMISSIONS',		'File/Dir permissions are not set correctly');
+define('_ERROR_UPLOADMOVEP',		'Error while moving uploaded file');
+define('_ERROR_UPLOADCOPY',			'Error while copying file');
+define('_ERROR_UPLOADDUPLICATE',	'Another file with that name already exists. Try to rename it before uploading.');
+define('_ERROR_LOGINDISALLOWED',	'Sorry, you\'re not allowed to log in to the admin area. You can log in as another user, though');
+define('_ERROR_DBCONNECT',			'Could not connect to mySQL server');
+define('_ERROR_DBSELECT',			'Could not select the nucleus database.');
+define('_ERROR_NOSUCHLANGUAGE',		'No such language file exists');
+define('_ERROR_NOSUCHCATEGORY',		'No such category exists');
+define('_ERROR_DELETELASTCATEGORY',	'There must at least be one category');
+define('_ERROR_DELETEDEFCATEGORY',	'Cannot delete default category');
+define('_ERROR_BADCATEGORYNAME',	'Bad category name');
+define('_ERROR_DUPCATEGORYNAME',	'Another category with this name already exists');
+
+// some warnings (used for mediadir setting)
+define('_WARNING_NOTADIR',			'Warning: Current value is not a directory!');
+define('_WARNING_NOTREADABLE',		'Warning: Current value is a non-readable directory!');
+define('_WARNING_NOTWRITABLE',		'Warning: Current value is NOT a writable directory!');
+
+// media and upload
+define('_MEDIA_UPLOADLINK',			'Upload a new file');
+define('_MEDIA_MODIFIED',			'modified');
+define('_MEDIA_FILENAME',			'filename');
+define('_MEDIA_DIMENSIONS',			'dimensions');
+define('_MEDIA_INLINE',				'Inline');
+define('_MEDIA_POPUP',				'Popup');
+define('_UPLOAD_TITLE',				'Choose File');
+define('_UPLOAD_MSG',				'Select the file you want to upload below, and hit the \'Upload\' button.');
+define('_UPLOAD_BUTTON',			'Upload');
+
+// some status messages
+//define('_MSG_ACCOUNTCREATED',		'Account created, password will be sent through email');
+//define('_MSG_PASSWORDSENT',			'Password has been sent by e-mail.');
+define('_MSG_LOGINAGAIN',			'You\'ll need to login again, because your info changed');
+define('_MSG_SETTINGSCHANGED',		'Settings Changed');
+define('_MSG_ADMINCHANGED',			'Admin Changed');
+define('_MSG_NEWBLOG',				'New Blog Created');
+define('_MSG_ACTIONLOGCLEARED',		'Action Log Cleared');
+
+// actionlog in admin area
+define('_ACTIONLOG_DISALLOWED',		'Disallowed action: ');
+define('_ACTIONLOG_PWDREMINDERSENT','New password sent for ');
+define('_ACTIONLOG_TITLE',			'Action Log');
+define('_ACTIONLOG_CLEAR_TITLE',	'Clear Action Log');
+define('_ACTIONLOG_CLEAR_TEXT',		'Clear action log now');
+
+// team management
+define('_TEAM_TITLE',				'Manage team for blog ');
+define('_TEAM_CURRENT',				'Current team');
+define('_TEAM_ADDNEW',				'Add new member to team');
+define('_TEAM_CHOOSEMEMBER',		'Choose member');
+define('_TEAM_ADMIN',				'Admin privileges? ');
+define('_TEAM_ADD',					'Add to team');
+define('_TEAM_ADD_BTN',				'Add to team');
+
+// blogsettings
+define('_EBLOG_TITLE',				'Edit Blog Settings');
+define('_EBLOG_TEAM_TITLE',			'Edit Team');
+define('_EBLOG_TEAM_TEXT',			'Click here to edit your team...');
+define('_EBLOG_SETTINGS_TITLE',		'Blog settings');
+define('_EBLOG_NAME',				'Blog Name');
+define('_EBLOG_SHORTNAME',			'Short Blog Name');
+define('_EBLOG_SHORTNAME_EXTRA',	'<br />(should only contain a-z and no spaces)');
+define('_EBLOG_DESC',				'Blog Description');
+define('_EBLOG_URL',				'URL');
+define('_EBLOG_DEFSKIN',			'Default Skin');
+define('_EBLOG_DEFCAT',				'Default Category');
+define('_EBLOG_LINEBREAKS',			'Convert line breaks');
+define('_EBLOG_DISABLECOMMENTS',	'Comments enabled?<br /><small>(Disabling comments means that adding comments is not possible.)</small>');
+define('_EBLOG_ANONYMOUS',			'Allow comments by non-members?');
+define('_EBLOG_NOTIFY',				'Notify Address(es) (use ; as separator)');
+define('_EBLOG_NOTIFY_ON',			'Notify on');
+define('_EBLOG_NOTIFY_COMMENT',		'New comments');
+define('_EBLOG_NOTIFY_KARMA',		'New karma votes');
+define('_EBLOG_NOTIFY_ITEM',		'New weblog items');
+define('_EBLOG_PING',				'Ping Weblogs.com on update?');
+define('_EBLOG_MAXCOMMENTS',		'Max Amount of comments');
+define('_EBLOG_UPDATE',				'Update file');
+define('_EBLOG_OFFSET',				'Time Offset');
+define('_EBLOG_STIME',				'Current server time is');
+define('_EBLOG_BTIME',				'Current blog time is');
+define('_EBLOG_CHANGE',				'Change Settings');
+define('_EBLOG_CHANGE_BTN',			'Change Settings');
+define('_EBLOG_ADMIN',				'Blog Admin');
+define('_EBLOG_ADMIN_MSG',			'You will be assigned admin privileges');
+define('_EBLOG_CREATE_TITLE',		'Create new weblog');
+define('_EBLOG_CREATE_TEXT',		'Fill out the form below to create a new weblog. <br /><br /> <b>Note:</b> Only the necessary options are listed. If you want to set extra options, enter the blogsettings page after creating the weblog.');
+define('_EBLOG_CREATE',				'Create!');
+define('_EBLOG_CREATE_BTN',			'Create Weblog');
+define('_EBLOG_CAT_TITLE',			'Categories');
+define('_EBLOG_CAT_NAME',			'Category Name');
+define('_EBLOG_CAT_DESC',			'Category Description');
+define('_EBLOG_CAT_CREATE',			'Create New Category');
+define('_EBLOG_CAT_UPDATE',			'Update Category');
+define('_EBLOG_CAT_UPDATE_BTN',		'Update Category');
+
+// templates
+define('_TEMPLATE_TITLE',			'Edit Templates');
+define('_TEMPLATE_AVAILABLE_TITLE',	'Available Templates');
+define('_TEMPLATE_NEW_TITLE',		'New Template');
+define('_TEMPLATE_NAME',			'Template Name');
+define('_TEMPLATE_DESC',			'Template Description');
+define('_TEMPLATE_CREATE',			'Create Template');
+define('_TEMPLATE_CREATE_BTN',		'Create Template');
+define('_TEMPLATE_EDIT_TITLE',		'Edit Template');
+define('_TEMPLATE_BACK',			'Back to Template Overview');
+define('_TEMPLATE_EDIT_MSG',		'Not all template parts are needed, leave empty those that are not needed.');
+define('_TEMPLATE_SETTINGS',		'Template Settings');
+define('_TEMPLATE_ITEMS',			'Items');
+define('_TEMPLATE_ITEMHEADER',		'Item Header');
+define('_TEMPLATE_ITEMBODY',		'Item Body');
+define('_TEMPLATE_ITEMFOOTER',		'Item Footer');
+define('_TEMPLATE_MORELINK',		'Link to extended entry');
+define('_TEMPLATE_NEW',				'Indication of new item');
+define('_TEMPLATE_COMMENTS_ANY',	'Comments (if any)');
+define('_TEMPLATE_CHEADER',			'Comments Header');
+define('_TEMPLATE_CBODY',			'Comments Body');
+define('_TEMPLATE_CFOOTER',			'Comments Footer');
+define('_TEMPLATE_CONE',			'One Comment');
+define('_TEMPLATE_CMANY',			'Two (or more) Comments');
+define('_TEMPLATE_CMORE',			'Comments Read More');
+define('_TEMPLATE_CMEXTRA',			'Member Extra');
+define('_TEMPLATE_COMMENTS_NONE',	'Comments (if none)');
+define('_TEMPLATE_CNONE',			'No Comments');
+define('_TEMPLATE_COMMENTS_TOOMUCH','Comments (if any, but too much to show inline)');
+define('_TEMPLATE_CTOOMUCH',		'Too Much Comments');
+define('_TEMPLATE_ARCHIVELIST',		'Archive Lists');
+define('_TEMPLATE_AHEADER',			'Archive List Header');
+define('_TEMPLATE_AITEM',			'Archive List Item');
+define('_TEMPLATE_AFOOTER',			'Archive List Footer');
+define('_TEMPLATE_DATETIME',		'Date and Time');
+define('_TEMPLATE_DHEADER',			'Date Header');
+define('_TEMPLATE_DFOOTER',			'Date Footer');
+define('_TEMPLATE_DFORMAT',			'Date Format');
+define('_TEMPLATE_TFORMAT',			'Time Format');
+define('_TEMPLATE_LOCALE',			'Locale');
+define('_TEMPLATE_IMAGE',			'Image popups');
+define('_TEMPLATE_PCODE',			'Popup Link Code');
+define('_TEMPLATE_ICODE',			'Inline Image Code');
+define('_TEMPLATE_MCODE',			'Media Object Link Code');
+define('_TEMPLATE_SEARCH',			'Search');
+define('_TEMPLATE_SHIGHLIGHT',		'Highlight');
+define('_TEMPLATE_SNOTFOUND',		'Nothing found in search');
+define('_TEMPLATE_UPDATE',			'Update');
+define('_TEMPLATE_UPDATE_BTN',		'Update Template');
+define('_TEMPLATE_RESET_BTN',		'Reset Data');
+define('_TEMPLATE_CATEGORYLIST',	'Category Lists');
+define('_TEMPLATE_CATHEADER',		'Category List Header');
+define('_TEMPLATE_CATITEM',			'Category List Item');
+define('_TEMPLATE_CATFOOTER',		'Category List Footer');
+
+// skins
+define('_SKIN_EDIT_TITLE',			'Edit Skins');
+define('_SKIN_AVAILABLE_TITLE',		'Available Skins');
+define('_SKIN_NEW_TITLE',			'New Skin');
+define('_SKIN_NAME',				'Name');
+define('_SKIN_DESC',				'Description');
+define('_SKIN_TYPE',				'Content Type');
+define('_SKIN_CREATE',				'Create');
+define('_SKIN_CREATE_BTN',			'Create Skin');
+define('_SKIN_EDITONE_TITLE',		'Edit skin');
+define('_SKIN_BACK',				'Back to Skin Overview');
+define('_SKIN_PARTS_TITLE',			'Skin Parts');
+define('_SKIN_PARTS_MSG',			'Not all types are needed for each skin. Leave empty those you don\'t need. Choose the skin type to edit below:');
+define('_SKIN_PART_MAIN',			'Main Index');
+define('_SKIN_PART_ITEM',			'Item Pages');
+define('_SKIN_PART_ALIST',			'Archive List');
+define('_SKIN_PART_ARCHIVE',		'Archive');
+define('_SKIN_PART_SEARCH',			'Search');
+define('_SKIN_PART_ERROR',			'Errors');
+define('_SKIN_PART_MEMBER',			'Member Details');
+define('_SKIN_PART_POPUP',			'Image Popups');
+define('_SKIN_GENSETTINGS_TITLE',	'General Settings');
+define('_SKIN_CHANGE',				'Change');
+define('_SKIN_CHANGE_BTN',			'Change these settings');
+define('_SKIN_UPDATE_BTN',			'Update Skin');
+define('_SKIN_RESET_BTN',			'Reset Data');
+define('_SKIN_EDITPART_TITLE',		'Edit Skin');
+define('_SKIN_GOBACK',				'Go Back');
+define('_SKIN_ALLOWEDVARS',			'Allowed Variables (click for info):');
+
+// global settings
+define('_SETTINGS_TITLE',			'General Settings');
+define('_SETTINGS_SUB_GENERAL',		'General Settings');
+define('_SETTINGS_DEFBLOG',			'Default Blog');
+define('_SETTINGS_ADMINMAIL',		'Administrator Email');
+define('_SETTINGS_SITENAME',		'Site Name');
+define('_SETTINGS_SITEURL',			'URL of Site (should end with a slash)');
+define('_SETTINGS_ADMINURL',		'URL of Admin Area (should end with a slash)');
+define('_SETTINGS_DIRS',			'Nucleus Directories');
+define('_SETTINGS_MEDIADIR',		'Media Directory');
+define('_SETTINGS_SEECONFIGPHP',	'(see config.php)');
+define('_SETTINGS_MEDIAURL',		'Media URL (should end with a slash)');
+define('_SETTINGS_ALLOWUPLOAD',		'Allow File Upload?');
+define('_SETTINGS_ALLOWUPLOADTYPES','Allow File Types for Upload');
+define('_SETTINGS_CHANGELOGIN',		'Allow Members to Change Login/Password');
+define('_SETTINGS_COOKIES_TITLE',	'Cookie Settings');
+define('_SETTINGS_COOKIELIFE',		'Login Cookie Lifetime');
+define('_SETTINGS_COOKIESESSION',	'Session Cookies');
+define('_SETTINGS_COOKIEMONTH',		'Lifetime of a Month');
+define('_SETTINGS_COOKIEPATH',		'Cookie Path (advanced)');
+define('_SETTINGS_COOKIEDOMAIN',	'Cookie Domain (advanced)');
+define('_SETTINGS_COOKIESECURE',	'Secure Cookie (advanced)');
+define('_SETTINGS_LASTVISIT',		'Save Last Visit Cookies');
+define('_SETTINGS_ALLOWCREATE',		'Allow Visitors to Create a Member Account');
+define('_SETTINGS_NEWLOGIN',		'Login Allowed for User-Created accounts');
+define('_SETTINGS_NEWLOGIN2',		'(only goes for newly created accounts)');
+define('_SETTINGS_MEMBERMSGS',		'Allow Member-2-Member Service');
+define('_SETTINGS_LANGUAGE',		'Default Language');
+define('_SETTINGS_DISABLESITE',		'Disable Site');
+define('_SETTINGS_DBLOGIN',			'mySQL Login &amp; Database');
+define('_SETTINGS_UPDATE',			'Update Settings');
+define('_SETTINGS_UPDATE_BTN',		'Update Settings');
+define('_SETTINGS_DISABLEJS',		'Disable JavaScript Toolbar');
+define('_SETTINGS_MEDIA',			'Media/Upload Settings');
+define('_SETTINGS_MEDIAPREFIX',		'Prefix uploaded files with date');
+define('_SETTINGS_MEMBERS',			'Member Settings');
+
+// bans
+define('_BAN_TITLE',				'Ban List for');
+define('_BAN_NONE',					'No bans for this weblog');
+define('_BAN_NEW_TITLE',			'Add New Ban');
+define('_BAN_NEW_TEXT',				'Add a new ban now');
+define('_BAN_REMOVE_TITLE',			'Remove Ban');
+define('_BAN_IPRANGE',				'IP Range');
+define('_BAN_BLOGS',				'Which blogs?');
+define('_BAN_DELETE_TITLE',			'Delete Ban');
+define('_BAN_ALLBLOGS',				'All blogs to which you have admin privileges.');
+define('_BAN_REMOVED_TITLE',		'Ban Removed');
+define('_BAN_REMOVED_TEXT',			'Ban was removed for the following blogs:');
+define('_BAN_ADD_TITLE',			'Add Ban');
+define('_BAN_IPRANGE_TEXT',			'Choose the IP range you want to block below. The less numbers in it, the more addresses will be blocked.');
+define('_BAN_BLOGS_TEXT',			'You can either select to ban the IP on one blog only, or you can select to block the IP on all blogs where you have administrator privileges. Make your choice below.');
+define('_BAN_REASON_TITLE',			'Reason');
+define('_BAN_REASON_TEXT',			'You can provide a reason for the ban, which will be displayed when the IP holder tries to add another comment or tries to cast a karma vote. Maximum length is 256 characters.');
+define('_BAN_ADD_BTN',				'Add Ban');
+
+// LOGIN screen
+define('_LOGIN_MESSAGE',			'Message');
+define('_LOGIN_NAME',				'Name');
+define('_LOGIN_PASSWORD',			'Password');
+define('_LOGIN_SHARED',				_LOGINFORM_SHARED);
+define('_LOGIN_FORGOT',				'Forgot your password?');
+
+// membermanagement
+define('_MEMBERS_TITLE',			'Member Management');
+define('_MEMBERS_CURRENT',			'Current Members');
+define('_MEMBERS_NEW',				'New Member');
+define('_MEMBERS_DISPLAY',			'Display Name');
+define('_MEMBERS_DISPLAY_INFO',		'(This is the name you use to login)');
+define('_MEMBERS_REALNAME',			'Real Name');
+define('_MEMBERS_PWD',				'Password');
+define('_MEMBERS_REPPWD',			'Repeat Password');
+define('_MEMBERS_EMAIL',			'Email address');
+define('_MEMBERS_EMAIL_EDIT',		'(When you change the email address, a new password will be automatically sent out to that address)');
+define('_MEMBERS_URL',				'Website Address (URL)');
+define('_MEMBERS_SUPERADMIN',		'Administrator privileges');
+define('_MEMBERS_CANLOGIN',			'Can login to admin area');
+define('_MEMBERS_NOTES',			'Notes');
+define('_MEMBERS_NEW_BTN',			'Add Member');
+define('_MEMBERS_EDIT',				'Edit Member');
+define('_MEMBERS_EDIT_BTN',			'Change Settings');
+define('_MEMBERS_BACKTOOVERVIEW',	'Back to Member Overview');
+define('_MEMBERS_DEFLANG',			'Language');
+define('_MEMBERS_USESITELANG',		'- use site settings -');
+
+// List of blogs (TT = tooltip)
+define('_BLOGLIST_TT_VISIT',		'Visit Site');
+define('_BLOGLIST_ADD',				'Add Item');
+define('_BLOGLIST_TT_ADD',			'Add a new item to this weblog');
+define('_BLOGLIST_EDIT',			'Edit/Delete Items');
+define('_BLOGLIST_TT_EDIT',			'');
+define('_BLOGLIST_BMLET',			'Bookmarklet');
+define('_BLOGLIST_TT_BMLET',		'');
+define('_BLOGLIST_SETTINGS',		'Settings');
+define('_BLOGLIST_TT_SETTINGS',		'Edit settings or manage team');
+define('_BLOGLIST_BANS',			'Bans');
+define('_BLOGLIST_TT_BANS',			'View, add or remove banned IPs');
+define('_BLOGLIST_DELETE',			'Delete All');
+define('_BLOGLIST_TT_DELETE',		'Delete this weblog');
+
+// OVERVIEW screen
+define('_OVERVIEW_YRBLOGS',			'Your weblogs');
+define('_OVERVIEW_YRDRAFTS',		'Your drafts');
+define('_OVERVIEW_YRSETTINGS',		'Your settings');
+define('_OVERVIEW_GSETTINGS',		'General settings');
+define('_OVERVIEW_NOBLOGS',			'You\'re not on any weblogs teamlist');
+define('_OVERVIEW_NODRAFTS',		'No drafts');
+define('_OVERVIEW_EDITSETTINGS',	'Edit Your Settings...');
+define('_OVERVIEW_BROWSEITEMS',		'Browse your items...');
+define('_OVERVIEW_BROWSECOMM',		'Browse your comments...');
+define('_OVERVIEW_VIEWLOG',			'View Action Log...');
+define('_OVERVIEW_MEMBERS',			'Manage Members...');
+define('_OVERVIEW_NEWLOG',			'Create New Weblog...');
+define('_OVERVIEW_SETTINGS',		'Edit Settings...');
+define('_OVERVIEW_TEMPLATES',		'Edit Templates...');
+define('_OVERVIEW_SKINS',			'Edit Skins...');
+define('_OVERVIEW_BACKUP',			'Backup/Restore...');
+
+// ITEMLIST
+define('_ITEMLIST_BLOG',			'Items for blog'); 
+define('_ITEMLIST_YOUR',			'Your items');
+
+// Comments
+define('_COMMENTS',					'Comments');
+define('_NOCOMMENTS',				'No comments for this item');
+define('_COMMENTS_YOUR',			'Your Comments');
+define('_NOCOMMENTS_YOUR',			'You didn\'t write any comments');
+
+// LISTS (general)
+define('_LISTS_NOMORE',				'No more results, or no results at all');
+define('_LISTS_PREV',				'Previous');
+define('_LISTS_NEXT',				'Next');
+define('_LISTS_SEARCH',				'Search');
+define('_LISTS_CHANGE',				'Change');
+define('_LISTS_PERPAGE',			'items/page');
+define('_LISTS_ACTIONS',			'Actions');
+define('_LISTS_DELETE',				'Delete');
+define('_LISTS_EDIT',				'Edit');
+define('_LISTS_MOVE',				'Move');
+define('_LISTS_CLONE',				'Clone');
+define('_LISTS_TITLE',				'Title');
+define('_LISTS_BLOG',				'Blog');
+define('_LISTS_NAME',				'Name');
+define('_LISTS_DESC',				'Description');
+define('_LISTS_TIME',				'Time');
+define('_LISTS_COMMENTS',			'Comments');
+define('_LISTS_TYPE',				'Type');
+
+
+// member list 
+define('_LIST_MEMBER_NAME',			'Display Name');
+define('_LIST_MEMBER_RNAME',		'Real Name');
+define('_LIST_MEMBER_ADMIN',		'Super-admin? ');
+define('_LIST_MEMBER_LOGIN',		'Can login? ');
+define('_LIST_MEMBER_URL',			'Website');
+
+// banlist
+define('_LIST_BAN_IPRANGE',			'IP Range');
+define('_LIST_BAN_REASON',			'Reason');
+
+// actionlist
+define('_LIST_ACTION_MSG',			'Message');
+
+// commentlist
+define('_LIST_COMMENT_BANIP',		'Ban IP');
+define('_LIST_COMMENT_WHO',			'Author');
+define('_LIST_COMMENT',				'Comment');
+define('_LIST_COMMENT_HOST',		'Host');
+
+// itemlist
+define('_LIST_ITEM_INFO',			'Info');
+define('_LIST_ITEM_CONTENT',		'Title and Text');
+
+
+// teamlist
+define('_LIST_TEAM_ADMIN',			'Admin ');
+define('_LIST_TEAM_CHADMIN',		'Change Admin');
+
+// edit comments
+define('_EDITC_TITLE',				'Edit Comments');
+define('_EDITC_WHO',				'Author');
+define('_EDITC_HOST',				'From Where?');
+define('_EDITC_WHEN',				'When?');
+define('_EDITC_TEXT',				'Text');
+define('_EDITC_EDIT',				'Edit Comment');
+define('_EDITC_MEMBER',				'member');
+define('_EDITC_NONMEMBER',			'non member');
+
+// move item
+define('_MOVE_TITLE',				'Move to which blog?');
+define('_MOVE_BTN',					'Move Item');
+?>
diff -ruN 3.24.src/nucleus/libs/ACTIONLOG.php 3.31.src/nucleus/libs/ACTIONLOG.php
--- 3.24.src/nucleus/libs/ACTIONLOG.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/ACTIONLOG.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,74 +1,77 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * Actionlog class for Nucleus
-  *
+ * Actionlog class for Nucleus
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: ACTIONLOG.php,v 1.11.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: ACTIONLOG.php 1125 2007-02-22 16:10:29Z kaigreve $
+ */
 define('ERROR',1);		// only errors
 define('WARNING',2);	// errors and warnings
 define('INFO',3);		// info, errors and warnings
-define('DEBUG',4);		// everything 
+define('DEBUG',4);		// everything
 $CONF['LogLevel'] = INFO;
 
 class ACTIONLOG {
 
 	/**
-	  * (Static) Method to add message to log
+	  * (Static) Method to add a message to the action log
 	  */
 	function add($level, $message) {
 		global $member, $CONF;
-		
+
 		if ($CONF['LogLevel'] < $level)
 			return;
-		
+
 		if ($member && $member->isLoggedIn())
 			$message = "[" . $member->getDisplayName() . "] " . $message;
-		
+
 		$message = addslashes($message);		// add slashes
 		$timestamp = date("Y-m-d H:i:s",time());	// format timestamp
 		$query = "INSERT INTO " . sql_table('actionlog') . " (timestamp, message) VALUES ('$timestamp', '$message')";
-		
+
 		sql_query($query);
-		
+
 		ACTIONLOG::trimLog();
 	}
-	
+
 	/**
-	  * (Static) Method to clear log
+	  * (Static) Method to clear the whole action log
 	  */
 	function clear() {
 		global $manager;
-		
+
 		$query = 'DELETE FROM ' . sql_table('actionlog');
 
 		$manager->notify('ActionLogCleared',array());
-		
+
 		return sql_query($query);
 	}
-	
+
+	/**
+	  * (Static) Method to trim the action log (from over 500 back to 250 entries)
+	  */
 	function trimLog() {
 		static $checked = 0;
-		
+
 		// only check once per run
 		if ($checked) return;
-		
+
 		// trim
 		$checked = 1;
-		
+
 		$iTotal = quickQuery('SELECT COUNT(*) AS result FROM ' . sql_table('actionlog'));
-		
+
 		// if size > 500, drop back to about 250
 		$iMaxSize = 500;
 		$iDropSize = 250;
@@ -76,7 +79,7 @@
 			$tsChop = quickQuery('SELECT timestamp as result FROM ' . sql_table('actionlog') . ' ORDER BY timestamp DESC LIMIT '.$iDropSize.',1');
 			sql_query('DELETE FROM ' . sql_table('actionlog') . ' WHERE timestamp < \'' . $tsChop . '\'');
 		}
-		
+
 	}
 
 }
diff -ruN 3.24.src/nucleus/libs/ACTION.php 3.31.src/nucleus/libs/ACTION.php
--- 3.24.src/nucleus/libs/ACTION.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/ACTION.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,32 +1,44 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * Actions that can be called via action.php
-  *
+ * Actions that can be called via action.php
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: ACTION.php,v 1.6.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: ACTION.php 1209 2007-10-13 19:59:05Z kaigreve $
+ */
 class ACTION
 {
+	/**
+	 *  Constructor for an new ACTION object
+	 */
 	function ACTION()
 	{
-	
+		// do nothing
 	}
-	
-	function doAction($action) 
+
+	/**
+	 *  Calls functions that handle an action called from action.php
+	 */
+	function doAction($action)
 	{
 		switch($action) {
+			case 'autodraft':
+				return $this->autoDraft();
+				break;
+			case 'updateticket':
+				return $this->updateTicket();
+				break;
 			case 'addcomment':
 				return $this->addComment();
 				break;
@@ -35,7 +47,7 @@
 				break;
 			case 'createaccount':
 				return $this->createAccount();
-				break;		
+				break;
 			case 'forgotpassword':
 				return $this->forgotPassword();
 				break;
@@ -52,13 +64,17 @@
 				doError(_ERROR_BADACTION);
 		}
 	}
-	
+
+	/**
+	 *  Adds a new comment to an item (if IP isn't banned)
+	 */
 	function addComment() {
 		global $CONF, $errormessage, $manager;
 
 		$post['itemid'] =	intPostVar('itemid');
 		$post['user'] = 	postVar('user');
 		$post['userid'] = 	postVar('userid');
+		$post['email'] =   postVar('email');
 		$post['body'] = 	postVar('body');
 
 		// set cookies when required
@@ -67,6 +83,7 @@
 			$lifetime = time()+2592000;
 			setcookie($CONF['CookiePrefix'] . 'comment_user',$post['user'],$lifetime,'/','',0);
 			setcookie($CONF['CookiePrefix'] . 'comment_userid', $post['userid'],$lifetime,'/','',0);
+			setcookie($CONF['CookiePrefix'] . 'comment_email',  $post['email'], $lifetime,'/','',0);
 		}
 
 		$comments = new COMMENTS($post['itemid']);
@@ -78,12 +95,12 @@
 		// note: PreAddComment and PostAddComment gets called somewhere inside addComment
 		$errormessage = $comments->addComment($blog->getCorrectTime(),$post);
 
-		if ($errormessage == '1') {		
+		if ($errormessage == '1') {
 			// redirect when adding comments succeeded
 			if (postVar('url')) {
 				redirect(postVar('url'));
 			} else {
-				$url = $CONF['IndexURL'] . createItemLink($post['itemid']);
+				$url = createItemLink($post['itemid']);
 				redirect($url);
 			}
 		} else {
@@ -93,11 +110,13 @@
 				'skinid' => $blog->getDefaultSkin()
 			);
 		}
-		
+
 		exit;
 	}
 
-	// Sends a message from the current member to the member given as argument
+	/**
+	 *  Sends a message from the current member to the member given as argument
+	 */
 	function sendMessage() {
 		global $CONF, $member;
 
@@ -139,15 +158,17 @@
 			}
 			redirect($url);
 		}
-		
 		exit;
-
 	}
-	
+
+	/**
+	 *  Checks if a mail to a member is allowed
+	 *  Returns a string with the error message if the mail is disallowed
+	 */
 	function validateMessage() {
 		global $CONF, $member, $manager;
 
-		if (!$CONF['AllowMemberMail']) 
+		if (!$CONF['AllowMemberMail'])
 			return _ERROR_MEMBERMAILDISABLED;
 
 		if (!$member->isLoggedIn() && !$CONF['NonmemberMail'])
@@ -155,50 +176,65 @@
 
 		if (!$member->isLoggedIn() && (!isValidMailAddress(postVar('frommail'))))
 			return _ERROR_BADMAILADDRESS;
-			
+
 		// let plugins do verification (any plugin which thinks the comment is invalid
 		// can change 'error' to something other than '')
 		$result = '';
 		$manager->notify('ValidateForm', array('type' => 'membermail', 'error' => &$result));
-		
+
 		return $result;
-		
+
 	}
 
-	// creates a new user account
+	/**
+	 *  Creates a new user account
+	 */
 	function createAccount() {
 		global $CONF, $manager;
 
-		if (!$CONF['AllowMemberCreate']) 
+		if (!$CONF['AllowMemberCreate'])
 			doError(_ERROR_MEMBERCREATEDISABLED);
 
+		// evaluate content from FormExtra
+		$result = 1;
+		$data = array('type' => 'membermail', 'error' => &$result);
+		$manager->notify('ValidateForm', &$data);
+
+		if ($result!=1) {
+			return $result;
+		}
+		else {
+
 		// even though the member can not log in, set some random initial password. One never knows.
 		srand((double)microtime()*1000000);
 		$initialPwd = md5(uniqid(rand(), true));
 
 		// create member (non admin/can not login/no notes/random string as password)
 		$r = MEMBER::create(postVar('name'), postVar('realname'), $initialPwd, postVar('email'), postVar('url'), 0, 0, '');
-		
-		if ($r != 1)
-			doError($r);
-			
+
+			if ($r != 1) {
+				return $r;
+			}
+
 		// send message containing password.
 		$newmem = new MEMBER();
 		$newmem->readFromName(postVar('name'));
 		$newmem->sendActivationLink('register');
 
-		$manager->notify('PostRegister',array('member' => &$newmem));		
+		$manager->notify('PostRegister',array('member' => &$newmem));
 
 		if (postVar('desturl')) {
 			redirect(postVar('desturl'));
 		} else {
 			echo _MSG_ACTIVATION_SENT;
 		}
-		
 		exit;
 	}
+	}
 
-	// sends a new password 
+	/**
+	 *  Sends a new password
+	 */
 	function forgotPassword() {
 		$membername = trim(postVar('name'));
 
@@ -221,26 +257,27 @@
 		} else {
 			echo _MSG_ACTIVATION_SENT;
 		}
-		
 		exit;
 	}
 
-	// handle karma votes
+	/**
+	 *  Handle karma votes
+	 */
 	function doKarma($type) {
 		global $itemid, $member, $CONF, $manager;
 
 		// check if itemid exists
-		if (!$manager->existsItem($itemid,0,0)) 
+		if (!$manager->existsItem($itemid,0,0))
 			doError(_ERROR_NOSUCHITEM);
 
 		$blogid = getBlogIDFromItemID($itemid);
-		$this->checkban($blogid);	
+		$this->checkban($blogid);
 
 		$karma =& $manager->getKarma($itemid);
 
 		// check if not already voted
-		if (!$karma->isVoteAllowed(serverVar('REMOTE_ADDR'))) 
-			doError(_ERROR_VOTEDBEFORE);		
+		if (!$karma->isVoteAllowed(serverVar('REMOTE_ADDR')))
+			doError(_ERROR_VOTEDBEFORE);
 
 		// check if item does allow voting
 		$item =& $manager->getItem($itemid,0,0);
@@ -248,7 +285,7 @@
 			doError(_ERROR_ITEMCLOSED);
 
 		switch($type) {
-			case 'pos': 
+			case 'pos':
 				$karma->votePositive();
 				break;
 			case 'neg':
@@ -287,7 +324,7 @@
 		else
 			$url = $CONF['IndexURL'] . 'index.php?itemid=' . $itemid;
 
-		redirect($url);	
+		redirect($url);
 		exit;
 	}
 
@@ -316,11 +353,14 @@
 		// - no actions are allowed (doAction is not implemented)
 		if ($error)
 			doError($error);
-			
+
 		exit;
 
 	}
 
+	/**
+	 *  Checks if an IP or IP range is banned
+	 */
 	function checkban($blogid) {
 		// check if banned
 		$ban = BAN::isBanned($blogid, serverVar('REMOTE_ADDR'));
@@ -330,6 +370,41 @@
 
 	}
 
+	/**
+	 * Gets a new ticket
+	 */
+	function updateTicket() {
+		global $manager;
+		if ($manager->checkTicket()) {
+			echo $manager->getNewTicket();
+		}
+		else {
+			echo 'err:' . _ERROR_BADTICKET;
+		}
+		return false;
+	}
+
+	/**
+	 * Handles AutoSaveDraft
+	 */
+	function autoDraft() {
+		global $manager;
+		if ($manager->checkTicket()) {
+			$manager->loadClass('ITEM');
+			$info = ITEM::CreateDraftFromRequest();
+			if ($info['status'] == 'error') {
+				echo $info['message'];
+			}
+			else {
+				echo $info['draftid'];
+			}
+		}
+		else {
+			echo 'err:' . _ERROR_BADTICKET;
+		}
+		return false;
+	}
+
 
 }
 
diff -ruN 3.24.src/nucleus/libs/ACTIONS.php 3.31.src/nucleus/libs/ACTIONS.php
--- 3.24.src/nucleus/libs/ACTIONS.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/libs/ACTIONS.php	2007-10-22 19:36:00.000000000 -0500
@@ -0,0 +1,1306 @@
+<?php
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+/**
+ * This class contains the functions that get called by using
+ * the special tags in the skins
+ *
+ * The allowed tags for a type of skinpart are defined by the
+ * SKIN::getAllowedActionsForType($type) method
+ *
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: ACTIONS.php 1141 2007-05-10 08:10:26Z kimitake $
+ */
+
+class ACTIONS extends BaseActions {
+
+	// part of the skin currently being parsed ('index', 'item', 'archive',
+	// 'archivelist', 'member', 'search', 'error', 'imagepopup')
+	var $skintype;
+
+	// contains an assoc array with parameters that need to be included when
+	// generating links to items/archives/... (e.g. catid)
+	var $linkparams;
+
+	// reference to the skin object for which a part is being parsed
+	var $skin;
+
+	// used when including templated forms from the include/ dir. The $formdata var
+	// contains the values to fill out in there (assoc array name -> value)
+	var $formdata;
+
+	// filled out with the number of displayed items after calling one of the
+	// (other)blog/(other)searchresults skinvars.
+	var $amountfound;
+
+	/**
+	 * Constructor for a new ACTIONS object
+	 */
+	function ACTIONS($type) {
+		// call constructor of superclass first
+		$this->BaseActions();
+
+		$this->skintype = $type;
+
+		global $catid;
+		if ($catid)
+			$this->linkparams = array('catid' => $catid);
+	}
+
+	/**
+	 *  Set the skin
+	 */
+	function setSkin(&$skin) {
+		$this->skin =& $skin;
+	}
+
+	/**
+	 *  Set the parser
+	 */
+	function setParser(&$parser) {
+		$this->parser =& $parser;
+	}
+
+	/**
+	 *	Forms get parsedincluded now, using an extra <formdata> skinvar
+	*/
+	function doForm($filename) {
+		global $DIR_NUCLEUS;
+		array_push($this->parser->actions,'formdata','text','callback','errordiv','ticket');
+		$oldIncludeMode = PARSER::getProperty('IncludeMode');
+		$oldIncludePrefix = PARSER::getProperty('IncludePrefix');
+		PARSER::setProperty('IncludeMode','normal');
+		PARSER::setProperty('IncludePrefix','');
+		$this->parse_parsedinclude($DIR_NUCLEUS . 'forms/' . $filename . '.template');
+		PARSER::setProperty('IncludeMode',$oldIncludeMode);
+		PARSER::setProperty('IncludePrefix',$oldIncludePrefix);
+		array_pop($this->parser->actions);		// errordiv
+		array_pop($this->parser->actions);		// callback
+		array_pop($this->parser->actions);		// text
+		array_pop($this->parser->actions);		// formdata
+		array_pop($this->parser->actions);		// ticket
+	}
+
+	/**
+	 * Checks conditions for if statements
+	 *
+	 * @param string $field type of <%if%>
+	 * @param string $name property of field
+	 * @param string $value value of property
+	 */
+	function checkCondition($field, $name='', $value = '') {
+		global $catid, $blog, $member, $itemidnext, $itemidprev, $manager, $archiveprevexists, $archivenextexists;
+
+		$condition = 0;
+		switch($field) {
+			case 'category':
+				$condition = ($blog && $this->_ifCategory($name,$value));
+				break;
+			case 'blogsetting':
+				$condition = ($blog && ($blog->getSetting($name) == $value));
+				break;
+			case 'loggedin':
+				$condition = $member->isLoggedIn();
+				break;
+			case 'onteam':
+				$condition = $member->isLoggedIn() && $this->_ifOnTeam($name);
+				break;
+			case 'admin':
+				$condition = $member->isLoggedIn() && $this->_ifAdmin($name);
+				break;
+			case 'nextitem':
+				$condition = ($itemidnext != '');
+				break;
+			case 'previtem':
+				$condition = ($itemidprev != '');
+				break;
+			case 'archiveprevexists':
+				$condition = ($archiveprevexists == true);
+				break;
+			case 'archivenextexists':
+				$condition = ($archivenextexists == true);
+				break;
+			case 'skintype':
+				$condition = ($name == $this->skintype);
+				break;
+			case 'hasplugin':
+				$condition = $this->_ifHasPlugin($name, $value);
+				break;
+			default:
+				$condition = $manager->pluginInstalled('NP_' . $field) && $this->_ifPlugin($field, $name, $value);
+				break;
+		}
+		return $condition;
+	}
+
+	/**
+	 *	hasplugin,PlugName
+	 *	   -> checks if plugin exists
+	 *	hasplugin,PlugName,OptionName
+	 *	   -> checks if the option OptionName from plugin PlugName is not set to 'no'
+	 *	hasplugin,PlugName,OptionName=value
+	 *	   -> checks if the option OptionName from plugin PlugName is set to value
+	 */
+	function _ifHasPlugin($name, $value) {
+		global $manager;
+		$condition = false;
+		// (pluginInstalled method won't write a message in the actionlog on failure)
+		if ($manager->pluginInstalled('NP_'.$name)) {
+			$plugin =& $manager->getPlugin('NP_' . $name);
+			if ($plugin != NULL) {
+				if ($value == "") {
+					$condition = true;
+				} else {
+					list($name2, $value2) = explode('=', $value, 2);
+					if ($value2 == "" && $plugin->getOption($name2) != 'no') {
+						$condition = true;
+					} else if ($plugin->getOption($name2) == $value2) {
+						$condition = true;
+					}
+				}
+			}
+		}
+		return $condition;
+	}
+
+	/**
+	 * Checks if a plugin exists and call its doIf function
+	 */
+	function _ifPlugin($name, $key = '', $value = '') {
+		global $manager;
+
+		$plugin =& $manager->getPlugin('NP_' . $name);
+		if (!$plugin) return;
+
+		$params = func_get_args();
+		array_shift($params);
+
+		return call_user_func_array(array(&$plugin, 'doIf'), $params);
+	}
+
+	/**
+	 *  Different checks for a category
+	 */
+	function _ifCategory($name = '', $value='') {
+		global $blog, $catid;
+
+		// when no parameter is defined, just check if a category is selected
+		if (($name != 'catname' && $name != 'catid') || ($value == ''))
+			return $blog->isValidCategory($catid);
+
+		// check category name
+		if ($name == 'catname') {
+			$value = $blog->getCategoryIdFromName($value);
+			if ($value == $catid)
+				return $blog->isValidCategory($catid);
+		}
+
+		// check category id
+		if (($name == 'catid') && ($value == $catid))
+			return $blog->isValidCategory($catid);
+
+		return false;
+	}
+
+	/**
+	 *  Checks if a member is on the team of a blog and return his rights
+	 */
+	function _ifOnTeam($blogName = '') {
+		global $blog, $member, $manager;
+
+		// when no blog found
+		if (($blogName == '') && (!is_object($blog)))
+			return 0;
+
+		// explicit blog selection
+		if ($blogName != '')
+			$blogid = getBlogIDFromName($blogName);
+
+		if (($blogName == '') || !$manager->existsBlogID($blogid))
+			// use current blog
+			$blogid = $blog->getID();
+
+		return $member->teamRights($blogid);
+	}
+
+	/**
+	 *  Checks if a member is admin of a blog
+	 */
+	function _ifAdmin($blogName = '') {
+		global $blog, $member, $manager;
+
+		// when no blog found
+		if (($blogName == '') && (!is_object($blog)))
+			return 0;
+
+		// explicit blog selection
+		if ($blogName != '')
+			$blogid = getBlogIDFromName($blogName);
+
+		if (($blogName == '') || !$manager->existsBlogID($blogid))
+			// use current blog
+			$blogid = $blog->getID();
+
+		return $member->isBlogAdmin($blogid);
+	}
+	
+	/**
+	 * returns either
+	 *		- a raw link (html/xml encoded) when no linktext is provided
+	 *		- a (x)html <a href... link when a text is present (text htmlencoded)
+	 */
+	function _link($url, $linktext = '')
+	{
+		$u = htmlspecialchars($url);
+		$u = preg_replace("/&amp;amp;/",'&amp;',$u); // fix URLs that already had encoded ampersands
+		if ($linktext != '')
+			$l = '<a href="' . $u .'">'.htmlspecialchars($linktext).'</a>';
+		else
+			$l = $u;
+		return $l;
+	}
+	
+	/**
+	 * Outputs a next/prev link
+	 *
+	 * @param $maxresults
+	 *		The maximum amount of items shown per page (e.g. 10)
+	 * @param $startpos
+	 *		Current start position (requestVar('startpos'))
+	 * @param $direction
+	 *		either 'prev' or 'next'
+	 * @param $linktext
+	 *		When present, the output will be a full <a href...> link. When empty,
+	 *		only a raw link will be outputted
+	 */
+	function _searchlink($maxresults, $startpos, $direction, $linktext = '') {
+		global $CONF, $blog, $query, $amount;
+		// TODO: Move request uri to linkparams. this is ugly. sorry for that.
+		$startpos	= intval($startpos);		// will be 0 when empty.
+		$parsed		= parse_url(serverVar('REQUEST_URI'));
+		$parsed		= $parsed['query'];
+		$url		= '';
+
+		switch ($direction) {
+			case 'prev':
+				if ( intval($startpos) - intval($maxresults) >= 0) {
+					$startpos 	= intval($startpos) - intval($maxresults);
+					$url		= $CONF['SearchURL'].'?'.alterQueryStr($parsed,'startpos',$startpos);
+				}
+				break;
+			case 'next':
+				$iAmountOnPage = $this->amountfound;
+				if ($iAmountOnPage == 0)
+				{
+					// [%nextlink%] or [%prevlink%] probably called before [%blog%] or [%searchresults%]
+					// try a count query
+					switch ($this->skintype)
+					{
+						case 'index':
+							$sqlquery = $blog->getSqlBlog('', 'count');
+							break;
+						case 'search':
+							$sqlquery = $blog->getSqlSearch($query, $amount, $unused_highlight, 'count');
+							break;
+					}
+					if ($sqlquery)
+						$iAmountOnPage = intval(quickQuery($sqlquery)) - intval($startpos);
+				}
+				if (intval($iAmountOnPage) >= intval($maxresults)) {
+					$startpos 	= intval($startpos) + intval($maxresults);
+					$url		= $CONF['SearchURL'].'?'.alterQueryStr($parsed,'startpos',$startpos);
+				}
+				break;
+			default:
+				break;
+		} // switch($direction)
+
+		if ($url != '')
+			echo $this->_link($url, $linktext);
+	}
+
+	/**
+	 *  Creates an item link and if no id is given a todaylink 
+	 */
+	function _itemlink($id, $linktext = '') {
+		global $CONF;
+		if ($id)
+			echo $this->_link(createItemLink($id, $this->linkparams), $linktext);
+		else
+			$this->parse_todaylink($linktext);
+	}
+	
+	/**
+	 *  Creates an archive link and if no id is given a todaylink 
+	 */
+	function _archivelink($id, $linktext = '') {
+		global $CONF, $blog;
+		if ($id)
+			echo $this->_link(createArchiveLink($blog->getID(), $id, $this->linkparams), $linktext);
+		else
+			$this->parse_todaylink($linktext);
+	}
+	
+	/**
+	  * Helper function that sets the category that a blog will need to use
+	  *
+	  * @param $blog
+	  *		An object of the blog class, passed by reference (we want to make changes to it)
+	  * @param $catname
+	  *		The name of the category to use
+	  */
+	function _setBlogCategory(&$blog, $catname) {
+		global $catid;
+		if ($catname != '')
+			$blog->setSelectedCategoryByName($catname);
+		else
+			$blog->setSelectedCategory($catid);
+	}
+
+	/**
+	 *  Notifies the Manager that a PreBlogContent event occurs
+	 */
+	function _preBlogContent($type, &$blog) {
+		global $manager;
+		$manager->notify('PreBlogContent',array('blog' => &$blog, 'type' => $type));
+	}
+
+	/**
+	 *  Notifies the Manager that a PostBlogContent event occurs
+	 */
+	function _postBlogContent($type, &$blog) {
+		global $manager;
+		$manager->notify('PostBlogContent',array('blog' => &$blog, 'type' => $type));
+	}
+	
+	/**
+	 * Parse skinvar additemform
+	 */
+	function parse_additemform() {
+		global $blog, $CONF;
+		$this->formdata = array(
+			'adminurl' => htmlspecialchars($CONF['AdminURL'],ENT_QUOTES),
+			'catid' => $blog->getDefaultCategory()
+		);
+		$blog->InsertJavaScriptInfo();
+		$this->doForm('additemform');
+	}
+	
+	/**
+	 * Parse skinvar adminurl
+	 * (shortcut for admin url)	 
+	 */
+	function parse_adminurl() {
+		$this->parse_sitevar('adminurl');
+	}
+
+	/**
+	 * Parse skinvar archive
+	 */
+	function parse_archive($template, $category = '') {
+		global $blog, $archive;
+		// can be used with either yyyy-mm or yyyy-mm-dd
+		sscanf($archive,'%d-%d-%d',$y,$m,$d);
+		$this->_setBlogCategory($blog, $category);
+		$this->_preBlogContent('achive',$blog);
+		$blog->showArchive($template, $y, $m, $d);
+		$this->_postBlogContent('achive',$blog);
+
+	}
+
+	/**
+	  * %archivedate(locale,date format)%
+	  */
+	function parse_archivedate($locale = '-def-') {
+		global $archive;
+
+		if ($locale == '-def-')
+			setlocale(LC_TIME,$template['LOCALE']);
+		else
+			setlocale(LC_TIME,$locale);
+
+		// get archive date
+		sscanf($archive,'%d-%d-%d',$y,$m,$d);
+
+		// get format
+		$args = func_get_args();
+		// format can be spread over multiple parameters
+		if (sizeof($args) > 1) {
+			// take away locale
+			array_shift($args);
+			// implode
+			$format=implode(',',$args);
+		} elseif ($d == 0) {
+			$format = '%B %Y';
+		} else {
+			$format = '%d %B %Y';
+		}
+
+		echo strftime($format,mktime(0,0,0,$m,$d?$d:1,$y));
+	}
+
+	/**
+	 *  Parse skinvar archivedaylist
+	 */	 	
+	function parse_archivedaylist($template, $category = 'all', $limit = 0) {
+		global $blog;
+		if ($category == 'all') $category = '';
+		$this->_preBlogContent('archivelist',$blog);
+		$this->_setBlogCategory($blog, $category);
+		$blog->showArchiveList($template, 'day', $limit);
+		$this->_postBlogContent('archivelist',$blog);
+	}
+	
+	/**
+	 *	A link to the archives for the current blog (or for default blog)
+	 */
+	function parse_archivelink($linktext = '') {
+		global $blog, $CONF;
+		if ($blog)
+			echo $this->_link(createArchiveListLink($blog->getID(),$this->linkparams), $linktext);
+		else
+			echo $this->_link(createArchiveListLink(), $linktext);
+	}
+
+	function parse_archivelist($template, $category = 'all', $limit = 0) {
+		global $blog;
+		if ($category == 'all') $category = '';
+		$this->_preBlogContent('archivelist',$blog);
+		$this->_setBlogCategory($blog, $category);
+		$blog->showArchiveList($template, 'month', $limit);
+		$this->_postBlogContent('archivelist',$blog);
+	}
+
+	/**
+	 * Parse skinvar archivetype
+	 */
+	function parse_archivetype() {
+		global $archivetype;
+		echo $archivetype;
+	}
+
+	/**
+	 * Parse skinvar blog
+	 */
+	function parse_blog($template, $amount = 10, $category = '') {
+		global $blog, $startpos;
+
+		list($limit, $offset) = sscanf($amount, '%d(%d)');
+		$this->_setBlogCategory($blog, $category);
+		$this->_preBlogContent('blog',$blog);
+		$this->amountfound = $blog->readLog($template, $limit, $offset, $startpos);
+		$this->_postBlogContent('blog',$blog);
+	}
+	
+	/*
+	*	Parse skinvar bloglist
+	*	Shows a list of all blogs
+	*	bnametype: whether 'name' or 'shortname' is used for the link text 	  
+	*/
+	function parse_bloglist($template, $bnametype = '') {
+		BLOG::showBlogList($template, $bnametype);
+	}
+	
+	/**
+	 * Parse skinvar blogsetting
+	 */
+	function parse_blogsetting($which) {
+		global $blog;
+		switch($which) {
+			case 'id':
+				echo htmlspecialchars($blog->getID(),ENT_QUOTES);
+				break;
+			case 'url':
+				echo htmlspecialchars($blog->getURL(),ENT_QUOTES);
+				break;
+			case 'name':
+				echo htmlspecialchars($blog->getName(),ENT_QUOTES);
+				break;
+			case 'desc':
+				echo htmlspecialchars($blog->getDescription(),ENT_QUOTES);
+				break;
+			case 'short':
+				echo htmlspecialchars($blog->getShortName(),ENT_QUOTES);
+				break;
+		}
+	}
+	
+	/**
+	 * Parse callback
+	 */
+	function parse_callback($eventName, $type)
+	{
+		global $manager;
+		$manager->notify($eventName, array('type' => $type));
+	}
+	
+	/**
+	 * Parse skinvar category
+	 */
+	function parse_category($type = 'name') {
+		global $catid, $blog;
+		if (!$blog->isValidCategory($catid))
+			return;
+
+		switch($type) {
+			case 'name':
+				echo $blog->getCategoryName($catid);
+				break;
+			case 'desc':
+				echo $blog->getCategoryDesc($catid);
+				break;
+			case 'id':
+				echo $catid;
+				break;
+		}
+	}
+	
+	/**
+	 * Parse categorylist
+	 */
+	function parse_categorylist($template, $blogname = '') {
+		global $blog, $manager;
+
+		if ($blogname == '') {
+			$this->_preBlogContent('categorylist',$blog);
+			$blog->showCategoryList($template);
+			$this->_postBlogContent('categorylist',$blog);
+		} else {
+			$b =& $manager->getBlog(getBlogIDFromName($blogname));
+			$this->_preBlogContent('categorylist',$b);
+			$b->showCategoryList($template);
+			$this->_postBlogContent('categorylist',$b);
+		}
+	}
+	
+	/**
+	 * Parse skinvar charset
+	 */
+	function parse_charset() {
+		echo _CHARSET;
+	}
+	
+	/**
+	 * Parse skinvar commentform
+	 */
+	function parse_commentform($destinationurl = '') {
+		global $blog, $itemid, $member, $CONF, $manager, $DIR_LIBS, $errormessage;
+
+		// warn when trying to provide a actionurl (used to be a parameter in Nucleus <2.0)
+		if (stristr($destinationurl, 'action.php')) {
+			$args = func_get_args();
+			$destinationurl = $args[1];
+			ACTIONLOG::add(WARNING,'actionurl is not longer a parameter on commentform skinvars. Moved to be a global setting instead.');
+		}
+
+		$actionurl = $CONF['ActionURL'];
+
+		// if item is closed, show message and do nothing
+		$item =& $manager->getItem($itemid,0,0);
+		if ($item['closed'] || !$blog->commentsEnabled()) {
+			$this->doForm('commentform-closed');
+			return;
+		}
+
+		if (!$destinationurl)
+		{
+			$destinationurl = createLink(
+				'item',
+				array(
+					'itemid' => $itemid,
+					'title' => $item['title'],
+					'timestamp' => $item['timestamp'],
+					'extra' => $this->linkparams
+				)
+			);
+
+			// note: createLink returns an HTML encoded URL
+		} else {
+			// HTML encode URL
+			$destinationurl = htmlspecialchars($destinationurl,ENT_QUOTES);
+		}
+
+		// values to prefill
+		$user = cookieVar($CONF['CookiePrefix'] .'comment_user');
+		if (!$user) $user = postVar('user');
+		$userid = cookieVar($CONF['CookiePrefix'] .'comment_userid');
+		if (!$userid) $userid = postVar('userid');
+		$email = cookieVar($CONF['CookiePrefix'] .'comment_email');
+		if (!$email) {
+			$email = postVar('email');
+		}
+		$body = postVar('body');
+
+		$this->formdata = array(
+			'destinationurl' => $destinationurl,	// url is already HTML encoded
+			'actionurl' => htmlspecialchars($actionurl,ENT_QUOTES),
+			'itemid' => $itemid,
+			'user' => htmlspecialchars($user,ENT_QUOTES),
+			'userid' => htmlspecialchars($userid,ENT_QUOTES),
+			'email' => htmlspecialchars($email,ENT_QUOTES),
+			'body' => htmlspecialchars($body,ENT_QUOTES),
+			'membername' => $member->getDisplayName(),
+			'rememberchecked' => cookieVar($CONF['CookiePrefix'] .'comment_user')?'checked="checked"':''
+		);
+
+		if (!$member->isLoggedIn()) {
+			$this->doForm('commentform-notloggedin');
+		} else {
+			$this->doForm('commentform-loggedin');
+		}
+	}
+	
+	/**
+	 * Parse skinvar comments
+	 * include comments for one item	 
+	 */
+	function parse_comments($template) {
+		global $itemid, $manager, $blog, $highlight;
+		$template =& $manager->getTemplate($template);
+
+		// create parser object & action handler
+		$actions =& new ITEMACTIONS($blog);
+		$parser =& new PARSER($actions->getDefinedActions(),$actions);
+		$actions->setTemplate($template);
+		$actions->setParser($parser);
+		$item = ITEM::getitem($itemid, 0, 0);
+		$actions->setCurrentItem($item);
+
+		$comments =& new COMMENTS($itemid);
+		$comments->setItemActions($actions);
+		$comments->showComments($template, -1, 1, $highlight);	// shows ALL comments
+	}
+
+	/**
+	 * Parse errordiv
+	 */
+	function parse_errordiv() {
+		global $errormessage;
+		if ($errormessage)
+			echo '<div class="error">', htmlspecialchars($errormessage),'</div>';
+	}
+	
+	/**
+	 * Parse skinvar errormessage
+	 */
+	function parse_errormessage() {
+		global $errormessage;
+		echo $errormessage;
+	}
+	
+	/**
+	 * Parse formdata
+	 */
+	function parse_formdata($what) {
+		echo $this->formdata[$what];
+	}
+	
+	/**
+	 * Parse ifcat
+	 */
+	function parse_ifcat($text = '') {
+		if ($text == '') {
+			// new behaviour
+			$this->parse_if('category');
+		} else {
+			// old behaviour
+			global $catid, $blog;
+			if ($blog->isValidCategory($catid))
+				echo $text;
+		}
+	}
+
+	/**
+	 * Parse skinvar image
+	 */
+	function parse_image($what = 'imgtag') {
+		global $CONF;
+
+		$imagetext 	= htmlspecialchars(requestVar('imagetext'));
+		$imagepopup = requestVar('imagepopup');
+		$width 		= intRequestVar('width');
+		$height 	= intRequestVar('height');
+		$fullurl 	= htmlspecialchars($CONF['MediaURL'] . $imagepopup);
+
+		switch($what)
+		{
+			case 'url':
+				echo $fullurl;
+				break;
+			case 'width':
+				echo $width;
+				break;
+			case 'height':
+				echo $height;
+				break;
+			case 'caption':
+			case 'text':
+				echo $imagetext;
+				break;
+			case 'imgtag':
+			default:
+				echo "<img src=\"$fullurl\" width=\"$width\" height=\"$height\" alt=\"$imagetext\" title=\"$imagetext\" />";
+				break;
+		}
+	}
+	
+	/**
+	 * Parse skinvar imagetext
+	 */
+	function parse_imagetext() {
+		echo htmlspecialchars(requestVar('imagetext'),ENT_QUOTES);
+	}
+
+	/**
+	 * Parse skinvar item
+	 * include one item (no comments)	 
+	 */
+	function parse_item($template) {
+		global $blog, $itemid, $highlight;
+		$this->_setBlogCategory($blog, '');	// need this to select default category
+		$this->_preBlogContent('item',$blog);
+		$r = $blog->showOneitem($itemid, $template, $highlight);
+		if ($r == 0)
+			echo _ERROR_NOSUCHITEM;
+		$this->_postBlogContent('item',$blog);
+	}
+
+	/**
+	 * Parse skinvar itemid
+	 */
+	function parse_itemid() {
+		global $itemid;
+		echo $itemid;
+	}
+	
+	/**
+	 * Parse skinvar itemlink
+	 */
+	function parse_itemlink($linktext = '') {
+		global $itemid;
+		$this->_itemlink($itemid, $linktext);
+	}
+
+	/**
+	 * Parse itemtitle
+	 */
+	function parse_itemtitle($format = '') {
+		global $manager, $itemid;
+		$item =& $manager->getItem($itemid,0,0);
+
+		switch ($format) {
+			case 'xml':
+				echo stringToXML ($item['title']);
+				break;
+			case 'attribute':
+				echo stringToAttribute ($item['title']);
+				break;
+			case 'raw':
+				echo $item['title'];
+				break;
+			default:
+				echo htmlspecialchars(strip_tags($item['title']),ENT_QUOTES);
+				break;
+		}
+	}
+
+	/**
+	 * Parse skinvar loginform
+	 */
+	function parse_loginform() {
+		global $member, $CONF;
+		if (!$member->isLoggedIn()) {
+			$filename = 'loginform-notloggedin';
+			$this->formdata = array();
+		} else {
+			$filename = 'loginform-loggedin';
+			$this->formdata = array(
+				'membername' => $member->getDisplayName(),
+			);
+		}
+		$this->doForm($filename);
+	}
+
+	/**
+	 * Parse skinvar member
+	 * (includes a member info thingie)	 
+	 */
+	function parse_member($what) {
+		global $memberinfo, $member;
+
+		// 1. only allow the member-details-page specific variables on member pages
+		if ($this->skintype == 'member') {
+
+			switch($what) {
+				case 'name':
+					echo htmlspecialchars($memberinfo->getDisplayName(),ENT_QUOTES);
+					break;
+				case 'realname':
+					echo htmlspecialchars($memberinfo->getRealName(),ENT_QUOTES);
+					break;
+				case 'notes':
+					echo htmlspecialchars($memberinfo->getNotes(),ENT_QUOTES);
+					break;
+				case 'url':
+					echo htmlspecialchars($memberinfo->getURL(),ENT_QUOTES);
+					break;
+				case 'email':
+					echo htmlspecialchars($memberinfo->getEmail(),ENT_QUOTES);
+					break;
+				case 'id':
+					echo htmlspecialchars($memberinfo->getID(),ENT_QUOTES);
+					break;
+			}
+		}
+
+		// 2. the next bunch of options is available everywhere, as long as the user is logged in
+		if ($member->isLoggedIn())
+		{
+			switch($what) {
+				case 'yourname':
+					echo $member->getDisplayName();
+					break;
+				case 'yourrealname':
+					echo $member->getRealName();
+					break;
+				case 'yournotes':
+					echo $member->getNotes();
+					break;
+				case 'yoururl':
+					echo $member->getURL();
+					break;
+				case 'youremail':
+					echo $member->getEmail();
+					break;
+				case 'yourid':
+					echo $member->getID();
+					break;
+			}
+		}
+
+	}
+
+	/**
+	 * Parse skinvar membermailform
+	 */
+	function parse_membermailform($rows = 10, $cols = 40, $desturl = '') {
+		global $member, $CONF, $memberid;
+
+		if ($desturl == '') {
+			if ($CONF['URLMode'] == 'pathinfo')
+				$desturl = createMemberLink($memberid);
+			else
+				$desturl = $CONF['IndexURL'] . createMemberLink($memberid);
+		}
+
+		$message = postVar('message');
+		$frommail = postVar('frommail');
+
+		$this->formdata = array(
+			'url' => htmlspecialchars($desturl),
+			'actionurl' => htmlspecialchars($CONF['ActionURL'],ENT_QUOTES),
+			'memberid' => $memberid,
+			'rows' => $rows,
+			'cols' => $cols,
+			'message' => htmlspecialchars($message,ENT_QUOTES),
+			'frommail' => htmlspecialchars($frommail,ENT_QUOTES)
+		);
+		if ($member->isLoggedIn()) {
+			$this->doForm('membermailform-loggedin');
+		} else if ($CONF['NonmemberMail']) {
+			$this->doForm('membermailform-notloggedin');
+		} else {
+			$this->doForm('membermailform-disallowed');
+		}
+
+	}
+	
+	/**
+	 * Parse skinvar nextarchive
+	 */
+	function parse_nextarchive() {
+		global $archivenext;
+		echo $archivenext;
+	}
+
+	/**
+	 * Parse skinvar nextitem
+	 * (include itemid of next item)
+	 */
+	function parse_nextitem() {
+		global $itemidnext;
+		if (isset($itemidnext)) echo (int)$itemidnext;
+	}
+
+	/**
+	 * Parse skinvar nextitemtitle
+	 * (include itemtitle of next item)
+	 */
+	function parse_nextitemtitle($format = '') {
+		global $itemtitlenext;
+
+		switch ($format) {
+			case 'xml':
+				echo stringToXML ($itemtitlenext);
+				break;
+			case 'attribute':
+				echo stringToAttribute ($itemtitlenext);
+				break;
+			case 'raw':
+				echo $itemtitlenext;
+				break;
+			default:
+				echo htmlspecialchars($itemtitlenext,ENT_QUOTES);
+				break;
+		}
+	}
+
+	/**
+	 * Parse skinvar nextlink
+	 */
+	function parse_nextlink($linktext = '', $amount = 10) {
+		global $itemidnext, $archivenext, $startpos;
+		if ($this->skintype == 'item')
+			$this->_itemlink($itemidnext, $linktext);
+		else if ($this->skintype == 'search' || $this->skintype == 'index')
+			$this->_searchlink($amount, $startpos, 'next', $linktext);
+		else
+			$this->_archivelink($archivenext, $linktext);
+	}
+
+	/**
+	 * Parse skinvar nucleusbutton
+	 */
+	function parse_nucleusbutton($imgurl = '',
+								 $imgwidth = '85',
+								 $imgheight = '31') {
+		global $CONF;
+		if ($imgurl == '') {
+			$imgurl = $CONF['AdminURL'] . 'nucleus.gif';
+		} else if (PARSER::getProperty('IncludeMode') == 'skindir'){
+			// when skindit IncludeMode is used: start from skindir
+			$imgurl = $CONF['SkinsURL'] . PARSER::getProperty('IncludePrefix') . $imgurl;
+		}
+
+		$this->formdata = array(
+			'imgurl' => $imgurl,
+			'imgwidth' => $imgwidth,
+			'imgheight' => $imgheight,
+		);
+		$this->doForm('nucleusbutton');
+	}
+	
+	/**
+	 * Parse skinvar otherarchive
+	 */	
+	function parse_otherarchive($blogname, $template, $category = '') {
+		global $archive, $manager;
+		sscanf($archive,'%d-%d-%d',$y,$m,$d);
+		$b =& $manager->getBlog(getBlogIDFromName($blogname));
+		$this->_setBlogCategory($b, $category);
+		$this->_preBlogContent('otherachive',$b);
+		$b->showArchive($template, $y, $m, $d);
+		$this->_postBlogContent('otherachive',$b);
+	}
+	
+	/**
+	 * Parse skinvar otherarchivedaylist
+	 */
+	function parse_otherarchivedaylist($blogname, $template, $category = 'all', $limit = 0) {
+		global $manager;
+		if ($category == 'all') $category = '';
+		$b =& $manager->getBlog(getBlogIDFromName($blogname));
+		$this->_setBlogCategory($b, $category);
+		$this->_preBlogContent('otherarchivelist',$b);
+		$b->showArchiveList($template, 'day', $limit);
+		$this->_postBlogContent('otherarchivelist',$b);
+	}
+	
+	/**
+	 * Parse skinvar otherarchivelist
+	 */
+	function parse_otherarchivelist($blogname, $template, $category = 'all', $limit = 0) {
+		global $manager;
+		if ($category == 'all') $category = '';
+		$b =& $manager->getBlog(getBlogIDFromName($blogname));
+		$this->_setBlogCategory($b, $category);
+		$this->_preBlogContent('otherarchivelist',$b);
+		$b->showArchiveList($template, 'month', $limit);
+		$this->_postBlogContent('otherarchivelist',$b);
+	}
+	
+	/**
+	 * Parse skinvar otherblog
+	 */
+	function parse_otherblog($blogname, $template, $amount = 10, $category = '') {
+		global $manager;
+
+		list($limit, $offset) = sscanf($amount, '%d(%d)');
+
+		$b =& $manager->getBlog(getBlogIDFromName($blogname));
+		$this->_setBlogCategory($b, $category);
+		$this->_preBlogContent('otherblog',$b);
+		$this->amountfound = $b->readLog($template, $limit, $offset);
+		$this->_postBlogContent('otherblog',$b);
+	}
+
+	/**
+	 * Parse skinvar othersearchresults
+	 */
+	function parse_othersearchresults($blogname, $template, $maxresults = 50) {
+		global $query, $amount, $manager, $startpos;
+		$b =& $manager->getBlog(getBlogIDFromName($blogname));
+		$this->_setBlogCategory($b, '');	// need this to select default category
+		$this->_preBlogContent('othersearchresults',$b);
+		$b->search($query, $template, $amount, $maxresults, $startpos);
+		$this->_postBlogContent('othersearchresults',$b);
+	}
+
+	/**
+	  * Executes a plugin skinvar
+	  *
+	  * @param pluginName name of plugin (without the NP_)
+	  *
+	  * extra parameters can be added
+	  */
+	function parse_plugin($pluginName) {
+		global $manager;
+
+		// only continue when the plugin is really installed
+		if (!$manager->pluginInstalled('NP_' . $pluginName))
+			return;
+
+		$plugin =& $manager->getPlugin('NP_' . $pluginName);
+		if (!$plugin) return;
+
+		// get arguments
+		$params = func_get_args();
+
+		// remove plugin name
+		array_shift($params);
+
+		// add skin type on front
+		array_unshift($params, $this->skintype);
+
+		call_user_func_array(array(&$plugin,'doSkinVar'), $params);
+	}
+	
+	/**
+	 * Parse skinvar prevarchive
+	 */
+	function parse_prevarchive() {
+		global $archiveprev;
+		echo $archiveprev;
+	}
+
+	/**
+	 * Parse skinvar preview
+	 */
+	function parse_preview($template) {
+		global $blog, $CONF, $manager;
+
+		$template =& $manager->getTemplate($template);
+		$row['body'] = '<span id="prevbody"></span>';
+		$row['title'] = '<span id="prevtitle"></span>';
+		$row['more'] = '<span id="prevmore"></span>';
+		$row['itemlink'] = '';
+		$row['itemid'] = 0; $row['blogid'] = $blog->getID();
+		echo TEMPLATE::fill($template['ITEM_HEADER'],$row);
+		echo TEMPLATE::fill($template['ITEM'],$row);
+		echo TEMPLATE::fill($template['ITEM_FOOTER'],$row);
+	}
+
+	/*
+	 * Parse skinvar previtem
+	 * (include itemid of prev item)	 	 
+	 */
+	function parse_previtem() {
+		global $itemidprev;
+		if (isset($itemidprev)) echo (int)$itemidprev;
+	}
+
+	/**
+	 * Parse skinvar previtemtitle
+	 * (include itemtitle of prev item)
+	 */
+	function parse_previtemtitle($format = '') {
+		global $itemtitleprev;
+
+		switch ($format) {
+			case 'xml':
+				echo stringToXML ($itemtitleprev);
+				break;
+			case 'attribute':
+				echo stringToAttribute ($itemtitleprev);
+				break;
+			case 'raw':
+				echo $itemtitleprev;
+				break;
+			default:
+				echo htmlspecialchars($itemtitleprev,ENT_QUOTES);
+				break;
+		}
+	}
+
+	/**
+	 * Parse skinvar prevlink
+	 */
+	function parse_prevlink($linktext = '', $amount = 10) {
+		global $itemidprev, $archiveprev, $startpos;
+
+		if ($this->skintype == 'item')
+			$this->_itemlink($itemidprev, $linktext);
+		else if ($this->skintype == 'search' || $this->skintype == 'index')
+			$this->_searchlink($amount, $startpos, 'prev', $linktext);
+		else
+			$this->_archivelink($archiveprev, $linktext);
+	}
+
+	/**
+	 * Parse skinvar query
+	 * (includes the search query)	 
+	 */
+	function parse_query() {
+		global $query;
+		echo htmlspecialchars($query,ENT_QUOTES);
+	}
+	
+	/**
+	 * Parse skinvar referer
+	 */
+	function parse_referer() {
+		echo htmlspecialchars(serverVar('HTTP_REFERER'),ENT_QUOTES);
+	}
+
+	/**
+	 * Parse skinvar searchform
+	 */
+	function parse_searchform($blogname = '') {
+		global $CONF, $manager, $maxresults;
+		if ($blogname) {
+			$blog =& $manager->getBlog(getBlogIDFromName($blogname));
+		} else {
+			global $blog;
+		}
+		// use default blog when no blog is selected
+		$this->formdata = array(
+			'id' => $blog?$blog->getID():$CONF['DefaultBlog'],
+			'query' => htmlspecialchars(getVar('query'),ENT_QUOTES),
+		);
+		$this->doForm('searchform');
+	}
+
+	/**
+	 * Parse skinvar searchresults
+	 */
+	function parse_searchresults($template, $maxresults = 50 ) {
+		global $blog, $query, $amount, $startpos;
+
+		$this->_setBlogCategory($blog, '');	// need this to select default category
+		$this->_preBlogContent('searchresults',$blog);
+		$this->amountfound = $blog->search($query, $template, $amount, $maxresults, $startpos);
+		$this->_postBlogContent('searchresults',$blog);
+	}
+
+	/**
+	 * Parse skinvar self
+	 */
+	function parse_self() {
+		global $CONF;
+		echo $CONF['Self'];
+	}
+
+	/**
+	 * Parse skinvar sitevar
+	 * (include a sitevar)	 
+	 */
+	function parse_sitevar($which) {
+		global $CONF;
+		switch($which) {
+			case 'url':
+				echo $CONF['IndexURL'];
+				break;
+			case 'name':
+				echo $CONF['SiteName'];
+				break;
+			case 'admin':
+				echo $CONF['AdminEmail'];
+				break;
+			case 'adminurl':
+				echo $CONF['AdminURL'];
+		}
+	}
+
+	/**
+	 * Parse skinname
+	 */
+	function parse_skinname() {
+		echo $this->skin->getName();
+	}
+	
+	/**
+	 * Parse skintype (experimental)
+	 */
+	function parse_skintype() {
+		echo $this->skintype;
+	}
+
+	/**
+	 * Parse text
+	 */
+	function parse_text($which) {
+		// constant($which) only available from 4.0.4 :(
+		if (defined($which)) {
+			eval("echo $which;");
+		}
+	}
+	
+	/**
+	 * Parse ticket
+	 */
+	function parse_ticket() {
+		global $manager;
+		$manager->addTicketHidden();
+	}
+
+	/**
+	 *	Parse skinvar todaylink
+	 *	A link to the today page (depending on selected blog, etc...)
+	 */
+	function parse_todaylink($linktext = '') {
+		global $blog, $CONF;
+		if ($blog)
+			echo $this->_link(createBlogidLink($blog->getID(),$this->linkparams), $linktext);
+		else
+			echo $this->_link($CONF['SiteUrl'], $linktext);
+	}
+
+	/**
+	 * Parse vars
+	 * When commentform is not used, to include a hidden field with itemid	 
+	 */
+	function parse_vars() {
+		global $itemid;
+		echo '<input type="hidden" name="itemid" value="'.$itemid.'" />';
+	}
+
+	/**
+	 * Parse skinvar version
+	 * (include nucleus versionnumber)	 
+	 */
+	function parse_version() {
+		global $nucleus;
+		echo 'Nucleus CMS ' . $nucleus['version'];
+	}
+
+}
+?>
diff -ruN 3.24.src/nucleus/libs/ADMIN.php 3.31.src/nucleus/libs/ADMIN.php
--- 3.24.src/nucleus/libs/ADMIN.php	2006-11-29 15:23:33.000000000 -0600
+++ 3.31.src/nucleus/libs/ADMIN.php	2007-10-22 19:36:02.000000000 -0500
@@ -1,37 +1,47 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * The code for the Nucleus admin area
-  *
+ * The code for the Nucleus admin area
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: ADMIN.php 1104 2006-11-11 10:21:45Z dekarma $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: ADMIN.php 1189 2007-08-06 15:30:51Z kaigreve $
+ */
+
+if ( !function_exists('requestVar') ) exit;
+require_once dirname(__FILE__) . '/showlist.php';
 
+/**
+ * Builds the admin area and executes admin actions
+ */
 class ADMIN {
 
-	// action currently being executed ($action=xxxx -> action_xxxx method)
+	/**
+	 * @var string $action action currently being executed ($action=xxxx -> action_xxxx method)
+	 */
 	var $action;
 
+	/**
+	 * Class constructor
+	 */
 	function ADMIN() {
 
 	}
 
 	/**
-	  * Executes an action
-	  *
-	  * @param $action
-	  *		action to be performed
-	  */
+	 * Executes an action
+	 *
+	 * @param string $action action to be performed
+	 */
 	function action($action) {
 		global $CONF, $manager;
 
@@ -41,7 +51,7 @@
 			'' => 'overview'
 		);
 
-		if ($alias[$action])
+		if (isset($alias[$action]))
 			$action = $alias[$action];
 
 		$methodName = 'action_' . $action;
@@ -51,7 +61,7 @@
 		// check ticket. All actions need a ticket, unless they are considered to be safe (a safe action
 		// is an action that requires user interaction before something is actually done)
 		// all safe actions are in this array:
-		$aActionsNotToCheck = array('showlogin', 'login', 'overview', 'itemlist', 'blogcommentlist', 'bookmarklet', 'blogsettings', 'banlist', 'deleteblog', 'editmembersettings', 'browseownitems', 'browseowncomments', 'createitem', 'itemedit', 'itemmove', 'categoryedit', 'categorydelete', 'manage', 'actionlog', 'settingsedit', 'backupoverview', 'pluginlist', 'createnewlog', 'usermanagement', 'skinoverview', 'templateoverview', 'skinieoverview', 'itemcommentlist', 'commentedit', 'commentdelete', 'banlistnewfromitem', 'banlistdelete', 'itemdelete', 'manageteam', 'teamdelete', 'banlistnew', 'memberedit', 'memberdelete', 'pluginhelp', 'pluginoptions', 'plugindelete', 'skinedittype', 'skindelete', 'skinedit', 'templateedit', 'templatedelete', 'activate');
+		$aActionsNotToCheck = array('showlogin', 'login', 'overview', 'itemlist', 'blogcommentlist', 'bookmarklet', 'blogsettings', 'banlist', 'deleteblog', 'editmembersettings', 'browseownitems', 'browseowncomments', 'createitem', 'itemedit', 'itemmove', 'categoryedit', 'categorydelete', 'manage', 'actionlog', 'settingsedit', 'backupoverview', 'pluginlist', 'createnewlog', 'usermanagement', 'skinoverview', 'templateoverview', 'skinieoverview', 'itemcommentlist', 'commentedit', 'commentdelete', 'banlistnewfromitem', 'banlistdelete', 'itemdelete', 'manageteam', 'teamdelete', 'banlistnew', 'memberedit', 'memberdelete', 'pluginhelp', 'pluginoptions', 'plugindelete', 'skinedittype', 'skinremovetype', 'skindelete', 'skinedit', 'templateedit', 'templatedelete', 'activate');
 /*
 		// the rest of the actions needs to be checked
 		$aActionsToCheck = array('additem', 'itemupdate', 'itemmoveto', 'categoryupdate', 'categorydeleteconfirm', 'itemdeleteconfirm', 'commentdeleteconfirm', 'teamdeleteconfirm', 'memberdeleteconfirm', 'templatedeleteconfirm', 'skindeleteconfirm', 'banlistdeleteconfirm', 'plugindeleteconfirm', 'batchitem', 'batchcomment', 'batchmember', 'batchcategory', 'batchteam', 'regfile', 'commentupdate', 'banlistadd', 'changemembersettings', 'clearactionlog', 'settingsupdate', 'blogsettingsupdate', 'categorynew', 'teamchangeadmin', 'teamaddmember', 'memberadd', 'addnewlog', 'addnewlog2', 'backupcreate', 'backuprestore', 'pluginup', 'plugindown', 'pluginupdate', 'pluginadd', 'pluginoptionsupdate', 'skinupdate', 'skinclone', 'skineditgeneral', 'templateclone', 'templatenew', 'templateupdate', 'skinieimport', 'skinieexport', 'skiniedoimport', 'skinnew', 'deleteblogconfirm', 'sendping', 'rawping', 'activatesetpwd');
@@ -65,16 +75,21 @@
 		if (method_exists($this, $methodName))
 			call_user_func(array(&$this, $methodName));
 		else
-			$this->error(_BADACTION . " ($action)");
+			$this->error(_BADACTION . htmlspecialchars(" ($action)"));
 
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_showlogin() {
 		global $error;
 		$this->action_login($error);
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_login($msg = '', $passvars = 1) {
 		global $member;
 
@@ -118,8 +133,9 @@
 
 
 	/**
-	  * provides a screen with the overview of the actions available
-	  */
+	 * provides a screen with the overview of the actions available
+	 * @todo document parameter
+	 */
 	function action_overview($msg = '') {
 		global $member;
 
@@ -188,11 +204,17 @@
 		$this->pagefoot();
 	}
 
-	// returns a link to a weblog (takes BLOG object as parameter)
+	/**
+	 * Returns a link to a weblog
+	 * @param object BLOG
+	 */
 	function bloglink(&$blog) {
-		return '<a href="'.htmlspecialchars($blog->getURL()).'" title="'._BLOGLIST_TT_VISIT.'">'.$blog->getName() .'</a>';
+		return '<a href="'.htmlspecialchars($blog->getURL()).'" title="'._BLOGLIST_TT_VISIT.'">'. htmlspecialchars( $blog->getName() ) .'</a>';
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_manage($msg = '') {
 		global $member;
 
@@ -231,6 +253,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_itemlist($blogid = '') {
 		global $member, $manager;
 
@@ -280,7 +305,7 @@
 		$template['content'] = 'itemlist';
 		$template['now'] = $blog->getCorrectTime(time());
 
-
+		$manager->loadClass("ENCAPSULATE");
 		$navList =& new NAVLIST('itemlist', $start, $amount, 0, 1000, $blogid, $search, 0);
 		$navList->showBatchList('item',$query,'table',$template);
 
@@ -288,7 +313,9 @@
 		$this->pagefoot();
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_batchitem() {
 		global $member, $manager;
 
@@ -336,7 +363,7 @@
 					$error = $this->moveOneItem($itemid, $destCatid);
 					break;
 				default:
-					$error = _BATCH_UNKNOWN . $action;
+					$error = _BATCH_UNKNOWN . htmlspecialchars($action);
 			}
 
 			echo '<b>',($error ? $error : _BATCH_SUCCESS),'</b>';
@@ -351,6 +378,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_batchcomment() {
 		global $member;
 
@@ -389,7 +419,7 @@
 					$error = $this->deleteOneComment($commentid);
 					break;
 				default:
-					$error = _BATCH_UNKNOWN . $action;
+					$error = _BATCH_UNKNOWN . htmlspecialchars($action);
 			}
 
 			echo '<b>',($error ? $error : _BATCH_SUCCESS),'</b>';
@@ -404,6 +434,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_batchmember() {
 		global $member;
 
@@ -453,7 +486,7 @@
 						sql_query('UPDATE ' . sql_table('member') .' SET madmin=0 WHERE mnumber='.$memberid);
 					break;
 				default:
-					$error = _BATCH_UNKNOWN . $action;
+					$error = _BATCH_UNKNOWN . htmlspecialchars($action);
 			}
 
 			echo '<b>',($error ? $error : _BATCH_SUCCESS),'</b>';
@@ -468,7 +501,9 @@
 
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_batchteam() {
 		global $member;
 
@@ -521,7 +556,7 @@
 						sql_query('UPDATE '.sql_table('team').' SET tadmin=0 WHERE tblog='.$blogid.' and tmember='.$memberid);
 					break;
 				default:
-					$error = _BATCH_UNKNOWN . $action;
+					$error = _BATCH_UNKNOWN . htmlspecialchars($action);
 			}
 
 			echo '<b>',($error ? $error : _BATCH_SUCCESS),'</b>';
@@ -536,8 +571,9 @@
 
 	}
 
-
-
+	/**
+	 * @todo document this
+	 */
 	function action_batchcategory() {
 		global $member, $manager;
 
@@ -584,7 +620,7 @@
 					$error = $this->moveOneCategory($catid, $destBlogId);
 					break;
 				default:
-					$error = _BATCH_UNKNOWN . $action;
+					$error = _BATCH_UNKNOWN . htmlspecialchars($action);
 			}
 
 			echo '<b>',($error ? 'Error: '.$error : _BATCH_SUCCESS),'</b>';
@@ -598,6 +634,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function batchMoveSelectDestination($type, $ids) {
 		global $manager;
 		$this->pagehead();
@@ -628,6 +667,9 @@
 		exit;
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function batchMoveCategorySelectDestination($type, $ids) {
 		global $manager;
 		$this->pagehead();
@@ -658,6 +700,9 @@
 		exit;
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function batchAskDeleteConfirmation($type, $ids) {
 		global $manager;
 
@@ -696,21 +741,24 @@
 
 
 	/**
-	  * Inserts a HTML select element with choices for all categories to which the current
-	  * member has access
-	  */
+	 * Inserts a HTML select element with choices for all categories to which the current
+	 * member has access
+	 * @see function selectBlog
+	 */
 	function selectBlogCategory($name, $selected = 0, $tabindex = 0, $showNewCat = 0, $iForcedBlogInclude = -1) {
 		ADMIN::selectBlog($name, 'category', $selected, $tabindex, $showNewCat, $iForcedBlogInclude);
 	}
 
 	/**
-	  * Inserts a HTML select element with choices for all blogs to which the user has access
-	  *		mode = 'blog' => shows blognames and values are blogids
-	  *		mode = 'category' => show category names and values are catids
-	  *
-	  * @param $iForcedBlogInclude
-	  *		ID of a blog that always needs to be included, without checking if the member is on the blog team (-1 = none)
-	  */
+	 * Inserts a HTML select element with choices for all blogs to which the user has access
+	 *		mode = 'blog' => shows blognames and values are blogids
+	 *		mode = 'category' => show category names and values are catids
+	 *
+	 * @param $iForcedBlogInclude
+	 *		ID of a blog that always needs to be included, without checking if the
+	 *		member is on the blog team (-1 = none)
+	 * @todo document parameters
+	 */
 	function selectBlog($name, $mode='blog', $selected = 0, $tabindex = 0, $showNewCat = 0, $iForcedBlogInclude = -1) {
 		global $member, $CONF;
 
@@ -778,8 +826,11 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_browseownitems() {
-		global $member;
+		global $member, $manager;
 
 		$this->pagehead();
 
@@ -788,13 +839,13 @@
 
 		// start index
 		if (postVar('start'))
-			$start = postVar('start');
+			$start = intPostVar('start');
 		else
 			$start = 0;
 
 		// amount of items to show
 		if (postVar('amount'))
-			$amount = postVar('amount');
+			$amount = intPostVar('amount');
 		else
 			$amount = 10;
 
@@ -813,7 +864,8 @@
 		$template['content'] = 'itemlist';
 		$template['now'] = time();
 
-		$navList =& new NAVLIST('browseownitems', $start, $amount, 0, 1000, $blogid, $search, 0);
+		$manager->loadClass("ENCAPSULATE");
+		$navList =& new NAVLIST('browseownitems', $start, $amount, 0, 1000, /*$blogid*/ 0, $search, 0);
 		$navList->showBatchList('item',$query,'table',$template);
 
 		$this->pagefoot();
@@ -821,10 +873,11 @@
 	}
 
 	/**
-	  * Show all the comments for a given item
-	  */
+	 * Show all the comments for a given item
+	 * @param int $itemid
+	 */
 	function action_itemcommentlist($itemid = '') {
-		global $member;
+		global $member, $manager;
 
 		if ($itemid == '')
 			$itemid = intRequestVar('itemid');
@@ -838,13 +891,13 @@
 
 		// start index
 		if (postVar('start'))
-			$start = postVar('start');
+			$start = intPostVar('start');
 		else
 			$start = 0;
 
 		// amount of items to show
 		if (postVar('amount'))
-			$amount = postVar('amount');
+			$amount = intPostVar('amount');
 		else
 			$amount = 10;
 
@@ -864,6 +917,7 @@
 		$template['content'] = 'commentlist';
 		$template['canAddBan'] = $member->blogAdminRights(getBlogIDFromItemID($itemid));
 
+		$manager->loadClass("ENCAPSULATE");
 		$navList =& new NAVLIST('itemcommentlist', $start, $amount, 0, 1000, 0, $search, $itemid);
 		$navList->showBatchList('comment',$query,'table',$template,_NOCOMMENTS);
 
@@ -871,20 +925,20 @@
 	}
 
 	/**
-	  * Browse own comments
-	  */
+	 * Browse own comments
+	 */
 	function action_browseowncomments() {
-		global $member;
+		global $member, $manager;
 
 		// start index
 		if (postVar('start'))
-			$start = postVar('start');
+			$start = intPostVar('start');
 		else
 			$start = 0;
 
 		// amount of items to show
 		if (postVar('amount'))
-			$amount = postVar('amount');
+			$amount = intPostVar('amount');
 		else
 			$amount = 10;
 
@@ -907,6 +961,7 @@
 		$template['content'] = 'commentlist';
 		$template['canAddBan'] = 0;	// doesn't make sense to allow banning yourself
 
+		$manager->loadClass("ENCAPSULATE");
 		$navList =& new NAVLIST('browseowncomments', $start, $amount, 0, 1000, 0, $search, 0);
 		$navList->showBatchList('comment',$query,'table',$template,_NOCOMMENTS_YOUR);
 
@@ -914,8 +969,9 @@
 	}
 
 	/**
-	  * Browse all comments for a weblog
-	  */
+	 * Browse all comments for a weblog
+	 * @param int $blogid
+	 */
 	function action_blogcommentlist($blogid = '')
 	{
 		global $member, $manager;
@@ -929,20 +985,20 @@
 
 		// start index
 		if (postVar('start'))
-			$start = postVar('start');
+			$start = intPostVar('start');
 		else
 			$start = 0;
 
 		// amount of items to show
 		if (postVar('amount'))
-			$amount = postVar('amount');
+			$amount = intPostVar('amount');
 		else
 			$amount = 10;
 
 		$search = postVar('search');		// search through comments
 
 
-		$query =  'SELECT cbody, cuser, cmail, mname, ctime, chost, cnumber, cip, citem FROM '.sql_table('comment').' LEFT OUTER JOIN '.sql_table('member').' ON mnumber=cmember WHERE cblog=' . intval($blogid);
+		$query =  'SELECT cbody, cuser, cemail, cmail, mname, ctime, chost, cnumber, cip, citem FROM '.sql_table('comment').' LEFT OUTER JOIN '.sql_table('member').' ON mnumber=cmember WHERE cblog=' . intval($blogid);
 
 		if ($search != '')
 			$query .= ' and cbody LIKE "%' . addslashes($search) . '%"';
@@ -962,6 +1018,7 @@
 		$template['content'] = 'commentlist';
 		$template['canAddBan'] = $member->blogAdminRights($blogid);
 
+		$manager->loadClass("ENCAPSULATE");
 		$navList =& new NAVLIST('blogcommentlist', $start, $amount, 0, 1000, $blogid, $search, 0);
 		$navList->showBatchList('comment',$query,'table',$template, _NOCOMMENTS_BLOG);
 
@@ -969,8 +1026,8 @@
 	}
 
 	/**
-	  * Provide a page to item a new item to the given blog
-	  */
+	 * Provide a page to item a new item to the given blog
+	 */
 	function action_createitem() {
 		global $member, $manager;
 
@@ -992,6 +1049,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_itemedit() {
 		global $member, $manager;
 
@@ -1017,6 +1077,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_itemupdate() {
 		global $member, $manager, $CONF;
 
@@ -1038,6 +1101,7 @@
 		$title 	= postVar('title');
 		$more 	= postVar('more');
 		$closed = intPostVar('closed');
+		$draftid = intPostVar('draftid');
 
 		// default action = add now
 		if (!$actiontype)
@@ -1102,7 +1166,19 @@
 
 		$blogid = getBlogIDFromItemID($itemid);
 		$blog =& $manager->getBlog($blogid);
-		if (!$closed && $publish && $wasdraft && $blog->pingUserland()) {
+
+		$isFuture = 0;
+		if ($timestamp > $blog->getCorrectTime(time())) {
+			$isFuture = 1;
+		}
+
+		$this->updateFuturePosted($blogid);
+
+		if ($draftid > 0 && $member->canAlterItem($draftid)) {
+			ITEM::delete($draftid);
+		}
+
+		if (!$closed && $publish && $wasdraft && $blog->sendPing() && numberOfEventSubscriber('SendPing') > 0 && !$isFuture) {
 			$this->action_sendping($blogid);
 			return;
 		}
@@ -1121,6 +1197,9 @@
 		}
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_itemdelete() {
 		global $member, $manager;
 
@@ -1159,6 +1238,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_itemdeleteconfirm() {
 		global $member;
 
@@ -1176,7 +1258,10 @@
 		$this->action_itemlist($blogid);
 	}
 
-	// deletes one item and returns error if something goes wrong
+	/**
+	 * Deletes one item and returns error if something goes wrong
+	 * @param int $itemid
+	 */
 	function deleteOneItem($itemid) {
 		global $member, $manager;
 
@@ -1184,10 +1269,38 @@
 		if (!$member->canAlterItem($itemid))
 			return _ERROR_DISALLOWED;
 
+		// need to get blogid before the item is deleted
+		$blogid = getBlogIDFromItemId($itemid);
+
 		$manager->loadClass('ITEM');
 		ITEM::delete($itemid);
+
+		// update blog's futureposted
+		$this->updateFuturePosted($blogid);
+	}
+
+	/**
+	 * Update a blog's future posted flag
+	 * @param int $blogid
+	 */
+	function updateFuturePosted($blogid) {
+		global $manager;
+
+		$blog =& $manager->getBlog($blogid);
+		$currenttime = $blog->getCorrectTime(time());
+		$result = sql_query("SELECT * FROM ".sql_table('item').
+			" WHERE iblog='".$blogid."' AND iposted=0 AND itime>".mysqldate($currenttime));
+		if (mysql_num_rows($result) > 0) {
+				$blog->setFuturePost();
+		}
+		else {
+				$blog->clearFuturePost();
+		}
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_itemmove() {
 		global $member, $manager;
 
@@ -1217,6 +1330,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_itemmoveto() {
 		global $member, $manager;
 
@@ -1240,8 +1356,16 @@
 		// only allow if user is allowed to alter item
 		$member->canUpdateItem($itemid, $catid) or $this->disallow();
 
+		$old_blogid = getBlogIDFromItemId($itemid);
+
 		ITEM::move($itemid, $catid);
 
+		// set the futurePosted flag on the blog
+		$this->updateFuturePosted(getBlogIDFromItemId($itemid));
+
+		// reset the futurePosted in case the item is moved from one blog to another
+		$this->updateFuturePosted($old_blogid);
+
 		if ($catid != intRequestVar('catid'))
 			$this->action_categoryedit($catid, $blog->getID());
 		else
@@ -1249,9 +1373,11 @@
 	}
 
 	/**
-	  * Moves one item to a given category (category existance should be checked by caller)
-	  * errors are returned
-	  */
+	 * Moves one item to a given category (category existance should be checked by caller)
+	 * errors are returned
+	 * @param int $itemid
+	 * @param int $destCatid category ID to which the item will be moved
+	 */
 	function moveOneItem($itemid, $destCatid) {
 		global $member;
 
@@ -1263,8 +1389,8 @@
 	}
 
 	/**
-	  * Adds a item to the chosen blog
-	  */
+	 * Adds a item to the chosen blog
+	 */
 	function action_additem() {
 		global $member, $manager, $CONF;
 
@@ -1284,21 +1410,21 @@
 			$this->action_categoryedit(
 				$result['catid'],
 				$blogid,
-				$blog->pingUserland() ? $pingUrl : ''
+				$blog->sendPing() && numberOfEventSubscriber('SendPing') > 0 ? $pingUrl : ''
 			);
-		elseif ((postVar('actiontype') == 'addnow') && $blog->pingUserland())
+		elseif ((postVar('actiontype') == 'addnow') && $blog->sendPing() && numberOfEventSubscriber('SendPing') > 0)
 			$this->action_sendping($blogid);
 		else
 			$this->action_itemlist($blogid);
 	}
 
 	/**
-	  * Shows a window that says we're about to ping weblogs.com.
-	  * immediately refresh to the real pinging page, which will
-	  * show an error, or redirect to the blog.
-	  *
-	  * @param $blogid ID of blog for which ping needs to be sent out
-	  */
+	 * Shows a window that says we're about to ping.
+	 * immediately refresh to the real pinging page, which will
+	 * show an error, or redirect to the blog.
+	 *
+	 * @param int $blogid ID of blog for which ping needs to be sent out
+	 */
 	function action_sendping($blogid = -1) {
 		global $member, $manager;
 
@@ -1311,12 +1437,10 @@
 
 		$this->pagehead('<meta http-equiv="refresh" content="1; url='.htmlspecialchars($rawPingUrl).'" />');
 		?>
-		<h2>Site Updated, Now pinging weblogs.com</h2>
+		<h2>Site Updated, Now pinging various weblog listing services...</h2>
 
 		<p>
-			Pinging weblogs.com! This can a while...
-			<br />
-			When the ping is complete (and successfull), your weblog will show up in the weblogs.com updates list.
+			This can take a while...
 		</p>
 
 		<p>
@@ -1325,8 +1449,9 @@
 		<?php		$this->pagefoot();
 	}
 
-	// ping to Weblogs.com
-	// sends the real ping (can take up to 10 seconds!)
+	/**
+	 * Sends the real ping (can take up to 10 seconds!)
+	 */
 	function action_rawping() {
 		global $manager;
 		// TODO: checks?
@@ -1334,17 +1459,19 @@
 		$blogid = intRequestVar('blogid');
 		$blog =& $manager->getBlog($blogid);
 
-		$result = $blog->sendUserlandPing();
-
 		$this->pagehead();
 
 		?>
 
-		<h2>Ping Results</h2>
+		<h2>Pinging services, please wait...</h2>
+		<div class='note'>
+                <?
 
-		<p>The following message was returned by weblogs.com:</p>
+		// send sendPing event
+		$manager->notify('SendPing', array('blogid' => $blogid));
 
-		<div class='note'><?php echo  $result ?></div>
+                ?>
+                </div>
 
 		<ul>
 			<li><a href="index.php?action=itemlist&amp;blogid=<?php echo $blog->getID()?>">View list of recent items for <?php echo htmlspecialchars($blog->getName())?></a></li>
@@ -1355,8 +1482,8 @@
 	}
 
 	/**
-	  * Allows to edit previously made comments
-	  */
+	 * Allows to edit previously made comments
+	 */
 	function action_commentedit() {
 		global $member, $manager;
 
@@ -1417,6 +1544,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_commentupdate() {
 		global $member, $manager;
 
@@ -1460,6 +1590,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_commentdelete() {
 		global $member, $manager;
 
@@ -1500,6 +1633,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_commentdeleteconfirm() {
 		global $member;
 
@@ -1520,6 +1656,9 @@
 			$this->action_browseowncomments();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function deleteOneComment($commentid) {
 		global $member, $manager;
 
@@ -1540,8 +1679,8 @@
 	}
 
 	/**
-	  * Usermanagement main
-	  */
+	 * Usermanagement main
+	 */
 	function action_usermanagement() {
 		global $member, $manager;
 
@@ -1562,12 +1701,13 @@
 		$template['content'] = 'memberlist';
 		$template['tabindex'] = 10;
 
+		$manager->loadClass("ENCAPSULATE");
 		$batch =& new BATCH('member');
 		$batch->showlist($query,'table',$template);
 
 		echo '<h3>' . _MEMBERS_NEW .'</h3>';
 		?>
-			<form method="post" action="index.php"><div>
+			<form method="post" action="index.php" name="memberedit"><div>
 
 			<input type="hidden" name="action" value="memberadd" />
 			<?php $manager->addTicketHidden() ?>
@@ -1577,7 +1717,7 @@
 				<th colspan="2"><?php echo _MEMBERS_NEW?></th>
 			</tr><tr>
 				<td><?php echo _MEMBERS_DISPLAY?> <?php help('shortnames');?>
-					<br /><small>(This is the name used to logon)</small>
+				<br /><small><?php echo _MEMBERS_DISPLAY_INFO?></small>
 				</td>
 				<td><input tabindex="10010" name="name" size="16" maxlength="16" /></td>
 			</tr><tr>
@@ -1615,11 +1755,15 @@
 	}
 
 	/**
-	  * Edit member settings
-	  */
+	 * Edit member settings
+	 */
 	function action_memberedit() {
 		$this->action_editmembersettings(intRequestVar('memberid'));
 	}
+
+	/**
+	 * @todo document this
+	 */
 	function action_editmembersettings($memberid = '') {
 		global $member, $manager, $CONF;
 
@@ -1643,7 +1787,7 @@
 		$mem = MEMBER::createFromID($memberid);
 
 		?>
-		<form method="post" action="index.php"><div>
+		<form method="post" action="index.php" name="memberedit"><div>
 
 		<input type="hidden" name="action" value="changemembersettings" />
 		<input type="hidden" name="memberid" value="<?php echo  $memberid; ?>" />
@@ -1691,7 +1835,7 @@
 				<td><?php $this->input_yesno('admin',$mem->isAdmin(),60); ?></td>
 			</tr><tr>
 				<td><?php echo _MEMBERS_CANLOGIN?> <?php help('canlogin'); ?></td>
-				<td><?php $this->input_yesno('canlogin',$mem->canLogin(),70); ?></td>
+				<td><?php $this->input_yesno('canlogin',$mem->canLogin(),70,1,0,_YES,_NO,$mem->isAdmin()); ?></td>
 		<?php } ?>
 		</tr><tr>
 			<td><?php echo _MEMBERS_NOTES?></td>
@@ -1748,7 +1892,9 @@
 		$this->pagefoot();
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_changemembersettings() {
 		global $member, $CONF, $manager;
 
@@ -1834,7 +1980,7 @@
 
 
 		$mem->write();
-		
+
 		// store plugin options
 		$aOptions = requestArray('plugoption');
 		NucleusPlugin::_applyPluginOptions($aOptions);
@@ -1846,7 +1992,7 @@
 			$mem->sendActivationLink('addresschange', $oldEmail);
 			// logout member
 			$mem->newCookieKey();
-			
+
 			// only log out if the member being edited is the current member.
 			if ($member->getID() == $memberid)
 				$member->logout();
@@ -1866,6 +2012,9 @@
 		}
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_memberadd() {
 		global $member, $manager;
 
@@ -1881,10 +2030,10 @@
 		if ($res != 1)
 			$this->error($res);
 
-		// fire PostRegister event			
+		// fire PostRegister event
 		$newmem = new MEMBER();
 		$newmem->readFromName(postVar('name'));
-		$manager->notify('PostRegister',array('member' => &$newmem)); 			
+		$manager->notify('PostRegister',array('member' => &$newmem));
 
 		$this->action_usermanagement();
 	}
@@ -1900,6 +2049,9 @@
 		$this->_showActivationPage($key);
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function _showActivationPage($key, $message = '')
 	{
 		global $manager;
@@ -2046,8 +2198,8 @@
 	}
 
 	/**
-	  * Manage team
-	  */
+	 * Manage team
+	 */
 	function action_manageteam() {
 		global $member, $manager;
 
@@ -2073,6 +2225,7 @@
 		$template['content'] = 'teamlist';
 		$template['tabindex'] = 10;
 
+		$manager->loadClass("ENCAPSULATE");
 		$batch =& new BATCH('team');
 		$batch->showlist($query, 'table', $template);
 
@@ -2109,8 +2262,8 @@
 	}
 
 	/**
-	  * Add member tot tram
-	  */
+	 * Add member to team
+	 */
 	function action_teamaddmember() {
 		global $member, $manager;
 
@@ -2129,6 +2282,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_teamdelete() {
 		global $member, $manager;
 
@@ -2145,7 +2301,7 @@
 		?>
 			<h2><?php echo _DELETE_CONFIRM?></h2>
 
-			<p><?php echo _CONFIRMTXT_TEAM1?><b><?php echo  $teammem->getDisplayName() ?></b><?php echo _CONFIRMTXT_TEAM2?><b><?php echo  htmlspecialchars(strip_tags($blog->getName())) ?></b>
+			<p><?php echo _CONFIRMTXT_TEAM1?><b><?php echo  htmlspecialchars($teammem->getDisplayName()) ?></b><?php echo _CONFIRMTXT_TEAM2?><b><?php echo  htmlspecialchars(strip_tags($blog->getName())) ?></b>
 			</p>
 
 
@@ -2160,6 +2316,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_teamdeleteconfirm() {
 		global $member;
 
@@ -2174,6 +2333,9 @@
 		$this->action_manageteam();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function deleteOneTeamMember($blogid, $memberid) {
 		global $member, $manager;
 
@@ -2207,6 +2369,9 @@
 		return '';
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_teamchangeadmin() {
 		global $member;
 
@@ -2240,6 +2405,9 @@
 			$this->action_overview(_MSG_ADMINCHANGED);
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_blogsettings() {
 		global $member, $manager;
 
@@ -2328,6 +2496,10 @@
 			</td>
 			<td><?php $this->input_yesno('public',$blog->isPublic(),70); ?></td>
 		</tr><tr>
+	<td><?php echo _EBLOG_REQUIREDEMAIL?>
+		 </td>
+		 <td><?php $this->input_yesno('reqemail',$blog->emailRequired(),72); ?></td>
+	  </tr><tr>
 			<td><?php echo _EBLOG_NOTIFY?> <?php help('blognotify'); ?></td>
 			<td><input name="notify" tabindex="80" maxlength="60" size="40" value="<?php echo  htmlspecialchars($blog->getNotifyAddress()); ?>" /></td>
 		</tr><tr>
@@ -2346,9 +2518,15 @@
 				/><label for="notifyNewItem"><?php echo _EBLOG_NOTIFY_ITEM?></label>
 			</td>
 		</tr><tr>
-			<td><?php echo _EBLOG_PING?> <?php help('pinguserland'); ?></td>
-			<td><?php $this->input_yesno('pinguserland',$blog->pingUserland(),85); ?></td>
+		<? 
+		if (numberOfEventSubscriber('SendPing') > 0) {
+		?>
+			<td><?php echo _EBLOG_PING?> <?php help('sendping'); ?></td>
+			<td><?php $this->input_yesno('sendping',$blog->sendPing(),85); ?></td>
 		</tr><tr>
+		<?
+		}
+		?>
 			<td><?php echo _EBLOG_MAXCOMMENTS?> <?php help('blogmaxcomments'); ?></td>
 			<td><input name="maxcomments" tabindex="90" size="3" value="<?php echo  htmlspecialchars($blog->getMaxComments()); ?>" /></td>
 		</tr><tr>
@@ -2398,6 +2576,7 @@
 		$template['content'] = 'categorylist';
 		$template['tabindex'] = 200;
 
+		$manager->loadClass("ENCAPSULATE");
 		$batch =& new BATCH('category');
 		$batch->showlist($query,'table',$template);
 
@@ -2438,6 +2617,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_categorynew() {
 		global $member, $manager;
 
@@ -2462,7 +2644,9 @@
 		$this->action_blogsettings();
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_categoryedit($catid = '', $blogid = '', $desturl = '') {
 		global $member, $manager;
 
@@ -2486,6 +2670,8 @@
 		$extrahead = '<script type="text/javascript" src="javascript/numbercheck.js"></script>';
 		$this->pagehead($extrahead);
 
+		echo "<p><a href='index.php?action=blogsettings&amp;blogid=$blogid'>(",_BACK_TO_BLOGSETTINGS,")</a></p>";
+
 		?>
 		<h2><?php echo _EBLOG_CAT_UPDATE?> '<?php echo htmlspecialchars($cname)?>'</h2>
 		<form method='post' action='index.php'><div>
@@ -2520,7 +2706,9 @@
 		$this->pagefoot();
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_categoryupdate() {
 		global $member, $manager;
 
@@ -2561,6 +2749,9 @@
 		}
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_categorydelete() {
 		global $member, $manager;
 
@@ -2591,7 +2782,7 @@
 			<h2><?php echo _DELETE_CONFIRM?></h2>
 
 			<div>
-			<?php echo _CONFIRMTXT_CATEGORY?><b><?php echo  $blog->getCategoryName($catid)?></b>
+			<?php echo _CONFIRMTXT_CATEGORY?><b><?php echo  htmlspecialchars($blog->getCategoryName($catid))?></b>
 			</div>
 
 			<form method="post" action="index.php"><div>
@@ -2605,6 +2796,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_categorydeleteconfirm() {
 		global $member, $manager;
 
@@ -2620,6 +2814,9 @@
 		$this->action_blogsettings();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function deleteOneCategory($catid) {
 		global $manager, $member;
 
@@ -2666,6 +2863,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function moveOneCategory($catid, $destblogid) {
 		global $manager, $member;
 
@@ -2731,6 +2931,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_blogsettingsupdate() {
 		global $member, $manager;
 
@@ -2784,11 +2987,12 @@
 		$blog->setDefaultSkin(intPostVar('defskin'));
 		$blog->setDescription(trim(postVar('desc')));
 		$blog->setPublic(postVar('public'));
-		$blog->setPingUserland(postVar('pinguserland'));
+		$blog->setPingUserland(postVar('sendping'));
 		$blog->setConvertBreaks(intPostVar('convertbreaks'));
 		$blog->setAllowPastPosting(intPostVar('allowpastposting'));
 		$blog->setDefaultCategory(intPostVar('defcat'));
 		$blog->setSearchable(intPostVar('searchable'));
+		$blog->setEmailRequired(intPostVar('reqemail'));
 
 		$blog->writeSettings();
 
@@ -2801,6 +3005,9 @@
 		$this->action_overview(_MSG_SETTINGSCHANGED);
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_deleteblog() {
 		global $member, $CONF, $manager;
 
@@ -2835,6 +3042,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_deleteblogconfirm() {
 		global $member, $CONF, $manager;
 
@@ -2880,6 +3090,9 @@
 		$this->action_overview(_DELETED_BLOG);
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_memberdelete() {
 		global $member, $manager;
 
@@ -2893,7 +3106,7 @@
 		?>
 			<h2><?php echo _DELETE_CONFIRM?></h2>
 
-			<p><?php echo _CONFIRMTXT_MEMBER?><b><?php echo  $mem->getDisplayName() ?></b>
+			<p><?php echo _CONFIRMTXT_MEMBER?><b><?php echo htmlspecialchars($mem->getDisplayName()) ?></b>
 			</p>
 
 			<p>
@@ -2910,6 +3123,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_memberdeleteconfirm() {
 		global $member;
 
@@ -2927,7 +3143,10 @@
 			$this->action_overview(_DELETED_MEMBER);
 	}
 
-	// (static)
+	/**
+	 * @static
+	 * @todo document this
+	 */
 	function deleteOneMember($memberid) {
 		global $manager;
 
@@ -2939,6 +3158,11 @@
 
 		$manager->notify('PreDeleteMember', array('member' => &$mem));
 
+		/* unlink comments from memberid */
+		$query = 'UPDATE ' . sql_table('comment') . ' SET cmember="0", cuser="'. addslashes($mem->getDisplayName())
+					.'" WHERE cmember='.$memberid;
+		sql_query($query);
+
 		$query = 'DELETE FROM '.sql_table('member').' WHERE mnumber='.$memberid;
 		sql_query($query);
 
@@ -2956,6 +3180,9 @@
 		return '';
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_createnewlog() {
 		global $member, $CONF, $manager;
 
@@ -3024,7 +3251,7 @@
 			<td><input name="timeoffset" tabindex="110" size="3" value="0" /></td>
 		</tr><tr>
 			<td><?php echo _EBLOG_ADMIN?>
-				<?php help('blogadmin'); ?>
+				<?php help('teamadmin'); ?>
 			</td>
 			<td><?php echo _EBLOG_ADMIN_MSG?></td>
 		</tr><tr>
@@ -3037,6 +3264,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_addnewlog() {
 		global $member, $manager, $CONF;
 
@@ -3106,6 +3336,9 @@
 		$manager->notify(
 			'PostAddCategory',
 			array(
+				'blog' => &$blog,
+				'name' => 'General',
+				'description' => 'Items that do not fit in other categories',
 				'catid' => $catid
 			)
 		);
@@ -3173,6 +3406,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_addnewlog2() {
 		global $member, $manager;
 
@@ -3188,6 +3424,9 @@
 		$this->action_overview(_MSG_NEWBLOG);
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skinieoverview() {
 		global $member, $DIR_LIBS, $manager;
 
@@ -3289,6 +3528,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skinieimport() {
 		global $member, $DIR_LIBS, $DIR_SKINS, $manager;
 
@@ -3367,6 +3609,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skiniedoimport() {
 		global $member, $DIR_LIBS, $DIR_SKINS;
 
@@ -3421,6 +3666,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skinieexport() {
 		global $member, $DIR_LIBS;
 
@@ -3452,6 +3700,9 @@
 		$exporter->export();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_templateoverview() {
 		global $member, $manager;
 
@@ -3493,6 +3744,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_templateedit($msg = '') {
 		global $member, $manager;
 
@@ -3514,7 +3768,7 @@
 		<a href="index.php?action=templateoverview">(<?php echo _TEMPLATE_BACK?>)</a>
 		</p>
 
-		<h2><?php echo _TEMPLATE_EDIT_TITLE?> '<?php echo  $templatename; ?>'</h2>
+		<h2><?php echo _TEMPLATE_EDIT_TITLE?> '<?php echo  htmlspecialchars($templatename); ?>'</h2>
 
 		<?php					if ($msg) echo "<p>"._MESSAGE.": $msg</p>";
 		?>
@@ -3579,6 +3833,12 @@
 	$this->_templateEditRow($template, _TEMPLATE_AFOOTER, 'ARCHIVELIST_FOOTER', '', 150);
 ?>
 		</tr><tr>
+			<th colspan="2"><?php echo _TEMPLATE_BLOGLIST?> <?php help('templatebloglists'); ?></th>
+<?php	$this->_templateEditRow($template, _TEMPLATE_BLOGHEADER, 'BLOGLIST_HEADER', '', 160);
+	$this->_templateEditRow($template, _TEMPLATE_BLOGITEM, 'BLOGLIST_LISTITEM', '', 170);
+	$this->_templateEditRow($template, _TEMPLATE_BLOGFOOTER, 'BLOGLIST_FOOTER', '', 180);
+?>
+		</tr><tr>
 			<th colspan="2"><?php echo _TEMPLATE_CATEGORYLIST?> <?php help('templatecategorylists'); ?></th>
 <?php	$this->_templateEditRow($template, _TEMPLATE_CATHEADER, 'CATLIST_HEADER', '', 160);
 	$this->_templateEditRow($template, _TEMPLATE_CATITEM, 'CATLIST_LISTITEM', '', 170);
@@ -3619,6 +3879,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function _templateEditRow(&$template, $description, $name, $help = '', $tabindex = 0, $big = 0) {
 		static $count = 1;
 	?>
@@ -3628,6 +3891,9 @@
 	<?php		$count++;
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_templateupdate() {
 		global $member;
 
@@ -3678,6 +3944,9 @@
 		$this->addToTemplate($templateid, 'ARCHIVELIST_HEADER', postVar('ARCHIVELIST_HEADER'));
 		$this->addToTemplate($templateid, 'ARCHIVELIST_LISTITEM', postVar('ARCHIVELIST_LISTITEM'));
 		$this->addToTemplate($templateid, 'ARCHIVELIST_FOOTER', postVar('ARCHIVELIST_FOOTER'));
+		$this->addToTemplate($templateid, 'BLOGLIST_HEADER', postVar('BLOGLIST_HEADER'));
+		$this->addToTemplate($templateid, 'BLOGLIST_LISTITEM', postVar('BLOGLIST_LISTITEM'));
+		$this->addToTemplate($templateid, 'BLOGLIST_FOOTER', postVar('BLOGLIST_FOOTER'));
 		$this->addToTemplate($templateid, 'CATLIST_HEADER', postVar('CATLIST_HEADER'));
 		$this->addToTemplate($templateid, 'CATLIST_LISTITEM', postVar('CATLIST_LISTITEM'));
 		$this->addToTemplate($templateid, 'CATLIST_FOOTER', postVar('CATLIST_FOOTER'));
@@ -3698,6 +3967,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function addToTemplate($id, $partname, $content) {
 		$partname = addslashes($partname);
 		$content = addslashes($content);
@@ -3709,10 +3981,13 @@
 
 		$query = 'INSERT INTO '.sql_table('template')." (tdesc, tpartname, tcontent) "
 			   . "VALUES ($id, '$partname', '$content')";
-		mysql_query($query) or die("Query error: " . mysql_error());
+		sql_query($query) or die("Query error: " . mysql_error());
 		return mysql_insert_id();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_templatedelete() {
 		global $member, $manager;
 
@@ -3730,7 +4005,7 @@
 			<h2><?php echo _DELETE_CONFIRM?></h2>
 
 			<p>
-			<?php echo _CONFIRMTXT_TEMPLATE?><b><?php echo $name?></b> (<?php echo  htmlspecialchars($desc) ?>)
+			<?php echo _CONFIRMTXT_TEMPLATE?><b><?php echo htmlspecialchars($name)?></b> (<?php echo  htmlspecialchars($desc) ?>)
 			</p>
 
 			<form method="post" action="index.php"><div>
@@ -3743,6 +4018,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_templatedeleteconfirm() {
 		global $member, $manager;
 
@@ -3763,6 +4041,9 @@
 		$this->action_templateoverview();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_templatenew() {
 		global $member;
 
@@ -3782,6 +4063,9 @@
 		$this->action_templateoverview();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_templateclone() {
 		global $member;
 
@@ -3816,6 +4100,9 @@
 		$this->action_templateoverview();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skinoverview() {
 		global $member, $manager;
 
@@ -3860,6 +4147,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skinnew() {
 		global $member;
 
@@ -3879,6 +4169,9 @@
 		$this->action_skinoverview();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skinedit() {
 		global $member, $manager;
 
@@ -3908,7 +4201,33 @@
 			<li><a tabindex="75" href="index.php?action=skinedittype&amp;skinid=<?php echo  $skinid ?>&amp;type=imagepopup"><?php echo _SKIN_PART_POPUP?></a> <?php help('skinpartimagepopup')?></li>
 		</ul>
 
-		<h3><?php echo _SKIN_GENSETTINGS_TITLE?></h3>
+		<?php
+
+		$query = "SELECT stype FROM " . sql_table('skin') . " WHERE stype NOT IN ('index', 'item', 'error', 'search', 'archive', 'archivelist', 'imagepopup', 'member') and sdesc = " . $skinid;
+		$res = sql_query($query);
+
+		echo '<h3>' . _SKIN_PARTS_SPECIAL . '</h3>';
+		echo '<form method="get" action="index.php">' . "\r\n";
+		echo '<input type="hidden" name="action" value="skinedittype" />' . "\r\n";
+		echo '<input type="hidden" name="skinid" value="' . $skinid . '" />' . "\r\n";
+		echo '<input name="type" tabindex="89" size="20" maxlength="20" />' . "\r\n";
+		echo '<input type="submit" tabindex="140" value="' . _SKIN_CREATE . '" onclick="return checkSubmit();" />' . "\r\n";
+		echo '</form>' . "\r\n";
+
+		if ($res && mysql_num_rows($res) > 0) {
+			echo '<ul>';
+			$tabstart = 75;
+
+			while ($row = mysql_fetch_assoc($res)) {
+				echo '<li><a tabindex="' . ($tabstart++) . '" href="index.php?action=skinedittype&amp;skinid=' . $skinid . '&amp;type=' . htmlspecialchars(strtolower($row['stype'])) . '">' . htmlspecialchars(ucfirst($row['stype'])) . '</a> (<a tabindex="' . ($tabstart++) . '" href="index.php?action=skinremovetype&amp;skinid=' . $skinid . '&amp;type=' . htmlspecialchars(strtolower($row['stype'])) . '">remove</a>)</li>';
+			}
+
+			echo '</ul>';
+		}
+
+		?>
+
+		<h3><?php echo _SKIN_GENSETTINGS_TITLE; ?></h3>
 		<form method="post" action="index.php">
 		<div>
 
@@ -3942,6 +4261,9 @@
 		<?php		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skineditgeneral() {
 		global $member;
 
@@ -3974,6 +4296,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skinedittype($msg = '') {
 		global $member, $manager;
 
@@ -3982,6 +4307,13 @@
 
 		$member->isAdmin() or $this->disallow();
 
+		$type = trim($type);
+		$type = strtolower($type);
+
+		if (!isValidShortName($type)) {
+			$this->error(_ERROR_SKIN_PARTS_SPECIAL_FORMAT);
+		}
+
 		$skin =& new SKIN($skinid);
 
 		$friendlyNames = SKIN::getFriendlyNames();
@@ -3990,7 +4322,7 @@
 		?>
 		<p>(<a href="index.php?action=skinoverview"><?php echo _SKIN_GOBACK?></a>)</p>
 
-		<h2><?php echo _SKIN_EDITPART_TITLE?> '<?php echo  $skin->getName() ?>': <?php echo  $friendlyNames[$type] ?></h2>
+		<h2><?php echo _SKIN_EDITPART_TITLE?> '<?php echo htmlspecialchars($skin->getName()) ?>': <?php echo htmlspecialchars(isset($friendlyNames[$type]) ? $friendlyNames[$type] : ucfirst($type)); ?></h2>
 
 		<?php			if ($msg) echo "<p>"._MESSAGE.": $msg</p>";
 		?>
@@ -4006,8 +4338,12 @@
 
 		<input type="submit" value="<?php echo _SKIN_UPDATE_BTN?>" onclick="return checkSubmit();" />
 		<input type="reset" value="<?php echo _SKIN_RESET_BTN?>" />
-		(skin type: <?php echo  $friendlyNames[$type] ?>)
-		<?php help('skinpart' . $type);?>
+		(skin type: <?php echo htmlspecialchars(isset($friendlyNames[$type]) ? $friendlyNames[$type] : ucfirst($type)); ?>)
+		<?php if (in_array($type, array('index', 'item', 'archivelist', 'archive', 'search', 'error', 'member', 'imagepopup'))) {
+			help('skinpart' . $type);
+		} else {
+			help('skinpartspecial');
+		}?>
 		<br />
 
 		<textarea class="skinedit" tabindex="10" rows="20" cols="80" name="content"><?php echo  htmlspecialchars($skin->getContent($type)) ?></textarea>
@@ -4015,7 +4351,7 @@
 		<br />
 		<input type="submit" tabindex="20" value="<?php echo _SKIN_UPDATE_BTN?>" onclick="return checkSubmit();" />
 		<input type="reset" value="<?php echo _SKIN_RESET_BTN?>" />
-		(skin type: <?php echo  $friendlyNames[$type] ?>)
+		(skin type: <?php echo htmlspecialchars(isset($friendlyNames[$type]) ? $friendlyNames[$type] : ucfirst($type)); ?>)
 
 		<br /><br />
 		<?php echo _SKIN_ALLOWEDVARS?>
@@ -4053,6 +4389,9 @@
 		<?php		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skinupdate() {
 		global $member;
 
@@ -4068,6 +4407,9 @@
 		$this->action_skinedittype(_SKIN_UPDATED);
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skindelete() {
 		global $member, $manager, $CONF;
 
@@ -4083,7 +4425,7 @@
 		$query = 'SELECT bname FROM '.sql_table('blog').' WHERE bdefskin=' . $skinid;
 		$r = sql_query($query);
 		if ($o = mysql_fetch_object($r))
-			$this->error(_ERROR_SKINDEFDELETE . $o->bname);
+			$this->error(_ERROR_SKINDEFDELETE . htmlspecialchars($o->bname));
 
 		$this->pagehead();
 
@@ -4095,7 +4437,7 @@
 			<h2><?php echo _DELETE_CONFIRM?></h2>
 
 			<p>
-				<?php echo _CONFIRMTXT_SKIN?><b><?php echo  $name ?></b> (<?php echo  htmlspecialchars($desc)?>)
+				<?php echo _CONFIRMTXT_SKIN?><b><?php echo htmlspecialchars($name) ?></b> (<?php echo  htmlspecialchars($desc)?>)
 			</p>
 
 			<form method="post" action="index.php"><div>
@@ -4108,6 +4450,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_skindeleteconfirm() {
 		global $member, $CONF, $manager;
 
@@ -4138,8 +4483,85 @@
 		$this->action_skinoverview();
 	}
 
-	function action_skinclone() {
-		global $member;
+	/**
+	 * @todo document this
+	 */
+	function action_skinremovetype() {
+		global $member, $manager, $CONF;
+
+		$skinid = intRequestVar('skinid');
+		$skintype = requestVar('type');
+
+		if (!isValidShortName($skintype)) {
+			$this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
+		}
+
+		$member->isAdmin() or $this->disallow();
+
+		// don't allow default skinparts to be deleted
+		if (in_array($skintype, array('index', 'item', 'archivelist', 'archive', 'search', 'error', 'member', 'imagepopup'))) {
+			$this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
+		}
+
+		$this->pagehead();
+
+		$skin =& new SKIN($skinid);
+		$name = $skin->getName();
+		$desc = $skin->getDescription();
+
+		?>
+			<h2><?php echo _DELETE_CONFIRM?></h2>
+
+			<p>
+				<?php echo _CONFIRMTXT_SKIN_PARTS_SPECIAL; ?> <b><?php echo htmlspecialchars($skintype); ?> (<?php echo htmlspecialchars($name); ?>)</b> (<?php echo  htmlspecialchars($desc)?>)
+			</p>
+
+			<form method="post" action="index.php"><div>
+				<input type="hidden" name="action" value="skinremovetypeconfirm" />
+				<?php $manager->addTicketHidden() ?>
+				<input type="hidden" name="skinid" value="<?php echo $skinid; ?>" />
+				<input type="hidden" name="type" value="<?php echo htmlspecialchars($skintype); ?>" />
+				<input type="submit" tabindex="10" value="<?php echo _DELETE_CONFIRM_BTN?>" />
+			</div></form>
+		<?php
+		$this->pagefoot();
+	}
+
+	/**
+	 * @todo document this
+	 */
+	function action_skinremovetypeconfirm() {
+		global $member, $CONF, $manager;
+
+		$skinid = intRequestVar('skinid');
+		$skintype = requestVar('type');
+
+		if (!isValidShortName($skintype)) {
+			$this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
+		}
+
+		$member->isAdmin() or $this->disallow();
+
+		// don't allow default skinparts to be deleted
+		if (in_array($skintype, array('index', 'item', 'archivelist', 'archive', 'search', 'error', 'member', 'imagepopup'))) {
+			$this->error(_ERROR_SKIN_PARTS_SPECIAL_DELETE);
+		}
+
+		$manager->notify('PreDeleteSkinPart', array('skinid' => $skinid, 'skintype' => $skintype));
+
+		// delete part
+		sql_query('DELETE FROM '.sql_table('skin').' WHERE sdesc=' . $skinid . ' AND stype=\'' . $skintype . '\'');
+
+		$manager->notify('PostDeleteSkinPart', array('skinid' => $skinid, 'skintype' => $skintype));
+
+		$this->action_skinedit();
+	}
+
+	/**
+	 * @todo document this
+	 */
+	function action_skinclone() {
+		global $member;
 
 		$skinid = intRequestVar('skinid');
 
@@ -4169,6 +4591,7 @@
 
 
 		// 3. clone
+		/*
 		$this->skinclonetype($skin, $newid, 'index');
 		$this->skinclonetype($skin, $newid, 'item');
 		$this->skinclonetype($skin, $newid, 'archivelist');
@@ -4177,11 +4600,21 @@
 		$this->skinclonetype($skin, $newid, 'error');
 		$this->skinclonetype($skin, $newid, 'member');
 		$this->skinclonetype($skin, $newid, 'imagepopup');
+		*/
+
+		$query = "SELECT stype FROM " . sql_table('skin') . " WHERE sdesc = " . $skinid;
+		$res = sql_query($query);
+		while ($row = mysql_fetch_assoc($res)) {
+			$this->skinclonetype($skin, $newid, $row['stype']);
+		}
 
 		$this->action_skinoverview();
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function skinclonetype($skin, $newid, $type) {
 		$newid = intval($newid);
 		$content = $skin->getContent($type);
@@ -4191,6 +4624,9 @@
 		}
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_settingsedit() {
 		global $member, $manager, $CONF, $DIR_NUCLEUS, $DIR_MEDIA;
 
@@ -4453,6 +4889,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_settingsupdate() {
 		global $member, $CONF;
 
@@ -4505,7 +4944,9 @@
 
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function updateConfig($name, $val) {
 		$name = addslashes($name);
 		$val = trim(addslashes($val));
@@ -4514,13 +4955,14 @@
 			   . " SET value='$val'"
 			   . " WHERE name='$name'";
 
-		mysql_query($query) or die("Query error: " . mysql_error());
+		sql_query($query) or die("Query error: " . mysql_error());
 		return mysql_insert_id();
 	}
 
 	/**
-	  * Error message
-	  */
+	 * Error message
+	 * @param string $msg message that will be shown
+	 */
 	function error($msg) {
 		$this->pagehead();
 		?>
@@ -4532,13 +4974,18 @@
 		exit;
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function disallow() {
 		ACTIONLOG::add(WARNING, _ACTIONLOG_DISALLOWED . serverVar('REQUEST_URI'));
 
 		$this->error(_ERROR_DISALLOWED);
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function pagehead($extrahead = '') {
 		global $member, $nucleus, $CONF, $manager;
 
@@ -4589,14 +5036,19 @@
 
 			echo '<br />(';
 
+			$codenamestring = ($nucleus['codename']!='')? ' &quot;'.$nucleus['codename'].'&quot;':'';
+
 			if ($member->isLoggedIn() && $member->isAdmin())
-				echo '<a href="http://nucleuscms.org/version.php?v=',getNucleusVersion(),'&amp;pl=',getNucleusPatchLevel(),'" title="Check for upgrade">Nucleus CMS ', $nucleus['version'], '</a>';
+				echo '<a href="http://nucleuscms.org/version.php?v=',getNucleusVersion(),'&amp;pl=',getNucleusPatchLevel(),'" title="Check for upgrade">Nucleus CMS ', $nucleus['version'], $codenamestring, '</a>';
 			else
-				echo 'Nucleus CMS ' , $nucleus['version'];
+				echo 'Nucleus CMS ', $nucleus['version'], $codenamestring;
 			echo ')';
 		echo '</div>';
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function pagefoot() {
 		global $action, $member, $manager;
 
@@ -4728,7 +5180,9 @@
 			</html>
 		<?php	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_regfile() {
 		global $member, $CONF;
 
@@ -4750,6 +5204,9 @@
 		echo '"contexts"=hex:31';
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_bookmarklet() {
 		global $member, $manager;
 
@@ -4815,7 +5272,9 @@
 
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_actionlog() {
 		global $member, $manager;
 
@@ -4841,7 +5300,9 @@
 
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_banlist() {
 		global $member, $manager;
 
@@ -4872,7 +5333,9 @@
 
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_banlistdelete() {
 		global $member, $manager;
 
@@ -4918,6 +5381,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_banlistdeleteconfirm() {
 		global $member, $manager;
 
@@ -4961,10 +5427,16 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_banlistnewfromitem() {
 		$this->action_banlistnew(getBlogIDFromItemID(intRequestVar('itemid')));
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_banlistnew($blogid = '') {
 		global $member, $manager;
 
@@ -5035,6 +5507,9 @@
 		<?php		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_banlistadd() {
 		global $member;
 
@@ -5068,6 +5543,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_clearactionlog() {
 		global $member;
 
@@ -5078,6 +5556,9 @@
 		$this->action_manage(_MSG_ACTIONLOGCLEARED);
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_backupoverview() {
 		global $member, $manager;
 
@@ -5127,6 +5608,9 @@
 		<?php		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_backupcreate() {
 		global $member, $DIR_LIBS;
 
@@ -5145,7 +5629,9 @@
 		exit;
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_backuprestore() {
 		global $member, $DIR_LIBS;
 
@@ -5171,7 +5657,9 @@
 
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_pluginlist() {
 		global $member, $manager;
 
@@ -5214,7 +5702,8 @@
 					if (ereg('^NP_(.*)\.php$',$filename,$matches)) {
 						$name = $matches[1];
 						// only show in list when not yet installed
-						if (mysql_num_rows(sql_query('SELECT * FROM '.sql_table('plugin').' WHERE pfile="NP_'.addslashes($name).'"')) == 0)
+						$res = sql_query('SELECT * FROM '.sql_table('plugin').' WHERE pfile="NP_'.addslashes($name).'"');
+						if (mysql_num_rows($res) == 0)
 							array_push($candidates,$name);
 					}
 				}
@@ -5244,6 +5733,9 @@
 		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_pluginhelp() {
 		global $member, $manager, $DIR_PLUGINS, $CONF;
 
@@ -5277,7 +5769,9 @@
 		$this->pagefoot();
 	}
 
-
+	/**
+	 * @todo document this
+	 */
 	function action_pluginadd() {
 		global $member, $manager, $DIR_PLUGINS;
 
@@ -5289,10 +5783,11 @@
 		if ($manager->pluginInstalled($name))
 			$this->error(_ERROR_DUPPLUGIN);
 		if (!checkPlugin($name))
-			$this->error(_ERROR_PLUGFILEERROR . ' (' . $name . ')');
+			$this->error(_ERROR_PLUGFILEERROR . ' (' . htmlspecialchars($name) . ')');
 
 		// get number of currently installed plugins
-		$numCurrent = mysql_num_rows(sql_query('SELECT * FROM '.sql_table('plugin')));
+		$res = sql_query('SELECT * FROM '.sql_table('plugin'));
+		$numCurrent = mysql_num_rows($res);
 
 		// plugin will be added as last one in the list
 		$newOrder = $numCurrent + 1;
@@ -5319,7 +5814,7 @@
 		{
 			sql_query('DELETE FROM ' . sql_table('plugin') . ' WHERE pid='. intval($iPid));
 			$manager->clearCachedInfo('installedPlugins');
-			$this->error('Plugin could not be loaded, or does not support certain features that are required for it to run on your Nucleus installation (you might want to check the <a href="?action=actionlog">actionlog</a> for more info)');
+			$this->error(_ERROR_PLUGIN_LOAD);
 		}
 
 		// check if plugin needs a newer Nucleus version
@@ -5329,7 +5824,7 @@
 			$this->deleteOnePlugin($plugin->getID());
 
 			// ...and show error
-			$this->error(_ERROR_NUCLEUSVERSIONREQ . $plugin->getMinNucleusVersion());
+			$this->error(_ERROR_NUCLEUSVERSIONREQ . htmlspecialchars($plugin->getMinNucleusVersion()));
 		}
 
 		// check if plugin needs a newer Nucleus version
@@ -5339,7 +5834,7 @@
 			$this->deleteOnePlugin($plugin->getID());
 
 			// ...and show error
-			$this->error(_ERROR_NUCLEUSVERSIONREQ . $plugin->getMinNucleusVersion() . ' patch ' . $plugin->getMinNucleusPatchLevel());
+			$this->error(_ERROR_NUCLEUSVERSIONREQ . htmlspecialchars( $plugin->getMinNucleusVersion() . ' patch ' . $plugin->getMinNucleusPatchLevel() ) );
 		}
 
 		$pluginList = $plugin->getPluginDep();
@@ -5352,7 +5847,7 @@
 				// uninstall plugin again...
 				$this->deleteOnePlugin($plugin->getID());
 
-				$this->error(_ERROR_INSREQPLUGIN . $pluginName);
+				$this->error(_ERROR_INSREQPLUGIN . htmlspecialchars($pluginName));
 			}
 		}
 
@@ -5370,6 +5865,9 @@
 		$this->action_pluginupdate();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_pluginupdate() {
 		global $member, $manager;
 
@@ -5395,6 +5893,9 @@
 		$this->action_pluginlist();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_plugindelete() {
 		global $member, $manager;
 
@@ -5421,6 +5922,9 @@
 		<?php		$this->pagefoot();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_plugindeleteconfirm() {
 		global $member, $manager;
 
@@ -5437,6 +5941,9 @@
 		$this->action_pluginlist();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function deleteOnePlugin($pid, $callUninstall = 0) {
 		global $manager;
 
@@ -5489,7 +5996,8 @@
 			sql_query('DELETE FROM '.sql_table('plugin_option').' WHERE oid in ('.implode(',',$aOIDs).')');
 
 		// update order numbers
-		$o = mysql_fetch_object(sql_query('SELECT porder FROM '.sql_table('plugin').' WHERE pid=' . $pid));
+		$res = sql_query('SELECT porder FROM '.sql_table('plugin').' WHERE pid=' . $pid);
+		$o = mysql_fetch_object($res);
 		sql_query('UPDATE '.sql_table('plugin').' SET porder=(porder - 1) WHERE porder>'.$o->porder);
 
 		// delete row
@@ -5501,6 +6009,9 @@
 		return '';
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_pluginup() {
 		global $member, $manager;
 
@@ -5513,7 +6024,8 @@
 			$this->error(_ERROR_NOSUCHPLUGIN);
 
 		// 1. get old order number
-		$o = mysql_fetch_object(sql_query('SELECT porder FROM '.sql_table('plugin').' WHERE pid='.$plugid));
+		$res = sql_query('SELECT porder FROM '.sql_table('plugin').' WHERE pid='.$plugid);
+		$o = mysql_fetch_object($res);
 		$oldOrder = $o->porder;
 
 		// 2. calculate new order number
@@ -5526,6 +6038,9 @@
 		$this->action_pluginlist();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_plugindown() {
 		global $member, $manager;
 
@@ -5537,10 +6052,12 @@
 			$this->error(_ERROR_NOSUCHPLUGIN);
 
 		// 1. get old order number
-		$o = mysql_fetch_object(sql_query('SELECT porder FROM '.sql_table('plugin').' WHERE pid='.$plugid));
+		$res = sql_query('SELECT porder FROM '.sql_table('plugin').' WHERE pid='.$plugid);
+		$o = mysql_fetch_object($res);
 		$oldOrder = $o->porder;
 
-		$maxOrder = mysql_num_rows(sql_query('SELECT * FROM '.sql_table('plugin')));
+		$res = sql_query('SELECT * FROM '.sql_table('plugin'));
+		$maxOrder = mysql_num_rows($res);
 
 		// 2. calculate new order number
 		$newOrder = ($oldOrder < $maxOrder) ? ($oldOrder + 1) : $maxOrder;
@@ -5552,6 +6069,9 @@
 		$this->action_pluginlist();
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_pluginoptions($message = '') {
 		global $member, $manager;
 
@@ -5621,6 +6141,9 @@
 
 	}
 
+	/**
+	 * @todo document this
+	 */
 	function action_pluginoptionsupdate() {
 		global $member, $manager;
 
@@ -5640,8 +6163,9 @@
 	}
 
 	/**
-	  * @static
-	  */
+	 * @static
+	 * @todo document this
+	 */
 	function _insertPluginOptions($context, $contextid = 0) {
 		// get all current values for this contextid
 		// (note: this might contain doubles for overlapping contextids)
@@ -5699,890 +6223,39 @@
 
 	}
 
-	/* helper functions to create option forms etc. */
-	function input_yesno($name, $checkedval,$tabindex = 0, $value1 = 1, $value2 = 0, $yesval = _YES, $noval = _NO) {
+	/**
+	 * Helper functions to create option forms etc.
+	 * @todo document parameters
+	 */
+	function input_yesno($name, $checkedval,$tabindex = 0, $value1 = 1, $value2 = 0, $yesval = _YES, $noval = _NO, $isAdmin = 0) {
 		$id = htmlspecialchars($name);
 		$id = str_replace('[','-',$id);
 		$id = str_replace(']','-',$id);
 		$id1 = $id . htmlspecialchars($value1);
 		$id2 = $id . htmlspecialchars($value2);
 
-		echo '<input type="radio" name="', htmlspecialchars($name),'" value="', htmlspecialchars($value1),'" ';
+		if ($name=="admin") {
+			echo '<input onclick="selectCanLogin(true);" type="radio" name="', htmlspecialchars($name),'" value="', htmlspecialchars($value1),'" ';
+	   	} else {
+			echo '<input type="radio" name="', htmlspecialchars($name),'" value="', htmlspecialchars($value1),'" ';
+		}
+
 			if ($checkedval == $value1)
 				echo "tabindex='$tabindex' checked='checked'";
 			echo ' id="'.$id1.'" /><label for="'.$id1.'">' . $yesval . '</label>';
 		echo ' ';
-		echo '<input type="radio" name="', htmlspecialchars($name),'" value="', htmlspecialchars($value2),'" ';
+		if ($name=="admin") {
+			echo '<input onclick="selectCanLogin(false);" type="radio" name="', htmlspecialchars($name),'" value="', htmlspecialchars($value2),'" ';
+		} else {
+			echo '<input type="radio" name="', htmlspecialchars($name),'" value="', htmlspecialchars($value2),'" ';
+		}
 			if ($checkedval != $value1)
 				echo "tabindex='$tabindex' checked='checked'";
+			if ($isAdmin && $name=="canlogin")
+				echo " disabled='true'";
 			echo ' id="'.$id2.'" /><label for="'.$id2.'">' . $noval . '</label>';
 	}
 
-
-
 } // class ADMIN
 
-class ENCAPSULATE {
-	/**
-	  * Uses $call to call a function using parameters $params
-	  * This function should return the amount of entries shown.
-	  * When entries are show, batch operation handlers are shown too.
-	  * When no entries were shown, $errormsg is used to display an error
-	  *
-	  * Passes on the amount of results found (for further encapsulation)
-	  */
-	function doEncapsulate($call, $params, $errorMessage = 'No entries') {
-		// start output buffering
-		ob_start();
-
-		$nbOfRows = call_user_func_array($call, $params);
-
-		// get list contents and stop buffering
-		$list = ob_get_contents();
-		ob_end_clean();
-
-		if ($nbOfRows > 0) {
-			$this->showHead();
-			echo $list;
-			$this->showFoot();
-		} else {
-			echo $errorMessage;
-		}
-
-		return $nbOfRows;
-	}
-}
-
-
-/**
-  * A class used to encapsulate a list of some sort inside next/prev buttons
-  */
-class NAVLIST extends ENCAPSULATE {
-
-	function NAVLIST($action, $start, $amount, $minamount, $maxamount, $blogid, $search, $itemid) {
-		$this->action = $action;
-		$this->start = $start;
-		$this->amount = $amount;
-		$this->minamount = $minamount;
-		$this->maxamount = $maxamount;
-		$this->blogid = $blogid;
-		$this->search = $search;
-		$this->itemid = $itemid;
-	}
-
-	function showBatchList($batchtype, $query, $type, $template, $errorMessage = _LISTS_NOMORE) {
-		$batch =& new BATCH($batchtype);
-
-		$this->doEncapsulate(
-				array(&$batch, 'showlist'),
-				array(&$query, $type, $template),
-				$errorMessage
-		);
-
-	}
-
-
-	function showHead() {
-		$this->showNavigation();
-	}
-	function showFoot() {
-		$this->showNavigation();
-	}
-
-	/**
-	  * Displays a next/prev bar for long tables
-	  */
-	function showNavigation() {
-		$action = $this->action;
-		$start = $this->start;
-		$amount = $this->amount;
-		$minamount = $this->minamount;
-		$maxamount = $this->maxamount;
-		$blogid = $this->blogid;
-		$search = $this->search;
-		$itemid = $this->itemid;
-
-		$prev = $start - $amount;
-		if ($prev < $minamount) $prev=$minamount;
-
-		// maxamount not used yet
-	//	if ($start + $amount <= $maxamount)
-			$next = $start + $amount;
-	//	else
-	//		$next = $start;
-
-	?>
-	<table class="navigation">
-	<tr><td>
-		<form method="post" action="index.php"><div>
-		<input type="submit" value="&lt;&lt; <?php echo  _LISTS_PREV?>" />
-		<input type="hidden" name="blogid" value="<?php echo  $blogid; ?>" />
-		<input type="hidden" name="itemid" value="<?php echo  $itemid; ?>" />
-		<input type="hidden" name="action" value="<?php echo  $action; ?>" />
-		<input type="hidden" name="amount" value="<?php echo  $amount; ?>" />
-		<input type="hidden" name="search" value="<?php echo  $search; ?>" />
-		<input type="hidden" name="start" value="<?php echo  $prev; ?>" />
-		</div></form>
-	</td><td>
-		<form method="post" action="index.php"><div>
-		<input type="hidden" name="blogid" value="<?php echo  $blogid; ?>" />
-		<input type="hidden" name="itemid" value="<?php echo  $itemid; ?>" />
-		<input type="hidden" name="action" value="<?php echo  $action; ?>" />
-		<input name="amount" size="3" value="<?php echo  $amount; ?>" /> <?php echo _LISTS_PERPAGE?>
-		<input type="hidden" name="start" value="<?php echo  $start; ?>" />
-		<input type="hidden" name="search" value="<?php echo  $search; ?>" />
-		<input type="submit" value="&gt; <?php echo _LISTS_CHANGE?>" />
-		</div></form>
-	</td><td>
-		<form method="post" action="index.php"><div>
-		<input type="hidden" name="blogid" value="<?php echo  $blogid; ?>" />
-		<input type="hidden" name="itemid" value="<?php echo  $itemid; ?>" />
-		<input type="hidden" name="action" value="<?php echo  $action; ?>" />
-		<input type="hidden" name="amount" value="<?php echo  $amount; ?>" />
-		<input type="hidden" name="start" value="0" />
-		<input type="text" name="search" value="<?php echo  $search; ?>" size="7" />
-		<input type="submit" value="&gt; <?php echo  _LISTS_SEARCH?>" />
-		</div></form>
-	</td><td>
-		<form method="post" action="index.php"><div>
-		<input type="submit" value="<?php echo _LISTS_NEXT?> &gt; &gt;" />
-		<input type="hidden" name="search" value="<?php echo  $search; ?>" />
-		<input type="hidden" name="blogid" value="<?php echo  $blogid; ?>" />
-		<input type="hidden" name="itemid" value="<?php echo  $itemid; ?>" />
-		<input type="hidden" name="action" value="<?php echo  $action; ?>" />
-		<input type="hidden" name="amount" value="<?php echo  $amount; ?>" />
-		<input type="hidden" name="start" value="<?php echo  $next; ?>" />
-		</div></form>
-	</td></tr>
-	</table>
-	<?php	}
-
-
-}
-
-/**
- * A class used to encapsulate a list of some sort in a batch selection
- */
-class BATCH extends ENCAPSULATE {
-	function BATCH($type) {
-		$this->type = $type;
-	}
-
-	function showHead() {
-		?>
-			<form method="post" action="index.php">
-		<?php
-// TODO: get a list op operations above the list too
-// (be careful not to use the same names for the select...)
-//		$this->showOperationList();
-	}
-
-	function showFoot() {
-		$this->showOperationList();
-		?>
-			</form>
-		<?php	}
-
-	function showOperationList() {
-		global $manager;
-		?>
-		<div class="batchoperations">
-			<?php echo _BATCH_WITH_SEL ?>
-			<select name="batchaction">
-			<?php				$options = array();
-				switch($this->type) {
-					case 'item':
-						$options = array(
-							'delete'	=> _BATCH_ITEM_DELETE,
-							'move'		=> _BATCH_ITEM_MOVE
-						);
-						break;
-					case 'member':
-						$options = array(
-							'delete'	=> _BATCH_MEMBER_DELETE,
-							'setadmin'	=> _BATCH_MEMBER_SET_ADM,
-							'unsetadmin' => _BATCH_MEMBER_UNSET_ADM
-						);
-						break;
-					case 'team':
-						$options = array(
-							'delete' 	=> _BATCH_TEAM_DELETE,
-							'setadmin'	=> _BATCH_TEAM_SET_ADM,
-							'unsetadmin' => _BATCH_TEAM_UNSET_ADM,
-						);
-						break;
-					case 'category':
-						$options = array(
-							'delete'	=> _BATCH_CAT_DELETE,
-							'move'		=> _BATCH_CAT_MOVE,
-						);
-						break;
-					case 'comment':
-						$options = array(
-							'delete'	=> _BATCH_COMMENT_DELETE,
-						);
-					break;
-				}
-				foreach ($options as $option => $label) {
-					echo '<option value="',$option,'">',$label,'</option>';
-				}
-			?>
-			</select>
-			<input type="hidden" name="action" value="batch<?php echo $this->type?>" />
-			<?php
-				$manager->addTicketHidden();
-
-				// add hidden fields for 'team' and 'comment' batchlists
-				if ($this->type == 'team')
-				{
-					echo '<input type="hidden" name="blogid" value="',intRequestVar('blogid'),'" />';
-				}
-				if ($this->type == 'comment')
-				{
-					echo '<input type="hidden" name="itemid" value="',intRequestVar('itemid'),'" />';
-				}
-
-				echo '<input type="submit" value="',_BATCH_EXEC,'" />';
-			?>(
-			 <a href="" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); return batchSelectAll(1); "><?php echo _BATCH_SELECTALL?></a> -
-			 <a href="" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); return batchSelectAll(0); "><?php echo _BATCH_DESELECTALL?></a>
-			)
-		</div>
-		<?php	}
-
-	// shortcut :)
-	function showList($query, $type, $template, $errorMessage = _LISTS_NOMORE) {
-		return $this->doEncapsulate(	'showlist',
-									array($query, $type, $template),
-									$errorMessage
-								);
-	}
-
-}
-
-
-
-// can take either an array of objects, or an SQL query
-function showlist($query, $type, $template) {
-
-	if (is_array($query)) {
-		if (sizeof($query) == 0)
-			return 0;
-
-		call_user_func('listplug_' . $type, $template, 'HEAD');
-
-		foreach ($query as $currentObj) {
-			$template['current'] = $currentObj;
-			call_user_func('listplug_' . $type, $template, 'BODY');
-		}
-
-		call_user_func('listplug_' . $type, $template, 'FOOT');
-
-		return sizeof($query);
-
-	} else {
-		$res = sql_query($query);
-
-		// don't do anything if there are no results
-		$numrows = mysql_num_rows($res);
-		if ($numrows == 0)
-			return 0;
-
-		call_user_func('listplug_' . $type, $template, 'HEAD');
-
-		while($template['current'] = mysql_fetch_object($res))
-			call_user_func('listplug_' . $type, $template, 'BODY');
-
-		call_user_func('listplug_' . $type, $template, 'FOOT');
-
-		mysql_free_result($res);
-
-		// return amount of results
-		return $numrows;
-	}
-}
-
-function listplug_select($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo '<select name="'.$template['name'].'" tabindex="'.$template['tabindex'].'" '.$template['javascript'].'>';
-
-			// add extra row if needed
-			if ($template['extra']) {
-				echo '<option value="',$template['extraval'],'">',$template['extra'],'</option>';
-			}
-
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<option value="' . htmlspecialchars($current->value) . '"';
-			if ($template['selected'] == $current->value)
-				echo ' selected="selected" ';
-			if ($template['shorten'] > 0) {
-				echo ' title="'. htmlspecialchars($current->text).'"';
-				$current->text = shorten($current->text, $template['shorten'], $template['shortenel']);
-			}
-			echo '>' . htmlspecialchars($current->text) . '</option>';
-			break;
-		case 'FOOT':
-			echo '</select>';
-			break;
-	}
-}
-
-function listplug_table($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo "<table>";
-			echo "<thead><tr>";
-			// print head
-			call_user_func("listplug_table_" . $template['content'] , $template, 'HEAD');
-			echo "</tr></thead><tbody>";
-			break;
-		case 'BODY':
-			// print tabletype specific thingies
-			echo "<tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>";
-			call_user_func("listplug_table_" . $template['content'] , $template,  'BODY');
-			echo "</tr>";
-			break;
-		case 'FOOT':
-			call_user_func("listplug_table_" . $template['content'] , $template,  'FOOT');
-			echo "</tbody></table>";
-			break;
-	}
-}
-
-function listplug_table_memberlist($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo '<th>' . _LIST_MEMBER_NAME . '</th><th>' . _LIST_MEMBER_RNAME . '</th><th>' . _LIST_MEMBER_URL . '</th><th>' . _LIST_MEMBER_ADMIN;
-			help('superadmin');
-			echo "</th><th>" . _LIST_MEMBER_LOGIN;
-			help('canlogin');
-			echo "</th><th colspan='2'>" . _LISTS_ACTIONS. "</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>';
-			$id = listplug_nextBatchId();
-			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->mnumber,'" />';
-			echo '<label for="batch',$id,'">';
-			echo "<a href='mailto:", htmlspecialchars($current->memail), "' tabindex='".$template['tabindex']."'>", htmlspecialchars($current->mname), "</a>";
-			echo '</label>';
-			echo '</td>';
-			echo '<td>', htmlspecialchars($current->mrealname), '</td>';
-			echo "<td><a href='", htmlspecialchars($current->murl), "' tabindex='", $template['tabindex'] , "'>", htmlspecialchars($current->murl), "</a></td>";
-			echo '<td>', ($current->madmin ? _YES : _NO),'</td>';
-			echo '<td>', ($current->mcanlogin ? _YES : _NO), '</td>';
-			echo "<td><a href='index.php?action=memberedit&amp;memberid=$current->mnumber' tabindex='".$template['tabindex']."'>"._LISTS_EDIT."</a></td>";
-			echo "<td><a href='index.php?action=memberdelete&amp;memberid=$current->mnumber' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
-			break;
-	}
-}
-
-function listplug_table_teamlist($template, $type) {
-	global $manager;
-	switch($type) {
-		case 'HEAD':
-			echo "<th>"._LIST_MEMBER_NAME."</th><th>"._LIST_MEMBER_RNAME."</th><th>"._LIST_TEAM_ADMIN;
-			help('teamadmin');
-			echo "</th><th colspan='2'>"._LISTS_ACTIONS."</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>';
-			$id = listplug_nextBatchId();
-			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->tmember,'" />';
-			echo '<label for="batch',$id,'">';
-			echo "<a href='mailto:", htmlspecialchars($current->memail), "' tabindex='".$template['tabindex']."'>", htmlspecialchars($current->mname), "</a>";
-			echo '</label>';
-			echo '</td>';
-			echo '<td>', htmlspecialchars($current->mrealname), '</td>';
-			echo '<td>', ($current->tadmin ? _YES : _NO) , '</td>';
-			echo "<td><a href='index.php?action=teamdelete&amp;memberid=$current->tmember&amp;blogid=$current->tblog' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
-
-			$url = 'index.php?action=teamchangeadmin&memberid=' . intval($current->tmember) . '&blogid=' . intval($current->tblog);
-			$url = $manager->addTicketToUrl($url);
-			echo "<td><a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>"._LIST_TEAM_CHADMIN."</a></td>";
-			break;
-	}
-}
-
-function encode_desc($data)
-	{   $to_entities = get_html_translation_table(HTML_ENTITIES);
-		$from_entities = array_flip($to_entities);
-		$data = strtr($data,$from_entities);
-		$data = strtr($data,$to_entities);
-		return $data;
-	}
-
-function listplug_table_pluginlist($template, $type) {
-	global $manager;
-	switch($type) {
-		case 'HEAD':
-			echo '<th>'._LISTS_INFO.'</th><th>'._LISTS_DESC.'</th>';
-			echo '<th>'._LISTS_ACTIONS.'</th>';
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			$plug =& $manager->getPlugin($current->pfile);
-			if ($plug) {
-				echo '<td>';
-					echo '<strong>' , htmlspecialchars($plug->getName()) , '</strong><br />';
-					echo _LIST_PLUGS_AUTHOR, ' ' , htmlspecialchars($plug->getAuthor()) , '<br />';
-					echo _LIST_PLUGS_VER, ' ' , htmlspecialchars($plug->getVersion()) , '<br />';
-					if ($plug->getURL())
-					echo '<a href="',htmlspecialchars($plug->getURL()),'" tabindex="'.$template['tabindex'].'">',_LIST_PLUGS_SITE,'</a><br />';
-				echo '</td>';
-				echo '<td>';
-					echo _LIST_PLUGS_DESC .'<br/>'. encode_desc($plug->getDescription());
-					if (sizeof($plug->getEventList()) > 0) {
-						echo '<br /><br />',_LIST_PLUGS_SUBS,'<br />',htmlspecialchars(implode($plug->getEventList(),', '));
-						// check the database to see if it is up-to-date and notice the user if not
-					}
-					if (!$plug->subscribtionListIsUptodate()) {
-						echo '<br /><br /><strong>',_LIST_PLUG_SUBS_NEEDUPDATE,'</strong>';
-					}
-					if (sizeof($plug->getPluginDep()) > 0)
-						echo '<br /><br />',_LIST_PLUGS_DEP,'<br />',htmlspecialchars(implode($plug->getPluginDep(),', '));
-				echo '</td>';
-			} else {
-				echo '<td colspan="2">Error: plugin file <b>',htmlspecialchars($current->pfile),'.php</b> could not be loaded, or it has been set inactive because it does not support some features (check the <a href="?action=actionlog">actionlog</a> for more info)</td>';
-			}
-			echo '<td>';
-
-				$baseUrl = 'index.php?plugid=' . intval($current->pid) . '&action=';
-				$url = $manager->addTicketToUrl($baseUrl . 'pluginup');
-				echo "<a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>",_LIST_PLUGS_UP,"</a>";
-				$url = $manager->addTicketToUrl($baseUrl . 'plugindown');
-				echo "<br /><a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>",_LIST_PLUGS_DOWN,"</a>";
-				echo "<br /><a href='index.php?action=plugindelete&amp;plugid=$current->pid' tabindex='".$template['tabindex']."'>",_LIST_PLUGS_UNINSTALL,"</a>";
-				if ($plug && ($plug->hasAdminArea() > 0))
-					echo "<br /><a href='".htmlspecialchars($plug->getAdminURL())."'  tabindex='".$template['tabindex']."'>",_LIST_PLUGS_ADMIN,"</a>";
-				if ($plug && ($plug->supportsFeature('HelpPage') > 0))
-					echo "<br /><a href='index.php?action=pluginhelp&amp;plugid=$current->pid'  tabindex='".$template['tabindex']."'>",_LIST_PLUGS_HELP,"</a>";
-				if (quickQuery('SELECT COUNT(*) AS result FROM '.sql_table('plugin_option_desc').' WHERE ocontext=\'global\' and opid='.$current->pid) > 0)
-					echo "<br /><a href='index.php?action=pluginoptions&amp;plugid=$current->pid'  tabindex='".$template['tabindex']."'>",_LIST_PLUGS_OPTIONS,"</a>";
-			echo '</td>';
-			break;
-	}
-}
-
-function listplug_table_plugoptionlist($template, $type) {
-	global $manager;
-	switch($type) {
-		case 'HEAD':
-			echo '<th>'._LISTS_INFO.'</th><th>'._LISTS_VALUE.'</th>';
-			break;
-		case 'BODY':
-			$current = $template['current'];
-			listplug_plugOptionRow($current);
-			break;
-		case 'FOOT':
-			?>
-			<tr>
-				<th colspan="2"><?php echo _PLUGS_SAVE?></th>
-			</tr><tr>
-				<td><?php echo _PLUGS_SAVE?></td>
-				<td><input type="submit" value="<?php echo _PLUGS_SAVE?>" /></td>
-			</tr>
-			<?php			break;
-	}
-}
-
-function listplug_plugOptionRow($current) {
-	$varname = 'plugoption['.$current['oid'].']['.$current['contextid'].']';
-	// retreive the optionmeta
-	$meta = NucleusPlugin::getOptionMeta($current['typeinfo']);
-
-	// only if it is not a hidden option write the controls to the page
-	if ($meta['access'] != 'hidden') {
-		echo '<td>',htmlspecialchars($current['description']?$current['description']:$current['name']),'</td>';
-		echo '<td>';
-		switch($current['type']) {
-			case 'yesno':
-				ADMIN::input_yesno($varname, $current['value'], 0, 'yes', 'no');
-				break;
-			case 'password':
-				echo '<input type="password" size="40" maxlength="128" name="',htmlspecialchars($varname),'" value="',htmlspecialchars($current['value']),'" />';
-				break;
-			case 'select':
-				echo '<select name="'.htmlspecialchars($varname).'">';
-				$aOptions = NucleusPlugin::getOptionSelectValues($current['typeinfo']);
-				$aOptions = explode('|', $aOptions);
-				for ($i=0; $i<(count($aOptions)-1); $i+=2) {
-					echo '<option value="'.htmlspecialchars($aOptions[$i+1]).'"';
-					if ($aOptions[$i+1] == $current['value'])
-						echo ' selected="selected"';
-					echo '>'.htmlspecialchars($aOptions[$i]).'</option>';
-				}
-				echo '</select>';
-				break;
-			case 'textarea':
-				//$meta = NucleusPlugin::getOptionMeta($current['typeinfo']);
-				echo '<textarea class="pluginoption" cols="30" rows="5" name="',htmlspecialchars($varname),'"';
-				if ($meta['access'] == 'readonly') {
-					echo ' readonly="readonly"';
-				}
-				echo '>',htmlspecialchars($current['value']),'</textarea>';
-				break;
-			case 'text':
-			default:
-				//$meta = NucleusPlugin::getOptionMeta($current['typeinfo']);
-
-				echo '<input type="text" size="40" maxlength="128" name="',htmlspecialchars($varname),'" value="',htmlspecialchars($current['value']),'"';
-				if ($meta['datatype'] == 'numerical') {
-					echo ' onkeyup="checkNumeric(this)" onblur="checkNumeric(this)"';
-				}
-				if ($meta['access'] == 'readonly') {
-					echo ' readonly="readonly"';
-				}
-				echo ' />';
-		}
-		echo $current['extra'];
-		echo '</td>';
-	}
-}
-
-function listplug_table_itemlist($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo "<th>"._LIST_ITEM_INFO."</th><th>"._LIST_ITEM_CONTENT."</th><th colspan='1'>"._LISTS_ACTIONS."</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-			$current->itime = strtotime($current->itime);	// string -> unix timestamp
-
-			if ($current->idraft == 1)
-				$cssclass = "class='draft'";
-
-			// (can't use offset time since offsets might vary between blogs)
-			if ($current->itime > $template['now'])
-				$cssclass = "class='future'";
-
-			echo "<td $cssclass>",_LIST_ITEM_BLOG,' ', htmlspecialchars($current->bshortname);
-			echo "    <br />",_LIST_ITEM_CAT,' ', htmlspecialchars($current->cname);
-			echo "    <br />",_LIST_ITEM_AUTHOR, ' ', htmlspecialchars($current->mname);
-			echo "    <br />",_LIST_ITEM_DATE," " . date("Y-m-d",$current->itime);
-			echo "<br />",_LIST_ITEM_TIME," " . date("H:i",$current->itime);
-			echo "</td>";
-			echo "<td $cssclass>";
-
-			$id = listplug_nextBatchId();
-
-			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->inumber,'" />';
-			echo '<label for="batch',$id,'">';
-			echo "<b>" . htmlspecialchars(strip_tags($current->ititle)) . "</b>";
-			echo '</label>';
-			echo "<br />";
-
-
-			$current->ibody = strip_tags($current->ibody);
-			$current->ibody = htmlspecialchars(shorten($current->ibody,300,'...'));
-
-			echo "$current->ibody</td>";
-			echo "<td $cssclass>";
-			echo 	"<a href='index.php?action=itemedit&amp;itemid=$current->inumber'>"._LISTS_EDIT."</a>";
-			echo    "<br /><a href='index.php?action=itemcommentlist&amp;itemid=$current->inumber'>"._LISTS_COMMENTS."</a>";
-			echo    "<br /><a href='index.php?action=itemmove&amp;itemid=$current->inumber'>"._LISTS_MOVE."</a>";
-			echo    "<br /><a href='index.php?action=itemdelete&amp;itemid=$current->inumber'>"._LISTS_DELETE."</a>";
-			echo "</td>";
-			break;
-	}
-}
-
-// for batch operations: generates the index numbers for checkboxes
-function listplug_nextBatchId() {
-	static $id = 0;
-	return $id++;
-}
-
-function listplug_table_commentlist($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo "<th>"._LISTS_INFO."</th><th>"._LIST_COMMENT."</th><th colspan='3'>"._LISTS_ACTIONS."</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-			$current->ctime = strtotime($current->ctime);	// string -> unix timestamp
-
-			echo '<td>';
-			echo date("Y-m-d@H:i",$current->ctime);
-			echo '<br />';
-			if ($current->mname)
-				echo htmlspecialchars($current->mname) ,' ', _LIST_COMMENTS_MEMBER;
-			else
-				echo htmlspecialchars($current->cuser);
-			echo '</td>';
-
-
-			$current->cbody = strip_tags($current->cbody);
-			$current->cbody = htmlspecialchars(shorten($current->cbody, 300, '...'));
-
-			echo '<td>';
-			$id = listplug_nextBatchId();
-			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->cnumber,'" />';
-			echo '<label for="batch',$id,'">';
-			echo $current->cbody;
-			echo '</label>';
-			echo '</td>';
-
-			echo "<td><a href='index.php?action=commentedit&amp;commentid=$current->cnumber'>"._LISTS_EDIT."</a></td>";
-			echo "<td><a href='index.php?action=commentdelete&amp;commentid=$current->cnumber'>"._LISTS_DELETE."</a></td>";
-			if ($template['canAddBan'])
-				echo "<td><a href='index.php?action=banlistnewfromitem&amp;itemid=$current->citem&amp;ip=", htmlspecialchars($current->cip), "' title='", htmlspecialchars($current->chost), "'>"._LIST_COMMENT_BANIP."</a></td>";
-			break;
-	}
-}
-
-
-function listplug_table_bloglist($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo "<th>" . _NAME . "</th><th colspan='7'>" ._LISTS_ACTIONS. "</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo "<td title='blogid:$current->bnumber shortname:$current->bshortname'><a href='$current->burl'><img src='images/globe.gif' width='13' height='13' alt='". _BLOGLIST_TT_VISIT."' /></a> " . htmlspecialchars($current->bname) . "</td>";
-			echo "<td><a href='index.php?action=createitem&amp;blogid=$current->bnumber' title='" . _BLOGLIST_TT_ADD ."'>" . _BLOGLIST_ADD . "</a></td>";
-			echo "<td><a href='index.php?action=itemlist&amp;blogid=$current->bnumber' title='". _BLOGLIST_TT_EDIT."'>". _BLOGLIST_EDIT."</a></td>";
-			echo "<td><a href='index.php?action=blogcommentlist&amp;blogid=$current->bnumber' title='". _BLOGLIST_TT_COMMENTS."'>". _BLOGLIST_COMMENTS."</a></td>";
-			echo "<td><a href='index.php?action=bookmarklet&amp;blogid=$current->bnumber' title='". _BLOGLIST_TT_BMLET."'>". _BLOGLIST_BMLET . "</a></td>";
-
-			if ($current->tadmin == 1) {
-				echo "<td><a href='index.php?action=blogsettings&amp;blogid=$current->bnumber' title='" . _BLOGLIST_TT_SETTINGS . "'>" ._BLOGLIST_SETTINGS. "</a></td>";
-				echo "<td><a href='index.php?action=banlist&amp;blogid=$current->bnumber' title='" . _BLOGLIST_TT_BANS. "'>". _BLOGLIST_BANS."</a></td>";
-			}
-
-			if ($template['superadmin']) {
-				echo "<td><a href='index.php?action=deleteblog&amp;blogid=$current->bnumber' title='". _BLOGLIST_TT_DELETE."'>" ._BLOGLIST_DELETE. "</a></td>";
-			}
-
-
-
-			break;
-	}
-}
-
-function listplug_table_shortblognames($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo "<th>" . _NAME . "</th><th>" . _NAME. "</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>' , htmlspecialchars($current->bshortname) , '</td>';
-			echo '<td>' , htmlspecialchars($current->bname) , '</td>';
-
-			break;
-	}
-}
-
-function listplug_table_shortnames($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo "<th>" . _NAME . "</th><th>" . _LISTS_DESC. "</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>' , htmlspecialchars($current->name) , '</td>';
-			echo '<td>' , htmlspecialchars($current->description) , '</td>';
-
-			break;
-	}
-}
-
-
-function listplug_table_categorylist($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo "<th>"._LISTS_NAME."</th><th>"._LISTS_DESC."</th><th colspan='2'>"._LISTS_ACTIONS."</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>';
-			$id = listplug_nextBatchId();
-			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->catid,'" />';
-			echo '<label for="batch',$id,'">';
-			echo htmlspecialchars($current->cname);
-			echo '</label>';
-			echo '</td>';
-
-			echo '<td>', htmlspecialchars($current->cdesc), '</td>';
-			echo "<td><a href='index.php?action=categorydelete&amp;blogid=$current->cblog&amp;catid=$current->catid' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
-			echo "<td><a href='index.php?action=categoryedit&amp;blogid=$current->cblog&amp;catid=$current->catid' tabindex='".$template['tabindex']."'>"._LISTS_EDIT."</a></td>";
-
-			break;
-	}
-}
-
-
-function listplug_table_templatelist($template, $type) {
-	global $manager;
-	switch($type) {
-		case 'HEAD':
-			echo "<th>"._LISTS_NAME."</th><th>"._LISTS_DESC."</th><th colspan='3'>"._LISTS_ACTIONS."</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo "<td>" , htmlspecialchars($current->tdname), "</td>";
-			echo "<td>" , htmlspecialchars($current->tddesc), "</td>";
-			echo "<td><a href='index.php?action=templateedit&amp;templateid=$current->tdnumber' tabindex='".$template['tabindex']."'>"._LISTS_EDIT."</a></td>";
-
-			$url = $manager->addTicketToUrl('index.php?action=templateclone&templateid=' . intval($current->tdnumber));
-			echo "<td><a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>"._LISTS_CLONE."</a></td>";
-			echo "<td><a href='index.php?action=templatedelete&amp;templateid=$current->tdnumber' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
-
-			break;
-	}
-}
-
-function listplug_table_skinlist($template, $type) {
-	global $CONF, $DIR_SKINS, $manager;
-	switch($type) {
-		case 'HEAD':
-			echo "<th>"._LISTS_NAME."</th><th>"._LISTS_DESC."</th><th colspan='3'>"._LISTS_ACTIONS."</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>';
-
-			// use a special style for the default skin
-			if ($current->sdnumber == $CONF['BaseSkin']) {
-				echo '<strong>',htmlspecialchars($current->sdname),'</strong>';
-			} else {
-				echo htmlspecialchars($current->sdname);
-			}
-
-			echo '<br /><br />';
-			echo _LISTS_TYPE ,': ' , htmlspecialchars($current->sdtype);
-			echo '<br />', _LIST_SKINS_INCMODE , ' ' , (($current->sdincmode=='skindir') ?_PARSER_INCMODE_SKINDIR:_PARSER_INCMODE_NORMAL);
-			if ($current->sdincpref) echo '<br />' , _LIST_SKINS_INCPREFIX , ' ', htmlspecialchars($current->sdincpref);
-
-			// add preview image when present
-			if ($current->sdincpref && @file_exists($DIR_SKINS . $current->sdincpref . 'preview.png'))
-			{
-				echo '<br /><br />';
-
-				$hasEnlargement = @file_exists($DIR_SKINS . $current->sdincpref . 'preview-large.png');
-				if ($hasEnlargement)
-					echo '<a href="',$CONF['SkinsURL'], htmlspecialchars($current->sdincpref),'preview-large.png" title="View larger">';
-
-				echo '<img class="skinpreview" src="',$CONF['SkinsURL'], htmlspecialchars($current->sdincpref),'preview.png" width="100" height="75" alt="Preview for \'',htmlspecialchars($current->sdname),'\' skin" />';
-
-				if ($hasEnlargement)
-					echo '</a>';
-
-				if (@file_exists($DIR_SKINS . $current->sdincpref . 'readme.html'))
-				{
-					echo '<br /><a href="',$CONF['SkinsURL'], htmlspecialchars($current->sdincpref),'readme.html" title="More info on the \'',htmlspecialchars($current->sdname),'\' skin">Readme</a>';
-				}
-
-
-			}
-
-			echo "</td>";
-
-
-			echo "<td>" , htmlspecialchars($current->sddesc);
-				// show list of defined parts
-				$r = sql_query('SELECT stype FROM '.sql_table('skin').' WHERE sdesc='.$current->sdnumber . ' ORDER BY stype');
-				$types = array();
-				while ($o = mysql_fetch_object($r))
-					array_push($types,$o->stype);
-				if (sizeof($types) > 0) {
-					$friendlyNames = SKIN::getFriendlyNames();
-					for ($i=0;$i<sizeof($types);$i++) {
-						$type = $types[$i];
-						$types[$i] = '<li>' . helpHtml('skinpart'.$type) . ' <a href="index.php?action=skinedittype&amp;skinid='.$current->sdnumber.'&amp;type='.$type.'" tabindex="'.$template['tabindex'].'">' . htmlspecialchars($friendlyNames[$type]) . "</a></li>";
-					}
-					echo '<br /><br />',_LIST_SKINS_DEFINED,' <ul>',implode($types,'') ,'</ul>';
-				}
-			echo "</td>";
-			echo "<td><a href='index.php?action=skinedit&amp;skinid=$current->sdnumber' tabindex='".$template['tabindex']."'>"._LISTS_EDIT."</a></td>";
-
-			$url = $manager->addTicketToUrl('index.php?action=skinclone&skinid=' . intval($current->sdnumber));
-			echo "<td><a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>"._LISTS_CLONE."</a></td>";
-			echo "<td><a href='index.php?action=skindelete&amp;skinid=$current->sdnumber' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
-
-			break;
-	}
-}
-
-function listplug_table_draftlist($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo "<th>"._LISTS_BLOG."</th><th>"._LISTS_TITLE."</th><th colspan='2'>"._LISTS_ACTIONS."</th>";
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>', htmlspecialchars($current->bshortname) , '</td>';
-			echo '<td>', htmlspecialchars(strip_tags($current->ititle)) , '</td>';
-			echo "<td><a href='index.php?action=itemedit&amp;itemid=$current->inumber'>"._LISTS_EDIT."</a></td>";
-			echo "<td><a href='index.php?action=itemdelete&amp;itemid=$current->inumber'>"._LISTS_DELETE."</a></td>";
-
-			break;
-	}
-}
-
-
-function listplug_table_actionlist($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo '<th>'._LISTS_TIME.'</th><th>'._LIST_ACTION_MSG.'</th>';
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>' , htmlspecialchars($current->timestamp), '</td>';
-			echo '<td>' , htmlspecialchars($current->message), '</td>';
-
-			break;
-	}
-}
-
-function listplug_table_banlist($template, $type) {
-	switch($type) {
-		case 'HEAD':
-			echo '<th>'._LIST_BAN_IPRANGE.'</th><th>'. _LIST_BAN_REASON.'</th><th>'._LISTS_ACTIONS.'</th>';
-			break;
-		case 'BODY':
-			$current = $template['current'];
-
-			echo '<td>' , htmlspecialchars($current->iprange) , '</td>';
-			echo '<td>' , htmlspecialchars($current->reason) , '</td>';
-			echo "<td><a href='index.php?action=banlistdelete&amp;blogid=", intval($current->blogid) , "&amp;iprange=" , htmlspecialchars($current->iprange) , "'>",_LISTS_DELETE,"</a></td>";
-			break;
-	}
-}
-
-/**
- * Returns the Javascript code for a bookmarklet that works on most modern browsers
- *
- * @param blogid
- */
-function getBookmarklet($blogid) {
-	global $CONF;
-
-	// normal
-	$document = 'document';
-	$bookmarkletline = "javascript:Q='';x=".$document.";y=window;if(x.selection){Q=x.selection.createRange().text;}else if(y.getSelection){Q=y.getSelection();}else if(x.getSelection){Q=x.getSelection();}wingm=window.open('";
-	$bookmarkletline .= $CONF['AdminURL'] . "bookmarklet.php?blogid=$blogid";
-	$bookmarkletline .="&logtext='+escape(Q)+'&loglink='+escape(x.location.href)+'&loglinktitle='+escape(x.title),'nucleusbm','scrollbars=yes,width=600,height=500,left=10,top=10,status=yes,resizable=yes');wingm.focus();";
-
-	return $bookmarkletline;
-}
-
-
 ?>
diff -ruN 3.24.src/nucleus/libs/backup.php 3.31.src/nucleus/libs/backup.php
--- 3.24.src/nucleus/libs/backup.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/backup.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,32 +1,32 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * Scripts to create/restore a backup of the Nucleus database
-  *
-  * Based on code in phpBB (http://phpBB.sourceforge.net)
-  *
+ * Scripts to create/restore a backup of the Nucleus database
+ *
+ * Based on code in phpBB (http://phpBB.sourceforge.net)
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: backup.php,v 1.19.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: backup.php 1183 2007-07-15 15:06:31Z kaigreve $
+ */
+
 
- 
 /**
   * This function creates an sql dump of the database and sends it to
   * the user as a file (can be gzipped if they want)
   *
-  * @requires 
+  * @requires
   *		no output may have preceded (new headers are sent)
-  * @param gzip 
+  * @param gzip
   *		1 = compress backup file, 0 = no compression (default)
   */
 function do_backup($gzip = 0) {
@@ -62,38 +62,38 @@
 	$res = sql_query('SELECT pfile FROM '.sql_table('plugin'));
 	while ($plugName = mysql_fetch_object($res)) {
 		$plug =& $manager->getPlugin($plugName->pfile);
-		if ($plug) $tables = array_merge($tables, $plug->getTableList());
+		if ($plug) $tables = array_merge($tables, (array) $plug->getTableList());
 	}
 	ob_end_clean();
-		
+
 	// remove duplicates
 	$tables = array_unique($tables);
-			  
+
 	// make sure browsers don't cache the backup
 	header("Pragma: no-cache");
-	
+
 	// don't allow gzip compression when extension is not loaded
 	if (($gzip != 0) && !extension_loaded("zlib"))
 		$gzip = 0;
-		
-	
+
+
 
 	if ($gzip) {
 		// use an output buffer
 		@ob_start();
 		@ob_implicit_flush(0);
-		
+
 		// set filename
 		$filename = 'nucleus_db_backup_'.strftime("%Y%m%d", time()).".sql.gz";
 	} else {
 		$filename = 'nucleus_db_backup_'.strftime("%Y%m%d", time()).".sql";
 	}
-	
-	
+
+
 	// send headers that tell the browser a file is coming
 	header("Content-Type: text/x-delimtext; name=\"$filename\"");
 	header("Content-disposition: attachment; filename=$filename");
-		
+
 	// dump header
 	echo "#\n";
 	echo "# This is a backup file generated by Nucleus \n";
@@ -101,15 +101,15 @@
 	echo "#\n";
 	echo "# backup-date: " .  gmdate("d-m-Y H:i:s", time()) . " GMT\n";
 	global $nucleus;
-	echo "# Nucleus CMS version: " . $nucleus['version'] . "\n";	
+	echo "# Nucleus CMS version: " . $nucleus['version'] . "\n";
 	echo "#\n";
 	echo "# WARNING: Only try to restore on servers running the exact same version of Nucleus\n";
 	echo "#\n";
-	
+
 	// dump all tables
 	reset($tables);
 	array_walk($tables, '_backup_dump_table');
-	
+
 	if($gzip)
 	{
 		$Size = ob_get_length();
@@ -118,7 +118,7 @@
 		ob_end_clean();
 		echo "\x1f\x8b\x08\x00\x00\x00\x00\x00".substr($contents, 0, strlen($contents) - 4).gzip_PrintFourChars($Crc).gzip_PrintFourChars($Size);
 	}
-	
+
 	exit;
 
 }
@@ -133,7 +133,7 @@
 	echo "#\n";
 	echo "# TABLE: " . $tablename . "\n";
 	echo "#\n";
-	
+
 	// dump table structure
 	_backup_dump_structure($tablename);
 
@@ -142,7 +142,7 @@
 }
 
 function _backup_dump_structure($tablename) {
-	
+
 	// add command to drop table on restore
 	echo "DROP TABLE IF EXISTS $tablename;\n";
 	echo "CREATE TABLE $tablename(\n";
@@ -156,7 +156,7 @@
 
 		echo '	' . $row['Field'] . ' ' . $row['Type'];
 
-		if(!empty($row['Default']))
+		if(isset($row['Default']))
 			echo ' DEFAULT \'' . $row['Default'] . '\'';
 
 		if($row['Null'] != "YES")
@@ -183,11 +183,11 @@
 			$kname = "UNIQUE|$kname";
 		if(($kname != 'PRIMARY') && ($row['Index_type'] == 'FULLTEXT'))
 			$kname = "FULLTEXT|$kname";
-			
+
 		if(!is_array($index[$kname]))
 			$index[$kname] = array();
-	
-		$index[$kname][] = $row['Column_name'];
+
+		$index[$kname][] = $row['Column_name'] . ( ($row['Sub_part']) ? ' (' . $row['Sub_part'] . ')' : '');
 	}
 
 	while(list($x, $columns) = @each($index)) {
@@ -200,43 +200,61 @@
 		elseif (substr($x,0,8) == 'FULLTEXT')
 			echo '	FULLTEXT KEY ' . substr($x,9) . ' (' . implode($columns, ', ') . ')';
 		elseif (($x == 'ibody') || ($x == 'cbody'))			// karma 2004-05-30 quick and dirty fix. fulltext keys were not in SQL correctly.
-			echo '	FULLTEXT KEY ' . substr($x,9) . ' (' . implode($columns, ', ') . ')';			
-		else 
+			echo '	FULLTEXT KEY ' . substr($x,9) . ' (' . implode($columns, ', ') . ')';
+		else
 			echo "	KEY $x (" . implode($columns, ', ') . ')';
 	}
 
 	echo "\n);\n\n";
 }
 
+/**
+ * Returns the field named for the given table in the 
+ * following format:
+ *
+ * (column1, column2, ..., columnn)
+ */
+function _backup_get_field_names($result, $num_fields) {
+
+/*	if (function_exists('mysqli_fetch_fields') ) {
+		
+		$fields = mysqli_fetch_fields($result);
+		for ($j = 0; $j < $num_fields; $j++)
+			$fields[$j] = $fields[$j]->name;
+
+	} else {*/
+
+		$fields = array();
+		for ($j = 0; $j < $num_fields; $j++) {
+			$fields[] = mysql_field_name($result, $j);
+		}
+
+/*	}*/
+	
+	return '(' . implode(', ', $fields) . ')';	
+}
+
 function _backup_dump_contents($tablename) {
 	//
 	// Grab the data from the table.
 	//
 	$result = mysql_query("SELECT * FROM $tablename");
 
-	if(mysql_numrows($result) > 0)
+	if(mysql_num_rows($result) > 0)
 		echo "\n#\n# Table Data for $tablename\n#\n";
-
+		
+	$num_fields = mysql_num_fields($result);
+	
+	//
+	// Compose fieldname list
+	//
+	$tablename_list = _backup_get_field_names($result, $num_fields);
+		
 	//
 	// Loop through the resulting rows and build the sql statement.
 	//
 	while ($row = mysql_fetch_array($result))
 	{
-		$tablename_list = '(';
-		$num_fields = mysql_num_fields($result);
-
-		//
-		// Grab the list of field names.
-		//
-		for ($j = 0; $j < $num_fields; $j++)
-			$tablename_list .= mysql_field_name($result, $j) . ', ';
-
-		//
-		// Get rid of the last comma
-		//
-		$tablename_list = ereg_replace(', $', '', $tablename_list);
-		$tablename_list .= ')';
-
 		// Start building the SQL statement.
 
 		echo "INSERT INTO $tablename $tablename_list VALUES(";
@@ -262,8 +280,8 @@
 		echo ");\n";
 
 	}
-	
-	
+
+
 	echo "\n";
 
 }
@@ -277,35 +295,35 @@
 		$Val = floor($Val / 256);
 	}
 	return $return;
-} 
+}
 
 function do_restore() {
-	
+
 	$uploadInfo = postFileInfo('backup_file');
-	
+
 	// first of all: get uploaded file:
 	if (empty($uploadInfo['name']))
 		return 'No file uploaded';
 	if (!is_uploaded_file($uploadInfo['tmp_name']))
 		return 'No file uploaded';
-		
+
 	$backup_file_name = $uploadInfo['name'];
 	$backup_file_tmpname = $uploadInfo['tmp_name'];
 	$backup_file_type = $uploadInfo['type'];
 
 	if (!file_exists($backup_file_tmpname))
 		return 'File Upload Error';
-	
+
 	if (!preg_match("/^(text\/[a-zA-Z]+)|(application\/(x\-)?gzip(\-compressed)?)|(application\/octet-stream)$/is", $backup_file_type) )
 		return 'The uploaded file is not of the correct type';
-		
-		
-	
-	if (preg_match("/\.gz/is",$backup_file_name)) 
+
+
+
+	if (preg_match("/\.gz/is",$backup_file_name))
 		$gzip = 1;
 	else
 		$gzip = 0;
-		
+
 	if (!extension_loaded("zlib") && $gzip)
 		return "Cannot decompress gzipped backup (zlib package not installed)";
 
@@ -361,10 +379,10 @@
 function remove_remarks($sql)
 {
 	$lines = explode("\n", $sql);
-	
+
 	// try to keep mem. use down
 	$sql = "";
-	
+
 	$linecount = count($lines);
 	$output = "";
 
@@ -384,9 +402,9 @@
 			$lines[$i] = "";
 		}
 	}
-	
+
 	return $output;
-	
+
 }
 
 
@@ -404,10 +422,10 @@
 	// try to save mem.
 	$sql = "";
 	$output = array();
-	
+
 	// we don't actually care about the matches preg gives us.
 	$matches = array();
-	
+
 	// this is faster than calling count($tokens) every time thru the loop.
 	$token_count = count($tokens);
 	for ($i = 0; $i < $token_count; $i++)
@@ -415,7 +433,7 @@
 		// Don't wanna add an empty string as the last thing in the array.
 		if (($i != ($token_count - 1)) || (strlen($tokens[$i] > 0)))
 		{
-			
+
 			// even number of quotes means a complete SQL statement
 			if (_evenNumberOfQuotes($tokens[$i]))
 			{
@@ -428,13 +446,13 @@
 				// $temp will hold what we have so far.
 				$temp = $tokens[$i] .  ";";
 				$tokens[$i] = "";	// save memory..
-				
-				// Do we have a complete statement yet? 
+
+				// Do we have a complete statement yet?
 				$complete_stmt = false;
-				
+
 				for ($j = $i + 1; (!$complete_stmt && ($j < $token_count)); $j++)
 				{
-					// odd number of quotes means a completed statement 
+					// odd number of quotes means a completed statement
 					// (in combination with the odd number we had already)
 					if (!_evenNumberOfQuotes($tokens[$j]))
 					{
@@ -443,7 +461,7 @@
 						// save memory.
 						$tokens[$j] = "";
 						$temp = "";
-						
+
 						// exit the loop.
 						$complete_stmt = true;
 						// make sure the outer loop continues at the right point.
@@ -451,13 +469,13 @@
 					}
 					else
 					{
-						// even number of unescaped quotes. We still don't have a complete statement. 
+						// even number of unescaped quotes. We still don't have a complete statement.
 						// (1 odd and 1 even always make an odd)
 						$temp .= $tokens[$j] .  ";";
 						// save memory.
 						$tokens[$j] = "";
 					}
-					
+
 				} // for..
 			} // else
 		}
@@ -470,7 +488,7 @@
 function _evenNumberOfQuotes($text) {
 		// This is the total number of single quotes in the token.
 		$total_quotes = preg_match_all("/'/", $text, $matches);
-		// Counts single quotes that are preceded by an odd number of backslashes, 
+		// Counts single quotes that are preceded by an odd number of backslashes,
 		// which means they're escaped quotes.
 		$escaped_quotes = preg_match_all("/(?<!\\\\)(\\\\\\\\)*\\\\'/", $text, $matches);
 
diff -ruN 3.24.src/nucleus/libs/BAN.php 3.31.src/nucleus/libs/BAN.php
--- 3.24.src/nucleus/libs/BAN.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/BAN.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,24 +1,24 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * PHP class responsible for ban-management. 
-  *
+ * PHP class responsible for ban-management.
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: BAN.php,v 1.9.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
-  
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: BAN.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
+
 class BAN {
-	
+
 	/**
 	  * Checks if a given IP is banned from commenting/voting
 	  *
@@ -31,21 +31,21 @@
 		$res = sql_query($query);
 		while ($obj = mysql_fetch_object($res)) {
 			$found = strpos ($ip, $obj->iprange);
-			if (!($found === false)) 
+			if (!($found === false))
 				// found a match!
-			    	return new BANINFO($obj->iprange, $obj->reason);
+					return new BANINFO($obj->iprange, $obj->reason);
 		}
 		return 0;
 	}
-	
+
 	/**
 	  * Adds a new ban to the banlist. Returns 1 on success, 0 on error
 	  */
 	function addBan($blogid, $iprange, $reason) {
 		global $manager;
-		
+
 		$blogid = intval($blogid);
-	
+
 		$manager->notify(
 			'PreAddBan',
 			array(
@@ -54,11 +54,11 @@
 				'reason' => &$reason
 			)
 		);
-	
+
 		$query = 'INSERT INTO '.sql_table('ban')." (blogid, iprange, reason) VALUES "
-		       . "($blogid,'".addslashes($iprange)."','".addslashes($reason)."')";
+			   . "($blogid,'".addslashes($iprange)."','".addslashes($reason)."')";
 		$res = sql_query($query);
-		
+
 		$manager->notify(
 			'PostAddBan',
 			array(
@@ -67,10 +67,10 @@
 				'reason' => $reason
 			)
 		);
-		
+
 		return $res ? 1 : 0;
 	}
-	
+
 	/**
 	  * Removes a ban from the banlist (correct iprange is needed as argument)
 	  * Returns 1 on success, 0 on error
@@ -78,16 +78,16 @@
 	function removeBan($blogid, $iprange) {
 		global $manager;
 		$blogid = intval($blogid);
-		
+
 		$manager->notify('PreDeleteBan', array('blogid' => $blogid, 'range' => $iprange));
-		
+
 		$query = 'DELETE FROM '.sql_table('ban')." WHERE blogid=$blogid and iprange='" .addslashes($iprange). "'";
 		sql_query($query);
-		
+
 		$result = (mysql_affected_rows() > 0);
-		
+
 		$manager->notify('PostDeleteBan', array('blogid' => $blogid, 'range' => $iprange));
-		
+
 		return $result;
 	}
 }
@@ -95,7 +95,7 @@
 class BANINFO {
 	var $iprange;
 	var $message;
-	
+
 	function BANINFO($iprange, $message) {
 		$this->iprange = $iprange;
 		$this->message = $message;
diff -ruN 3.24.src/nucleus/libs/BaseActions.php 3.31.src/nucleus/libs/BaseActions.php
--- 3.24.src/nucleus/libs/BaseActions.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/libs/BaseActions.php	2007-10-22 19:36:00.000000000 -0500
@@ -0,0 +1,313 @@
+<?php
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+/**
+ * This class contains parse actions that are available in all ACTION classes
+ * e.g. include, phpinclude, parsedinclude, skinfile, ...
+ *
+ * It should never be used on it's own
+ *
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: BaseActions.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
+
+class BaseActions {
+
+	// depth level for includes (max. level is 3)
+	var $level;
+
+	// array of evaluated conditions (true/false). The element at the end is the one for the most nested
+	// if block.
+	var $if_conditions;
+
+	// in the "elseif" / "elseifnot" sequences, if one of the conditions become "true" remained conditions should not
+	// be tested. this variable (actually a stack) holds this information.
+	var $if_execute;
+
+	// at all times, can be evaluated to either true if the current block needs to be displayed. This
+	// variable is used to decide to skip skinvars in parts that will never be outputted.
+	var $if_currentlevel;
+
+	// contains a search string with keywords that need to be highlighted. These get parsed into $aHighlight
+	var $strHighlight;
+
+	// array of keywords that need to be highlighted in search results (see the highlight()
+	// and parseHighlight() methods)
+	var $aHighlight;
+
+	// reference to the parser object that is using this object as actions-handler
+	var $parser;
+
+	function BaseActions() {
+		$this->level = 0;
+
+		// if nesting level
+		$this->if_conditions = array(); // array on which condition values are pushed/popped
+		$this->if_execute = array(); 	// array on which condition values are pushed/popped
+		$this->if_currentlevel = 1;		// 1 = current level is displayed; 0 = current level not displayed
+
+		// highlights
+		$this->strHighlight = '';			// full highlight
+		$this->aHighlight = array();		// parsed highlight
+
+	}
+
+	// include file (no parsing of php)
+	function parse_include($filename) {
+		@readfile($this->getIncludeFileName($filename));
+	}
+
+	// php-include file
+	function parse_phpinclude($filename) {
+		includephp($this->getIncludeFileName($filename));
+	}
+
+	// parsed include
+	function parse_parsedinclude($filename) {
+		// check current level
+		if ($this->level > 3) return;	// max. depth reached (avoid endless loop)
+		$filename = $this->getIncludeFileName($filename);
+		if (!file_exists($filename)) return '';
+
+		$fsize = filesize($filename);
+
+		// nothing to include
+		if ($fsize <= 0)
+			return;
+
+		$this->level = $this->level + 1;
+
+		// read file
+		$fd = fopen ($filename, 'r');
+		$contents = fread ($fd, $fsize);
+		fclose ($fd);
+
+		// parse file contents
+		$this->parser->parse($contents);
+
+		$this->level = $this->level - 1;
+	}
+
+	/**
+	 * Returns the correct location of the file to be included, according to
+	 * parser properties
+	 *
+	 * IF IncludeMode = 'skindir' => use skindir
+	 */
+	function getIncludeFileName($filename) {
+		// leave absolute filenames and http urls as they are
+		if (
+				(substr($filename,0,1) == '/')
+			||	(substr($filename,0,7) == 'http://')
+			||	(substr($filename,0,6) == 'ftp://')
+			)
+			return $filename;
+
+		$filename = PARSER::getProperty('IncludePrefix') . $filename;
+		if (PARSER::getProperty('IncludeMode') == 'skindir') {
+			global $DIR_SKINS;
+			return $DIR_SKINS . $filename;
+		} else {
+			return $filename;
+		}
+	}
+
+	/**
+	 * Inserts an url relative to the skindir (useful when doing import/export)
+	 *
+	 * e.g. <skinfile(default/myfile.sth)>
+	 */
+	function parse_skinfile($filename) {
+		global $CONF;
+
+		echo $CONF['SkinsURL'] . PARSER::getProperty('IncludePrefix') . $filename;
+	}
+
+	/**
+	 * Sets a property for the parser
+	 */
+	function parse_set($property, $value) {
+		PARSER::setProperty($property, $value);
+	}
+
+	/**
+	 * Helper function: add if condition
+	 */
+	function _addIfCondition($condition) {
+
+		array_push($this->if_conditions,$condition);
+
+		$this->_updateTopIfCondition();
+
+		ob_start();
+	}
+
+	function _updateTopIfCondition() {
+		if (sizeof($this->if_conditions) == 0)
+			$this->if_currentlevel = 1;
+		else
+			$this->if_currentlevel = $this->if_conditions[sizeof($this->if_conditions) - 1];
+	}
+
+	/**
+	 * Helper function for elseif / elseifnot
+	 */
+	function _addIfExecute() {
+		array_push($this->if_execute, 0);
+	}
+
+	/**
+	 * Helper function for elseif / elseifnot
+	 * @param string condition to be fullfilled
+	 */
+	function _updateIfExecute($condition) {
+		$index = sizeof($this->if_execute) - 1;
+		$this->if_execute[$index] = $this->if_execute[$index] || $condition;
+	}
+
+	/**
+	 * returns the currently top if condition
+	 */
+	function _getTopIfCondition() {
+		return $this->if_currentlevel;
+	}
+
+	/**
+	 * Sets the search terms to be highlighted
+	 *
+	 * @param $highlight
+	 *		A series of search terms
+	 */
+	function setHighlight($highlight) {
+		$this->strHighlight = $highlight;
+		if ($highlight) {
+			$this->aHighlight = parseHighlight($highlight);
+		}
+	}
+
+	/**
+	 * Applies the highlight to the given piece of text
+	 *
+	 * @param &$data
+	 *		Data that needs to be highlighted
+	 * @see setHighlight
+	 */
+	function highlight(&$data) {
+		if ($this->aHighlight)
+			return highlight($data,$this->aHighlight,$this->template['SEARCH_HIGHLIGHT']);
+		else
+			return $data;
+	}
+
+	/**
+	 * Parses <%if%> statements
+	 */
+	function parse_if() {
+		$this->_addIfExecute();
+
+		$args = func_get_args();
+		$condition = call_user_func_array(array(&$this,'checkCondition'), $args);
+		$this->_addIfCondition($condition);
+	}
+
+	/**
+	 * Parses <%else%> statements
+	 */
+	function parse_else() {
+		if (sizeof($this->if_conditions) == 0) return;
+		array_pop($this->if_conditions);
+		if ($this->if_currentlevel) {
+			ob_end_flush();
+			$this->_updateIfExecute(1);
+			$this->_addIfCondition(0);
+		} elseif ($this->if_execute[sizeof($this->if_execute) - 1]) {
+			ob_end_clean();
+			$this->_addIfCondition(0);
+		} else {
+			ob_end_clean();
+			$this->_addIfCondition(1);
+		}
+	}
+
+	/**
+	 * Parses <%elseif%> statements
+	 */
+	function parse_elseif() {
+		if (sizeof($this->if_conditions) == 0) return;
+		array_pop($this->if_conditions);
+		if ($this->if_currentlevel) {
+			ob_end_flush();
+			$this->_updateIfExecute(1);
+			$this->_addIfCondition(0);
+		} elseif ($this->if_execute[sizeof($this->if_execute) - 1]) {
+			ob_end_clean();
+			$this->_addIfCondition(0);
+		} else {
+			ob_end_clean();
+			$args = func_get_args();
+			$condition = call_user_func_array(array(&$this,'checkCondition'), $args);
+			$this->_addIfCondition($condition);
+		}
+	}
+
+	/**
+	 * Parses <%ifnot%> statements
+	 */
+	function parse_ifnot() {
+		$this->_addIfExecute();
+
+		$args = func_get_args();
+		$condition = call_user_func_array(array(&$this,'checkCondition'), $args);
+		$this->_addIfCondition(!$condition);
+	}
+
+	/**
+	 * Parses <%elseifnot%> statements
+	 */
+	function parse_elseifnot() {
+		if (sizeof($this->if_conditions) == 0) return;
+		array_pop($this->if_conditions);
+		if ($this->if_currentlevel) {
+			ob_end_flush();
+			$this->_updateIfExecute(1);
+			$this->_addIfCondition(0);
+		} elseif ($this->if_execute[sizeof($this->if_execute) - 1]) {
+			ob_end_clean();
+			$this->_addIfCondition(0);
+		} else {
+			ob_end_clean();
+			$args = func_get_args();
+			$condition = call_user_func_array(array(&$this,'checkCondition'), $args);
+			$this->_addIfCondition(!$condition);
+		}
+	}
+
+	/**
+	 * Ends a conditional if-block
+	 * see e.g. ifcat (BLOG), ifblogsetting (PAGEFACTORY)
+	 */
+	function parse_endif() {
+		// we can only close what has been opened
+		if (sizeof($this->if_conditions) == 0) return;
+
+		if ($this->if_currentlevel) {
+			ob_end_flush();
+		} else {
+			ob_end_clean();
+		}
+		array_pop($this->if_conditions);
+		array_pop($this->if_execute);
+
+		$this->_updateTopIfCondition();
+	}
+}
+?>
diff -ruN 3.24.src/nucleus/libs/BLOG.php 3.31.src/nucleus/libs/BLOG.php
--- 3.24.src/nucleus/libs/BLOG.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/BLOG.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,38 +1,42 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * A class representing a blog and containing functions to get that blog shown
-  * on the screen 
-  *
+ * A class representing a blog and containing functions to get that blog shown
+ * on the screen
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: BLOG.php,v 1.46.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: BLOG.php 1171 2007-06-14 03:36:49Z ehui $
+ */
+
+if ( !function_exists('requestVar') ) exit;
+require_once dirname(__FILE__) . '/ITEMACTIONS.php';
+
 class BLOG {
-	
+
 	// blog id
 	var $blogid;
-	
+
 	// ID of currently selected category
 	var $selectedcatid;
-	
-	// After creating an object of the blog class, contains true if the BLOG object is 
+
+	// After creating an object of the blog class, contains true if the BLOG object is
 	// valid (the blog exists)
 	var $isValid;
-	
+
 	// associative array, containing all blogsettings (use the get/set functions instead)
 	var $settings;
-	
+
 	/**
 	 * Creates a new BLOG object for the given blog
 	 *
@@ -42,7 +46,7 @@
 		$this->blogid = intval($id);
 		$this->readSettings();
 
-		// try to set catid 
+		// try to set catid
 		// (the parse functions in SKIN.php will override this, so it's mainly useless)
 		global $catid;
 		$this->setSelectedCategory($catid);
@@ -53,7 +57,7 @@
 	 *
 	 * @param $template
 	 *		String representing the template _NAME_ (!)
-	 * @param $amountEntries 
+	 * @param $amountEntries
 	 *		amount of entries to show
 	 * @param $startpos
 	 *		offset from where items should be shown (e.g. 5 = start at fifth item)
@@ -70,24 +74,24 @@
 	 * @param $year
 	 *		year
 	 * @param $month
-	 *		month 
+	 *		month
 	 * @param $template
 	 *		String representing the template name to be used
 	 */
 	function showArchive($templatename, $year, $month, $day=0) {
-		
+
 		// create extra where clause for select query
 		if ($day == 0) {
 			$timestamp_start = mktime(0,0,0,$month,1,$year);
 			$timestamp_end = mktime(0,0,0,$month+1,1,$year);  // also works when $month==12
 		} else {
 			$timestamp_start = mktime(0,0,0,$month,$day,$year);
-			$timestamp_end = mktime(0,0,0,$month,$day+1,$year);  
+			$timestamp_end = mktime(0,0,0,$month,$day+1,$year);
 		}
 		$extra_query = ' and i.itime>=' . mysqldate($timestamp_start)
-		             . ' and i.itime<' . mysqldate($timestamp_end);
-		
-	
+					 . ' and i.itime<' . mysqldate($timestamp_end);
+
+
 		$this->readLogAmount($templatename,0,$extra_query,'',1,1);
 
 	}
@@ -95,16 +99,16 @@
 
 	// sets/gets current category (only when category exists)
 	function setSelectedCategory($catid) {
-		if ($this->isValidCategory($catid) || (intval($catid) == 0)) 
+		if ($this->isValidCategory($catid) || (intval($catid) == 0))
 			$this->selectedcatid = intval($catid);
 	}
-	
+
 	function setSelectedCategoryByName($catname) {
 		$this->setSelectedCategory($this->getCategoryIdFromName($catname));
 	}
 
-	function getSelectedCategory() { 
-		return $this->selectedcatid; 
+	function getSelectedCategory() {
+		return $this->selectedcatid;
 	}
 
 	/**
@@ -130,11 +134,11 @@
 	function readLogAmount($template, $amountEntries, $extraQuery, $highlight, $comments, $dateheads, $offset = 0, $startpos = 0) {
 
 		$query = $this->getSqlBlog($extraQuery);
-		
+
 		if ($amountEntries > 0) {
-		        // $offset zou moeten worden:
-		        // (($startpos / $amountentries) + 1) * $offset ... later testen ...
-		       $query .= ' LIMIT ' . intval($startpos + $offset).',' . intval($amountEntries);
+				// $offset zou moeten worden:
+				// (($startpos / $amountentries) + 1) * $offset ... later testen ...
+			   $query .= ' LIMIT ' . intval($startpos + $offset).',' . intval($amountEntries);
 		}
 		return $this->showUsingQuery($template, $query, $highlight, $comments, $dateheads);
 	}
@@ -149,9 +153,9 @@
 		// set templatename as global variable (so plugins can access it)
 		global $currentTemplateName;
 		$currentTemplateName = $templateName;
-		
+
 		$template =& $manager->getTemplate($templateName);
-		
+
 		// create parser object & action handler
 		$actions =& new ITEMACTIONS($this);
 		$parser =& new PARSER($actions->getDefinedActions(),$actions);
@@ -163,15 +167,16 @@
 
 		// execute query
 		$items = sql_query($query);
-		
+
 		// loop over all items
+		$old_date = 0;
 		while ($item = mysql_fetch_object($items)) {
-			
+
 			$item->timestamp = strtotime($item->itime);	// string timestamp -> unix timestamp
-		
+
 			// action handler needs to know the item we're handling
 			$actions->setCurrentItem($item);
-			
+
 			// add date header if needed
 			if ($dateheads) {
 				$new_date = date('dFY',$item->timestamp);
@@ -183,53 +188,53 @@
 						$manager->notify('PreDateFoot',array('blog' => &$this, 'timestamp' => $oldTS));
 						$tmp_footer = strftime($template['DATE_FOOTER'], $oldTS);
 						$parser->parse($tmp_footer);
-						$manager->notify('PostDateFoot',array('blog' => &$this, 'timestamp' => $oldTS));						
+						$manager->notify('PostDateFoot',array('blog' => &$this, 'timestamp' => $oldTS));
 					}
 					$manager->notify('PreDateHead',array('blog' => &$this, 'timestamp' => $timestamp));
 					// note, to use templatvars in the dateheader, the %-characters need to be doubled in
 					// order to be preserved by strftime
-					$tmp_header = strftime($template['DATE_HEADER'],$timestamp);
+					$tmp_header = strftime((isset($template['DATE_HEADER']) ? $template['DATE_HEADER'] : null), $timestamp);
 					$parser->parse($tmp_header);
-					$manager->notify('PostDateHead',array('blog' => &$this, 'timestamp' => $timestamp));					
+					$manager->notify('PostDateHead',array('blog' => &$this, 'timestamp' => $timestamp));
 				}
 				$old_date = $new_date;
 			}
-			
-			// parse item 
+
+			// parse item
 			$parser->parse($template['ITEM_HEADER']);
-			$manager->notify('PreItem', array('blog' => &$this, 'item' => &$item));			
-			$parser->parse($template['ITEM']);			
-			$manager->notify('PostItem', array('blog' => &$this, 'item' => &$item));			
+			$manager->notify('PreItem', array('blog' => &$this, 'item' => &$item));
+			$parser->parse($template['ITEM']);
+			$manager->notify('PostItem', array('blog' => &$this, 'item' => &$item));
 			$parser->parse($template['ITEM_FOOTER']);
 
 		}
-		
+
 		$numrows = mysql_num_rows($items);
-		
+
 		// add another date footer if there was at least one item
 		if (($numrows > 0) && $dateheads) {
-			$manager->notify('PreDateFoot',array('blog' => &$this, 'timestamp' => strtotime($old_date)));		
+			$manager->notify('PreDateFoot',array('blog' => &$this, 'timestamp' => strtotime($old_date)));
 			$parser->parse($template['DATE_FOOTER']);
 			$manager->notify('PostDateFoot',array('blog' => &$this, 'timestamp' => strtotime($old_date)));
 		}
-		
+
 		mysql_free_result($items);	// free memory
-		
+
 		return $numrows;
-		
-	}	 
-	
+
+	}
+
 	function showOneitem($itemid, $template, $highlight) {
 		$extraQuery = ' and inumber=' . intval($itemid);
-		
+
 		return $this->readLogAmount($template, 1, $extraQuery, $highlight, 0, 0);
 	}
-	
+
 
 	/**
 	  * Adds an item to this blog
 	  */
-	function additem($catid, $title, $body, $more, $blogid, $authorid, $timestamp, $closed, $draft) {
+	function additem($catid, $title, $body, $more, $blogid, $authorid, $timestamp, $closed, $draft, $posted='1') {
 		global $manager;
 
 		$blogid 	= intval($blogid);
@@ -244,13 +249,13 @@
 			$body = addBreaks($body);
 			$more = addBreaks($more);
 		}
-		
-		if ($closed != '1')	$closed = '0';
+
+		if ($closed != '1') $closed = '0';
 		if ($draft != '0') $draft = '1';
 
 		if (!$this->isValidCategory($catid))
 			$catid = $this->getDefaultCategory();
-		
+
 		if ($timestamp > $this->getCorrectTime())
 			$isFuture = 1;
 
@@ -262,74 +267,91 @@
 		$body = addslashes($body);
 		$more = addslashes($more);
 
-		$query = 'INSERT INTO '.sql_table('item').' (ITITLE, IBODY, IMORE, IBLOG, IAUTHOR, ITIME, ICLOSED, IDRAFT, ICAT) '
-		       . "VALUES ('$title', '$body', '$more', $blogid, $authorid, '$timestamp', $closed, $draft, $catid)";
-		sql_query($query);  
+		$query = 'INSERT INTO '.sql_table('item').' (ITITLE, IBODY, IMORE, IBLOG, IAUTHOR, ITIME, ICLOSED, IDRAFT, ICAT, IPOSTED) '
+			   . "VALUES ('$title', '$body', '$more', $blogid, $authorid, '$timestamp', $closed, $draft, $catid, $posted)";
+		sql_query($query);
 		$itemid = mysql_insert_id();
-		
+
 		$manager->notify('PostAddItem',array('itemid' => $itemid));
-		
-		if (!$draft) 
+
+		if (!$draft)
 			$this->updateUpdateFile();
-		
+
 		// send notification mail
-		if (!$draft && !$isFuture && $this->getNotifyAddress() && $this->notifyOnNewItem()) 
+		if (!$draft && !$isFuture && $this->getNotifyAddress() && $this->notifyOnNewItem())
 			$this->sendNewItemNotification($itemid, stripslashes($title), stripslashes($body));
-		
+
 		return $itemid;
 	}
-	
+
 	function sendNewItemNotification($itemid, $title, $body) {
 		global $CONF, $member;
-		
+
 		// create text version of html post
 		$ascii = toAscii($body);
 
 		$mailto_msg = _NOTIFY_NI_MSG . " \n";
-		$mailto_msg .= $CONF['IndexURL'] . 'index.php?itemid=' . $itemid . "\n\n";
+//		$mailto_msg .= $CONF['IndexURL'] . 'index.php?itemid=' . $itemid . "\n\n";
+		$temp = parse_url($CONF['Self']);
+		if ($temp['scheme']) {
+			$mailto_msg .= createItemLink($itemid) . "\n\n";
+		} else {
+			$tempurl = $this->getURL();
+			if (substr($tempurl, -1) == '/' || substr($tempurl, -4) == '.php') {
+				$mailto_msg .= $tempurl . '?itemid=' . $itemid . "\n\n";
+			} else {
+				$mailto_msg .= $tempurl . '/?itemid=' . $itemid . "\n\n";
+			}
+		}
 		$mailto_msg .= _NOTIFY_TITLE . ' ' . strip_tags($title) . "\n";
 		$mailto_msg .= _NOTIFY_CONTENTS . "\n " . $ascii . "\n";
 		$mailto_msg .= getMailFooter();
-		
+
 		$mailto_title = $this->getName() . ': ' . _NOTIFY_NI_TITLE;
-			
+
 		$frommail = $member->getNotifyFromMailAddress();
 
 		$notify =& new NOTIFICATION($this->getNotifyAddress());
 		$notify->notify($mailto_title, $mailto_msg , $frommail);
-				
+
 
 
 	}
 
-	
+
 	/**
 	  * Creates a new category for this blog
 	  *
 	  * @param $catName
-	  *		name of the new category. When empty, a name is generated automatically 
+	  *		name of the new category. When empty, a name is generated automatically
 	  *		(starting with newcat)
 	  * @param $catDescription
 	  *		description of the new category. Defaults to 'New Category'
 	  *
-	  * @returns 
-	  *		the new category-id in case of success. 
+	  * @returns
+	  *		the new category-id in case of success.
 	  *		0 on failure
 	  */
 	function createNewCategory($catName = '', $catDescription = 'New category') {
 		global $member, $manager;
 
 		if ($member->blogAdminRights($this->getID())) {
-			// generate 
+			// generate
 			if ($catName == '')
 			{
 				$catName = 'newcat';
 				$i = 1;
-				while(mysql_num_rows(sql_query('SELECT * FROM '.sql_table('category')." WHERE cname='".$catName.$i."' and cblog=".$this->getID())) > 0) 
+
+				$res = sql_query('SELECT * FROM '.sql_table('category')." WHERE cname='".$catName.$i."' and cblog=".$this->getID());
+				while (mysql_num_rows($res) > 0)
+				{
 					$i++;
+					$res = sql_query('SELECT * FROM '.sql_table('category')." WHERE cname='".$catName.$i."' and cblog=".$this->getID());
+				}
+
 				$catName = $catName . $i;
 			}
-			
+
 			$manager->notify(
 				'PreAddCategory',
 				array(
@@ -338,11 +360,11 @@
 					'description' => $catDescription
 				)
 			);
-			
+
 			$query = 'INSERT INTO '.sql_table('category').' (cblog, cname, cdesc) VALUES (' . $this->getID() . ", '" . addslashes($catName) . "', '" . addslashes($catDescription) . "')";
 			sql_query($query);
 			$catid = mysql_insert_id();
-			
+
 			$manager->notify(
 				'PostAddCategory',
 				array(
@@ -351,14 +373,14 @@
 					'description' => $catDescription,
 					'catid' => $catid
 				)
-			);			
-			
+			);
+
 			return $catid;
 		} else {
 			return 0;
 		}
-	
-	}	
+
+	}
 
 
 	/**
@@ -378,40 +400,40 @@
 	 *		amount of hits found
 	 */
 	function search($query, $template, $amountMonths, $maxresults, $startpos) {
-        global $CONF, $manager;
+		global $CONF, $manager;
 
 		$highlight 	= '';
 		$sqlquery	= $this->getSqlSearch($query, $amountMonths, $highlight);
-		
+
 		if ($sqlquery == '')
 		{
 			// no query -> show everything
-            $extraquery = '';
-		    $amountfound = $this->readLogAmount($template, $maxresults, $extraQuery, $query, 1, 1);
+			$extraquery = '';
+			$amountfound = $this->readLogAmount($template, $maxresults, $extraQuery, $query, 1, 1);
 		} else {
-		
+
 			// add LIMIT to query (to split search results into pages)
-            if (intval($maxresults > 0)) 
-	            $sqlquery .= ' LIMIT ' . intval($startpos).',' . intval($maxresults);
+			if (intval($maxresults > 0))
+				$sqlquery .= ' LIMIT ' . intval($startpos).',' . intval($maxresults);
 
 			// show results
-		    $amountfound = $this->showUsingQuery($template, $sqlquery, $highlight, 1, 1);
-		    
-			// when no results were found, show a message 
-    		if ($amountfound == 0) 
-    		{
-	    		$template =& $manager->getTemplate($template);
-    			$vars = array(
-    				'query'		=> htmlspecialchars($query),
-    				'blogid'	=> $this->getID()
-    			);
-	    		echo TEMPLATE::fill($template['SEARCH_NOTHINGFOUND'],$vars);
-    		}
-        }
-        
+			$amountfound = $this->showUsingQuery($template, $sqlquery, $highlight, 1, 1);
+
+			// when no results were found, show a message
+			if ($amountfound == 0)
+			{
+				$template =& $manager->getTemplate($template);
+				$vars = array(
+					'query'		=> htmlspecialchars($query),
+					'blogid'	=> $this->getID()
+				);
+				echo TEMPLATE::fill($template['SEARCH_NOTHINGFOUND'],$vars);
+			}
+		}
+
 		return $amountfound;
 	}
-	
+
 	/**
 	 * Returns an SQL query to use for a search query
 	 *
@@ -423,22 +445,22 @@
 	 *		either empty, or 'count'. In this case, the query will be a SELECT COUNT(*) query
 	 * @returns $highlight
 	 *		words to highlight (out parameter)
-	 * @returns 
+	 * @returns
 	 *		either a full SQL query, or an empty string (if querystring empty)
 	 * @note
 	 *		No LIMIT clause is added. (caller should add this if multiple pages are requested)
 	 */
 	function getSqlSearch($query, $amountMonths = 0, &$highlight, $mode = '')
 	{
-        $searchclass =& new SEARCH($query);
-        
-        $highlight	  = $searchclass->inclusive;
-        
-        // if querystring is empty, return empty string
-        if ($searchclass->inclusive == '') 
-        	return '';
-            
-           
+		$searchclass =& new SEARCH($query);
+
+		$highlight	  = $searchclass->inclusive;
+
+		// if querystring is empty, return empty string
+		if ($searchclass->inclusive == '')
+			return '';
+
+
 		$where  = $searchclass->boolean_sql_where('ititle,ibody,imore');
 		$select = $searchclass->boolean_sql_select('ititle,ibody,imore');
 
@@ -450,15 +472,15 @@
 		if (count($blogs) > 0)
 			$selectblogs = ' and i.iblog in (' . implode(',', $blogs) . ')';
 
-		if ($mode == '') 
+		if ($mode == '')
 		{
 			$query = 'SELECT i.inumber as itemid, i.ititle as title, i.ibody as body, m.mname as author, m.mrealname as authorname, i.itime, i.imore as more, m.mnumber as authorid, m.memail as authormail, m.murl as authorurl, c.cname as category, i.icat as catid, i.iclosed as closed';
-			if ($select) 
+			if ($select)
 				$query .= ', '.$select. ' as score ';
 		} else {
 			$query = 'SELECT COUNT(*) as result ';
 		}
-			
+
 		$query .= ' FROM '.sql_table('item').' as i, '.sql_table('member').' as m, '.sql_table('category').' as c'
 			   . ' WHERE i.iauthor=m.mnumber'
 			   . ' and i.icat=c.catid'
@@ -469,7 +491,7 @@
 			   . ' and '.$where;
 
 		// take into account amount of months to search
-		if ($amountMonths > 0) 
+		if ($amountMonths > 0)
 		{
 			$localtime = getdate($this->getCorrectTime());
 			$timestamp_start = mktime(0,0,0,$localtime['mon'] - $amountMonths,1,$localtime['year']);
@@ -478,22 +500,22 @@
 
 		if ($mode == '')
 		{
-			if ($select) 
+			if ($select)
 				$query .= ' ORDER BY score DESC';
-			else 
+			else
 				$query .= ' ORDER BY i.itime DESC ';
 		}
 
-		return $query;		
+		return $query;
 	}
-	
+
 	/**
 	 * Returns the SQL query that's normally used to display the blog items on the index type skins
 	 *
 	 * @param $mode
 	 *		either empty, or 'count'. In this case, the query will be a SELECT COUNT(*) query
-	 * @returns 
-	 *		either a full SQL query, or an empty string 
+	 * @returns
+	 *		either a full SQL query, or an empty string
 	 * @note
 	 *		No LIMIT clause is added. (caller should add this if multiple pages are requested)
 	 */
@@ -503,24 +525,24 @@
 			$query = 'SELECT i.inumber as itemid, i.ititle as title, i.ibody as body, m.mname as author, m.mrealname as authorname, i.itime, i.imore as more, m.mnumber as authorid, m.memail as authormail, m.murl as authorurl, c.cname as category, i.icat as catid, i.iclosed as closed';
 		else
 			$query = 'SELECT COUNT(*) as result ';
-		
+
 		$query .= ' FROM '.sql_table('item').' as i, '.sql_table('member').' as m, '.sql_table('category').' as c'
-		       . ' WHERE i.iblog='.$this->blogid
-		       . ' and i.iauthor=m.mnumber'
-		       . ' and i.icat=c.catid'
-		       . ' and i.idraft=0'	// exclude drafts
+			   . ' WHERE i.iblog='.$this->blogid
+			   . ' and i.iauthor=m.mnumber'
+			   . ' and i.icat=c.catid'
+			   . ' and i.idraft=0'	// exclude drafts
 					// don't show future items
-		       . ' and i.itime<=' . mysqldate($this->getCorrectTime());
+			   . ' and i.itime<=' . mysqldate($this->getCorrectTime());
 
 		if ($this->getSelectedCategory())
 			$query .= ' and i.icat=' . $this->getSelectedCategory() . ' ';
 
 
 		$query .= $extraQuery;
-		
+
 		if ($mode == '')
 			$query .= ' ORDER BY i.itime DESC';
-		       
+
 		return $query;
 	}
 
@@ -530,9 +552,9 @@
 	function showArchiveList($template, $mode = 'month', $limit = 0) {
 		global $CONF, $catid, $manager;
 
-		if ($catid) 
+		if ($catid)
 			$linkparams = array('catid' => $catid);
-		
+
 		$template =& $manager->getTemplate($template);
 		$data['blogid'] = $this->getID();
 
@@ -542,30 +564,30 @@
 		. ' WHERE iblog=' . $this->getID()
 		. ' and itime <=' . mysqldate($this->getCorrectTime())	// don't show future items!
 		. ' and idraft=0'; // don't show draft items
-		
+
 		if ($catid)
 			$query .= ' and icat=' . intval($catid);
-		
+
 		$query .= ' GROUP BY Year, Month';
 		if ($mode == 'day')
 			$query .= ', Day';
-		
-			
-		$query .= ' ORDER BY itime DESC';				
-		
-		if ($limit > 0) 
+
+
+		$query .= ' ORDER BY itime DESC';
+
+		if ($limit > 0)
 			$query .= ' LIMIT ' . intval($limit);
-		
+
 		$res = sql_query($query);
 
 		while ($current = mysql_fetch_object($res)) {
 			$current->itime = strtotime($current->itime);	// string time -> unix timestamp
-		
+
 			if ($mode == 'day') {
 				$archivedate = date('Y-m-d',$current->itime);
 				$archive['day'] = date('d',$current->itime);
 			} else {
-				$archivedate = date('Y-m',$current->itime);			
+				$archivedate = date('Y-m',$current->itime);
 			}
 			$data['month'] = date('m',$current->itime);
 			$data['year'] = date('Y',$current->itime);
@@ -575,23 +597,23 @@
 			echo strftime($temp,$current->itime);
 
 		}
-		
+
 		mysql_free_result($res);
 
 		echo TEMPLATE::fill($template['ARCHIVELIST_FOOTER'],$data);
 	}
-	
+
 
 	/**
 	  * Shows the list of categories using a given template
 	  */
 	function showCategoryList($template) {
 		global $CONF, $manager;
-		
+
 		// determine arguments next to catids
 		// I guess this can be done in a better way, but it works
 		global $archive, $archivelist;
-		
+
 		$linkparams = array();
 		if ($archive) {
 			$blogurl = createArchiveLink($this->getID(), $archive, '');
@@ -603,14 +625,14 @@
 		} else {
 			$blogurl = createBlogidLink($this->getID(), '');
 			$linkparams['blogid'] = $this->getID();
-		} 
-			
+		}
+
 		//$blogurl = $this->getURL() . $qargs;
-		$blogurl = createBlogLink($this->getURL(), $linkparams);
+		//$blogurl = createBlogLink($this->getURL(), $linkparams);
 
 		$template =& $manager->getTemplate($template);
 
-		echo TEMPLATE::fill($template['CATLIST_HEADER'],
+		echo TEMPLATE::fill((isset($template['CATLIST_HEADER']) ? $template['CATLIST_HEADER'] : null),
 							array(
 								'blogid' => $this->getID(),
 								'blogurl' => $blogurl,
@@ -622,7 +644,7 @@
 
 
 		while ($data = mysql_fetch_assoc($res)) {
-			$data['blogid'] = $this->getID();	
+			$data['blogid'] = $this->getID();
 			$data['blogurl'] = $blogurl;
 			$data['catlink'] = createLink(
 								'category',
@@ -634,70 +656,119 @@
 							   );
 			$data['self'] = $CONF['Self'];
 
-			$temp = TEMPLATE::fill($template['CATLIST_LISTITEM'],$data);
-			echo strftime($temp,$current->itime);
+			echo TEMPLATE::fill((isset($template['CATLIST_LISTITEM']) ? $template['CATLIST_LISTITEM'] : null), $data);
+			//$temp = TEMPLATE::fill((isset($template['CATLIST_LISTITEM']) ? $template['CATLIST_LISTITEM'] : null), $data);
+			//echo strftime($temp, $current->itime);
 
 		}
-		
+
 		mysql_free_result($res);
 
-		echo TEMPLATE::fill($template['CATLIST_FOOTER'],
+		echo TEMPLATE::fill((isset($template['CATLIST_FOOTER']) ? $template['CATLIST_FOOTER'] : null),
 							array(
 								'blogid' => $this->getID(),
 								'blogurl' => $blogurl,
-								'self' => $CONF['Self']								
+								'self' => $CONF['Self']
+							));
+	}
+	
+	/**
+	  * Shows a list of all blogs in the system using a given template
+	  */
+	function showBlogList($template, $bnametype) {
+		global $CONF, $manager;
+		
+		$template =& $manager->getTemplate($template);
+		
+		echo TEMPLATE::fill((isset($template['BLOGLIST_HEADER']) ? $template['BLOGLIST_HEADER'] : null),
+							array(
+								'sitename' => $CONF['SiteName'],
+								'siteurl' => $CONF['IndexURL']
+							));
+		
+		$query = 'SELECT bnumber, bname, bshortname, bdesc, burl FROM '.sql_table('blog').' ORDER BY bnumber ASC';
+		$res = sql_query($query);
+		
+		while ($data = mysql_fetch_assoc($res)) {
+		
+			$list = array();
+		
+//			$list['bloglink'] = createLink('blog', array('blogid' => $data['bnumber']));
+			$list['bloglink'] = createBlogidLink($data['bnumber']);
+		
+			$list['blogdesc'] = $data['bdesc'];
+			
+			if ($bnametype=='shortname') {
+				$list['blogname'] = $data['bshortname'];
+			}
+			else { // all other cases
+				$list['blogname'] = $data['bname'];
+			}
+			
+			echo TEMPLATE::fill((isset($template['BLOGLIST_LISTITEM']) ? $template['BLOGLIST_LISTITEM'] : null), $list);
+			
+		}
+		
+		mysql_free_result($res);
+		
+		echo TEMPLATE::fill((isset($template['BLOGLIST_FOOTER']) ? $template['BLOGLIST_FOOTER'] : null),
+							array(
+								'sitename' => $CONF['SiteName'],
+								'siteurl' => $CONF['IndexURL']
 							));
+
 	}
 
 	/**
 	  * Blogsettings functions
 	  */
-	  
+
 	function readSettings() {
 		$query =  'SELECT *'
-		       . ' FROM '.sql_table('blog')
-		       . ' WHERE bnumber=' . $this->blogid;
+			   . ' FROM '.sql_table('blog')
+			   . ' WHERE bnumber=' . $this->blogid;
 		$res = sql_query($query);
-		
+
 		$this->isValid = (mysql_num_rows($res) > 0);
 		if (!$this->isValid)
 			return;
-		
+
 		$this->settings = mysql_fetch_assoc($res);
 	}
-	
+
 	function writeSettings() {
-	
+
 		// (can't use floatval since not available prior to PHP 4.2)
 		$offset = $this->getTimeOffset();
 		if (!is_float($offset))
 			$offset = intval($offset);
-		
+
 		$query =  'UPDATE '.sql_table('blog')
-		       . " SET bname='" . addslashes($this->getName()) . "',"
-		       . "     bshortname='". addslashes($this->getShortName()) . "',"
-		       . "     bcomments=". intval($this->commentsEnabled()) . ","
-		       . "     bmaxcomments=" . intval($this->getMaxComments()) . ","
-		       . "     btimeoffset=" . $offset . ","
-		       . "     bpublic=" . intval($this->isPublic()) . ","
-		       . "     bsendping=" . intval($this->pingUserland()) . ","
-		       . "     bconvertbreaks=" . intval($this->convertBreaks()) . ","
-		       . "     ballowpast=" . intval($this->allowPastPosting()) . ","			   
-		       . "     bnotify='" . addslashes($this->getNotifyAddress()) . "',"
-		       . "     bnotifytype=" . intval($this->getNotifyType()) . ","		       
-		       . "     burl='" . addslashes($this->getURL()) . "',"
-		       . "     bupdate='" . addslashes($this->getUpdateFile()) . "',"
-		       . "     bdesc='" . addslashes($this->getDescription()) . "',"
-		       . "     bdefcat=" . intval($this->getDefaultCategory()) . ","		       
-		       . "     bdefskin=" . intval($this->getDefaultSkin()) . ","
-		       . "     bincludesearch=" . intval($this->getSearchable())
-		       . " WHERE bnumber=" . intval($this->getID());
+			   . " SET bname='" . addslashes($this->getName()) . "',"
+			   . "     bshortname='". addslashes($this->getShortName()) . "',"
+			   . "     bcomments=". intval($this->commentsEnabled()) . ","
+			   . "     bmaxcomments=" . intval($this->getMaxComments()) . ","
+			   . "     btimeoffset=" . $offset . ","
+			   . "     bpublic=" . intval($this->isPublic()) . ","
+			   . "     breqemail=" . intval($this->emailRequired()) . ","
+			   . "     bsendping=" . intval($this->sendPing()) . ","
+			   . "     bconvertbreaks=" . intval($this->convertBreaks()) . ","
+			   . "     ballowpast=" . intval($this->allowPastPosting()) . ","
+			   . "     bnotify='" . addslashes($this->getNotifyAddress()) . "',"
+			   . "     bnotifytype=" . intval($this->getNotifyType()) . ","
+			   . "     burl='" . addslashes($this->getURL()) . "',"
+			   . "     bupdate='" . addslashes($this->getUpdateFile()) . "',"
+			   . "     bdesc='" . addslashes($this->getDescription()) . "',"
+			   . "     bdefcat=" . intval($this->getDefaultCategory()) . ","
+			   . "     bdefskin=" . intval($this->getDefaultSkin()) . ","
+			   . "     bincludesearch=" . intval($this->getSearchable())
+			   . " WHERE bnumber=" . intval($this->getID());
 		sql_query($query);
 
 	}
-	
 
-		
+
+
 	// update update file if requested
 	function updateUpdatefile() {
 		 if ($this->getUpdateFile()) {
@@ -707,140 +778,95 @@
 		 }
 
 	}
-	
-	/**
-	  * Sends a XML-RPC ping message to Userland, so the weblog can
-	  * show up in the weblogs.com updates-list
-	  */
-	function sendUserlandPing() {
-		global $php_errormsg;
-		
-		 if ($this->pingUserland()) {
-			  // testmessage for adding an item
-			  $message = new xmlrpcmsg('weblogUpdates.ping',array(
-					new xmlrpcval($this->getName(),'string'),	
-					new xmlrpcval($this->getURL(),'string')
-			  ));
-			  
-			  $c = new xmlrpc_client('/RPC2', 'rpc.weblogs.com', 80);
-
-			  // $c->setDebug(1);
-
-			  $r = $c->send($message,15); // 15 seconds timeout...
-			  
-			  if (($r == 0) && ($r->errno || $r->errstring)) {
-			  	return 'Error ' . $r->errno . ' : ' . $r->errstring;
-			  } elseif (($r == 0) && ($php_errormsg)) {
-			  	return 'PHP Error: ' . $php_errormsg;
-			  } elseif ($r == 0) {
-			  	return 'Error while trying to send ping. Sorry about that.';
-			  } elseif ($r->faultCode() != 0) {
-			  	return 'Error: ' . $r->faultString();
-			  } else {
-				  $r = $r->value();	// get response struct
-				  // get values
-				  $flerror = $r->structmem('flerror');
-				  $flerror = $flerror->scalarval();
- 
-				  
-				  $message = $r->structmem('message');
-				  $message = $message->scalarval();
-
-				  if ($flerror != 0)
-				  	return 'Error (flerror=1): ' . $message;
-				  else
-				 	return 'Success: ' . $message;
-			  }			  
-		 }
-	}
-	
+
 	function isValidCategory($catid) {
 		$query = 'SELECT * FROM '.sql_table('category').' WHERE cblog=' . $this->getID() . ' and catid=' . intval($catid);
-		return (mysql_num_rows(mysql_query($query)) != 0);
+		$res = sql_query($query);
+		return (mysql_num_rows($res) != 0);
 	}
-	
+
 	function getCategoryName($catid) {
-		$res = mysql_query('SELECT cname FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and catid=' . intval($catid));
+		$res = sql_query('SELECT cname FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and catid=' . intval($catid));
 		$o = mysql_fetch_object($res);
 		return $o->cname;
 	}
-	
+
 	function getCategoryDesc($catid) {
-		$res = mysql_query('SELECT cdesc FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and catid=' . intval($catid));
+		$res = sql_query('SELECT cdesc FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and catid=' . intval($catid));
 		$o = mysql_fetch_object($res);
 		return $o->cdesc;
 	}
 
 	function getCategoryIdFromName($name) {
-		$res = mysql_query('SELECT catid FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and cname="' . addslashes($name) . '"');
+		$res = sql_query('SELECT catid FROM '.sql_table('category').' WHERE cblog='.$this->getID().' and cname="' . addslashes($name) . '"');
 		if (mysql_num_rows($res) > 0) {
 			$o = mysql_fetch_object($res);
-			return $o->catid;	
+			return $o->catid;
 		} else {
 			return $this->getDefaultCategory();
 		}
 	}
-	
-	function pingUserland() {
+
+	function sendPing() {
 		return $this->getSetting('bsendping');
 	}
-	
+
 	function setPingUserland($val) {
 		$this->setSetting('bsendping',$val);
 	}
-	
+
 	function convertBreaks() {
 		return $this->getSetting('bconvertbreaks');
 	}
-	
+
 	function insertJavaScriptInfo($authorid = '') {
 		global $member, $CONF;
-		
-		if ($authorid == '')	
+
+		if ($authorid == '')
 			$authorid = $member->getID();
-			
+
 		?>
 		<script type="text/javascript">
 			setConvertBreaks(<?php echo  $this->convertBreaks() ? 'true' : 'false' ?>);
 			setMediaUrl("<?php echo $CONF['MediaURL']?>");
 			setAuthorId(<?php echo $authorid?>);
 		</script><?php	}
-	
+
 	function setConvertBreaks($val) {
 		$this->setSetting('bconvertbreaks',$val);
 	}
 	function setAllowPastPosting($val) {
 		$this->setSetting('ballowpast',$val);
-	}		
+	}
 	function allowPastPosting() {
 		return $this->getSetting('ballowpast');
 	}
-	
+
 	function getCorrectTime($t=0) {
 		if ($t == 0) $t = time();
 		return ($t + 3600 * $this->getTimeOffset());
 	}
-	
+
 	function getName() {
 		return $this->getSetting('bname');
 	}
-	
+
 	function getShortName() {
 		return $this->getSetting('bshortname');
 	}
-	
+
 	function getMaxComments() {
 		return $this->getSetting('bmaxcomments');
 	}
-	
+
 	function getNotifyAddress() {
 		return $this->getSetting('bnotify');
 	}
-	
+
 	function getNotifyType() {
 		return $this->getSetting('bnotifytype');
 	}
-	
+
 	function notifyOnComment() {
 		$n = $this->getNotifyType();
 		return (($n != 0) && (($n % 3) == 0));
@@ -855,40 +881,44 @@
 		$n = $this->getNotifyType();
 		return (($n != 0) && (($n % 7) == 0));
 	}
-	
+
 	function setNotifyType($val) {
-		$this->setSetting('bnotifytype',$val);	
+		$this->setSetting('bnotifytype',$val);
 	}
-	
+
 
 	function getTimeOffset() {
 		return $this->getSetting('btimeoffset');
 	}
-	
+
 	function commentsEnabled() {
 		return $this->getSetting('bcomments');
 	}
-	
+
 	function getURL() {
 		return $this->getSetting('burl');
 	}
-	
+
 	function getDefaultSkin() {
 		return $this->getSetting('bdefskin');
 	}
-	
+
 	function getUpdateFile() {
 		return $this->getSetting('bupdate');
 	}
-	
+
 	function getDescription() {
 		return $this->getSetting('bdesc');
 	}
-	
+
 	function isPublic() {
 		return $this->getSetting('bpublic');
 	}
-	
+
+	function emailRequired() {
+		return $this->getSetting('breqemail');
+	}
+
 	function getSearchable() {
 		return $this->getSetting('bincludesearch');
 	}
@@ -896,7 +926,7 @@
 	function getDefaultCategory() {
 		return $this->getSetting('bdefcat');
 	}
-	
+
 	function setPublic($val) {
 		$this->setSetting('bpublic',$val);
 	}
@@ -912,35 +942,39 @@
 	function setUpdateFile($val) {
 		$this->setSetting('bupdate',$val);
 	}
-	
+
 	function setDefaultSkin($val) {
 		$this->setSetting('bdefskin',$val);
 	}
-	
+
 	function setURL($val) {
 		$this->setSetting('burl',$val);
 	}
-	
+
 	function setName($val) {
 		$this->setSetting('bname',$val);
 	}
-	
+
 	function setShortName($val) {
 		$this->setSetting('bshortname',$val);
 	}
-	
-	function setCommentsEnabled($val) { 
+
+	function setCommentsEnabled($val) {
 		$this->setSetting('bcomments',$val);
 	}
-	
+
 	function setMaxComments($val) {
 		$this->setSetting('bmaxcomments',$val);
 	}
-	
+
 	function setNotifyAddress($val) {
 		$this->setSetting('bnotify',$val);
 	}
-	
+
+	function setEmailRequired($val) {
+		$this->setSetting('breqemail',$val);
+	}
+
 	function setTimeOffset($val) {
 		// check validity of value
 		// 1. replace , by . (common mistake)
@@ -951,10 +985,10 @@
 		} else {
 			$val = intval($val);
 		}
-	
+
 		$this->setSetting('btimeoffset',$val);
 	}
-	
+
 	function setDefaultCategory($val) {
 		$this->setSetting('bdefcat',$val);
 	}
@@ -962,26 +996,26 @@
 	function getSetting($key) {
 		return $this->settings[$key];
 	}
-	
+
 	function setSetting($key,$value) {
 		$this->settings[$key] = $value;
 	}
-	
-	
+
+
 	// tries to add a member to the team. Returns false if the member was already on
 	// the team
 	function addTeamMember($memberid, $admin) {
 		global $manager;
-		
+
 		$memberid = intval($memberid);
 		$admin = intval($admin);
-		
+
 		// check if member is already a member
 		$tmem = MEMBER::createFromID($memberid);
-		
+
 		if ($tmem->isTeamMember($this->getID()))
 			return 0;
-		
+
 		$manager->notify(
 			'PreAddTeamMember',
 			array(
@@ -990,12 +1024,12 @@
 				'admin' => &$admin
 			)
 		);
-		
+
 		// add to team
 		$query = 'INSERT INTO '.sql_table('team').' (TMEMBER, TBLOG, TADMIN) '
-		       . 'VALUES (' . $memberid .', '.$this->getID().', "'.$admin.'")';
+			   . 'VALUES (' . $memberid .', '.$this->getID().', "'.$admin.'")';
 		sql_query($query);
-		
+
 		$manager->notify(
 			'PostAddTeamMember',
 			array(
@@ -1003,19 +1037,19 @@
 				'member' => &$tmem,
 				'admin' => $admin
 			)
-			
+
 		);
-		
+
 		ACTIONLOG::add(INFO, 'Added ' . $tmem->getDisplayName() . ' (ID=' .
-		               $memberid .') to the team of blog "' . $this->getName() . '"');
-		
+					   $memberid .') to the team of blog "' . $this->getName() . '"');
+
 		return 1;
 	}
-	
+
 	function getID() {
-		return $this->blogid;
+		return intVal($this->blogid);
 	}
-	
+
 	// returns true if there is a blog with the given shortname (static)
 	function exists($name) {
 		$r = sql_query('select * FROM '.sql_table('blog').' WHERE bshortname="'.addslashes($name).'"');
@@ -1026,469 +1060,54 @@
 	function existsID($id) {
 		$r = sql_query('select * FROM '.sql_table('blog').' WHERE bnumber='.intval($id));
 		return (mysql_num_rows($r) != 0);
-	}	
-	
-	
-}
-
-/**
-  * This class is used when parsing item templates
-  */
-class ITEMACTIONS extends BaseActions {
-
-	// contains an assoc array with parameters that need to be included when
-	// generating links to items/archives/... (e.g. catid)
-	var $linkparams;
-	
-	// true when the current user is a blog admin (and thus allowed to edit all items)
-	var $allowEditAll;
-	
-	// timestamp of last visit
-	var $lastVisit;
-	
-	// item currently being handled (mysql result object, see BLOG::showUsingQuery)
-	var $currentItem;
-	
-	// reference to the blog currently being displayed
-	var $blog;
-	
-	// associative array with template info (part name => contents)
-	var $template;
-	
-	// true when comments need to be displayed
-	var $showComments;
-	
-	function ITEMACTIONS(&$blog) {
-		// call constructor of superclass first
-		$this->BaseActions();	
-		
-		// extra parameters for created links
-		global $catid;
-		if ($catid)
-			$this->linkparams = array('catid' => $catid);
-			
-		// check if member is blog admin (and thus allowed to edit all items)
-		global $member;
-		$this->allowEditAll = ($member->isLoggedIn() && $member->blogAdminRights($blog->getID()));
-		$this->setBlog($blog);
-	}
-
-	function getDefinedActions() {
-		return array(
-			'blogid',
-			'title',
-			'body',
-			'more',
-			'smartbody',
-			'itemid',
-			'morelink',
-			'category',
-			'categorylink',
-			'author',
-			'authorid',
-			'authorlink',
-			'catid',
-			'karma',
-			'date',
-			'time',
-			'query',
-			'itemlink',
-			'blogurl',
-			'closed',
-			'syndicate_title',
-			'syndicate_description',
-			'karmaposlink',
-			'karmaneglink',
-			'new',
-			'image',
-			'popup',
-			'media',
-			'daylink',
-			'query',
-			'include',
-			'phpinclude',
-			'parsedinclude',
-			'skinfile',
-			'set',
-			'plugin',
-			'edit',
-			'editlink',
-			'editpopupcode',
-			'comments',
-			'relevance'
-		);
-	}
-	
-
-	
-	function setLastVisit($lastVisit) {		$this->lastVisit = $lastVisit; }
-	function setParser(&$parser) {			$this->parser =& $parser; }
-	function setCurrentItem(&$item) {		$this->currentItem =& $item; }
-	function setBlog(&$blog) {				$this->blog =& $blog; }
-	function setTemplate($template) {		$this->template =& $template; }
-	function setShowComments($val) {		$this->showComments = $val; }
-	
-	// methods used by parser to insert content
-	
-	function parse_blogid() {		echo $this->blog->getID();	}
-	function parse_body() {			$this->highlightAndParse($this->currentItem->body); }
-	function parse_more() {			$this->highlightAndParse($this->currentItem->more); }	
-	function parse_itemid() {		echo $this->currentItem->itemid; }		
-	function parse_category() {		echo $this->currentItem->category; }				
-	function parse_categorylink() {	echo createLink('category', array('catid' => $this->currentItem->catid, 'name' => $this->currentItem->category)); }
-	function parse_catid() {		echo $this->currentItem->catid; }					
-	function parse_authorid() {		echo $this->currentItem->authorid; }
-	function parse_authorlink() {
-		echo createLink(
-			'member',
-			array(
-				'memberid' => $this->currentItem->authorid,
-				'name' => $this->currentItem->author,
-				'extra' => $this->linkparams
-			)
-		);
-	}
-	function parse_query() {		echo $this->strHighlight; }
-	function parse_itemlink() {		
-		echo createLink(
-			'item', 
-			array(
-				'itemid' => $this->currentItem->itemid,
-				'title' => $this->currentItem->title,
-				'timestamp' => $this->currentItem->timestamp,
-				'extra' => $this->linkparams
-			)
-		);
 	}
-	function parse_blogurl() {		echo $this->blog->getURL(); }
-	function parse_closed() {		echo $this->currentItem->closed; }
-	function parse_relevance() {    echo round($this->currentItem->score,2);}
-	
-	function parse_title($format = '') {
-		switch ($format) {
-			case 'xml':
-				echo stringToXML ($this->currentItem->title);
-				break;
-			case 'attribute':
-				echo stringToAttribute ($this->currentItem->title);
-				break;
-			case 'raw':
-				echo $this->currentItem->title;
-				break;
-			default:
-				$this->highlightAndParse($this->currentItem->title); 
-				break;
-		}
-	}
-
-	function parse_karma($type = 'totalscore') {
-		global $manager;
-
-		// get karma object
-		$karma =& $manager->getKarma($this->currentItem->itemid);
-		
-		switch($type) {
-			case 'pos':
-				echo $karma->getNbPosVotes();
-				break;
-			case 'neg':
-				echo $karma->getNbNegVotes();
-				break;				
-			case 'votes':
-				echo $karma->getNbOfVotes();
-				break;		
-			case 'posp':
-				$percentage = $karma->getNbOfVotes() ? 100 * ($karma->getNbPosVotes() / $karma->getNbOfVotes()) : 50;
-				echo number_format($percentage,2), '%';				
-				break;				
-			case 'negp':
-				$percentage = $karma->getNbOfVotes() ? 100 * ($karma->getNbNegVotes() / $karma->getNbOfVotes()) : 50;
-				echo number_format($percentage,2), '%';				
-				break;				
-			case 'totalscore':
-			default:
-				echo $karma->getTotalScore();
-				break;
-		}
-		
-	}						
 
-	function parse_author($which = '') {		
-		switch($which)
-		{
-			case 'realname':
-				echo $this->currentItem->authorname;
-				break;
-			case 'id':
-				echo $this->currentItem->authorid;
-				break;
-			case 'email':
-				echo $this->currentItem->authormail;
-				break;
-			case 'url':
-				echo $this->currentItem->authorurl;
-				break;
-			case 'name':
-			default:
-				echo $this->currentItem->author;
-		}
-	}		
-	
-	function parse_smartbody() {
-		if (!$this->currentItem->more) {
-			$this->highlightAndParse($this->currentItem->body);
-		} else {
-			$this->highlightAndParse($this->currentItem->more);		
-		}
-	}
+        // flag there is a future post pending
+        function setFuturePost() {
+		$query =  'UPDATE '.sql_table('blog')
+			   . " SET bfuturepost='1' WHERE bnumber=" . $this->getID();
+		sql_query($query);
+        }
 
-	function parse_morelink() {		
-		if ($this->currentItem->more)
-			$this->parser->parse($this->template['MORELINK']);
-	}			
-	
-	function parse_date($format = '') {
-		echo formatDate($format, $this->currentItem->timestamp, $this->template['FORMAT_DATE'], $this->blog);
-	}
-	
-	/**
-	  * @param format optional strftime format
-	  */
-	function parse_time($format = '') {			
-		echo strftime($format ? $format : $this->template['FORMAT_TIME'],$this->currentItem->timestamp); 
-	}
-	
-	/**
-	  * @param maxLength optional maximum length
-	  */
-	function parse_syndicate_title($maxLength = 100) { 
-		$syndicated = strip_tags($this->currentItem->title);
-		echo htmlspecialchars(shorten($syndicated,$maxLength,'...'));
-	}
-	
-	/**
-	  * @param maxLength optional maximum length
-	  */
-	function parse_syndicate_description($maxLength = 250, $addHighlight = 0) { 
-		$syndicated = strip_tags($this->currentItem->body);
-		if ($addHighlight) {
-			$tmp_highlight = htmlspecialchars(shorten($syndicated,$maxLength,'...'));
-			echo $this->highlightAndParse($tmp_highlight);
-		} else {
-    		echo htmlspecialchars(shorten($syndicated,$maxLength,'...'));
-		}
-	}
-	
-	function parse_karmaposlink($text = '') { 
-		global $CONF;
-		$link = $CONF['ActionURL'] . '?action=votepositive&amp;itemid='.$this->currentItem->itemid; 
-		echo $text ? '<a href="'.$link.'">'.$text.'</a>' : $link;
-	}
-	
-	function parse_karmaneglink($text = '') { 
-		global $CONF;
-		$link = $CONF['ActionURL'] . '?action=votenegative&amp;itemid='.$this->currentItem->itemid; 
-		echo $text ? '<a href="'.$link.'">'.$text.'</a>' : $link;
-	}
-	
-	function parse_new() { 	
-		if (($this->lastVisit != 0) && ($this->currentItem->timestamp > $this->lastVisit))
-			echo $this->template['NEW'];
-	}
-	
-	function parse_image() {
-		// image/popup calls have arguments separated by |
-		$args = func_get_args();
-		$args = explode('|',implode($args,', '));
-		call_user_func_array(array(&$this,'createImageCode'),$args);
-	}
-	function parse_popup() {
-		// image/popup calls have arguments separated by |
-		$args = func_get_args();
-		$args = explode('|',implode($args,', '));
-		call_user_func_array(array(&$this,'createPopupCode'),$args);
-	}
-	function parse_media() {
-		// image/popup calls have arguments separated by |
-		$args = func_get_args();
-		$args = explode('|',implode($args,', '));
-		call_user_func_array(array(&$this,'createMediaCode'),$args);
-	}
-	
-	function parse_daylink() {		
-		echo createArchiveLink($this->blog->getID(), strftime('%Y-%m-%d',$this->currentItem->timestamp), $this->linkparams);
-	}
-	
-	function parse_comments($maxToShow = 0) {
-		if ($maxToShow == 0)
-			$maxToShow = $this->blog->getMaxComments();
-			
-		// add comments
-		if ($this->showComments && $this->blog->commentsEnabled()) {
-			$comments =& new COMMENTS($this->currentItem->itemid);
-			$comments->setItemActions($this);
-			$comments->showComments($this->template, $maxToShow, $this->currentItem->closed ? 0 : 1, $this->strHighlight); 
-		}
+	// clear there is a future post pending
+	function clearFuturePost() {
+		$query =  'UPDATE '.sql_table('blog')
+			   . " SET bfuturepost='0' WHERE bnumber=" . $this->getID();
+		sql_query($query);
 	}
 
-	/**
-	  * Executes a plugin templatevar
-	  *
-	  * @param pluginName name of plugin (without the NP_)
-	  * 
-	  * extra parameters can be added
-	  */
-	function parse_plugin($pluginName) {
+	// check if we should throw justPosted event
+	function checkJustPosted() {
 		global $manager;
-		
-		// only continue when the plugin is really installed
-		if (!$manager->pluginInstalled('NP_' . $pluginName))
-			return;
-		
-		$plugin =& $manager->getPlugin('NP_' . $pluginName);
-		if (!$plugin) return;
-
-		// get arguments
-		$params = func_get_args();
-		
-		// remove plugin name 
-		array_shift($params);
-		
-		// add item reference (array_unshift didn't work)
-		$params = array_merge(array(&$this->currentItem),$params);
-
-		call_user_func_array(array(&$plugin,'doTemplateVar'), $params);
-	}
-	
-	function parse_edit() {
-		global $member, $CONF;
-		if ($this->allowEditAll || ($member->isLoggedIn() && ($member->getID() == $this->currentItem->authorid)) ) {
-			$this->parser->parse($this->template['EDITLINK']);
-		}
-	}
-	
-	function parse_editlink() {
-		global $CONF;
-		echo $CONF['AdminURL'],'bookmarklet.php?action=edit&amp;itemid=',$this->currentItem->itemid;
-	}
-	
-	function parse_editpopupcode() {
-		echo "if (event &amp;&amp; event.preventDefault) event.preventDefault();winbm=window.open(this.href,'nucleusbm','scrollbars=yes,width=600,height=500,left=10,top=10,status=yes,resizable=yes');winbm.focus();return false;";
-	}
-	
-	// helper functions
 
-	/**
-	  * Parses highlighted text, with limited actions only (to prevent not fully trusted team members
-	  * from hacking your weblog. 
-	  */
-	function highlightAndParse(&$data) {
-		// allow only a limited subset of actions (do not allow includes etc, they might be evil)
-		$this->parser->actions = array('image','media','popup');
-		$tmp_highlight = $this->highlight($data);
-		$this->parser->parse($tmp_highlight);
-		$this->parser->actions = $this->getDefinedActions();
-	}
-	
-	function createPopupCode($filename, $width, $height, $text = '') {
-		global $CONF;
-	
-		// select private collection when no collection given
-		if (!strstr($filename,'/')) {
-			$filename = $this->currentItem->authorid . '/' . $filename;
-		}
-		
-		$windowwidth = $width;
-		$windowheight = $height;
-		
-		$vars['rawpopuplink'] 	= $CONF['Self'] . "?imagepopup=" . htmlspecialchars($filename) . "&amp;width=$width&amp;height=$height&amp;imagetext=" . urlencode(htmlspecialchars($text));
-		$vars['popupcode'] 		= "window.open(this.href,'imagepopup','status=no,toolbar=no,scrollbars=no,resizable=yes,width=$windowwidth,height=$windowheight');return false;";
-		$vars['popuptext'] 		= htmlspecialchars($text);
-		$vars['popuplink'] 		= '<a href="' . $vars['rawpopuplink']. '" onclick="'. $vars['popupcode'].'" >' . $vars['popuptext'] . '</a>';
-		$vars['width'] 			= $width;
-		$vars['height']			= $height;
-		$vars['text']			= $text;
-		$vars['link']			= htmlspecialchars($CONF['MediaURL'] . $filename);
-		$vars['media'] 			= '<a href="' . $vars['link'] . '">' . $vars['popuptext'] . '</a>';		
-		
-		echo TEMPLATE::fill($this->template['POPUP_CODE'],$vars);
-	}
-	
-	function createImageCode($filename, $width, $height, $text = '') {
-		global $CONF;
-		
-		// select private collection when no collection given
-		if (!strstr($filename,'/')) {
-			$filename = $this->currentItem->authorid . '/' . $filename;
+		if ($this->settings['bfuturepost'] == 1) {
+			$blogid = $this->getID();
+			$result = sql_query("SELECT * FROM " . sql_table('item')
+			          . " WHERE iposted=0 AND iblog=" . $blogid . " AND itime<NOW()");
+			if (mysql_num_rows($result) > 0) {
+				// This $pinged is allow a plugin to tell other hook to the event that a ping is sent already
+				// Note that the plugins's calling order is subject to thri order in the plugin list
+				$pinged = false;
+				$manager->notify(
+						'JustPosted',
+						array('blogid' => $blogid,
+						'pinged' => &$pinged
+						)
+				);
+
+				// clear all expired future posts
+				sql_query("UPDATE " . sql_table('item') . " SET iposted='1' WHERE iblog=" . $blogid . " AND itime<NOW()");
+
+				// check to see any pending future post, clear the flag is none 
+				$result = sql_query("SELECT * FROM " . sql_table('item') 
+				          . " WHERE iposted=0 AND iblog=" . $blogid);
+				if (mysql_num_rows($result) == 0) {
+					$this->clearFuturePost();
+				}
+			}
 		}
-		
-		$windowwidth = $width;
-		$windowheight = $height;
-		
-		$vars['link']			= htmlspecialchars($CONF['MediaURL']. $filename);
-		$vars['text']			= htmlspecialchars($text);
-		$vars['image'] = '<img src="' . $vars['link'] . '" width="' . $width . '" height="' . $height . '" alt="' . $vars['text'] . '" title="' . $vars['text'] . '" />';
-		$vars['width'] 			= $width;
-		$vars['height']			= $height;
-		$vars['media'] 			= '<a href="' . $vars['link'] . '">' . $vars['text'] . '</a>';
-		
-		
-		echo TEMPLATE::fill($this->template['IMAGE_CODE'],$vars);;
-
-	}
-	
-	function createMediaCode($filename, $text = '') {
-		global $CONF;
-		
-		// select private collection when no collection given
-		if (!strstr($filename,'/')) {
-			$filename = $this->currentItem->authorid . '/' . $filename;
-		}		
-
-		$vars['link']			= htmlspecialchars($CONF['MediaURL'] . $filename);
-		$vars['text']			= htmlspecialchars($text);
-		$vars['media'] 			= '<a href="' . $vars['link'] . '">' . $vars['text'] . '</a>';
-
-		echo TEMPLATE::fill($this->template['MEDIA_CODE'],$vars);;
 	}
-	
-	
-}
 
-
-// used for mail notification (html -> text)
-
-function toAscii($html) {
-	// strip off most tags 
-	$html = strip_tags($html,'<a>');
-	$to_replace = "/<a[^>]*href=[\"\']([^\"^']*)[\"\'][^>]*>([^<]*)<\/a>/i"; 
-	_links_init(); 
-	$ascii = preg_replace_callback ($to_replace, '_links_add', $html); 
-	$ascii .= "\n\n" . _links_list(); 
-	return strip_tags($ascii);
 }
 
-function _links_init() { 
-   global $tmp_links; 
-   $tmp_links = array(); 
-} 
-
-function _links_add($match) { 
-   global $tmp_links; 
-   array_push($tmp_links, $match[1]); 
-   return $match[2] . ' [' . sizeof($tmp_links) .']'; 
-} 
-
-function _links_list() { 
-   global $tmp_links; 
-   $output = ''; 
-   $i = 1; 
-   foreach ($tmp_links as $current) { 
-      $output .= "[$i] $current\n"; 
-      $i++; 
-   } 
-   return $output; 
-} 
-
- 
 ?>
diff -ruN 3.24.src/nucleus/libs/BODYACTIONS.php 3.31.src/nucleus/libs/BODYACTIONS.php
--- 3.24.src/nucleus/libs/BODYACTIONS.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/libs/BODYACTIONS.php	2007-10-22 19:36:00.000000000 -0500
@@ -0,0 +1,151 @@
+<?php
+
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+/**
+ * A class to parses plugin calls inside items
+ *
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: BODYACTIONS.php 1147 2007-05-11 08:26:02Z kimitake $
+ */
+
+class BODYACTIONS extends BaseActions {
+
+	var $currentItem;
+
+	var $template;
+
+	function BODYACTIONS () {
+		$this->BaseActions();	
+	}
+	
+	function setCurrentItem(&$item) {
+		$this->currentItem =& $item;
+	}
+	
+	function setTemplate($template) {
+		$this->template =& $template;
+	}
+
+	function getDefinedActions() {
+		return array('image', 'media', 'popup', 'plugin');
+	}
+
+	function parse_plugin($pluginName) {
+		global $manager;
+
+		// only continue when the plugin is really installed
+		if (!$manager->pluginInstalled('NP_' . $pluginName)) {
+			return;
+		}
+
+		$plugin =& $manager->getPlugin('NP_' . $pluginName);
+		if (!$plugin) return;
+
+		// get arguments
+		$params = func_get_args();
+
+		// remove plugin name
+		array_shift($params);
+
+		// add item reference (array_unshift didn't work)
+		$params = array_merge(array(&$this->currentItem),$params);
+
+		call_user_func_array(array(&$plugin,'doItemVar'), $params);
+	}
+	
+	function parse_image() {
+		// image/popup calls have arguments separated by |
+		$args = func_get_args();
+		$args = explode('|',implode($args,', '));
+		call_user_func_array(array(&$this,'createImageCode'),$args);
+	}
+	
+	function createImageCode($filename, $width, $height, $text = '') {
+		global $CONF;
+
+		// select private collection when no collection given
+		if (!strstr($filename,'/')) {
+			$filename = $this->currentItem->authorid . '/' . $filename;
+		}
+
+		$windowwidth = $width;
+		$windowheight = $height;
+
+		$vars['link']			= htmlspecialchars($CONF['MediaURL']. $filename ,ENT_QUOTES);
+		$vars['text']			= htmlspecialchars($text ,ENT_QUOTES);
+		$vars['image'] = '<img src="' . $vars['link'] . '" width="' . $width . '" height="' . $height . '" alt="' . $vars['text'] . '" title="' . $vars['text'] . '" />';
+		$vars['width'] 			= $width;
+		$vars['height']			= $height;
+		$vars['media'] 			= '<a href="' . $vars['link'] . '">' . $vars['text'] . '</a>';
+
+
+		echo TEMPLATE::fill($this->template['IMAGE_CODE'],$vars);;
+
+	}
+	
+	function parse_media() {
+		// image/popup calls have arguments separated by |
+		$args = func_get_args();
+		$args = explode('|',implode($args,', '));
+		call_user_func_array(array(&$this,'createMediaCode'),$args);
+	}
+
+	function createMediaCode($filename, $text = '') {
+		global $CONF;
+
+		// select private collection when no collection given
+		if (!strstr($filename,'/')) {
+			$filename = $this->currentItem->authorid . '/' . $filename;
+		}
+
+		$vars['link']			= htmlspecialchars($CONF['MediaURL'] . $filename ,ENT_QUOTES);
+		$vars['text']			= htmlspecialchars($text ,ENT_QUOTES);
+		$vars['media'] 			= '<a href="' . $vars['link'] . '">' . $vars['text'] . '</a>';
+
+		echo TEMPLATE::fill($this->template['MEDIA_CODE'],$vars);;
+	}
+
+
+	function parse_popup() {
+		// image/popup calls have arguments separated by |
+		$args = func_get_args();
+		$args = explode('|',implode($args,', '));
+		call_user_func_array(array(&$this,'createPopupCode'),$args);
+	}
+
+	function createPopupCode($filename, $width, $height, $text = '') {
+		global $CONF;
+
+		// select private collection when no collection given
+		if (!strstr($filename,'/')) {
+			$filename = $this->currentItem->authorid . '/' . $filename;
+		}
+
+		$windowwidth = $width;
+		$windowheight = $height;
+
+		$vars['rawpopuplink'] 	= $CONF['Self'] . "?imagepopup=" . htmlspecialchars($filename,ENT_QUOTES) . "&amp;width=$width&amp;height=$height&amp;imagetext=" . urlencode(htmlspecialchars($text));
+		$vars['popupcode'] 		= "window.open(this.href,'imagepopup','status=no,toolbar=no,scrollbars=no,resizable=yes,width=$windowwidth,height=$windowheight');return false;";
+		$vars['popuptext'] 		= htmlspecialchars($text,ENT_QUOTES);
+		$vars['popuplink'] 		= '<a href="' . $vars['rawpopuplink']. '" onclick="'. $vars['popupcode'].'" >' . $vars['popuptext'] . '</a>';
+		$vars['width'] 			= $width;
+		$vars['height']			= $height;
+		$vars['text']			= $text;
+		$vars['link']			= htmlspecialchars($CONF['MediaURL'] . $filename ,ENT_QUOTES);
+		$vars['media'] 			= '<a href="' . $vars['link'] . '">' . $vars['popuptext'] . '</a>';
+
+		echo TEMPLATE::fill($this->template['POPUP_CODE'],$vars);
+	}
+
+}
+?>
diff -ruN 3.24.src/nucleus/libs/COMMENTACTIONS.php 3.31.src/nucleus/libs/COMMENTACTIONS.php
--- 3.24.src/nucleus/libs/COMMENTACTIONS.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/libs/COMMENTACTIONS.php	2007-10-22 19:36:00.000000000 -0500
@@ -0,0 +1,317 @@
+<?php
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+/**
+ * This class is used when parsing comment templates
+ *
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: COMMENTACTIONS.php 1156 2007-05-20 23:47:36Z kaigreve $
+ */
+
+class COMMENTACTIONS extends BaseActions {
+
+	// ref to COMMENTS object which is using this object to handle
+	// its templatevars
+	var $commentsObj;
+
+	// template to use to parse the comments
+	var $template;
+
+	// comment currenlty being handled (mysql result assoc array; see COMMENTS::showComments())
+	var $currentComment;
+
+	function COMMENTACTIONS(&$comments) {
+		// call constructor of superclass first
+		$this->BaseActions();
+
+		// reference to the comments object
+		$this->setCommentsObj($comments);
+	}
+
+	function getDefinedActions() {
+		return array(
+			'blogurl',
+			'commentcount',
+			'commentword',
+			'email',
+			'itemlink',
+			'itemid',
+			'itemtitle',
+			'date',
+			'time',
+			'commentid',
+			'body',
+			'memberid',
+			'timestamp',
+			'host',
+			'ip',
+			'blogid',
+			'authtext',
+			'user',
+			'userid',
+			'userlinkraw',
+			'userlink',
+			'useremail',
+			'userwebsite',
+			'excerpt',
+			'short',
+			'skinfile',
+			'set',
+			'plugin',
+			'include',
+			'phpinclude',
+			'parsedinclude'
+		);
+	}
+
+	function setParser(&$parser) {
+		$this->parser =& $parser;
+	}
+	
+	function setCommentsObj(&$commentsObj) {
+		$this->commentsObj =& $commentsObj;
+	}
+	
+	function setTemplate($template) {
+		$this->template =& $template;
+	}
+	
+	function setCurrentComment(&$comment) {
+		global $manager;
+		if ($comment['memberid'] != 0) {
+			$comment['authtext'] = $template['COMMENTS_AUTH'];
+
+			$mem =& $manager->getMember($comment['memberid']);
+			$comment['user'] = $mem->getDisplayName();
+			if ($mem->getURL())
+				$comment['userid'] = $mem->getURL();
+			else
+				$comment['userid'] = $mem->getEmail();
+
+			$comment['userlinkraw'] = createLink(
+										'member',
+										array(
+											'memberid' => $comment['memberid'],
+											'name' => $mem->getDisplayName(),
+											'extra' => $this->commentsObj->itemActions->linkparams
+										)
+									  );
+
+		} else {
+
+			// create smart links
+/*			if (isValidMailAddress($comment['userid']))
+				$comment['userlinkraw'] = 'mailto:'.$comment['userid'];
+			elseif (strstr($comment['userid'],'http://') != false)
+				$comment['userlinkraw'] = $comment['userid'];
+			elseif (strstr($comment['userid'],'www') != false)
+				$comment['userlinkraw'] = 'http://'.$comment['userid'];*/
+			if (strstr($comment['userid'],'http://') != false)
+				$comment['userlinkraw'] = $comment['userid'];
+			elseif (strstr($comment['userid'],'www') != false)
+				$comment['userlinkraw'] = 'http://'.$comment['userid'];
+			elseif (isValidMailAddress($comment['email']))
+				$comment['userlinkraw'] = 'mailto:'.$comment['email'];
+			elseif (isValidMailAddress($comment['userid']))
+				$comment['userlinkraw'] = 'mailto:'.$comment['userid'];
+		}
+
+		$this->currentComment =& $comment;
+	}
+
+	function parse_blogurl() {
+		global $manager;
+		$blogid = getBlogIDFromItemID($this->commentsObj->itemid);
+		$blog =& $manager->getBlog($blogid);
+		echo $blog->getURL();
+	}
+
+	function parse_commentcount() {
+			echo $this->commentsObj->commentcount;
+	}
+	
+	function parse_commentword() {
+		if ($this->commentsObj->commentcount == 1)
+			echo $this->template['COMMENTS_ONE'];
+		else
+			echo $this->template['COMMENTS_MANY'];
+	}
+
+	function parse_itemlink() {
+		echo createLink(
+			'item',
+			array(
+				'itemid' => $this->commentsObj->itemid,
+				'timestamp' => $this->commentsObj->itemActions->currentItem->timestamp,
+				'title' => $this->commentsObj->itemActions->currentItem->title,
+				'extra' => $this->commentsObj->itemActions->linkparams
+			)
+		);
+	}
+	
+	function parse_itemid() {
+		echo $this->commentsObj->itemid;
+	}
+	
+	function parse_itemtitle($maxLength = 0) {
+		if ($maxLength == 0)
+			$this->commentsObj->itemActions->parse_title();
+		else
+			$this->commentsObj->itemActions->parse_syndicate_title($maxLength);
+	}
+
+	function parse_date($format = '') {
+		echo formatDate($format, $this->currentComment['timestamp'], $this->template['FORMAT_DATE'], $this->commentsObj->itemActions->blog);
+	}
+	
+	function parse_time($format = '') {
+		echo strftime(
+				($format == '') ? $this->template['FORMAT_TIME'] : $format,
+				$this->currentComment['timestamp']
+			);
+	}
+
+	function parse_commentid() {
+		echo $this->currentComment['commentid'];
+	}
+	
+	function parse_body() {
+		echo $this->highlight($this->currentComment['body']);
+	}
+	
+	function parse_memberid() {
+		echo $this->currentComment['memberid'];
+	}
+	
+	function parse_timestamp() {
+		echo $this->currentComment['timestamp'];
+	}
+	
+	function parse_host() {
+		echo $this->currentComment['host'];
+	}
+	
+	function parse_ip() {
+		echo $this->currentComment['ip'];
+	}
+	
+	function parse_blogid() {
+		echo $this->currentComment['blogid'];
+	}
+
+//	function parse_user() {
+	function parse_user($mode='') {
+		global $manager;
+		if ($mode == 'realname' && $this->currentComment['memberid'] > 0) {
+			$member =& $manager->getMember($this->currentComment['memberid']);
+			echo $member->getRealName();
+		} else {
+			echo $this->currentComment['user'];
+	}
+	}
+	
+	function parse_userid() {
+			echo $this->currentComment['userid'];
+	}
+	
+	function parse_email() {
+		$email = $this->currentComment['email'];
+		$email = str_replace('@', ' (at) ', $email);
+		$email = str_replace('.', ' (dot) ', $email);
+		echo $email;
+	}
+	
+	function parse_userlinkraw() {
+		echo $this->currentComment['userlinkraw'];
+	}
+	
+	function parse_userlink() {
+		if ($this->currentComment['userlinkraw']) {
+			echo '<a href="'.$this->currentComment['userlinkraw'].'" rel="nofollow">'.$this->currentComment['user'].'</a>';
+		} else {
+			echo $this->currentComment['user'];
+		}
+	}
+
+	function parse_useremail() {
+		global $manager;
+		if ($this->currentComment['memberid'] > 0)
+		{
+			$member =& $manager->getMember($this->currentComment['memberid']);
+
+			if ($member->email != '')
+				echo $member->email;
+		}
+		else
+		{
+			if (isValidMailAddress($this->currentComment['email']))
+				echo $this->currentComment['email'];
+			elseif (isValidMailAddress($this->currentComment['userid']))
+				echo $this->currentComment['userid'];
+//			if (!(strpos($this->currentComment['userlinkraw'], 'mailto:') === false))
+//				echo str_replace('mailto:', '', $this->currentComment['userlinkraw']);
+		}
+	}
+
+	function parse_userwebsite() {
+		if (!(strpos($this->currentComment['userlinkraw'], 'http://') === false))
+			echo $this->currentComment['userlinkraw'];
+	}
+
+	function parse_excerpt() {
+		echo stringToXML(shorten($this->currentComment['body'], 60, '...'));
+	}
+	
+	function parse_short() {
+		$tmp = strtok($this->currentComment['body'],"\n");
+		$tmp = str_replace('<br />','',$tmp);
+		echo $tmp;
+		if ($tmp != $this->currentComment['body'])
+			$this->parser->parse($this->template['COMMENTS_CONTINUED']);
+	}
+	
+	function parse_authtext() {
+		if ($this->currentComment['memberid'] != 0)
+			$this->parser->parse($this->template['COMMENTS_AUTH']);
+	}
+
+	/**
+	  * Executes a plugin templatevar
+	  *
+	  * @param pluginName name of plugin (without the NP_)
+	  *
+	  * extra parameters can be added
+	  */
+	function parse_plugin($pluginName) {
+		global $manager;
+
+		// only continue when the plugin is really installed
+		if (!$manager->pluginInstalled('NP_' . $pluginName))
+			return;
+
+		$plugin =& $manager->getPlugin('NP_' . $pluginName);
+		if (!$plugin) return;
+
+		// get arguments
+		$params = func_get_args();
+
+		// remove plugin name
+		array_shift($params);
+
+		// pass info on current item and current comment as well
+		$params = array_merge(array(&$this->currentComment),$params);
+		$params = array_merge(array(&$this->commentsObj->itemActions->currentItem),$params);
+
+		call_user_func_array(array(&$plugin,'doTemplateCommentsVar'), $params);
+	}
+}
+?>
diff -ruN 3.24.src/nucleus/libs/COMMENT.php 3.31.src/nucleus/libs/COMMENT.php
--- 3.24.src/nucleus/libs/COMMENT.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/COMMENT.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,29 +1,29 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * A class representing a single comment
-  *
+ * A class representing a single comment
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: COMMENT.php,v 1.18.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: COMMENT.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 class COMMENT {
 
 	/**
 	  * Returns the requested comment (static)
 	  */
 	function getComment($commentid) {
-		$query =  'SELECT cnumber as commentid, cbody as body, cuser as user, cmail as userid, cmember as memberid, ctime, chost as host, mname as member, cip as ip, cblog as blogid'
+		$query =  'SELECT cnumber as commentid, cbody as body, cuser as user, cmail as userid, cemail as email, cmember as memberid, ctime, chost as host, mname as member, cip as ip, cblog as blogid'
 			   . ' FROM '.sql_table('comment').' left outer join '.sql_table('member').' on cmember=mnumber'
 			   . ' WHERE cnumber=' . intval($commentid);
 		$comments = sql_query($query);
@@ -43,10 +43,12 @@
 	function prepare($comment) {
 		$comment['user'] = strip_tags($comment['user']);
 		$comment['userid'] = strip_tags($comment['userid']);
+		$comment['email'] = strip_tags($comment['email']);
 
 		// remove quotes and newlines from user and userid
 		$comment['user'] = strtr($comment['user'], "\'\"\n",'-- ');
 		$comment['userid'] = strtr($comment['userid'], "\'\"\n",'-- ');
+		$comment['email'] = strtr($comment['email'], "\'\"\n",'-- ');
 
 		$comment['body'] = COMMENT::prepareBody($comment['body']);
 
diff -ruN 3.24.src/nucleus/libs/COMMENTS.php 3.31.src/nucleus/libs/COMMENTS.php
--- 3.24.src/nucleus/libs/COMMENTS.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/COMMENTS.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,22 +1,26 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * A class representing the comments (all of them) for a certain post on a ceratin blog
-  *
+ * A class representing the comments (all of them) for a certain post on a ceratin blog
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: COMMENTS.php,v 1.23.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: COMMENTS.php 1155 2007-05-20 23:40:48Z kaigreve $
+ */
+
+if ( !function_exists('requestVar') ) exit;
+require_once dirname(__FILE__) . '/COMMENTACTIONS.php';
+
 class COMMENTS {
 
 	// item for which comment are being displayed
@@ -73,7 +77,7 @@
 		if ($maxToShow == 0) {
 			$this->commentcount = $this->amountComments();
 		} else {
-			$query =  'SELECT c.citem as itemid, c.cnumber as commentid, c.cbody as body, c.cuser as user, c.cmail as userid, c.cmember as memberid, c.ctime, c.chost as host, c.cip as ip, c.cblog as blogid'
+			$query =  'SELECT c.citem as itemid, c.cnumber as commentid, c.cbody as body, c.cuser as user, c.cmail as userid, c.cemail as email, c.cmember as memberid, c.ctime, c.chost as host, c.cip as ip, c.cblog as blogid'
 				   . ' FROM '.sql_table('comment').' as c'
 				   . ' WHERE c.citem=' . $this->itemid
 				   . ' ORDER BY c.ctime';
@@ -145,10 +149,10 @@
 		if ($CONF['ProtectMemNames'] && !$member->isLoggedIn() && MEMBER::isNameProtected($comment['user']))
 			return _ERROR_COMMENTS_MEMBERNICK;
 
-		// isValidComment returns either "1" or an error message
-		$isvalid = $this->isValidComment($comment);
-		if ($isvalid != 1)
-			return $isvalid;
+		// email required protection
+		if ($settings->emailRequired() && strlen($comment['email']) == 0 && !$member->isLoggedIn()) {
+			return _ERROR_EMAIL_REQUIRED;
+		}
 
 		$comment['timestamp'] = $timestamp;
 		$comment['host'] = gethostbyaddr(serverVar('REMOTE_ADDR'));
@@ -159,16 +163,75 @@
 			$comment['memberid'] = $member->getID();
 			$comment['user'] = '';
 			$comment['userid'] = '';
+			$comment['email'] = '';
 		} else {
 			$comment['memberid'] = 0;
 		}
 
+		// spam check
+		$continue = false;
+		$plugins = array();
+
+		if (isset($manager->subscriptions['ValidateForm']))
+			$plugins = array_merge($plugins, $manager->subscriptions['ValidateForm']);
+
+		if (isset($manager->subscriptions['PreAddComment']))
+			$plugins = array_merge($plugins, $manager->subscriptions['PreAddComment']);
+
+		if (isset($manager->subscriptions['PostAddComment']))
+			$plugins = array_merge($plugins, $manager->subscriptions['PostAddComment']);
+
+		$plugins = array_unique($plugins);
+
+		while (list(,$plugin) = each($plugins)) {
+			$p = $manager->getPlugin($plugin);
+			$continue = $continue || $p->supportsFeature('handleSpam');
+		}
+
+		$spamcheck = array (
+			'type'  	=> 'comment',
+			'body'		=> $comment['body'],
+			'id'        => $comment['itemid'],
+			'live'   	=> true,
+			'return'	=> $continue
+		);
+
+		if ($member->isLoggedIn()) {
+			$spamcheck['author'] = $member->displayname;
+			$spamcheck['email'] = $member->email;
+		} else {
+			$spamcheck['author'] = $comment['user'];
+			$spamcheck['email'] = $comment['email'];
+			$spamcheck['url'] = $comment['userid'];
+		}
+
+		$manager->notify('SpamCheck', array ('spamcheck' => &$spamcheck));
+
+		if (!$continue && isset($spamcheck['result']) && $spamcheck['result'] == true)
+			return _ERROR_COMMENTS_SPAM;
+
+
+		// isValidComment returns either "1" or an error message
+		$isvalid = $this->isValidComment($comment, $spamcheck);
+		if ($isvalid != 1)
+			return $isvalid;
 
 		// send email to notification address, if any
 		if ($settings->getNotifyAddress() && $settings->notifyOnComment()) {
 
 			$mailto_msg = _NOTIFY_NC_MSG . ' ' . $this->itemid . "\n";
-			$mailto_msg .= $CONF['IndexURL'] . 'index.php?itemid=' . $this->itemid . "\n\n";
+//			$mailto_msg .= $CONF['IndexURL'] . 'index.php?itemid=' . $this->itemid . "\n\n";
+			$temp = parse_url($CONF['Self']);
+			if ($temp['scheme']) {
+				$mailto_msg .= createItemLink($this->itemid) . "\n\n";
+			} else {
+				$tempurl = $settings->getURL();
+				if (substr($tempurl, -1) == '/' || substr($tempurl, -4) == '.php') {
+					$mailto_msg .= $tempurl . '?itemid=' . $this->itemid . "\n\n";
+				} else {
+					$mailto_msg .= $tempurl . '/?itemid=' . $this->itemid . "\n\n";
+				}
+			}
 			if ($comment['memberid'] == 0) {
 				$mailto_msg .= _NOTIFY_USER . ' ' . $comment['user'] . "\n";
 				$mailto_msg .= _NOTIFY_USERID . ' ' . $comment['userid'] . "\n";
@@ -190,10 +253,11 @@
 
 		$comment = COMMENT::prepare($comment);
 
-		$manager->notify('PreAddComment',array('comment' => &$comment));
+		$manager->notify('PreAddComment',array('comment' => &$comment, 'spamcheck' => &$spamcheck));
 
 		$name		= addslashes($comment['user']);
 		$url		= addslashes($comment['userid']);
+		$email      = addslashes($comment['email']);
 		$body		= addslashes($comment['body']);
 		$host		= addslashes($comment['host']);
 		$ip			= addslashes($comment['ip']);
@@ -201,21 +265,21 @@
 		$timestamp	= date('Y-m-d H:i:s', $comment['timestamp']);
 		$itemid		= $this->itemid;
 
-		$query = 'INSERT INTO '.sql_table('comment').' (CUSER, CMAIL, CMEMBER, CBODY, CITEM, CTIME, CHOST, CIP, CBLOG) '
-			   . "VALUES ('$name', '$url', $memberid, '$body', $itemid, '$timestamp', '$host', '$ip', '$blogid')";
+		$query = 'INSERT INTO '.sql_table('comment').' (CUSER, CMAIL, CEMAIL, CMEMBER, CBODY, CITEM, CTIME, CHOST, CIP, CBLOG) '
+			   . "VALUES ('$name', '$url', '$email', $memberid, '$body', $itemid, '$timestamp', '$host', '$ip', '$blogid')";
 
 		sql_query($query);
 
 		// post add comment
 		$commentid = mysql_insert_id();
-		$manager->notify('PostAddComment',array('comment' => &$comment, 'commentid' => &$commentid));
+		$manager->notify('PostAddComment',array('comment' => &$comment, 'commentid' => &$commentid, 'spamcheck' => &$spamcheck));
 
 		// succeeded !
 		return true;
 	}
 
 
-	function isValidComment($comment) {
+	function isValidComment($comment, & $spamcheck) {
 		global $member, $manager;
 
 		// check if there exists a item for this date
@@ -243,238 +307,18 @@
 			if (strlen($comment['user'])<2)
 				return _ERROR_COMMENT_NOUSERNAME;
 
+		if ((strlen($comment['email']) != 0) && !(isValidMailAddress($comment['email']))) {
+			return _ERROR_BADMAILADDRESS;
+		}
+
 		// let plugins do verification (any plugin which thinks the comment is invalid
 		// can change 'error' to something other than '1')
 		$result = 1;
-		$manager->notify('ValidateForm', array('type' => 'comment', 'comment' => &$comment, 'error' => &$result));
+		$manager->notify('ValidateForm', array('type' => 'comment', 'comment' => &$comment, 'error' => &$result, 'spamcheck' => &$spamcheck));
 
 		return $result;
 	}
 
-
-}
-
-/**
-  * This class is used when parsing comment templates
-  */
-class COMMENTACTIONS extends BaseActions {
-
-	// ref to COMMENTS object which is using this object to handle
-	// its templatevars
-	var $commentsObj;
-
-	// template to use to parse the comments
-	var $template;
-
-	// comment currenlty being handled (mysql result assoc array; see COMMENTS::showComments())
-	var $currentComment;
-
-	function COMMENTACTIONS(&$comments) {
-		// call constructor of superclass first
-		$this->BaseActions();
-
-		// reference to the comments object
-		$this->setCommentsObj($comments);
-	}
-
-	function getDefinedActions() {
-		return array(
-		    'blogurl',
-			'commentcount',
-			'commentword',
-			'itemlink',
-			'itemid',
-			'itemtitle',
-			'date',
-			'time',
-			'commentid',
-			'body',
-			'memberid',
-			'timestamp',
-			'host',
-			'ip',
-			'blogid',
-			'authtext',
-			'user',
-			'userid',
-			'userlinkraw',
-			'userlink',
-			'useremail',
-			'userwebsite',
-			'excerpt',
-			'short',
-			'skinfile',
-			'set',
-			'plugin',
-			'include',
-			'phpinclude',
-			'parsedinclude'
-		);
-	}
-
-	function setParser(&$parser) {			$this->parser =& $parser; }
-	function setCommentsObj(&$commentsObj) {$this->commentsObj =& $commentsObj; }
-	function setTemplate($template) {		$this->template =& $template; }
-	function setCurrentComment(&$comment) {
-		if ($comment['memberid'] != 0) {
-			$comment['authtext'] = $template['COMMENTS_AUTH'];
-
-			$mem = MEMBER::createFromID($comment['memberid']);
-			$comment['user'] = $mem->getDisplayName();
-			if ($mem->getURL())
-				$comment['userid'] = $mem->getURL();
-			else
-				$comment['userid'] = $mem->getEmail();
-
-			$comment['userlinkraw'] = createLink(
-										'member',
-										array(
-											'memberid' => $comment['memberid'],
-											'name' => $mem->getDisplayName(),
-											'extra' => $this->commentsObj->itemActions->linkparams
-										)
-									  );
-
-		} else {
-
-			// create smart links
-			if (isValidMailAddress($comment['userid']))
-				$comment['userlinkraw'] = 'mailto:'.$comment['userid'];
-			elseif (strstr($comment['userid'],'http://') != false)
-				$comment['userlinkraw'] = $comment['userid'];
-			elseif (strstr($comment['userid'],'www') != false)
-				$comment['userlinkraw'] = 'http://'.$comment['userid'];
-		}
-
-		$this->currentComment =& $comment;
-	}
-
-	function parse_blogurl() {		
-		global $manager;
-		$blogid = getBlogIDFromItemID($this->commentsObj->itemid);
-		$blog =& $manager->getBlog($blogid);
-		echo $blog->getURL(); 
-	}
-
-	function parse_commentcount() {			echo $this->commentsObj->commentcount; }
-	function parse_commentword() {
-		if ($this->commentsObj->commentcount == 1)
-			echo $this->template['COMMENTS_ONE'];
-		else
-			echo $this->template['COMMENTS_MANY'];
-	}
-
-	function parse_itemlink() {
-		echo createLink(
-			'item',
-			array(
-				'itemid' => $this->commentsObj->itemid,
-				'extra' => $this->commentsObj->itemActions->linkparams
-			)
-		);
-	}
-	function parse_itemid() {				echo $this->commentsObj->itemid; }
-	function parse_itemtitle($maxLength = 0) {
-		if ($maxLength == 0)
-			$this->commentsObj->itemActions->parse_title();
-		else
-			$this->commentsObj->itemActions->parse_syndicate_title($maxLength);
-	}
-
-	function parse_date($format = '') {
-		echo formatDate($format, $this->currentComment['timestamp'], $this->template['FORMAT_DATE'], $this->commentsObj->itemActions->blog);
-	}
-	function parse_time($format = '') {
-		echo strftime(
-				($format == '') ? $this->template['FORMAT_TIME'] : $format,
-				$this->currentComment['timestamp']
-			);
-	}
-
-	function parse_commentid() {			echo $this->currentComment['commentid']; }
-	function parse_body() {					echo $this->highlight($this->currentComment['body']); }
-	function parse_memberid() {				echo $this->currentComment['memberid']; }
-	function parse_timestamp() {			echo $this->currentComment['timestamp']; }
-	function parse_host() {					echo $this->currentComment['host']; }
-	function parse_ip() {					echo $this->currentComment['ip']; }
-	function parse_blogid() {				echo $this->currentComment['blogid']; }
-
-	function parse_user() {					echo $this->currentComment['user']; }
-	function parse_userid() {				echo $this->currentComment['userid']; }
-	function parse_userlinkraw() {			echo $this->currentComment['userlinkraw']; }
-	function parse_userlink() {
-		if ($this->currentComment['userlinkraw']) {
-			echo '<a href="'.$this->currentComment['userlinkraw'].'" rel="nofollow">'.$this->currentComment['user'].'</a>';
-		} else {
-			echo $this->currentComment['user'];
-		}
-	}
-
-	function parse_useremail() {
-		if ($this->currentComment['memberid'] > 0)
-		{
-			$member = new MEMBER();
-			$member->readFromID($this->currentComment['memberid']);
-			
-			if ($member->email != '')
-				echo $member->email;		
-		}
-		else
-		{
-			if (!(strpos($this->currentComment['userlinkraw'], 'mailto:') === false))
-				echo str_replace('mailto:', '', $this->currentComment['userlinkraw']);
-		}
-	}
-
-	function parse_userwebsite() {
-		if (!(strpos($this->currentComment['userlinkraw'], 'http://') === false))
-			echo $this->currentComment['userlinkraw'];
-	}
-	
-	function parse_excerpt() {
-		echo stringToXML(shorten($this->currentComment['body'], 60, '...'));
-	}
-	function parse_short() {
-		$tmp = strtok($this->currentComment['body'],"\n");
-		$tmp = str_replace('<br />','',$tmp);
-		echo $tmp;
-		if ($tmp != $this->currentComment['body'])
-			$this->parser->parse($this->template['COMMENTS_CONTINUED']);
-	}
-	function parse_authtext() {
-		if ($this->currentComment['memberid'] != 0)
-			$this->parser->parse($this->template['COMMENTS_AUTH']);
-	}
-
-	/**
-	  * Executes a plugin templatevar
-	  *
-	  * @param pluginName name of plugin (without the NP_)
-	  *
-	  * extra parameters can be added
-	  */
-	function parse_plugin($pluginName) {
-		global $manager;
-
-		// only continue when the plugin is really installed
-		if (!$manager->pluginInstalled('NP_' . $pluginName))
-			return;
-
-		$plugin =& $manager->getPlugin('NP_' . $pluginName);
-		if (!$plugin) return;
-
-		// get arguments
-		$params = func_get_args();
-
-		// remove plugin name
-		array_shift($params);
-
-		// pass info on current item and current comment as well
-		$params = array_merge(array(&$this->currentComment),$params);
-		$params = array_merge(array(&$this->commentsObj->itemActions->currentItem),$params);
-
-		call_user_func_array(array(&$plugin,'doTemplateCommentsVar'), $params);
-	}
 }
 
 ?>
diff -ruN 3.24.src/nucleus/libs/ENCAPSULATE.php 3.31.src/nucleus/libs/ENCAPSULATE.php
--- 3.24.src/nucleus/libs/ENCAPSULATE.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/libs/ENCAPSULATE.php	2007-10-22 19:36:00.000000000 -0500
@@ -0,0 +1,258 @@
+<?php
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+
+/**
+ * Part of the code for the Nucleus admin area
+ *
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: ENCAPSULATE.php 1154 2007-05-20 23:24:09Z kaigreve $
+ */
+
+class ENCAPSULATE {
+	/**
+	  * Uses $call to call a function using parameters $params
+	  * This function should return the amount of entries shown.
+	  * When entries are show, batch operation handlers are shown too.
+	  * When no entries were shown, $errormsg is used to display an error
+	  *
+	  * Passes on the amount of results found (for further encapsulation)
+	  */
+	function doEncapsulate($call, $params, $errorMessage = 'No entries') {
+		// start output buffering
+		ob_start();
+
+		$nbOfRows = call_user_func_array($call, $params);
+
+		// get list contents and stop buffering
+		$list = ob_get_contents();
+		ob_end_clean();
+
+		if ($nbOfRows > 0) {
+			$this->showHead();
+			echo $list;
+			$this->showFoot();
+		} else {
+			echo $errorMessage;
+		}
+
+		return $nbOfRows;
+	}
+}
+
+/**
+  * A class used to encapsulate a list of some sort inside next/prev buttons
+  */
+class NAVLIST extends ENCAPSULATE {
+
+	function NAVLIST($action, $start, $amount, $minamount, $maxamount, $blogid, $search, $itemid) {
+		$this->action = $action;
+		$this->start = $start;
+		$this->amount = $amount;
+		$this->minamount = $minamount;
+		$this->maxamount = $maxamount;
+		$this->blogid = $blogid;
+		$this->search = $search;
+		$this->itemid = $itemid;
+	}
+
+	function showBatchList($batchtype, $query, $type, $template, $errorMessage = _LISTS_NOMORE) {
+		$batch =& new BATCH($batchtype);
+
+		$this->doEncapsulate(
+				array(&$batch, 'showlist'),
+				array(&$query, $type, $template),
+				$errorMessage
+		);
+
+	}
+
+
+	function showHead() {
+		$this->showNavigation();
+	}
+	function showFoot() {
+		$this->showNavigation();
+	}
+
+	/**
+	  * Displays a next/prev bar for long tables
+	  */
+	function showNavigation() {
+		$action = $this->action;
+		$start = $this->start;
+		$amount = $this->amount;
+		$minamount = $this->minamount;
+		$maxamount = $this->maxamount;
+		$blogid = $this->blogid;
+		$search = htmlspecialchars($this->search);
+		$itemid = $this->itemid;
+
+		$prev = $start - $amount;
+		if ($prev < $minamount) $prev=$minamount;
+
+		// maxamount not used yet
+	//	if ($start + $amount <= $maxamount)
+			$next = $start + $amount;
+	//	else
+	//		$next = $start;
+
+	?>
+	<table class="navigation">
+	<tr><td>
+		<form method="post" action="index.php"><div>
+		<input type="submit" value="&lt;&lt; <?php echo  _LISTS_PREV?>" />
+		<input type="hidden" name="blogid" value="<?php echo  $blogid; ?>" />
+		<input type="hidden" name="itemid" value="<?php echo  $itemid; ?>" />
+		<input type="hidden" name="action" value="<?php echo  $action; ?>" />
+		<input type="hidden" name="amount" value="<?php echo  $amount; ?>" />
+		<input type="hidden" name="search" value="<?php echo  $search; ?>" />
+		<input type="hidden" name="start" value="<?php echo  $prev; ?>" />
+		</div></form>
+	</td><td>
+		<form method="post" action="index.php"><div>
+		<input type="hidden" name="blogid" value="<?php echo  $blogid; ?>" />
+		<input type="hidden" name="itemid" value="<?php echo  $itemid; ?>" />
+		<input type="hidden" name="action" value="<?php echo  $action; ?>" />
+		<input name="amount" size="3" value="<?php echo  $amount; ?>" /> <?php echo _LISTS_PERPAGE?>
+		<input type="hidden" name="start" value="<?php echo  $start; ?>" />
+		<input type="hidden" name="search" value="<?php echo  $search; ?>" />
+		<input type="submit" value="&gt; <?php echo _LISTS_CHANGE?>" />
+		</div></form>
+	</td><td>
+		<form method="post" action="index.php"><div>
+		<input type="hidden" name="blogid" value="<?php echo  $blogid; ?>" />
+		<input type="hidden" name="itemid" value="<?php echo  $itemid; ?>" />
+		<input type="hidden" name="action" value="<?php echo  $action; ?>" />
+		<input type="hidden" name="amount" value="<?php echo  $amount; ?>" />
+		<input type="hidden" name="start" value="0" />
+		<input type="text" name="search" value="<?php echo  $search; ?>" size="7" />
+		<input type="submit" value="&gt; <?php echo  _LISTS_SEARCH?>" />
+		</div></form>
+	</td><td>
+		<form method="post" action="index.php"><div>
+		<input type="submit" value="<?php echo _LISTS_NEXT?> &gt; &gt;" />
+		<input type="hidden" name="search" value="<?php echo  $search; ?>" />
+		<input type="hidden" name="blogid" value="<?php echo  $blogid; ?>" />
+		<input type="hidden" name="itemid" value="<?php echo  $itemid; ?>" />
+		<input type="hidden" name="action" value="<?php echo  $action; ?>" />
+		<input type="hidden" name="amount" value="<?php echo  $amount; ?>" />
+		<input type="hidden" name="start" value="<?php echo  $next; ?>" />
+		</div></form>
+	</td></tr>
+	</table>
+	<?php	}
+
+
+}
+
+
+/**
+ * A class used to encapsulate a list of some sort in a batch selection
+ */
+class BATCH extends ENCAPSULATE {
+	function BATCH($type) {
+		$this->type = $type;
+	}
+
+	function showHead() {
+		?>
+			<form method="post" action="index.php">
+		<?php
+// TODO: get a list op operations above the list too
+// (be careful not to use the same names for the select...)
+//		$this->showOperationList();
+	}
+
+	function showFoot() {
+		$this->showOperationList();
+		?>
+			</form>
+		<?php	}
+
+	function showOperationList() {
+		global $manager;
+		?>
+		<div class="batchoperations">
+			<?php echo _BATCH_WITH_SEL ?>
+			<select name="batchaction">
+			<?php				$options = array();
+				switch($this->type) {
+					case 'item':
+						$options = array(
+							'delete'	=> _BATCH_ITEM_DELETE,
+							'move'		=> _BATCH_ITEM_MOVE
+						);
+						break;
+					case 'member':
+						$options = array(
+							'delete'	=> _BATCH_MEMBER_DELETE,
+							'setadmin'	=> _BATCH_MEMBER_SET_ADM,
+							'unsetadmin' => _BATCH_MEMBER_UNSET_ADM
+						);
+						break;
+					case 'team':
+						$options = array(
+							'delete' 	=> _BATCH_TEAM_DELETE,
+							'setadmin'	=> _BATCH_TEAM_SET_ADM,
+							'unsetadmin' => _BATCH_TEAM_UNSET_ADM,
+						);
+						break;
+					case 'category':
+						$options = array(
+							'delete'	=> _BATCH_CAT_DELETE,
+							'move'		=> _BATCH_CAT_MOVE,
+						);
+						break;
+					case 'comment':
+						$options = array(
+							'delete'	=> _BATCH_COMMENT_DELETE,
+						);
+					break;
+				}
+				foreach ($options as $option => $label) {
+					echo '<option value="',$option,'">',$label,'</option>';
+				}
+			?>
+			</select>
+			<input type="hidden" name="action" value="batch<?php echo $this->type?>" />
+			<?php
+				$manager->addTicketHidden();
+
+				// add hidden fields for 'team' and 'comment' batchlists
+				if ($this->type == 'team')
+				{
+					echo '<input type="hidden" name="blogid" value="',intRequestVar('blogid'),'" />';
+				}
+				if ($this->type == 'comment')
+				{
+					echo '<input type="hidden" name="itemid" value="',intRequestVar('itemid'),'" />';
+				}
+
+				echo '<input type="submit" value="',_BATCH_EXEC,'" />';
+			?>(
+			 <a href="" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); return batchSelectAll(1); "><?php echo _BATCH_SELECTALL?></a> -
+			 <a href="" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); return batchSelectAll(0); "><?php echo _BATCH_DESELECTALL?></a>
+			)
+		</div>
+		<?php	}
+
+	// shortcut :)
+	function showList($query, $type, $template, $errorMessage = _LISTS_NOMORE) {
+		return $this->doEncapsulate(	'showlist',
+									array($query, $type, $template),
+									$errorMessage
+								);
+	}
+
+}
+?>
diff -ruN 3.24.src/nucleus/libs/globalfunctions.php 3.31.src/nucleus/libs/globalfunctions.php
--- 3.24.src/nucleus/libs/globalfunctions.php	2006-11-29 15:23:33.000000000 -0600
+++ 3.31.src/nucleus/libs/globalfunctions.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,33 +1,40 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: globalfunctions.php 1104 2006-11-11 10:21:45Z dekarma $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: globalfunctions.php 1211 2007-10-21 17:43:27Z kaigreve $
+
+ */
 
 // needed if we include globalfunctions from install.php
-global $nucleus, $CONF, $DIR_LIBS, $DIR_LANG, $manager, $member; 
+global $nucleus, $CONF, $DIR_LIBS, $DIR_LANG, $manager, $member;
 
+$nucleus['version'] = 'v3.31';
+$nucleus['codename'] = '';
 
 checkVars(array('nucleus', 'CONF', 'DIR_LIBS', 'MYSQL_HOST', 'MYSQL_USER', 'MYSQL_PASSWORD', 'MYSQL_DATABASE', 'DIR_LANG', 'DIR_PLUGINS', 'HTTP_GET_VARS', 'HTTP_POST_VARS', 'HTTP_COOKIE_VARS', 'HTTP_ENV_VARS', 'HTTP_SESSION_VARS', 'HTTP_POST_FILES', 'HTTP_SERVER_VARS', 'GLOBALS', 'argv', 'argc', '_GET', '_POST', '_COOKIE', '_ENV', '_SESSION', '_SERVER', '_FILES'));
 
 $CONF['debug'] = 0;
+if ($CONF['debug']) {
+	error_reporting(E_ALL);	// report all errors!
+} else {
+	error_reporting(E_ERROR | E_WARNING | E_PARSE);
+}
 
-$nucleus['version'] = 'v3.24';
-if (getNucleusPatchLevel() > 0)
-{
-	$nucleus['version'] .= '/' . getNucleusPatchLevel();
+// Avoid notices
+if (!isset($CONF['Self'])) {
+	$CONF['Self'] = $_SERVER['PHP_SELF'];
 }
 
 /*
@@ -46,67 +53,71 @@
 */
 $CONF['alertOnHeadersSent'] = 1;
 $CONF['alertOnSecurityRisk'] = 1;
+$CONF['ItemURL'] = $CONF['Self'];
+$CONF['ArchiveURL'] = $CONF['Self'];
+$CONF['ArchiveListURL'] = $CONF['Self'];
+$CONF['MemberURL'] = $CONF['Self'];
+$CONF['SearchURL'] = $CONF['Self'];
+$CONF['BlogURL'] = $CONF['Self'];
+$CONF['CategoryURL'] = $CONF['Self'];
 
-/**
-  * returns the currently used version (100 = 1.00, 101 = 1.01, etc...)
-  */
-function getNucleusVersion() {
-	return 324;
+// switch URLMode back to normal when $CONF['Self'] ends in .php
+// this avoids urls like index.php/item/13/index.php/item/15
+if (!isset($CONF['URLMode']) || (($CONF['URLMode'] == 'pathinfo') && (substr($CONF['Self'], strlen($CONF['Self']) - 4) == '.php'))) {
+	$CONF['URLMode'] = 'normal';
 }
 
-/**
- * power users can install patches in between nucleus releases. These patches
- * usually add new functionality in the plugin API and allow those to
- * be tested without having to install CVS.
- */
-function getNucleusPatchLevel() {
-	return 0;
+if (getNucleusPatchLevel() > 0) {
+	$nucleus['version'] .= '/' . getNucleusPatchLevel();
 }
 
-
-if ($CONF['debug']) {
-	error_reporting(E_ALL & ~E_NOTICE);	// report almost all errors!
-										// (no uninitialized vars and such)
-} else {
-	error_reporting(E_ERROR | E_WARNING | E_PARSE);
+// Avoid notices
+if (!isset($CONF['installscript'])) {
+	$CONF['installscript'] = 0;
 }
 
 // we will use postVar, getVar, ... methods instead of HTTP_GET_VARS or _GET
-if ($CONF['installscript']!=1){ // vars were already included in install.php
-  if (phpversion() >= '4.1.0')
-	  include_once($DIR_LIBS . 'vars4.1.0.php');
-  else
-	  include_once($DIR_LIBS . 'vars4.0.6.php');
+if ($CONF['installscript'] != 1) { // vars were already included in install.php
+	if (phpversion() >= '4.1.0') {
+		include_once($DIR_LIBS . 'vars4.1.0.php');
+	} else {
+		include_once($DIR_LIBS . 'vars4.0.6.php');
+	}
 }
 
-function intPostVar($name) { return intval(postVar($name));}
-function intGetVar($name) { return intval(getVar($name));}
-function intRequestVar($name) { return intval(requestVar($name)); }
-function intCookieVar($name) { return intval(cookieVar($name)); }
+// sanitize option
+$bLoggingSanitizedResult=0;
+$bSanitizeAndContinue=0;
+
+$orgRequestURI = serverVar('REQUEST_URI');
+sanitizeParams();
 
 // get all variables that can come from the request and put them in the global scope
-$blogid			= requestVar('blogid');
-$itemid			= intRequestVar('itemid');
-$catid			= intRequestVar('catid');
-$skinid			= requestVar('skinid');
-$memberid		= requestVar('memberid');
-$archivelist	= requestVar('archivelist');
-$imagepopup		= requestVar('imagepopup');
-$archive 		= requestVar('archive');
-$query			= requestVar('query');
-$highlight		= requestVar('highlight');
-$amount			= requestVar('amount');
-$action			= requestVar('action');
-$nextaction		= requestVar('nextaction');
-$maxresults     = requestVar('maxresults');
-$startpos       = intRequestVar('startpos');
-$errormessage	= '';
-$error			= '';
+$blogid	= requestVar('blogid');
+$itemid	= intRequestVar('itemid');
+$catid = intRequestVar('catid');
+$skinid	= requestVar('skinid');
+$memberid = requestVar('memberid');
+$archivelist = requestVar('archivelist');
+$imagepopup = requestVar('imagepopup');
+$archive = requestVar('archive');
+$query = requestVar('query');
+$highlight = requestVar('highlight');
+$amount = requestVar('amount');
+$action = requestVar('action');
+$nextaction = requestVar('nextaction');
+$maxresults = requestVar('maxresults');
+$startpos = intRequestVar('startpos');
+$errormessage = '';
+$error = '';
+$virtualpath = ((getVar('virtualpath') != null) ? getVar('virtualpath') : serverVar('PATH_INFO'));
 
-if (!headers_sent())
+if (!headers_sent() ) {
 	header('Generator: Nucleus CMS ' . $nucleus['version']);
+}
 
 // include core classes that are needed for login & plugin handling
+include($DIR_LIBS . 'mysql.php');
 include($DIR_LIBS . 'MEMBER.php');
 include($DIR_LIBS . 'ACTIONLOG.php');
 include($DIR_LIBS . 'MANAGER.php');
@@ -117,15 +128,32 @@
 // make sure there's no unnecessary escaping:
 set_magic_quotes_runtime(0);
 
+// Avoid notices
+if (!isset($CONF['UsingAdminArea'])) {
+	$CONF['UsingAdminArea'] = 0;
+}
+
 // only needed when updating logs
 if ($CONF['UsingAdminArea']) {
 	include($DIR_LIBS . 'xmlrpc.inc.php');	// XML-RPC client classes
 	include_once($DIR_LIBS . 'ADMIN.php');
 }
 
-
-// connect to sql
+// connect to database
 sql_connect();
+$SQLCount = 0;
+
+// logs sanitized result if need
+if ($orgRequestURI!==serverVar('REQUEST_URI')) {
+	$msg = "Sanitized [" . serverVar('REMOTE_ADDR') . "] ";
+	$msg .= $orgRequestURI . " -> " . serverVar('REQUEST_URI');
+    if ($bLoggingSanitizedResult) {
+        addToLog(WARNING, $msg);
+    }
+    if (!$bSanitizeAndContinue) {
+        die("");
+    }
+}
 
 // makes sure database connection gets closed on script termination
 register_shutdown_function('sql_disconnect');
@@ -134,37 +162,65 @@
 getConfig();
 
 // automatically use simpler toolbar for mozilla
-if (($CONF['DisableJsTools'] == 0) && strstr(serverVar('HTTP_USER_AGENT'),'Mozilla/5.0') && strstr(serverVar('HTTP_USER_AGENT'),'Gecko'))
+if (($CONF['DisableJsTools'] == 0) && strstr(serverVar('HTTP_USER_AGENT'), 'Mozilla/5.0') && strstr(serverVar('HTTP_USER_AGENT'), 'Gecko') ) {
 	$CONF['DisableJsTools'] = 2;
+}
 
 // login if cookies set
+$member = new MEMBER();
 
-$member =& new MEMBER();
+// secure cookie key settings (either 'none', 0, 8, 16, 24, or 32)
+if (!isset($CONF['secureCookieKey'])) $CONF['secureCookieKey']=24;
+switch($CONF['secureCookieKey']){
+case 8:
+	$CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
+	break;
+case 16:
+	$CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
+	break;
+case 24:
+	$CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
+	break;
+case 32:
+	$CONF['secureCookieKeyIP']=serverVar('REMOTE_ADDR');
+	break;
+default:
+	$CONF['secureCookieKeyIP']='';
+}
 
 // login/logout when required or renew cookies
 if ($action == 'login') {
 	// Form Authentication
-	$login 	= postVar('login');
-	$pw 	= postVar('password');
+	$login = postVar('login');
+	$pw = postVar('password');
 	$shared	= intPostVar('shared');	// shared computer or not
 
-	if ($member->login($login,$pw)) {
+	$pw=substr($pw,0,40); // avoid md5 collision by using a long key
+
+	if ($member->login($login, $pw) ) {
 
 		$member->newCookieKey();
 		$member->setCookies($shared);
 
+		if ($CONF['secureCookieKey']!=='none') {
+			// secure cookie key
+			$member->setCookieKey(md5($member->getCookieKey().$CONF['secureCookieKeyIP']));
+			$member->write();
+		}
+
 		// allows direct access to parts of the admin area after logging in
-		if ($nextaction)
+		if ($nextaction) {
 			$action = $nextaction;
+		}
 
-		$manager->notify('LoginSuccess',array('member' => &$member));
+		$manager->notify('LoginSuccess', array('member' => &$member) );
 		$errormessage = '';
 		ACTIONLOG::add(INFO, "Login successful for $login (sharedpc=$shared)");
 	} else {
 		// errormessage for [%errordiv%]
 		$errormessage = 'Login failed for ' . $login;
-		
-		$manager->notify('LoginFailed',array('username' => $login));
+
+		$manager->notify('LoginFailed', array('username' => $login) );
 		ACTIONLOG::add(INFO, $errormessage);
 	}
 /*
@@ -173,40 +229,48 @@
 
 } elseif (serverVar('PHP_AUTH_USER') && serverVar('PHP_AUTH_PW')) {
 	// HTTP Authentication
-       $login  = serverVar('PHP_AUTH_USER');
-       $pw     = serverVar('PHP_AUTH_PW');
+	$login  = serverVar('PHP_AUTH_USER');
+	$pw     = serverVar('PHP_AUTH_PW');
 
-       if ($member->login($login,$pw)) {
-               $manager->notify('LoginSuccess',array('member' => &$member));
-               ACTIONLOG::add(INFO, "HTTP authentication successful for $login");
-       } else {
-               $manager->notify('LoginFailed',array('username' => $login));
-               ACTIONLOG::add(INFO, 'HTTP authentication failed for ' . $login);
-
-               //Since bad credentials, generate an apropriate error page
-               header("WWW-Authenticate: Basic realm=\"Nucleus CMS {$nucleus['version']}\"");
-               header('HTTP/1.0 401 Unauthorized');
-               echo 'Invalid username or password';
-               exit;
-       }
+	if ($member->login($login, $pw) ) {
+		$manager->notify('LoginSuccess',array('member' => &$member));
+		ACTIONLOG::add(INFO, "HTTP authentication successful for $login");
+	} else {
+		$manager->notify('LoginFailed',array('username' => $login));
+		ACTIONLOG::add(INFO, 'HTTP authentication failed for ' . $login);
+
+		//Since bad credentials, generate an apropriate error page
+		header("WWW-Authenticate: Basic realm=\"Nucleus CMS {$nucleus['version']}\"");
+		header('HTTP/1.0 401 Unauthorized');
+		echo 'Invalid username or password';
+		exit;
+	}
 */
 
-} elseif (($action == 'logout') && (!headers_sent()) && cookieVar($CONF['CookiePrefix'] . 'user')){
+} elseif (($action == 'logout') && (!headers_sent() ) && cookieVar($CONF['CookiePrefix'] . 'user') ) {
 	// remove cookies on logout
-	setcookie($CONF['CookiePrefix'] .'user','',(time()-2592000),$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
-	setcookie($CONF['CookiePrefix'] .'loginkey','',(time()-2592000),$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
-	$manager->notify('Logout',array('username' => cookieVar($CONF['CookiePrefix'] .'user')));
-} elseif (cookieVar($CONF['CookiePrefix'] .'user')) {
+	setcookie($CONF['CookiePrefix'] . 'user', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
+	setcookie($CONF['CookiePrefix'] . 'loginkey', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
+	$manager->notify('Logout', array('username' => cookieVar($CONF['CookiePrefix'] . 'user') ) );
+} elseif (cookieVar($CONF['CookiePrefix'] . 'user') ) {
 	// Cookie Authentication
-	$res = $member->cookielogin(cookieVar($CONF['CookiePrefix'] .'user'), cookieVar($CONF['CookiePrefix'] .'loginkey'));
+	$ck=cookieVar($CONF['CookiePrefix'] . 'loginkey');
+	// secure cookie key
+	$ck=substr($ck,0,32); // avoid md5 collision by using a long key
+	if ($CONF['secureCookieKey']!=='none') $ck=md5($ck.$CONF['secureCookieKeyIP']);
+	$res = $member->cookielogin(cookieVar($CONF['CookiePrefix'] . 'user'), $ck );
+	unset($ck);
 
 	// renew cookies when not on a shared computer
-	if ($res && (cookieVar($CONF['CookiePrefix'] .'sharedpc') != 1) && (!headers_sent()))
+	if ($res && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) && (!headers_sent() ) ) {
+		$member->setCookieKey(cookieVar($CONF['CookiePrefix'] . 'loginkey'));
 		$member->setCookies();
+	}
 }
 
 // login completed
-$manager->notify('PostAuthentication',array('loggedIn' => $member->isLoggedIn()));
+$manager->notify('PostAuthentication', array('loggedIn' => $member->isLoggedIn() ) );
+ticketForPlugin();
 
 // first, let's see if the site is disabled or not. always allow admin area access.
 if ($CONF['DisableSite'] && !$member->isAdmin() && !$CONF['UsingAdminArea']) {
@@ -219,6 +283,7 @@
 include($DIR_LIBS . 'SKIN.php');
 include($DIR_LIBS . 'TEMPLATE.php');
 include($DIR_LIBS . 'BLOG.php');
+include($DIR_LIBS . 'BODYACTIONS.php');
 include($DIR_LIBS . 'COMMENTS.php');
 include($DIR_LIBS . 'COMMENT.php');
 //include($DIR_LIBS . 'ITEM.php');
@@ -230,11 +295,12 @@
 
 
 // set lastVisit cookie (if allowed)
-if (!headers_sent()) {
-	if ($CONF['LastVisit'])
-		setcookie($CONF['CookiePrefix'] .'lastVisit',time(),time()+2592000,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
-	else
-		setcookie($CONF['CookiePrefix'] .'lastVisit','',(time()-2592000),$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
+if (!headers_sent() ) {
+	if ($CONF['LastVisit']) {
+		setcookie($CONF['CookiePrefix'] . 'lastVisit', time(), time() + 2592000, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
+	} else {
+		setcookie($CONF['CookiePrefix'] . 'lastVisit', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
+	}
 }
 
 // read language file, only after user has been initialized
@@ -243,8 +309,8 @@
 
 /*
 	Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
-	
-// To remove after v2.5 is released and language files have been updated. 
+
+// To remove after v2.5 is released and language files have been updated.
 // Including this makes sure that language files for v2.5beta can still be used for v2.5final
 // without having weird _SETTINGS_EXTAUTH string showing up in the admin area.
 if (!defined('_MEMBERS_BYPASS'))
@@ -257,69 +323,119 @@
 */
 
 // make sure the archivetype skinvar keeps working when _ARCHIVETYPE_XXX not defined
-if (!defined('_ARCHIVETYPE_MONTH'))
-{
-	define('_ARCHIVETYPE_DAY','day');
-	define('_ARCHIVETYPE_MONTH','month');
+if (!defined('_ARCHIVETYPE_MONTH') ) {
+	define('_ARCHIVETYPE_DAY', 'day');
+	define('_ARCHIVETYPE_MONTH', 'month');
 }
 
-
 // decode path_info
-if ($CONF['URLMode'] == 'pathinfo')
-{
+if ($CONF['URLMode'] == 'pathinfo') {
 	// initialize keywords if this hasn't been done before
-    if ($CONF['ItemKey'] == '')     $CONF['ItemKey'] = 'item';
-    if ($CONF['ArchiveKey'] == '')  $CONF['ArchiveKey'] = 'archive';
-    if ($CONF['ArchivesKey'] == '') $CONF['ArchivesKey'] = 'archives';
-    if ($CONF['MemberKey'] == '')   $CONF['MemberKey'] = 'member';
-    if ($CONF['BlogKey'] == '')     $CONF['BlogKey'] = 'blog';
-    if ($CONF['CategoryKey'] == '') $CONF['CategoryKey'] = 'category';
-        
-    $parsed = false;
-    $manager->notify(
-    	'ParseURL', 
-    	array(
-    		'type' => basename(serverVar('SCRIPT_NAME')),	// e.g. item, blog, ...
-    		'info' => serverVar('PATH_INFO'),
-    		'complete' => &$parsed		
-    	)
-    );
-    
-    if (!$parsed)
-    {
-        // default implementation
-		$data = explode("/",serverVar('PATH_INFO'));
-		for ($i=0;$i<sizeof($data);$i++) {
+	if ($CONF['ItemKey'] == '') {
+		$CONF['ItemKey'] = 'item';
+	}
+
+	if ($CONF['ArchiveKey'] == '') {
+		$CONF['ArchiveKey'] = 'archive';
+	}
+
+	if ($CONF['ArchivesKey'] == '') {
+		$CONF['ArchivesKey'] = 'archives';
+	}
+
+	if ($CONF['MemberKey'] == '') {
+		$CONF['MemberKey'] = 'member';
+	}
+
+	if ($CONF['BlogKey'] == '') {
+		$CONF['BlogKey'] = 'blog';
+	}
+
+	if ($CONF['CategoryKey'] == '') {
+		$CONF['CategoryKey'] = 'category';
+	}
+
+	if ($CONF['SpecialskinKey'] == '') {
+		$CONF['SpecialskinKey'] = 'special';
+	}
+
+	$parsed = false;
+	$manager->notify(
+		'ParseURL',
+		array(
+			'type' => basename(serverVar('SCRIPT_NAME') ), // e.g. item, blog, ...
+			'info' => $virtualpath,
+			'complete' => &$parsed
+		)
+	);
+
+	if (!$parsed) {
+		// default implementation
+		$data = explode("/", $virtualpath );
+		for ($i = 0; $i < sizeof($data); $i++) {
 			switch ($data[$i]) {
-				case $CONF['ItemKey']:			// item/1 (blogid)
+				case $CONF['ItemKey']: // item/1 (blogid)
 					$i++;
-					if ($i<sizeof($data)) $itemid = intval($data[$i]);
+
+					if ($i < sizeof($data) ) {
+						$itemid = intval($data[$i]);
+					}
 					break;
-				case $CONF['ArchivesKey']:		// archives/1 (blogid)
+
+				case $CONF['ArchivesKey']: // archives/1 (blogid)
 					$i++;
-					if ($i<sizeof($data)) $archivelist = intval($data[$i]);
+
+					if ($i < sizeof($data) ) {
+						$archivelist = intval($data[$i]);
+					}
 					break;
-				case $CONF['ArchiveKey']:		// two possibilities: archive/yyyy-mm or archive/1/yyyy-mm (with blogid)
-					if ((($i+1)<sizeof($data)) && (!strstr($data[$i+1],'-')) ){
+
+				case $CONF['ArchiveKey']: // two possibilities: archive/yyyy-mm or archive/1/yyyy-mm (with blogid)
+					if ((($i + 1) < sizeof($data) ) && (!strstr($data[$i + 1], '-') ) ) {
 						$blogid = intval($data[++$i]);
 					}
+
 					$i++;
-					if ($i<sizeof($data)) $archive = $data[$i];
+
+					if ($i < sizeof($data) ) {
+						$archive = $data[$i];
+					}
 					break;
-				case 'blogid':			// blogid/1
-					case $CONF['BlogKey']:	// blog/1
+
+				case 'blogid': // blogid/1
+				case $CONF['BlogKey']: // blog/1
 					$i++;
-					if ($i<sizeof($data)) $blogid = intval($data[$i]);
+
+					if ($i < sizeof($data) ) {
+						$blogid = intval($data[$i]);
+					}
 					break;
-					case $CONF['CategoryKey']:	// category/1 (catid)
+
+				case $CONF['CategoryKey']: // category/1 (catid)
 				case 'catid':
 					$i++;
-					if ($i<sizeof($data)) $catid = intval($data[$i]);
+
+					if ($i < sizeof($data) ) {
+						$catid = intval($data[$i]);
+					}
 					break;
-					case $CONF['MemberKey']:
+
+				case $CONF['MemberKey']:
 					$i++;
-					if ($i<sizeof($data)) $memberid = intval($data[$i]);
+
+					if ($i < sizeof($data) ) {
+						$memberid = intval($data[$i]);
+					}
 					break;
+
+                case $CONF['SpecialskinKey']:
+                    $i++;
+
+					if ($i < sizeof($data) ) {
+                    	$_REQUEST['special'] = $data[$i];
+                    }
+                    break;
+
 				default:
 					// skip...
 			}
@@ -327,48 +443,82 @@
 	}
 }
 
+function intPostVar($name) {
+	return intval(postVar($name) );
+}
+
+function intGetVar($name) {
+	return intval(getVar($name) );
+}
+
+function intRequestVar($name) {
+	return intval(requestVar($name) );
+}
+
+function intCookieVar($name) {
+	return intval(cookieVar($name) );
+}
+
+/**
+  * returns the currently used version (100 = 1.00, 101 = 1.01, etc...)
+  */
+function getNucleusVersion() {
+	return 331;
+}
+
+/**
+ * power users can install patches in between nucleus releases. These patches
+ * usually add new functionality in the plugin API and allow those to
+ * be tested without having to install CVS.
+ */
+function getNucleusPatchLevel() {
+	return 0;
+}
+
 /**
   * Connects to mysql server
   */
 function sql_connect() {
-	global $MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD, $MYSQL_DATABASE;
+	global $MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD, $MYSQL_DATABASE, $MYSQL_CONN;
 
-	$connection = @mysql_connect($MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD) or startUpError('<p>Could not connect to MySQL database.</p>','Connect Error');
-	mysql_select_db($MYSQL_DATABASE) or startUpError('<p>Could not select database: '. mysql_error().'</p>', 'Connect Error');
+	$MYSQL_CONN = @mysql_connect($MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD) or startUpError('<p>Could not connect to MySQL database.</p>', 'Connect Error');
+	mysql_select_db($MYSQL_DATABASE) or startUpError('<p>Could not select database: ' . mysql_error() . '</p>', 'Connect Error');
 
-	return $connection;
+	return $MYSQL_CONN;
 }
 
 /**
  * returns a prefixed nucleus table name
  */
-function sql_table($name)
-{
+function sql_table($name) {
 	global $MYSQL_PREFIX;
 
-	if ($MYSQL_PREFIX)
+	if ($MYSQL_PREFIX) {
 		return $MYSQL_PREFIX . 'nucleus_' . $name;
-	else
+	} else {
 		return 'nucleus_' . $name;
+	}
 }
 
 function sendContentType($contenttype, $pagetype = '', $charset = _CHARSET) {
 	global $manager, $CONF;
-	
-	if (!headers_sent()) {
+
+	if (!headers_sent() ) {
 		// if content type is application/xhtml+xml, only send it to browsers
 		// that can handle it (IE6 cannot). Otherwise, send text/html
-		
+
 		// v2.5: For admin area pages, keep sending text/html (unless it's a debug version)
 		//       application/xhtml+xml still causes too much problems with the javascript implementations
+
+		// v3.3: ($CONF['UsingAdminArea'] && !$CONF['debug']) gets removed,
+		//       application/xhtml+xml seems to be working, so we're going to use it if we can.
 		if (
 				($contenttype == 'application/xhtml+xml')
-			&&	(($CONF['UsingAdminArea'] && !$CONF['debug']) || !stristr(serverVar('HTTP_ACCEPT'),'application/xhtml+xml'))
-			)
-		{
+			&&	(!stristr(serverVar('HTTP_ACCEPT'), 'application/xhtml+xml') )
+			) {
 			$contenttype = 'text/html';
 		}
-			
+
 		$manager->notify(
 			'PreSendContentType',
 			array(
@@ -381,16 +531,13 @@
 		// strip strange characters
 		$contenttype = preg_replace('|[^a-z0-9-+./]|i', '', $contenttype);
 		$charset = preg_replace('|[^a-z0-9-_]|i', '', $charset);
-		
-		if ($charset != '')
-			header('Content-Type: ' . $contenttype . '; charset=' . $charset);			
-		else
-			header('Content-Type: ' . $contenttype);			
-	}
-	
-	
 
-	
+		if ($charset != '') {
+			header('Content-Type: ' . $contenttype . '; charset=' . $charset);
+		} else {
+			header('Content-Type: ' . $contenttype);
+		}
+	}
 }
 
 /**
@@ -419,6 +566,8 @@
   * executes an SQL query
   */
 function sql_query($query) {
+	global $SQLCount;
+	$SQLCount++;
 	$res = mysql_query($query) or print("mySQL error with query $query: " . mysql_error() . '<p />');
 	return $res;
 }
@@ -436,12 +585,16 @@
  *
  */
 function highlight($text, $expression, $highlight) {
-	if (!$highlight || !$expression) return $text;
-	if (is_array($expression) && (count($expression) == 0))
+	if (!$highlight || !$expression) {
 		return $text;
+	}
+
+	if (is_array($expression) && (count($expression) == 0) ) {
+		return $text;
+	}
 
 	// add a tag in front (is needed for preg_match_all to work correct)
-	$text = '<!--h-->'.$text;
+	$text = '<!--h-->' . $text;
 
 	// split the HTML up so we have HTML tags
 	// $matches[0][i] = HTML + text
@@ -452,15 +605,20 @@
 	// throw it all together again while applying the highlight to the text pieces
 	$result = '';
 	for ($i = 0; $i < sizeof($matches[2]); $i++) {
-		if ($i != 0) $result .= $matches[1][$i];
+		if ($i != 0) {
+			$result .= $matches[1][$i];
+		}
+
+		if (is_array($expression) ) {
+			foreach ($expression as $regex) {
+				if ($regex) {
+					$matches[2][$i] = @eregi_replace($regex, $highlight, $matches[2][$i]);
+				}
+			}
 
-		if (is_array($expression)) {
-			foreach ($expression as $regex)
-				if ($regex)
-					$matches[2][$i] = @eregi_replace($regex,$highlight,$matches[2][$i]);
 			$result .= $matches[2][$i];
 		} else {
-			$result .= @eregi_replace($expression,$highlight,$matches[2][$i]);
+			$result .= @eregi_replace($expression, $highlight, $matches[2][$i]);
 		}
 	}
 
@@ -474,54 +632,66 @@
 	// TODO: add more intelligent splitting logic
 
 	// get rid of quotes
-	$query = preg_replace('/\'|"/','',$query);
+	$query = preg_replace('/\'|"/', '', $query);
 
-	if (!query) return array();
+	if (!query) {
+		return array();
+	}
 
 	$aHighlight = explode(' ', $query);
 
-	for ($i = 0; $i<count($aHighlight); $i++) {
+	for ($i = 0; $i < count($aHighlight); $i++) {
 		$aHighlight[$i] = trim($aHighlight[$i]);
-		if (strlen($aHighlight[$i]) < 3)
+
+		if (strlen($aHighlight[$i]) < 3) {
 			unset($aHighlight[$i]);
+		}
 	}
 
-	if (count($aHighlight) == 1)
+	if (count($aHighlight) == 1) {
 		return $aHighlight[0];
-	else
+	} else {
 		return $aHighlight;
+	}
 }
 
 /**
   * Checks if email address is valid
   */
 function isValidMailAddress($address) {
-	if (preg_match('/^[a-zA-Z0-9\._-]+@[a-zA-Z0-9\._-]+\.[A-Za-z]{2,5}$/', $address))
+	if (preg_match('/^[a-zA-Z+0-9\._-]+@[a-zA-Z0-9\._-]+\.[A-Za-z]{2,5}$/', $address)) {
 		return 1;
-	else
+	} else {
 		return 0;
+	}
 }
 
 
 // some helper functions
 function getBlogIDFromName($name) {
-	return quickQuery('SELECT bnumber as result FROM '.sql_table('blog').' WHERE bshortname="'.addslashes($name).'"');
+	return quickQuery('SELECT bnumber as result FROM ' . sql_table('blog') . ' WHERE bshortname="' . addslashes($name) . '"');
 }
+
 function getBlogNameFromID($id) {
-	return quickQuery('SELECT bname as result FROM '.sql_table('blog').' WHERE bnumber='.intval($id));
+	return quickQuery('SELECT bname as result FROM ' . sql_table('blog') . ' WHERE bnumber=' . intval($id) );
 }
+
 function getBlogIDFromItemID($itemid) {
-	return quickQuery('SELECT iblog as result FROM '.sql_table('item').' WHERE inumber='.intval($itemid));
+	return quickQuery('SELECT iblog as result FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid) );
 }
+
 function getBlogIDFromCommentID($commentid) {
-	return quickQuery('SELECT cblog as result FROM '.sql_table('comment').' WHERE cnumber='.intval($commentid));
+	return quickQuery('SELECT cblog as result FROM ' . sql_table('comment') . ' WHERE cnumber=' . intval($commentid) );
 }
+
 function getBlogIDFromCatID($catid) {
-	return quickQuery('SELECT cblog as result FROM '.sql_table('category').' WHERE catid='.intval($catid));
+	return quickQuery('SELECT cblog as result FROM ' . sql_table('category') . ' WHERE catid=' . intval($catid) );
 }
+
 function getCatIDFromName($name) {
-	return quickQuery('SELECT catid as result FROM '.sql_table('category').' WHERE cname="'.addslashes($name).'"');
+	return quickQuery('SELECT catid as result FROM ' . sql_table('category') . ' WHERE cname="' . addslashes($name) . '"');
 }
+
 function quickQuery($q) {
 	$res = sql_query($q);
 	$obj = mysql_fetch_object($res);
@@ -529,7 +699,8 @@
 }
 
 function getPluginNameFromPid($pid) {
-	$obj = mysql_fetch_object(sql_query('SELECT pfile FROM '.sql_table('plugin').' WHERE pid='.intval($pid)));
+	$res = sql_query('SELECT pfile FROM ' . sql_table('plugin') . ' WHERE pid=' . intval($pid) );
+	$obj = mysql_fetch_object($res);
 	return $obj->pfile;
 }
 
@@ -541,30 +712,31 @@
 
 	$actionNames = array('addcomment', 'sendmessage', 'createaccount', 'forgotpassword', 'votepositive', 'votenegative', 'plugin');
 	$action = requestVar('action');
-	if (in_array($action, $actionNames))
-	{
+
+	if (in_array($action, $actionNames) ) {
 		global $DIR_LIBS, $errormessage;
 		include_once($DIR_LIBS . 'ACTION.php');
-		$a =& new ACTION();
+		$a = new ACTION();
 		$errorInfo = $a->doAction($action);
-		if ($errorInfo)
+
+		if ($errorInfo) {
 			$errormessage = $errorInfo['message'];
-	}	
+		}
+	}
 
 	// show error when headers already sent out
 	if (headers_sent() && $CONF['alertOnHeadersSent']) {
 
 		// try to get line number/filename (extra headers_sent params only exists in PHP 4.3+)
-		if (function_exists('version_compare') && version_compare('4.3.0', phpversion(), '<=')) {
+		if (function_exists('version_compare') && version_compare('4.3.0', phpversion(), '<=') ) {
 			headers_sent($hsFile, $hsLine);
-			$extraInfo = ' in <code>'.$hsFile.'</code> line <code>'.$hsLine.'</code>';
+			$extraInfo = ' in <code>' . $hsFile . '</code> line <code>' . $hsLine . '</code>';
 		} else {
 			$extraInfo = '';
 		}
 
-
 		startUpError(
-			'<p>The page headers have already been sent out'.$extraInfo.'. This could cause Nucleus not to work in the expected way.</p><p>Usually, this is caused by spaces or newlines at the end of the <code>config.php</code> file, at the end of the language file or at the end of a plugin file. Please check this and try again.</p><p>If you don\'t want to see this error message again, without solving the problem, set <code>$CONF[\'alertOnHeadersSent\']</code> in <code>globalfunctions.php</code> to <code>0</code></p>',
+			'<p>The page headers have already been sent out' . $extraInfo . '. This could cause Nucleus not to work in the expected way.</p><p>Usually, this is caused by spaces or newlines at the end of the <code>config.php</code> file, at the end of the language file or at the end of a plugin file. Please check this and try again.</p><p>If you don\'t want to see this error message again, without solving the problem, set <code>$CONF[\'alertOnHeadersSent\']</code> in <code>globalfunctions.php</code> to <code>0</code></p>',
 			'Page headers already sent'
 		);
 		exit;
@@ -572,33 +744,35 @@
 
 	// make is so ?archivelist without blogname or blogid shows the archivelist
 	// for the default weblog
-	if (serverVar('QUERY_STRING') == 'archivelist')
+	if (serverVar('QUERY_STRING') == 'archivelist') {
 		$archivelist = $CONF['DefaultBlog'];
+	}
 
 	// now decide which type of skin we need
 	if ($itemid) {
 		// itemid given -> only show that item
 		$type = 'item';
-		if (!$manager->existsItem($itemid,0,0))
-			doError(_ERROR_NOSUCHITEM);
 
+		if (!$manager->existsItem($itemid,0,0) ) {
+			doError(_ERROR_NOSUCHITEM);
+		}
 
 		global $itemidprev, $itemidnext, $catid, $itemtitlenext, $itemtitleprev;
 
 		// 1. get timestamp, blogid and catid for item
-		$query = 'SELECT itime, iblog, icat FROM '.sql_table('item').' WHERE inumber=' . intval($itemid);
+		$query = 'SELECT itime, iblog, icat FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid);
 		$res = sql_query($query);
 		$obj = mysql_fetch_object($res);
 
 		// if a different blog id has been set through the request or selectBlog(),
 		// deny access
-		if ($blogid && (intval($blogid) != $obj->iblog))
+		if ($blogid && (intval($blogid) != $obj->iblog) ) {
 			doError(_ERROR_NOSUCHITEM);
+		}
 
-		// if a category has been selected which doesn't match the item, ignore the 
+		// if a category has been selected which doesn't match the item, ignore the
 		// category. #85
-		if (($catid != 0) && ($catid != $obj->icat))
-		{
+		if (($catid != 0) && ($catid != $obj->icat) ) {
 			$catid = 0;
 		}
 
@@ -606,24 +780,28 @@
 		$timestamp = strtotime($obj->itime);
 
 		$b =& $manager->getBlog($blogid);
-		if ($b->isValidCategory($catid))
+
+		if ($b->isValidCategory($catid) ) {
 			$catextra = ' and icat=' . $catid;
+		}
 
 		// get previous itemid and title
-		$query = 'SELECT inumber, ititle FROM '.sql_table('item').' WHERE itime<' . mysqldate($timestamp) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime DESC LIMIT 1';
+		$query = 'SELECT inumber, ititle FROM ' . sql_table('item') . ' WHERE itime<' . mysqldate($timestamp) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime DESC LIMIT 1';
 		$res = sql_query($query);
 
 		$obj = mysql_fetch_object($res);
+
 		if ($obj) {
 			$itemidprev = $obj->inumber;
 			$itemtitleprev = $obj->ititle;
-    	}
+		}
 
 		// get next itemid and title
-		$query = 'SELECT inumber, ititle FROM '.sql_table('item').' WHERE itime>' . mysqldate($timestamp) . ' and itime <= ' . mysqldate($b->getCorrectTime()) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime ASC LIMIT 1';
+		$query = 'SELECT inumber, ititle FROM ' . sql_table('item') . ' WHERE itime>' . mysqldate($timestamp) . ' and itime <= ' . mysqldate($b->getCorrectTime()) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime ASC LIMIT 1';
 		$res = sql_query($query);
 
 		$obj = mysql_fetch_object($res);
+
 		if ($obj) {
 			$itemidnext = $obj->inumber;
 			$itemtitlenext = $obj->ititle;
@@ -633,43 +811,99 @@
 		// show archive
 		$type = 'archive';
 
-		// get next and prev month links
-		global $archivenext, $archiveprev, $archivetype;
+		// get next and prev month links ...
+		global $archivenext, $archiveprev, $archivetype, $archivenextexists, $archiveprevexists;
+		
+		// sql queries for the timestamp of the first and the last published item
+		$query = "SELECT UNIX_TIMESTAMP(itime) as result FROM ".sql_table('item')." WHERE idraft=0 ORDER BY itime ASC";
+		$first_timestamp=quickQuery ($query); 
+		$query = "SELECT UNIX_TIMESTAMP(itime) as result FROM ".sql_table('item')." WHERE idraft=0 ORDER BY itime DESC";
+		$last_timestamp=quickQuery ($query); 
+
+		sscanf($archive, '%d-%d-%d', $y, $m, $d);
 
-		sscanf($archive,'%d-%d-%d',$y,$m,$d);
 		if ($d != 0) {
 			$archivetype = _ARCHIVETYPE_DAY;
-			$t = mktime(0,0,0,$m,$d,$y);
-			$archiveprev = strftime('%Y-%m-%d',$t - (24*60*60));
-			$archivenext = strftime('%Y-%m-%d',$t + (24*60*60));
-
+			$t = mktime(0, 0, 0, $m, $d, $y);
+			// one day has 24 * 60 * 60 = 86400 seconds			
+			$archiveprev = strftime('%Y-%m-%d', $t - 86400 );
+			// check for published items			
+			if ($t > $first_timestamp) {
+				$archiveprevexists = true;
+			}
+			else {
+				$archiveprevexists = false;
+			}
+			
+			// one day later
+			$t += 86400; 
+			$archivenext = strftime('%Y-%m-%d', $t);
+			if ($t < $last_timestamp) {
+				$archivenextexists = true;
+			}
+			else {
+				$archivenextexists = false;
+			}
+			
 		} else {
 			$archivetype = _ARCHIVETYPE_MONTH;
-			$t = mktime(0,0,0,$m,1,$y);
-			$archiveprev = strftime('%Y-%m',$t - (1*24*60*60));
-			$archivenext = strftime('%Y-%m',$t + (32*24*60*60));
+			$t = mktime(0, 0, 0, $m, 1, $y);
+			// one day before is in the previous month
+			$archiveprev = strftime('%Y-%m', $t - 86400);
+			if ($t > $first_timestamp) {
+				$archiveprevexists = true;
+			}
+			else {
+				$archiveprevexists = false;
+			}
+			
+			// timestamp for the next month			
+			$t = mktime(0, 0, 0, $m+1, 1, $y);
+			$archivenext = strftime('%Y-%m', $t);
+			if ($t < $last_timestamp) {
+				$archivenextexists = true;
+			}
+			else {
+				$archivenextexists = false;
+			}
 		}
 
-
 	} elseif ($archivelist) {
 		$type = 'archivelist';
-		if (intval($archivelist) != 0)
-			$blogid = $archivelist;
-		else
+
+		if (is_numeric($archivelist)) {
+			$blogid = intVal($archivelist);
+		} else {
 			$blogid = getBlogIDFromName($archivelist);
-		if (!$blogid) doError(_ERROR_NOSUCHBLOG);
+		}
+
+		if (!$blogid) {
+			doError(_ERROR_NOSUCHBLOG);
+		}
+
 	} elseif ($query) {
-	    global $startpos;
+		global $startpos;
 		$type = 'search';
 		$query = stripslashes($query);
-		if (intval($blogid)==0)
+
+		if (is_numeric($blogid)) {
+			$blogid = intVal($blogid);
+		} else {
 			$blogid = getBlogIDFromName($blogid);
-		if (!$blogid) doError(_ERROR_NOSUCHBLOG);
+		}
+
+		if (!$blogid) {
+			doError(_ERROR_NOSUCHBLOG);
+		}
+
 	} elseif ($memberid) {
 		$type = 'member';
-		if (!MEMBER::existsID($memberid))
+
+		if (!MEMBER::existsID($memberid) ) {
 			doError(_ERROR_NOSUCHMEMBER);
-		$memberinfo = MEMBER::createFromID($memberid);
+		}
+
+		$memberinfo = $manager->getMember($memberid);
 
 	} elseif ($imagepopup) {
 		// media object (images etc.)
@@ -679,36 +913,52 @@
 		// TODO: set some vars?
 	} else {
 		// show regular index page
-	    global $startpos;
+		global $startpos;
 		$type = 'index';
 	}
 
 	// decide which blog should be displayed
-	if (!$blogid)
+	if (!$blogid) {
 		$blogid = $CONF['DefaultBlog'];
+	}
 
 	$b =& $manager->getBlog($blogid);
 	$blog = $b;	// references can't be placed in global variables?
-	if (!$blog->isValid)
+
+	if (!$blog->isValid) {
 		doError(_ERROR_NOSUCHBLOG);
+	}
 
 	// set catid if necessary
-	if ($catid)
+	if ($catid) {
 		$blog->setSelectedCategory($catid);
+	}
 
 	// decide which skin should be used
-	if ($skinid != '' && ($skinid == 0))
+	if ($skinid != '' && ($skinid == 0) ) {
 		selectSkin($skinid);
-	if (!$skinid)
+	}
+
+	if (!$skinid) {
 		$skinid = $blog->getDefaultSkin();
+	}
 
-	
-	$skin =& new SKIN($skinid);
-	if (!$skin->isValid)
+	$special = requestVar('special');
+	if (!empty($special) && isValidShortName($special)) {
+		$type = strtolower($special);
+	}
+
+	$skin = new SKIN($skinid);
+
+	if (!$skin->isValid) {
 		doError(_ERROR_NOSUCHSKIN);
+	}
 
 	// parse the skin
 	$skin->parse($type);
+
+	// check to see we should throw JustPosted event
+	$blog->checkJustPosted();
 }
 
 /**
@@ -718,18 +968,20 @@
 	global $errormessage, $CONF, $skinid, $blogid, $manager;
 
 	if ($skin == '') {
-		if (SKIN::existsID($skinid)) {
-			$skin =& new SKIN($skinid);
-		} elseif ($manager->existsBlogID($blogid)) {
+
+		if (SKIN::existsID($skinid) ) {
+			$skin = new SKIN($skinid);
+		} elseif ($manager->existsBlogID($blogid) ) {
 			$blog =& $manager->getBlog($blogid);
-			$skin =& new SKIN($blog->getDefaultSkin());
+			$skin = new SKIN($blog->getDefaultSkin() );
 		} elseif ($CONF['DefaultBlog']) {
 			$blog =& $manager->getBlog($CONF['DefaultBlog']);
-			$skin =& new SKIN($blog->getDefaultSkin());
+			$skin = new SKIN($blog->getDefaultSkin() );
 		} else {
 			// this statement should actually never be executed
-			$skin =& new SKIN($CONF['BaseSkin']);
+			$skin = new SKIN($CONF['BaseSkin']);
 		}
+
 	}
 
 	$errormessage = $msg;
@@ -740,23 +992,43 @@
 function getConfig() {
 	global $CONF;
 
-	$query = 'SELECT * FROM '.sql_table('config');
+	$query = 'SELECT * FROM ' . sql_table('config');
 	$res = sql_query($query);
-	while ($obj = mysql_fetch_object($res)) {
+
+	while ($obj = mysql_fetch_object($res) ) {
 		$CONF[$obj->name] = $obj->value;
 	}
 }
 
 // some checks for names of blogs, categories, templates, members, ...
-function isValidShortName($name) {		return eregi('^[a-z0-9]+$', $name); }
-function isValidDisplayName($name) {	return eregi('^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$', $name); }
-function isValidCategoryName($name) {	return 1; } 
-function isValidTemplateName($name) {	return eregi('^[a-z0-9/]+$', $name); }
-function isValidSkinName($name) {		return eregi('^[a-z0-9/]+$', $name); }
+function isValidShortName($name) {
+	return eregi('^[a-z0-9]+$', $name);
+}
+
+function isValidDisplayName($name) {
+	return eregi('^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$', $name);
+}
+
+function isValidCategoryName($name) {
+	return 1;
+}
+
+function isValidTemplateName($name) {
+	return eregi('^[a-z0-9/]+$', $name);
+}
+
+function isValidSkinName($name) {
+	return eregi('^[a-z0-9/]+$', $name);
+}
 
 // add and remove linebreaks
-function addBreaks($var) { 				return nl2br($var); }
-function removeBreaks($var) {			return preg_replace("/<br \/>([\r\n])/","$1",$var); }
+function addBreaks($var) {
+	return nl2br($var);
+}
+
+function removeBreaks($var) {
+	return preg_replace("/<br \/>([\r\n])/", "$1", $var);
+}
 
 // shortens a text string to maxlength ($toadd) is what needs to be added
 // at the end (end length is <= $maxlength)
@@ -765,9 +1037,12 @@
 	$trans = get_html_translation_table(HTML_ENTITIES);
 	$trans = array_flip($trans);
 	$text = strtr($text, $trans);
+
 	// 2. the actual shortening
-	if (strlen($text) > $maxlength)
-		$text = substr($text,0,$maxlength-strlen($toadd)) . $toadd;
+	if (strlen($text) > $maxlength) {
+		$text = substr($text, 0, $maxlength - strlen($toadd) ) . $toadd;
+	}
+
 	return $text;
 }
 
@@ -776,7 +1051,7 @@
   * quotes around it.
   */
 function mysqldate($timestamp) {
-	return '"' . date('Y-m-d H:i:s',$timestamp) . '"';
+	return '"' . date('Y-m-d H:i:s', $timestamp) . '"';
 }
 
 /**
@@ -787,8 +1062,9 @@
 	$blogid = getBlogIDFromName($shortname);
 
 	// also force archivelist variable, if it is set
-	if ($archivelist)
+	if ($archivelist) {
 		$archivelist = $blogid;
+	}
 }
 
 function selectSkin($skinname) {
@@ -802,13 +1078,14 @@
  */
 function selectCategory($cat) {
 	global $catid;
-	if (is_numeric($cat))
+	if (is_numeric($cat) ) {
 		$catid = intval($cat);
-	else
+	} else {
 		$catid = getCatIDFromName($cat);
+	}
 }
 
-function selectItem($id){
+function selectItem($id) {
 	global $itemid;
 	$itemid = intval($id);
 }
@@ -819,16 +1096,24 @@
 	include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
 }
 
-function parseFile($filename) {
-	$handler =& new ACTIONS('fileparser');
-	$parser =& new PARSER(SKIN::getAllowedActionsForType('fileparser'), $handler);
+function parseFile($filename, $includeMode = 'normal', $includePrefix = '') {
+	$handler = new ACTIONS('fileparser');
+	$parser = new PARSER(SKIN::getAllowedActionsForType('fileparser'), $handler);
 	$handler->parser =& $parser;
 
-	if (!file_exists($filename)) doError('A file is missing');
+	// set IncludeMode properties of parser
+	PARSER::setProperty('IncludeMode', $includeMode);
+	PARSER::setProperty('IncludePrefix', $includePrefix);
+
+	if (!file_exists($filename) ) {
+		doError('A file is missing');
+	}
 
 	$fsize = filesize($filename);
-	if ($fsize <= 0)
+
+	if ($fsize <= 0) {
 		return;
+	}
 
 	// read file
 	$fd = fopen ($filename, 'r');
@@ -847,7 +1132,9 @@
 }
 
 // shortcut
-function addToLog($level, $msg) { ACTIONLOG::add($level, $msg); }
+function addToLog($level, $msg) {
+	ACTIONLOG::add($level, $msg);
+}
 
 // shows a link to help file
 function help($id) {
@@ -855,7 +1142,7 @@
 }
 
 function helpHtml($id) {
-	return helplink($id) . '<img src="documentation/icon-help.gif" width="15" height="15" alt="'._HELP_TT.'" /></a>';
+	return helplink($id) . '<img src="documentation/icon-help.gif" width="15" height="15" alt="' . _HELP_TT . '" /></a>';
 }
 
 function helplink($id) {
@@ -879,19 +1166,21 @@
 function getLanguageName() {
 	global $CONF, $member;
 
-	if ($member && $member->isLoggedIn()) {
+	if ($member && $member->isLoggedIn() ) {
 		// try to use members language
 		$memlang = $member->getLanguage();
 
-		if (($memlang != '') && (checkLanguage($memlang)))
+		if (($memlang != '') && (checkLanguage($memlang) ) ) {
 			return $memlang;
+		}
 	}
 
 	// use default language
-	if (checkLanguage($CONF['Language']))
+	if (checkLanguage($CONF['Language']) ) {
 		return $CONF['Language'];
-	else
+	} else {
 		return 'english';
+	}
 }
 
 /**
@@ -916,7 +1205,9 @@
 	// other
 	global $PATH_INFO, $HTTPS, $HTTP_RAW_POST_DATA, $HTTP_X_FORWARDED_FOR;
 
-	if (@file_exists($filename)) include($filename);
+	if (@file_exists($filename) ) {
+		include($filename);
+	}
 }
 
 /**
@@ -926,62 +1217,49 @@
 	global $DIR_LANG ;
 	return file_exists($DIR_LANG . ereg_replace( '[\\|/]', '', $lang) . '.php');
 }
+
 function checkPlugin($plug) {
 	global $DIR_PLUGINS;
 	return file_exists($DIR_PLUGINS . ereg_replace( '[\\|/]', '', $plug) . '.php');
 }
 
-
-$CONF['ItemURL'] = $CONF['Self'];
-$CONF['ArchiveURL'] = $CONF['Self'];
-$CONF['ArchiveListURL'] = $CONF['Self'];
-$CONF['MemberURL'] = $CONF['Self'];
-$CONF['SearchURL'] = $CONF['Self'];
-$CONF['BlogURL'] = $CONF['Self'];
-$CONF['CategoryURL'] = $CONF['Self'];
-
-// switch URLMode back to normal when $CONF['Self'] ends in .php
-// this avoids urls like index.php/item/13/index.php/item/15
-if (	($CONF['URLMode'] == 'pathinfo')
-	&&	(substr($CONF['Self'], strlen($CONF['Self']) - 4) == '.php')
-	) {
-	$CONF['URLMode'] = 'normal';
-}
-
 /**
   * Centralisation of the functions that generate links
   */
 function createItemLink($itemid, $extra = '') {
-	return createLink('item', array('itemid' => $itemid));
+	return createLink('item', array('itemid' => $itemid, 'extra' => $extra) );
 }
+
 function createMemberLink($memberid, $extra = '') {
-	return createLink('member', array('memberid' => $memberid));
+	return createLink('member', array('memberid' => $memberid, 'extra' => $extra) );
 }
+
 function createCategoryLink($catid, $extra = '') {
-	return createLink('category', array('catid' => $catid, 'extra' => $extra));
+	return createLink('category', array('catid' => $catid, 'extra' => $extra) );
 }
+
 function createArchiveListLink($blogid = '', $extra = '') {
-	return createLink('archivelist', array('blogid' => $blogid, 'extra' => $extra));
+	return createLink('archivelist', array('blogid' => $blogid, 'extra' => $extra) );
 }
+
 function createArchiveLink($blogid, $archive, $extra = '') {
-	return createLink('archive', array('blogid' => $blogid, 'archive' => $archive, 'extra' => $extra));
+	return createLink('archive', array('blogid' => $blogid, 'archive' => $archive, 'extra' => $extra) );
 }
+
 function createBlogidLink($blogid, $params = '') {
-	return createLink('blog', array('blogid' => $blogid, 'extra' => $params));
+	return createLink('blog', array('blogid' => $blogid, 'extra' => $params) );
 }
 
-function createLink($type, $params)
-{
+function createLink($type, $params) {
 	global $manager, $CONF;
-	
+
 	$generatedURL = '';
 	$usePathInfo = ($CONF['URLMode'] == 'pathinfo');
-	
+
 	// ask plugins first
 	$created = false;
-	
-	if ($usePathInfo)
-	{
+
+	if ($usePathInfo) {
 		$manager->notify(
 			'GenerateURL',
 			array(
@@ -991,74 +1269,106 @@
 				'url' => &$url
 			)
 		);
-	} 
-	
+	}
+
 	// if a plugin created the URL, return it
-	if ($created)
+	if ($created) {
 		return $url;
-		
+	}
+
 	// default implementation
-	switch ($type)
-	{
+	switch ($type) {
 		case 'item':
-			if ($usePathInfo)
+			if ($usePathInfo) {
 				$url = $CONF['ItemURL'] . '/' . $CONF['ItemKey'] . '/' . $params['itemid'];
-			else
+			} else {
 				$url = $CONF['ItemURL'] . '?itemid=' . $params['itemid'];
+			}
 			break;
+
 		case 'member':
-			if ($usePathInfo)
+			if ($usePathInfo) {
 				$url = $CONF['MemberURL'] . '/' . $CONF['MemberKey'] . '/' . $params['memberid'];
-			else
+			} else {
 				$url = $CONF['MemberURL'] . '?memberid=' . $params['memberid'];
+			}
 			break;
+
 		case 'category':
-			if ($usePathInfo)
+			if ($usePathInfo) {
 				$url = $CONF['CategoryURL'] . '/' . $CONF['CategoryKey'] . '/' . $params['catid'];
-			else
+			} else {
 				$url = $CONF['CategoryURL'] . '?catid=' . $params['catid'];
+			}
 			break;
+
 		case 'archivelist':
-			if (!$params['blogid'])
+			if (!$params['blogid']) {
 				$params['blogid'] = $CONF['DefaultBlog'];
-			if ($usePathInfo)
+			}
+
+			if ($usePathInfo) {
 				$url = $CONF['ArchiveListURL'] . '/' . $CONF['ArchivesKey'] . '/' . $params['blogid'];
-			else
+			} else {
 				$url = $CONF['ArchiveListURL'] . '?archivelist=' . $params['blogid'];
+			}
 			break;
+
 		case 'archive':
-			if ($usePathInfo)
+			if ($usePathInfo) {
 				$url = $CONF['ArchiveURL'] . '/' . $CONF['ArchiveKey'] . '/'.$params['blogid'].'/' . $params['archive'];
-			else
+			} else {
 				$url = $CONF['ArchiveURL'] . '?blogid='.$params['blogid'].'&amp;archive=' . $params['archive'];
+			}
 			break;
+
 		case 'blog':
-			if ($usePathInfo)
+			if ($usePathInfo) {
 				$url = $CONF['BlogURL'] . '/' . $CONF['BlogKey'] . '/' . $params['blogid'];
-			else
+			} else {
 				$url = $CONF['BlogURL'] . '?blogid=' . $params['blogid'];
+			}
 			break;
-	}	
-	
-	return addLinkParams($url, $params['extra']);
+	}
+
+	return addLinkParams($url, (isset($params['extra'])? $params['extra'] : null));
 }
+
 function createBlogLink($url, $params) {
-	return addLinkParams($url . '?', $params);
+    global $CONF;
+    if ($CONF['URLMode'] == 'normal') {
+        if (strpos($url, '?') === FALSE && is_array($params)) {
+            $fParam = reset($params);
+            $fKey   = key($params);
+            array_shift($params);
+            $url .= '?' . $fKey . '=' . $fParam;
+        }
+    } elseif ($CONF['URLMode'] == 'pathinfo' && substr($url, -1) == '/') {
+        $url = substr($url, 0, -1);
+    }
+	return addLinkParams($url, $params);
 }
 
 function addLinkParams($link, $params) {
 	global $CONF;
-	if (is_array($params)) {
+
+	if (is_array($params) ) {
+
 		if ($CONF['URLMode'] == 'pathinfo')	{
+
 			foreach ($params as $param => $value) {
 				$link .= '/' . $param . '/' . urlencode($value);
 			}
+
 		} else {
+
 			foreach ($params as $param => $value) {
 				$link .= '&amp;' . $param . '=' . urlencode($value);
 			}
+
 		}
 	}
+
 	return $link;
 }
 
@@ -1069,108 +1379,435 @@
  *		name of parameter to change (e.g. 'foo')
  * @param $value
  *		New value for that parameter (e.g. 3)
- * @result 
+ * @result
  *		altered query string (for the examples above: foo=3&bar=2&x=y)
  */
 function alterQueryStr($querystr, $param, $value) {
-    $vars = explode("&", $querystr);
-    $set  = false;
-    for ($i=0;$i<count($vars);$i++) {
-        $v = explode('=',$vars[$i]);
-        if ($v[0] == $param) {
-            $v[1]     = $value;
-            $vars[$i] = implode('=', $v);
-            $set      = true;
-            break;
-        }
-    }
-    if (!$set) {$vars[] = $param . '=' . $value;}
-    return ltrim(implode('&', $vars), '&');
+	$vars = explode('&', $querystr);
+	$set  = false;
+
+	for ($i = 0; $i < count($vars); $i++) {
+		$v = explode('=', $vars[$i]);
+
+		if ($v[0] == $param) {
+			$v[1] = $value;
+			$vars[$i] = implode('=', $v);
+			$set = true;
+			break;
+		}
+	}
+
+	if (!$set) {
+		$vars[] = $param . '=' . $value;
+	}
+
+	return ltrim(implode('&', $vars), '&');
 }
 
 // passes one variable as hidden input field (multiple fields for arrays)
 // @see passRequestVars in varsx.x.x.php
 function passVar($key, $value) {
 	// array ?
-	if (is_array($value)) {
-		for ($i=0;$i<sizeof($value);$i++)
-			passVar($key.'['.$i.']',$value[$i]);
-			return;
+	if (is_array($value) ) {
+		for ($i = 0; $i < sizeof($value); $i++) {
+			passVar($key . '[' . $i . ']', $value[$i]);
+		}
+
+		return;
 	}
 
 	// other values: do stripslashes if needed
-	?><input type="hidden" name="<?php echo htmlspecialchars($key)?>" value="<?php echo htmlspecialchars(undoMagic($value))?>" /><?php
+	?><input type="hidden" name="<?php echo htmlspecialchars($key)?>" value="<?php echo htmlspecialchars(undoMagic($value) )?>" /><?php
 }
 
 /*
 	Date format functions (to be used from [%date(..)%] skinvars
 */
-function formatDate($format, $timestamp, $defaultFormat, &$blog) 
-{
+function formatDate($format, $timestamp, $defaultFormat, &$blog) {
 	// apply blog offset (#42)
 	$boffset = $blog ? $blog->getTimeOffset() * 3600 : 0;
 	$offset = date('Z', $timestamp) + $boffset;
 
 	switch ($format) {
-		case 'rfc822' :
-			if ($offset >= 0) $tz = '+';
-		else            { $tz = '-'; $offset = -$offset;}
-			$tz .= sprintf("%02d%02d",floor($offset / 3600),round(($offset % 3600)/60));
+		case 'rfc822':
+			if ($offset >= 0) {
+				$tz = '+';
+			} else {
+				$tz = '-';
+				$offset = -$offset;
+			}
+
+			$tz .= sprintf("%02d%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
 			return date('D, j M Y H:i:s ', $timestamp) . $tz;
-		case 'rfc822GMT' :
+
+		case 'rfc822GMT':
 			$timestamp -= $offset;
 			return date('D, j M Y H:i:s ', $timestamp) . 'GMT';
-		case 'utc' :
+
+		case 'utc':
 			$timestamp -= $offset;
 			return date('Y-m-d\TH:i:s\Z', $timestamp);
-		case 'iso8601' :
-			if ($offset >= 0) $tz = '+';
-			else            { $tz = '-'; $offset = -$offset;}
-			$tz .= sprintf("%02d:%02d",floor($offset / 3600),round(($offset % 3600)/60));
+
+		case 'iso8601':
+			if ($offset >= 0) {
+				$tz = '+';
+			} else {
+				$tz = '-';
+				$offset = -$offset;
+			}
+
+			$tz .= sprintf("%02d:%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
 			return date('Y-m-d\TH:i:s', $timestamp) . $tz;
-		default :
-		return strftime($format ? $format : $defaultFormat,$timestamp); 
-	}  
 
+		default :
+			return strftime($format ? $format : $defaultFormat, $timestamp);
+	}
 }
 
-function checkVars($aVars)
-{
+function checkVars($aVars) {
 	global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_SESSION_VARS;
-	foreach ($aVars as $varName)
-	{
-		if (phpversion() >= '4.1.0')
-		{
-			if (   isset($_GET[$varName]) 
-				|| isset($_POST[$varName]) 
+
+	foreach ($aVars as $varName) {
+
+		if (phpversion() >= '4.1.0') {
+
+			if (   isset($_GET[$varName])
+				|| isset($_POST[$varName])
 				|| isset($_COOKIE[$varName])
 				|| isset($_ENV[$varName])
 				|| isset($_SESSION[$varName])
 				|| isset($_FILES[$varName])
-			){
+			) {
 				die('Sorry. An error occurred.');
 			}
+
 		} else {
-			if (   isset($HTTP_GET_VARS[$varName]) 
-				|| isset($HTTP_POST_VARS[$varName]) 
+
+			if (   isset($HTTP_GET_VARS[$varName])
+				|| isset($HTTP_POST_VARS[$varName])
 				|| isset($HTTP_COOKIE_VARS[$varName])
 				|| isset($HTTP_ENV_VARS[$varName])
 				|| isset($HTTP_SESSION_VARS[$varName])
 				|| isset($HTTP_POST_FILES[$varName])
-			){
+			) {
 				die('Sorry. An error occurred.');
-			}		
+			}
+
 		}
 	}
 }
 
+
 /** 
+ * Sanitize parameters such as $_GET and $_SERVER['REQUEST_URI'] etc.
+ * to avoid XSS 
+ */
+function sanitizeParams()
+{
+	global $HTTP_SERVER_VARS;
+	
+	$array = array();
+	$str = '';
+	$frontParam = '';
+	
+	// REQUEST_URI of $HTTP_SERVER_VARS
+	$str =& $HTTP_SERVER_VARS["REQUEST_URI"];
+	serverStringToArray($str, $array, $frontParam);
+	sanitizeArray($array);
+	arrayToServerString($array, $frontParam, $str);
+	
+	// QUERY_STRING of $HTTP_SERVER_VARS
+	$str =& $HTTP_SERVER_VARS["QUERY_STRING"];
+	serverStringToArray($str, $array, $frontParam);
+	sanitizeArray($array);
+	arrayToServerString($array, $frontParam, $str);
+	
+	if (phpversion() >= '4.1.0') {
+		// REQUEST_URI of $_SERVER
+		$str =& $_SERVER["REQUEST_URI"];
+		serverStringToArray($str, $array, $frontParam);
+		sanitizeArray($array);
+		arrayToServerString($array, $frontParam, $str);
+	
+		// QUERY_STRING of $_SERVER
+		$str =& $_SERVER["QUERY_STRING"];
+		serverStringToArray($str, $array, $frontParam);
+		sanitizeArray($array);
+		arrayToServerString($array, $frontParam, $str);
+	}
+	
+	// $_GET
+	convArrayForSanitizing($_GET, $array);
+	sanitizeArray($array);
+	revertArrayForSanitizing($array, $_GET);
+	
+	// $_REQUEST (only GET param)
+	convArrayForSanitizing($_REQUEST, $array);
+	sanitizeArray($array);
+	revertArrayForSanitizing($array, $_REQUEST);
+}
+
+/** 
+ * Check ticket when not checked in plugin's admin page
+ * to avoid CSRF.
+ * Also avoid the access to plugin/index.php by guest user.
+ */
+function ticketForPlugin(){
+	global $CONF,$DIR_PLUGINS,$member,$ticketforplugin;
+	
+	/* initialize */
+	$ticketforplugin=array();
+	$ticketforplugin['ticket']=false;
+	
+	/* Check if using plugin's php file. */
+	if ($p_translated=serverVar('PATH_TRANSLATED')) {
+		if (!file_exists($p_translated)) $p_translated='';
+	}
+	if (!$p_translated) {
+		$p_translated=serverVar('SCRIPT_FILENAME');
+		if (!file_exists($p_translated)) {
+			header("HTTP/1.0 404 Not Found");
+			exit('');
+		}
+	}
+	$p_translated=str_replace('\\','/',$p_translated);
+	$d_plugins=str_replace('\\','/',$DIR_PLUGINS);
+	if (strpos($p_translated,$d_plugins)!==0) return;// This isn't plugin php file.
+	
+	/* Solve the plugin php file or admin directory */
+	$phppath=substr($p_translated,strlen($d_plugins));
+	$phppath=preg_replace('!^/!','',$phppath);// Remove the first "/" if exists.
+	$path=preg_replace('/^NP_(.*)\.php$/','$1',$phppath); // Remove the first "NP_" and the last ".php" if exists.
+	$path=preg_replace('!^([^/]*)/(.*)$!','$1',$path); // Remove the "/" and beyond.
+	
+	/* Solve the plugin name. */
+	$plugins=array();
+	$query='SELECT pfile FROM '.sql_table('plugin');
+	$res=sql_query($query);
+	while($row=mysql_fetch_row($res)) {
+		$name=substr($row[0],3);
+		$plugins[strtolower($name)]=$name;
+	}
+	mysql_free_result($res);
+	if ($plugins[$path]) $plugin_name=$plugins[$path];
+	else if (in_array($path,$plugins)) $plugin_name=$path;
+	else {
+		header("HTTP/1.0 404 Not Found");
+		exit('');
+	}
+	
+	/* Return if not index.php */
+	if ( $phppath!=strtolower($plugin_name).'/'
+		&& $phppath!=strtolower($plugin_name).'/index.php' ) return;
+	
+	/* Exit if not logged in. */
+	if ( !$member->isLoggedIn() ) exit("You aren't logged in.");
+	
+	global $manager,$DIR_LIBS,$DIR_LANG,$HTTP_GET_VARS,$HTTP_POST_VARS;
+	
+	/* Check if this feature is needed (ie, if "$manager->checkTicket()" is not included in the script). */
+	if (!($p_translated=serverVar('PATH_TRANSLATED'))) $p_translated=serverVar('SCRIPT_FILENAME');
+	if ($file=@file($p_translated)) {
+		$prevline='';
+		foreach($file as $line) {
+			if (preg_match('/[\$]manager([\s]*)[\-]>([\s]*)checkTicket([\s]*)[\(]/i',$prevline.$line)) return;
+			$prevline=$line;
+		}
+	}
+	
+	/* Show a form if not valid ticket */
+	if ( ( strstr(serverVar('REQUEST_URI'),'?') || serverVar('QUERY_STRING')
+			|| strtoupper(serverVar('REQUEST_METHOD'))=='POST' )
+				&& (!$manager->checkTicket()) ){
+
+		if (!class_exists('PluginAdmin')) {
+			$language = getLanguageName();
+			include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
+			include($DIR_LIBS . 'PLUGINADMIN.php');
+		}
+		if (!(function_exists('mb_strimwidth') || extension_loaded('mbstring'))) {
+			if (file_exists($DIR_LIBS.'mb_emulator/mb-emulator.php')) {
+				global $mbemu_internals;
+				include_once($DIR_LIBS.'mb_emulator/mb-emulator.php');
+			}
+		}
+		$oPluginAdmin = new PluginAdmin($plugin_name);
+		$oPluginAdmin->start();
+		echo '<p>' . _ERROR_BADTICKET . "</p>\n";
+		
+		/* Show the form to confirm action */
+		// PHP 4.0.x support
+		$get=  (isset($_GET))  ? $_GET  : $HTTP_GET_VARS;
+		$post= (isset($_POST)) ? $_POST : $HTTP_POST_VARS;
+		// Resolve URI and QUERY_STRING
+		if ($uri=serverVar('REQUEST_URI')) {
+			list($uri,$qstring)=explode('?',$uri);
+		} else {
+			if ( !($uri=serverVar('PHP_SELF')) ) $uri=serverVar('SCRIPT_NAME');
+			$qstring=serverVar('QUERY_STRING');
+		}
+		if ($qstring) $qstring='?'.$qstring;
+		echo '<p>'._SETTINGS_UPDATE.' : '._QMENU_PLUGINS.' <span style="color:red;">'.
+			htmlspecialchars($plugin_name)."</span> ?</p>\n";
+		switch(strtoupper(serverVar('REQUEST_METHOD'))){
+		case 'POST':
+			echo '<form method="POST" action="'.htmlspecialchars($uri.$qstring).'">';
+			$manager->addTicketHidden();
+			_addInputTags($post);
+			break;
+		case 'GET':
+			echo '<form method="GET" action="'.htmlspecialchars($uri).'">';
+			$manager->addTicketHidden();
+			_addInputTags($get);
+		default:
+			break;
+		}
+		echo '<input type="submit" value="'._YES.'" />&nbsp;&nbsp;&nbsp;&nbsp;';
+		echo '<input type="button" value="'._NO.'" onclick="history.back(); return false;" />';
+		echo "</form>\n";
+		
+		$oPluginAdmin->end();
+		exit;
+	}
+	
+	/* Create new ticket */
+	$ticket=$manager->addTicketToUrl('');
+	$ticketforplugin['ticket']=substr($ticket,strpos($ticket,'ticket=')+7);
+}
+function _addInputTags(&$keys,$prefix=''){
+	foreach($keys as $key=>$value){
+		if ($prefix) $key=$prefix.'['.$key.']';
+		if (is_array($value)) _addInputTags($value,$key);
+		else {
+			if (get_magic_quotes_gpc()) $value=stripslashes($value);
+			if ($key=='ticket') continue;
+			echo '<input type="hidden" name="'.htmlspecialchars($key).
+				'" value="'.htmlspecialchars($value).'" />'."\n";
+		}
+	}
+}
+
+/** 
+ * Convert the server string such as $_SERVER['REQUEST_URI']
+ * to arry like arry['blogid']=1 and array['page']=2 etc.
+ */
+function serverStringToArray($str, &$array, &$frontParam)
+{
+	// init param
+	$array = array();
+	$fronParam = "";
+
+	// split front param, e.g. /index.php, and others, e.g. blogid=1&page=2
+	if (strstr($str, "?")){
+		list($frontParam, $args) = preg_split("/\?/", $str, 2);
+	}
+	else {
+		$args = $str;
+		$frontParam = "";
+	}
+	
+	// If there is no args like blogid=1&page=2, return
+	if (!strstr($str, "=") && !strlen($frontParam)) {
+		$frontParam = $str;
+		return;
+	}
+
+	$array = explode("&", $args);
+}
+
+/** 
+ * Convert array like array['blogid'] to server string
+ * such as $_SERVER['REQUEST_URI']
+ */
+function arrayToServerString($array, $frontParam, &$str)
+{
+	if (strstr($str, "?")) {
+		$str = $frontParam . "?";
+	} else {
+		$str = $frontParam;
+	}
+	if (count($array)) {
+		$str .= implode("&", $array);
+	}
+}
+
+/** 
+ * Sanitize array parameters.
+ * This function checks both key and value.
+ * - check key if it inclues " (double quote),  remove from array
+ * - check value if it includes \ (escape sequece), remove remaining string
+ */
+function sanitizeArray(&$array)
+{	
+	$excludeListForSanitization = array('query');
+//	$excludeListForSanitization = array();
+
+	foreach ($array as $k => $v) {
+
+		// split to key and value
+		list($key, $val) = preg_split("/=/", $v, 2);
+		if (!isset($val)) {
+			continue;
+		}
+
+		// when magic quotes is on, need to use stripslashes,
+		// and then addslashes
+		if (get_magic_quotes_gpc()) {
+			$val = stripslashes($val);
+		}
+		$val = addslashes($val);
+		
+		// if $key is included in exclude list, skip this param
+		if (!in_array($key, $excludeListForSanitization)) {
+				
+			// check value
+			list($val, $tmp) = explode('\\', $val);
+			
+			// remove control code etc.
+			$val = strtr($val, "\0\r\n<>'\"", "       ");
+				
+			// check key
+			if (preg_match('/\"/i', $key)) {
+				unset($array[$k]);
+				continue;
+			}
+				
+			// set sanitized info
+			$array[$k] = sprintf("%s=%s", $key, $val);
+		}
+	}
+}
+
+/**
+ * Convert array for sanitizeArray function
+ */
+function convArrayForSanitizing($src, &$array)
+{
+	$array = array();
+	foreach ($src as $key => $val) {
+		if (key_exists($key, $_GET)) {
+			array_push($array, sprintf("%s=%s", $key, $val));
+		}
+	}
+}
+
+/**
+ * Revert array after sanitizeArray function
+ */
+function revertArrayForSanitizing($array, &$dst)
+{
+	foreach ($array as $v) {
+		list($key, $val) = preg_split("/=/", $v, 2);
+		$dst[$key] = $val;
+	}
+}
+
+/**
  * Stops processing the request and redirects to the given URL.
  * - no actual contents should have been sent to the output yet
  * - the URL will be stripped of illegal or dangerous characters
  */
-function redirect($url)
-{
+function redirect($url) {
 	$url = preg_replace('|[^a-z0-9-~+_.?#=&;,/:@%]|i', '', $url);
 	header('Location: ' . $url);
 	exit;
@@ -1179,7 +1816,7 @@
 /**
  * Strip HTML tags from a string
  * This function is a bit more intelligent than a regular call to strip_tags(),
- * because it also deletes the contents of certain tags and cleans up any 
+ * because it also deletes the contents of certain tags and cleans up any
  * unneeded whitespace.
  */
 function stringStripTags ($string) {
@@ -1189,7 +1826,6 @@
 	$string = str_replace('>', '> ', $string);
 	$string = str_replace('<', ' <', $string);
 	$string = strip_tags($string);
-
 	$string = preg_replace("/\s+/", " ", $string);
 	$string = trim($string);
 	return $string;
@@ -1222,7 +1858,7 @@
 	$string = stringStripTags($string);
 	$string = entity::named_to_numeric($string);
 	$string = entity::normalize_numeric($string);
-		
+
 	if (_CHARSET == 'UTF-8') {
 		$string = entity::numeric_to_utf8($string);
 	}
@@ -1231,4 +1867,96 @@
 	return $string;
 }
 
+// START: functions from the end of file BLOG.php
+// used for mail notification (html -> text)
+function toAscii($html) {
+	// strip off most tags
+	$html = strip_tags($html,'<a>');
+	$to_replace = "/<a[^>]*href=[\"\']([^\"^']*)[\"\'][^>]*>([^<]*)<\/a>/i";
+	_links_init();
+	$ascii = preg_replace_callback ($to_replace, '_links_add', $html);
+	$ascii .= "\n\n" . _links_list();
+	return strip_tags($ascii);
+}
+
+function _links_init() {
+   global $tmp_links;
+   $tmp_links = array();
+}
+
+function _links_add($match) {
+   global $tmp_links;
+   array_push($tmp_links, $match[1]);
+   return $match[2] . ' [' . sizeof($tmp_links) .']';
+}
+
+function _links_list() {
+   global $tmp_links;
+   $output = '';
+   $i = 1;
+   foreach ($tmp_links as $current) {
+	  $output .= "[$i] $current\n";
+	  $i++;
+   }
+   return $output;
+}
+// END: functions from the end of file BLOG.php
+
+// START: functions from the end of file ADMIN.php
+/**
+ * @todo document this
+ */
+function encode_desc($data)
+	{   $to_entities = get_html_translation_table(HTML_ENTITIES);
+		$from_entities = array_flip($to_entities);
+		$data = strtr($data,$from_entities);
+		$data = strtr($data,$to_entities);
+		return $data;
+	}
+
+/**
+ * Returns the Javascript code for a bookmarklet that works on most modern browsers
+ *
+ * @param blogid
+ */
+function getBookmarklet($blogid) {
+	global $CONF;
+
+	// normal
+	$document = 'document';
+	$bookmarkletline = "javascript:Q='';x=".$document.";y=window;if(x.selection){Q=x.selection.createRange().text;}else if(y.getSelection){Q=y.getSelection();}else if(x.getSelection){Q=x.getSelection();}wingm=window.open('";
+	$bookmarkletline .= $CONF['AdminURL'] . "bookmarklet.php?blogid=$blogid";
+	$bookmarkletline .="&logtext='+escape(Q)+'&loglink='+escape(x.location.href)+'&loglinktitle='+escape(x.title),'nucleusbm','scrollbars=yes,width=600,height=500,left=10,top=10,status=yes,resizable=yes');wingm.focus();";
+
+	return $bookmarkletline;
+}
+// END: functions from the end of file ADMIN.php
+
+/**
+ * Returns a variable or null if not set
+ *
+ * @param mixed Variable
+ * @return mixed Variable
+ */
+function ifset(&$var) {
+	if (isset($var)) {
+		return $var;
+	}
+
+	return null;
+}
+
+/**
+ * Returns number of subscriber to an event
+ *
+ * @param event
+ * @return number of subscriber(s)
+ */
+function numberOfEventSubscriber($event) {
+	$query = 'SELECT COUNT(*) as count FROM ' . sql_table('plugin_event') . ' WHERE event=\'' . $event . '\'';
+	$res = sql_query($query);
+	$obj = mysql_fetch_object($res);
+	return $obj->count;
+}
+
 ?>
diff -ruN 3.24.src/nucleus/libs/include/admin-add.template 3.31.src/nucleus/libs/include/admin-add.template
--- 3.24.src/nucleus/libs/include/admin-add.template	2004-09-26 19:35:28.000000000 -0500
+++ 3.31.src/nucleus/libs/include/admin-add.template	2007-10-22 19:36:00.000000000 -0500
@@ -2,19 +2,24 @@
 
 <%init%>
 <script type="text/javascript" src="javascript/numbercheck.js"></script>
+<script type="text/javascript" src="javascript/xmlhttprequest.js"></script>
 
-<form method="post" action="index.php" >
+<form id="addform" method="post" action="index.php" >
 
 <div>
 
 <input type="hidden" name="action" value="additem" />
 <input name="blogid" value="<%blogid%>" type="hidden" />
+<input type="hidden" name="draftid" value="0" />
 <%ticket%>
 
 <table>
 	<tr>
 		<th colspan="2"><%text(_ADD_CREATENEW)%></th>
 	</tr><tr>
+		<td><%text(_AUTOSAVEDRAFT)%></td>
+		<td><span id="info"><%text(_AUTOSAVEDRAFT_NOTYETSAVED)%></span></td>
+	</tr><tr>
 		<td><%text(_ADD_TITLE)%></td>
 		<td><input 
 			<%jsinput(title)%>
@@ -37,9 +42,9 @@
 		</td>
 	</tr><tr id="edit" style="display:none;">
 		<td><%text(_ADD_PREVIEW)%></td>
-		<td><b><span id="prevtitle"></span></b><br />
-			<span id="prevbody"></span><br />
-			<span id="prevmore"></span><br />
+		<td><b><span id="prevtitle">&#160;</span></b><br />
+			<span id="prevbody">&#160;</span><br />
+			<span id="prevmore">&#160;</span><br />
 		</td>
 	</tr><tr>
 	
@@ -110,9 +115,24 @@
 		<td>
 			<input tabindex="60" type="submit" value="<%text(_ADD_ADDITEM)%>" 
 				onclick="return checkSubmit();" />
+			<input tabindex="80" type="button" name="autosavenow" value="<%text(_AUTOSAVEDRAFT_NOW)%>"
+				onclick="autoSaveDraft();" />
 		</td>
 	</tr>
 </table>
 
 </div>
-</form>	
+</form>
+
+<script type="text/javascript">
+	var xmlhttprequest = new Array();
+	xmlhttprequest[0] = createHTTPHandler(); // AutoDraft handler
+	xmlhttprequest[1] = createHTTPHandler(); // UpdateTicket handler
+	var seconds = now(); // Last AutoDraft time
+	var checks = 0; // Number of checks since last AutoDraft
+	var addform = document.getElementById('addform'); // The form id
+	var goal = document.getElementById('info'); // The html div id where 'Last saved: date time' must come
+	var goalurl = '../action.php'; // The PHP file where the content must be posted to
+	var lastsavedtext = '<%text(_AUTOSAVEDRAFT_LASTSAVED)%>'; // The language variable for 'Last saved'
+	var formtype = 'add'; // Add or edit form
+</script>	
diff -ruN 3.24.src/nucleus/libs/include/admin-edit.template 3.31.src/nucleus/libs/include/admin-edit.template
--- 3.24.src/nucleus/libs/include/admin-edit.template	2004-09-26 19:35:28.000000000 -0500
+++ 3.31.src/nucleus/libs/include/admin-edit.template	2007-10-22 19:36:00.000000000 -0500
@@ -2,17 +2,22 @@
 
 <%init%>
 <script type="text/javascript" src="javascript/numbercheck.js"></script>
+<script type="text/javascript" src="javascript/xmlhttprequest.js"></script>
 
-<form method="post" action="index.php">
+<form id="editform" method="post" action="index.php">
 <div>
 
 <input type="hidden" name="action" value="itemupdate" />
 <input name="itemid" value="<%contents(itemid)%>" type="hidden" />
+<input type="hidden" name="draftid" value="0" />
 <%ticket%>
 
 <table><tr>
 	<th colspan="2"><%text(_EDIT_ITEM)%></th>
 </tr><tr>
+	<td><%text(_AUTOSAVEDRAFT)%></td>
+	<td><span id="info"><%text(_AUTOSAVEDRAFT_NOTYETSAVED)%></span></td>
+</tr><tr>
 	<td><%text(_EDIT_ORIG_AUTHOR)%></td>
 	<td><%contents(author)%></td>
 </tr><tr>
@@ -38,9 +43,9 @@
 	</td>
 </tr><tr id="edit" style="display:none;">
 	<td><%text(_ADD_PREVIEW)%></td>
-	<td><b><span id="prevtitle"></span></b><br />
-		<span id="prevbody"></span><br />
-		<span id="prevmore"></span><br />
+	<td><b><span id="prevtitle">&#160;</span></b><br />
+		<span id="prevbody">&#160;</span><br />
+		<span id="prevmore">&#160;</span><br />
 	</td>
 </tr><tr>
 
@@ -137,9 +142,24 @@
 		<td>
 			<input tabindex="60" type="submit" value="<%text(_EDIT_SUBMIT)%>" 
 				onclick="return checkSubmit();" />
+			<input tabindex="80" type="button" name="autosavenow" value="<%text(_AUTOSAVEDRAFT_NOW)%>"
+				onclick="autoSaveDraft();" />
 		</td>
 	
 </tr></table>
 
 </div>
-</form>		
+</form>
+
+<script type="text/javascript">
+	var xmlhttprequest = new Array();
+	xmlhttprequest[0] = createHTTPHandler(); // AutoDraft handler
+	xmlhttprequest[1] = createHTTPHandler(); // UpdateTicket handler
+	var seconds = now(); // Last AutoDraft time
+	var checks = 0; // Number of checks since last AutoDraft
+	var addform = document.getElementById('editform'); // The form id
+	var goal = document.getElementById('info'); // The html div id where 'Last saved: date time' must come
+	var goalurl = '../action.php'; // The PHP file where the content must be posted to
+	var lastsavedtext = '<%text(_AUTOSAVEDRAFT_LASTSAVED)%>'; // The language variable for 'Last saved'
+	var formtype = 'edit'; // Add or edit form
+</script>	
diff -ruN 3.24.src/nucleus/libs/include/bookmarklet-add.template 3.31.src/nucleus/libs/include/bookmarklet-add.template
--- 3.24.src/nucleus/libs/include/bookmarklet-add.template	2004-09-26 19:35:28.000000000 -0500
+++ 3.31.src/nucleus/libs/include/bookmarklet-add.template	2007-10-22 19:36:00.000000000 -0500
@@ -7,6 +7,7 @@
 		<script type="text/javascript" src="javascript/bookmarklet.js"></script>
 		<script type="text/javascript" src="javascript/edit.js"></script>
 		<script type="text/javascript" src="javascript/numbercheck.js"></script>
+		<script type="text/javascript" src="javascript/xmlhttprequest.js"></script>
 		<%init%>
 		<%extrahead%>
 		<script type="text/javascript">
@@ -24,10 +25,11 @@
 	</head>
 	<body>
 		<h1><%text(_ADD_ADDTO)%> '<%bloglink%>'</h1>
-		<form method="post" action="bookmarklet.php" ><div>
+		<form id="addform" method="post" action="bookmarklet.php" ><div>
 			
 			<input name="action" type="hidden" value="additem" />
 			<input name="blogid" type="hidden" value="<%blogid%>" />
+			<input type="hidden" name="draftid" value="0" />
 			<%ticket%>
 			
 			<div id="submit" class="buttonbar">
@@ -44,6 +46,10 @@
 
 				<table>
 				<tr>
+				<td><%text(_AUTOSAVEDRAFT)%></td>
+				<td><span id="info"><%text(_AUTOSAVEDRAFT_NOTYETSAVED)%></span></td>
+				</tr>
+				<tr>
 				<td><%text(_ADD_TITLE)%></td>
 				<td>
 				<input 
@@ -65,7 +71,12 @@
 				<tr><td>
 				<%text(_ADD_CATEGORY)%></td>
 				<td><%categories%></td>
-				</tr></table>
+				</tr>
+				<tr>
+				<td><%text(_AUTOSAVEDRAFT_NOW)%></td>
+				<td><input tabindex="80" type="button" name="autosavenow" value="<%text(_AUTOSAVEDRAFT_NOW)%>" onclick="autoSaveDraft();" /></td>
+				</tr>
+				</table>
 
 					
 			</div>
@@ -133,14 +144,28 @@
 			<div id="preview" class="contentblock">
 				<h2><%text(_ADD_PREVIEW)%></h2>
 				
-				<b><span id="prevtitle"></span></b>
+				<b><span id="prevtitle">&#160;</span></b>
 				<br />
-				<span id="prevbody"></span>
+				<span id="prevbody">&#160;</span>
 				<br />
-				<span id="prevmore"></span>
+				<span id="prevmore">&#160;</span>
 			</div>
 			
 		</div></form>
+
+	<script type="text/javascript">
+		var xmlhttprequest = new Array();
+		xmlhttprequest[0] = createHTTPHandler(); // AutoDraft handler
+		xmlhttprequest[1] = createHTTPHandler(); // UpdateTicket handler
+		var seconds = now(); // Last AutoDraft time
+		var checks = 0; // Number of checks since last AutoDraft
+		var addform = document.getElementById('addform'); // The form id
+		var goal = document.getElementById('info'); // The html div id where 'Last saved: date time' must come
+		var goalurl = '../action.php'; // The PHP file where the content must be posted to
+		var lastsavedtext = '<%text(_AUTOSAVEDRAFT_LASTSAVED)%>'; // The language variable for 'Last saved'
+		var formtype = 'add'; // Add or edit form
+	</script>
+
 	</body>
 	</html>
 
diff -ruN 3.24.src/nucleus/libs/include/bookmarklet-edit.template 3.31.src/nucleus/libs/include/bookmarklet-edit.template
--- 3.24.src/nucleus/libs/include/bookmarklet-edit.template	2004-09-26 19:35:30.000000000 -0500
+++ 3.31.src/nucleus/libs/include/bookmarklet-edit.template	2007-10-22 19:36:00.000000000 -0500
@@ -7,6 +7,7 @@
 		<script type="text/javascript" src="javascript/bookmarklet.js"></script>
 		<script type="text/javascript" src="javascript/edit.js"></script>
 		<script type="text/javascript" src="javascript/numbercheck.js"></script>
+		<script type="text/javascript" src="javascript/xmlhttprequest.js"></script>
 		<%init%>
 		<%extrahead%>
 		<script type="text/javascript">
@@ -24,10 +25,11 @@
 	</head>
 	<body>
 		<h1><%text(_EDIT_ITEM)%> (<%contents(itemid)%>)</h1>
-		<form method="post" action="bookmarklet.php" ><div>
+		<form id="editform" method="post" action="bookmarklet.php" ><div>
 			
 			<input name="action" type="hidden" value="edititem" />
 			<input name="itemid" type="hidden" value="<%contents(itemid)%>" />
+			<input type="hidden" name="draftid" value="0" />
 			<%ticket%>
 			
 			<div id="submit" class="buttonbar">
@@ -43,6 +45,10 @@
 			<div id="body" class="contentblock">
 				<table>
 				<tr>
+				<td><%text(_AUTOSAVEDRAFT)%></td>
+				<td><span id="info"><%text(_AUTOSAVEDRAFT_NOTYETSAVED)%></span></td>
+				</tr>
+				<tr>
 				<td><%text(_ADD_TITLE)%></td>
 				<td><input 
 					<%jsinput(title)%>
@@ -64,6 +70,10 @@
 				<td><%text(_ADD_CATEGORY)%></td>
 				<td><%categories%></td>
 				</tr>
+				<tr>
+				<td><%text(_AUTOSAVEDRAFT_NOW)%></td>
+				<td><input tabindex="80" type="button" name="autosavenow" value="<%text(_AUTOSAVEDRAFT_NOW)%>" onclick="autoSaveDraft();" /></td>
+				</tr>
 				</table>
 					
 			</div>
@@ -130,14 +140,28 @@
 			<div id="preview" class="contentblock">
 				<h2><%text(_ADD_PREVIEW)%></h2>
 				
-				<b><span id="prevtitle"></span></b>
+				<b><span id="prevtitle">&#160;</span></b>
 				<br />
-				<span id="prevbody"></span>
+				<span id="prevbody">&#160;</span>
 				<br />
-				<span id="prevmore"></span>
+				<span id="prevmore">&#160;</span>
 			</div>
 			
 		</div></form>
+
+	<script type="text/javascript">
+		var xmlhttprequest = new Array();
+		xmlhttprequest[0] = createHTTPHandler(); // AutoDraft handler
+		xmlhttprequest[1] = createHTTPHandler(); // UpdateTicket handler
+		var seconds = now(); // Last AutoDraft time
+		var checks = 0; // Number of checks since last AutoDraft
+		var addform = document.getElementById('editform'); // The form id
+		var goal = document.getElementById('info'); // The html div id where 'Last saved: date time' must come
+		var goalurl = '../action.php'; // The PHP file where the content must be posted to
+		var lastsavedtext = '<%text(_AUTOSAVEDRAFT_LASTSAVED)%>'; // The language variable for 'Last saved'
+		var formtype = 'edit'; // Add or edit form
+	</script>
+
 	</body>
 	</html>
 
diff -ruN 3.24.src/nucleus/libs/ITEMACTIONS.php 3.31.src/nucleus/libs/ITEMACTIONS.php
--- 3.24.src/nucleus/libs/ITEMACTIONS.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/libs/ITEMACTIONS.php	2007-10-22 19:36:00.000000000 -0500
@@ -0,0 +1,433 @@
+<?php
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+/**
+ * This class to parse item templates
+ *
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: ITEMACTIONS.php 1149 2007-05-19 23:16:15Z kaigreve $
+ */
+class ITEMACTIONS extends BaseActions {
+
+	// contains an assoc array with parameters that need to be included when
+	// generating links to items/archives/... (e.g. catid)
+	var $linkparams;
+
+	// true when the current user is a blog admin (and thus allowed to edit all items)
+	var $allowEditAll;
+
+	// timestamp of last visit
+	var $lastVisit;
+
+	// item currently being handled (mysql result object, see BLOG::showUsingQuery)
+	var $currentItem;
+
+	// reference to the blog currently being displayed
+	var $blog;
+
+	// associative array with template info (part name => contents)
+	var $template;
+
+	// true when comments need to be displayed
+	var $showComments;
+
+	function ITEMACTIONS(&$blog) {
+		// call constructor of superclass first
+		$this->BaseActions();
+
+		// extra parameters for created links
+		global $catid;
+		if ($catid)
+			$this->linkparams = array('catid' => $catid);
+
+		// check if member is blog admin (and thus allowed to edit all items)
+		global $member;
+		$this->allowEditAll = ($member->isLoggedIn() && $member->blogAdminRights($blog->getID()));
+		$this->setBlog($blog);
+	}
+
+	function getDefinedActions() {
+		return array(
+			'blogid',
+			'title',
+			'body',
+			'more',
+			'smartbody',
+			'itemid',
+			'morelink',
+			'category',
+			'categorylink',
+			'author',
+			'authorid',
+			'authorlink',
+			'catid',
+			'karma',
+			'date',
+			'time',
+			'query',
+			'itemlink',
+			'blogurl',
+			'closed',
+			'syndicate_title',
+			'syndicate_description',
+			'karmaposlink',
+			'karmaneglink',
+			'new',
+			'image',
+			'popup',
+			'media',
+			'daylink',
+			'query',
+			'include',
+			'phpinclude',
+			'parsedinclude',
+			'skinfile',
+			'set',
+			'plugin',
+			'edit',
+			'editlink',
+			'editpopupcode',
+			'comments',
+			'relevance'/*,
+			'if',
+			'else',
+			'endif',
+			'elseif',
+			'ifnot',
+			'elseifnot'*/
+		);
+	}
+
+	function setLastVisit($lastVisit) {
+		$this->lastVisit = $lastVisit;
+	}
+	
+	function setParser(&$parser) {
+		$this->parser =& $parser;
+	}
+	
+	function setCurrentItem(&$item) {
+		$this->currentItem =& $item;
+	}
+	
+	function setBlog(&$blog) {
+		$this->blog =& $blog;
+	}
+	
+	function setTemplate($template) {
+		$this->template =& $template;
+	}
+	
+	function setShowComments($val) {
+		$this->showComments = $val;
+	}
+
+	// methods used by parser to insert content
+
+	function parse_blogid() {
+		echo $this->blog->getID();
+	}
+	
+	function parse_body() {
+		$this->highlightAndParse($this->currentItem->body);
+	}
+	
+	function parse_more() {
+		$this->highlightAndParse($this->currentItem->more);
+	}
+	
+	function parse_itemid() {
+		echo $this->currentItem->itemid;
+	}
+	
+	function parse_category() {
+		echo $this->currentItem->category;
+	}
+	
+	function parse_categorylink() {
+		echo createLink('category', array('catid' => $this->currentItem->catid, 'name' => $this->currentItem->category));
+	}
+	
+	function parse_catid() {
+		echo $this->currentItem->catid;
+	}
+	
+	function parse_authorid() {
+		echo $this->currentItem->authorid;
+	}
+	
+	function parse_authorlink() {
+		echo createLink(
+			'member',
+			array(
+				'memberid' => $this->currentItem->authorid,
+				'name' => $this->currentItem->author,
+				'extra' => $this->linkparams
+			)
+		);
+	}
+	
+	function parse_query() {
+		echo $this->strHighlight;
+	}
+	
+	function parse_itemlink() {
+		echo createLink(
+			'item',
+			array(
+				'itemid' => $this->currentItem->itemid,
+				'title' => $this->currentItem->title,
+				'timestamp' => $this->currentItem->timestamp,
+				'extra' => $this->linkparams
+			)
+		);
+	}
+	
+	function parse_blogurl() {
+		echo $this->blog->getURL();
+	}
+	
+	function parse_closed() {
+		echo $this->currentItem->closed;
+	}
+	
+	function parse_relevance() {
+		echo round($this->currentItem->score,2);
+	}
+
+	function parse_title($format = '') {
+		switch ($format) {
+			case 'xml':
+				echo stringToXML ($this->currentItem->title);
+				break;
+			case 'attribute':
+				echo stringToAttribute ($this->currentItem->title);
+				break;
+			case 'raw':
+				echo $this->currentItem->title;
+				break;
+			default:
+				$this->highlightAndParse($this->currentItem->title);
+				break;
+		}
+	}
+
+	function parse_karma($type = 'totalscore') {
+		global $manager;
+
+		// get karma object
+		$karma =& $manager->getKarma($this->currentItem->itemid);
+
+		switch($type) {
+			case 'pos':
+				echo $karma->getNbPosVotes();
+				break;
+			case 'neg':
+				echo $karma->getNbNegVotes();
+				break;
+			case 'votes':
+				echo $karma->getNbOfVotes();
+				break;
+			case 'posp':
+				$percentage = $karma->getNbOfVotes() ? 100 * ($karma->getNbPosVotes() / $karma->getNbOfVotes()) : 50;
+				echo number_format($percentage,2), '%';
+				break;
+			case 'negp':
+				$percentage = $karma->getNbOfVotes() ? 100 * ($karma->getNbNegVotes() / $karma->getNbOfVotes()) : 50;
+				echo number_format($percentage,2), '%';
+				break;
+			case 'totalscore':
+			default:
+				echo $karma->getTotalScore();
+				break;
+		}
+
+	}
+
+	function parse_author($which = '') {
+		switch($which)
+		{
+			case 'realname':
+				echo $this->currentItem->authorname;
+				break;
+			case 'id':
+				echo $this->currentItem->authorid;
+				break;
+			case 'email':
+				echo $this->currentItem->authormail;
+				break;
+			case 'url':
+				echo $this->currentItem->authorurl;
+				break;
+			case 'name':
+			default:
+				echo $this->currentItem->author;
+		}
+	}
+
+	function parse_smartbody() {
+		if (!$this->currentItem->more) {
+			$this->highlightAndParse($this->currentItem->body);
+		} else {
+			$this->highlightAndParse($this->currentItem->more);
+		}
+	}
+
+	function parse_morelink() {
+		if ($this->currentItem->more)
+			$this->parser->parse($this->template['MORELINK']);
+	}
+
+	function parse_date($format = '') {
+		echo formatDate($format, $this->currentItem->timestamp, $this->template['FORMAT_DATE'], $this->blog);
+	}
+
+	/**
+	  * @param format optional strftime format
+	  */
+	function parse_time($format = '') {
+		echo strftime($format ? $format : $this->template['FORMAT_TIME'],$this->currentItem->timestamp);
+	}
+
+	/**
+	  * @param maxLength optional maximum length
+	  */
+	function parse_syndicate_title($maxLength = 100) {
+		$syndicated = strip_tags($this->currentItem->title);
+		echo htmlspecialchars(shorten($syndicated,$maxLength,'...'),ENT_QUOTES);
+	}
+
+	/**
+	  * @param maxLength optional maximum length
+	  */
+	function parse_syndicate_description($maxLength = 250, $addHighlight = 0) {
+		$syndicated = strip_tags($this->currentItem->body);
+		if ($addHighlight) {
+			$tmp_highlight = htmlspecialchars(shorten($syndicated,$maxLength,'...'),ENT_QUOTES);
+			echo $this->highlightAndParse($tmp_highlight);
+		} else {
+			echo htmlspecialchars(shorten($syndicated,$maxLength,'...'),ENT_QUOTES);
+		}
+	}
+
+	function parse_karmaposlink($text = '') {
+		global $CONF;
+		$link = $CONF['ActionURL'] . '?action=votepositive&amp;itemid='.$this->currentItem->itemid;
+		echo $text ? '<a href="'.$link.'">'.$text.'</a>' : $link;
+	}
+
+	function parse_karmaneglink($text = '') {
+		global $CONF;
+		$link = $CONF['ActionURL'] . '?action=votenegative&amp;itemid='.$this->currentItem->itemid;
+		echo $text ? '<a href="'.$link.'">'.$text.'</a>' : $link;
+	}
+
+	function parse_new() {
+		if (($this->lastVisit != 0) && ($this->currentItem->timestamp > $this->lastVisit))
+			echo $this->template['NEW'];
+	}
+
+
+	function parse_daylink() {
+		echo createArchiveLink($this->blog->getID(), strftime('%Y-%m-%d',$this->currentItem->timestamp), $this->linkparams);
+	}
+
+	function parse_comments($maxToShow = 0) {
+		if ($maxToShow == 0)
+			$maxToShow = $this->blog->getMaxComments();
+
+		// add comments
+		if ($this->showComments && $this->blog->commentsEnabled()) {
+			$comments =& new COMMENTS($this->currentItem->itemid);
+			$comments->setItemActions($this);
+			$comments->showComments($this->template, $maxToShow, $this->currentItem->closed ? 0 : 1, $this->strHighlight);
+		}
+	}
+
+	/**
+	  * Executes a plugin templatevar
+	  *
+	  * @param pluginName name of plugin (without the NP_)
+	  *
+	  * extra parameters can be added
+	  */
+	function parse_plugin($pluginName) {
+		global $manager;
+
+		// only continue when the plugin is really installed
+		if (!$manager->pluginInstalled('NP_' . $pluginName))
+			return;
+
+		$plugin =& $manager->getPlugin('NP_' . $pluginName);
+		if (!$plugin) return;
+
+		// get arguments
+		$params = func_get_args();
+
+		// remove plugin name
+		array_shift($params);
+
+		// add item reference (array_unshift didn't work)
+		$params = array_merge(array(&$this->currentItem),$params);
+
+		call_user_func_array(array(&$plugin,'doTemplateVar'), $params);
+	}
+
+	function parse_edit() {
+		global $member, $CONF;
+		if ($this->allowEditAll || ($member->isLoggedIn() && ($member->getID() == $this->currentItem->authorid)) ) {
+			$this->parser->parse($this->template['EDITLINK']);
+		}
+	}
+
+	function parse_editlink() {
+		global $CONF;
+		echo $CONF['AdminURL'],'bookmarklet.php?action=edit&amp;itemid=',$this->currentItem->itemid;
+	}
+
+	function parse_editpopupcode() {
+		echo "if (event &amp;&amp; event.preventDefault) event.preventDefault();winbm=window.open(this.href,'nucleusbm','scrollbars=yes,width=600,height=500,left=10,top=10,status=yes,resizable=yes');winbm.focus();return false;";
+	}
+
+	// helper functions
+
+	/**
+	 * Parses highlighted text, with limited actions only (to prevent not fully trusted team members
+	 * from hacking your weblog.
+	 * 'plugin variables in items' implementation by Andy
+	 */
+	function highlightAndParse(&$data) {
+		$actions =& new BODYACTIONS($this->blog);
+		$parser =& new PARSER($actions->getDefinedActions(), $actions);
+		$actions->setTemplate($this->template);
+		$actions->setHighlight($this->strHighlight);
+		$actions->setCurrentItem($this->currentItem);
+		//$actions->setParser($parser);
+		$parser->parse($actions->highlight($data));
+	}
+
+	/*
+	// this is the function previous to the 'plugin variables in items' implementation by Andy
+	function highlightAndParse(&$data) {
+		// allow only a limited subset of actions (do not allow includes etc, they might be evil)
+		$this->parser->actions = array('image','media','popup');
+		$tmp_highlight = $this->highlight($data);
+		$this->parser->parse($tmp_highlight);
+		$this->parser->actions = $this->getDefinedActions();
+	}
+	*/
+
+}
+	
+
+
+?>
diff -ruN 3.24.src/nucleus/libs/ITEM.php 3.31.src/nucleus/libs/ITEM.php
--- 3.24.src/nucleus/libs/ITEM.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/ITEM.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,30 +1,30 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * A class representing an item
-  *
+ * A class representing an item
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: ITEM.php,v 1.16.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: ITEM.php 1195 2007-09-05 06:19:47Z kimitake $
+ */
 class ITEM {
-	
+
 	var $itemid;
-	
+
 	function ITEM($itemid) {
 		$this->itemid = $itemid;
 	}
-	
+
 	/**
 	  * Returns one item with the specific itemid
 	  * (static)
@@ -33,24 +33,24 @@
 		global $manager;
 
 		$itemid = intval($itemid);
-		
+
 		$query =  'SELECT i.idraft as draft, i.inumber as itemid, i.iclosed as closed, '
-		       . ' i.ititle as title, i.ibody as body, m.mname as author, '
-		       . ' i.iauthor as authorid, i.itime, i.imore as more, i.ikarmapos as karmapos, '
-		       . ' i.ikarmaneg as karmaneg, i.icat as catid, i.iblog as blogid '
-		       . ' FROM '.sql_table('item').' as i, '.sql_table('member').' as m, ' . sql_table('blog') . ' as b '
-		       . ' WHERE i.inumber=' . $itemid
-		       . ' and i.iauthor=m.mnumber '
-		       . ' and i.iblog=b.bnumber';
-		       
+			   . ' i.ititle as title, i.ibody as body, m.mname as author, '
+			   . ' i.iauthor as authorid, i.itime, i.imore as more, i.ikarmapos as karmapos, '
+			   . ' i.ikarmaneg as karmaneg, i.icat as catid, i.iblog as blogid '
+			   . ' FROM '.sql_table('item').' as i, '.sql_table('member').' as m, ' . sql_table('blog') . ' as b '
+			   . ' WHERE i.inumber=' . $itemid
+			   . ' and i.iauthor=m.mnumber '
+			   . ' and i.iblog=b.bnumber';
+
 		if (!$allowdraft)
 			$query .= ' and i.idraft=0';
-			
+
 		if (!$allowfuture) {
 			$blog =& $manager->getBlog(getBlogIDFromItemID($itemid));
-			$query .= ' and i.itime <=' . mysqldate($blog->getCorrectTime());		
+			$query .= ' and i.itime <=' . mysqldate($blog->getCorrectTime());
 		}
-		
+
 		$query .= ' LIMIT 1';
 
 		$res = sql_query($query);
@@ -58,17 +58,17 @@
 		if (mysql_num_rows($res) == 1)
 		{
 			$aItemInfo = mysql_fetch_assoc($res);
-			$aItemInfo['timestamp'] = strtotime($aItemInfo['itime']);	
+			$aItemInfo['timestamp'] = strtotime($aItemInfo['itime']);
 			return $aItemInfo;
 		} else {
 			return 0;
 		}
 
-	}	
-	
+	}
+
 	/**
 	 * Tries to create an item from the data in the current request (comes from
-	 * bookmarklet or admin area 
+	 * bookmarklet or admin area
 	 *
 	 * Returns an array with status info (status = 'added', 'error', 'newcategory')
 	 *
@@ -76,173 +76,193 @@
 	 */
 	function createFromRequest() {
 		 global $member, $manager;
-		 
-	 	 $i_author = 		$member->getID();
+
+		 $i_author = 		$member->getID();
 		 $i_body = 			postVar('body');
 		 $i_title =			postVar('title');
 		 $i_more = 			postVar('more');
-		 $i_actiontype = 	postVar('actiontype');		 
+		 $i_actiontype = 	postVar('actiontype');
 		 $i_closed = 		intPostVar('closed');
-		 $i_hour = 			intPostVar('hour');		 
-		 $i_minutes = 		intPostVar('minutes');		 
-		 $i_month = 		intPostVar('month');		 
-		 $i_day = 			intPostVar('day');		 
-		 $i_year = 			intPostVar('year');		 		 
+		 $i_hour = 			intPostVar('hour');
+		 $i_minutes = 		intPostVar('minutes');
+		 $i_month = 		intPostVar('month');
+		 $i_day = 			intPostVar('day');
+		 $i_year = 			intPostVar('year');
 
 		 $i_catid = 		postVar('catid');
-		 
+
+		 $i_draftid = 		intPostVar('draftid');
+
 		 if (!$member->canAddItem($i_catid))
-		 	return array('status' => 'error', 'message' => _ERROR_DISALLOWED);
-		 
+			return array('status' => 'error', 'message' => _ERROR_DISALLOWED);
+
 		 if (!$i_actiontype) $i_actiontype = 'addnow';
 
 		 switch ($i_actiontype) {
-		 	case 'adddraft':
-		 		$i_draft = 1;
-		 		break;
-		 	case 'addfuture':
-		 	case 'addnow':
-		 	default:
-		 		$i_draft = 0;
+			case 'adddraft':
+				$i_draft = 1;
+				break;
+			case 'addfuture':
+			case 'addnow':
+			default:
+				$i_draft = 0;
 		 }
-		 
+
 		 if (!trim($i_body))
-		 	return array('status' => 'error', 'message' => _ERROR_NOEMPTYITEMS);
-		 
-		// create new category if needed 
+			return array('status' => 'error', 'message' => _ERROR_NOEMPTYITEMS);
+
+		// create new category if needed
 		if (strstr($i_catid,'newcat')) {
-			// get blogid 
+			// get blogid
 			list($i_blogid) = sscanf($i_catid,"newcat-%d");
-			
+
 			// create
 			$blog =& $manager->getBlog($i_blogid);
 			$i_catid = $blog->createNewCategory();
 
 			// show error when sth goes wrong
-			if (!$i_catid) 
+			if (!$i_catid)
 				return array('status' => 'error','message' => 'Could not create new category');
 		} else {
 			// force blogid (must be same as category id)
 			$i_blogid = getBlogIDFromCatID($i_catid);
 			$blog =& $manager->getBlog($i_blogid);
 		}
-		
+
 		if ($i_actiontype == 'addfuture') {
 			$posttime = mktime($i_hour, $i_minutes, 0, $i_month, $i_day, $i_year);
-			
-			// make sure the date is in the future, unless we allow past dates 
+
+			// make sure the date is in the future, unless we allow past dates
 			if ((!$blog->allowPastPosting()) && ($posttime < $blog->getCorrectTime()))
 				$posttime = $blog->getCorrectTime();
 		} else {
 			// time with offset, or 0 for drafts
-			$posttime = $i_draft ? 0 : $blog->getCorrectTime();	
+			$posttime = $i_draft ? 0 : $blog->getCorrectTime();
 		}
-		
-	 	$itemid = $blog->additem($i_catid, $i_title,$i_body,$i_more,$i_blogid,$i_author,$posttime,$i_closed,$i_draft);	
-	 	
+
+		if ($posttime > $blog->getCorrectTime()) {
+			$posted = 0;
+			$blog->setFuturePost();
+		}
+		else {
+			$posted = 1;
+		}
+
+		$itemid = $blog->additem($i_catid, $i_title,$i_body,$i_more,$i_blogid,$i_author,$posttime,$i_closed,$i_draft,$posted);
+
 		//Setting the itemOptions
 		$aOptions = requestArray('plugoption');
 		NucleusPlugin::_applyPluginOptions($aOptions, $itemid);
 		$manager->notify('PostPluginOptionsUpdate',array('context' => 'item', 'itemid' => $itemid, 'item' => array('title' => $i_title, 'body' => $i_body, 'more' => $i_more, 'closed' => $i_closed, 'catid' => $i_catid)));
-	 	
-	 	// success
-	 	if ($i_catid != intRequestVar('catid'))
-		 	return array('status' => 'newcategory', 'itemid' => $itemid, 'catid' => $i_catid);
+
+		if ($i_draftid > 0) {
+			ITEM::delete($i_draftid);
+		}
+
+		// success
+		if ($i_catid != intRequestVar('catid'))
+			return array('status' => 'newcategory', 'itemid' => $itemid, 'catid' => $i_catid);
 		else
 			return array('status' => 'added', 'itemid' => $itemid);
 	}
-	
-	
+
+
 	/**
 	  * Updates an item (static)
 	  */
 	function update($itemid, $catid, $title, $body, $more, $closed, $wasdraft, $publish, $timestamp = 0) {
 		global $manager;
-		
+
 		$itemid = intval($itemid);
 
 		// make sure value is 1 or 0
 		if ($closed != 1) $closed = 0;
-			
-		// get destination blogid 
+
+		// get destination blogid
 		$new_blogid = getBlogIDFromCatID($catid);
 		$old_blogid = getBlogIDFromItemID($itemid);
-		
+
 		// move will be done on end of method
 		if ($new_blogid != $old_blogid)
 			$moveNeeded = 1;
-		
+
 		// add <br /> before newlines
 		$blog =& $manager->getBlog($new_blogid);
 		if ($blog->convertBreaks()) {
 			$body = addBreaks($body);
 			$more = addBreaks($more);
 		}
-	
+
 		// call plugins
 		$manager->notify('PreUpdateItem',array('itemid' => $itemid, 'title' => &$title, 'body' => &$body, 'more' => &$more, 'blog' => &$blog, 'closed' => &$closed, 'catid' => &$catid));
-	
+
 		// update item itsself
 		$query =  'UPDATE '.sql_table('item')
-		       . ' SET' 
-		       . " ibody='". addslashes($body) ."',"
-		       . " ititle='" . addslashes($title) . "',"
-		       . " imore='" . addslashes($more) . "',"
-		       . " iclosed=" . intval($closed) . ","
-		       . " icat=" . intval($catid);
+			   . ' SET'
+			   . " ibody='". addslashes($body) ."',"
+			   . " ititle='" . addslashes($title) . "',"
+			   . " imore='" . addslashes($more) . "',"
+			   . " iclosed=" . intval($closed) . ","
+			   . " icat=" . intval($catid);
 
 		// if we received an updated timestamp in the past, but past posting is not allowed,
 		// reject that date change (timestamp = 0 will make sure the current date is kept)
 		if ( (!$blog->allowPastPosting()) && ($timestamp < $blog->getCorrectTime()))
 				$timestamp = 0;
-		
+
+		if ($timestamp > $blog->getCorrectTime(time())) {
+			$isFuture = 1;
+			$query .= ', iposted=0';
+		}
+		else {
+			$isFuture = 0;
+			$query .= ', iposted=1';
+		}
+
 		if ($wasdraft && $publish) {
-			$query .= ', idraft=0';
-			
 			// set timestamp to current date only if it's not a future item
 			// draft items have timestamp == 0
 			// don't allow timestamps in the past (unless otherwise defined in blogsettings)
-			if ($timestamp > $blog->getCorrectTime())
-				$isFuture = 1;
-			
+			$query .= ', idraft=0';
+
 			if ($timestamp == 0)
 				$timestamp = $blog->getCorrectTime();
-			
+
 			// send new item notification
-			if (!$isFuture && $blog->getNotifyAddress() && $blog->notifyOnNewItem()) 
+			if (!$isFuture && $blog->getNotifyAddress() && $blog->notifyOnNewItem())
 				$blog->sendNewItemNotification($itemid, $title, $body);
 		}
-		
+
 		// update timestamp when needed
 		if ($timestamp != 0)
-			$query .= ", itime=" . mysqldate($timestamp);	
+			$query .= ", itime=" . mysqldate($timestamp);
 
-		// make sure the correct item is updated			
+		// make sure the correct item is updated
 		$query .= ' WHERE inumber=' . $itemid;
-		
+
 		// off we go!
-		sql_query($query);	
-		
+		sql_query($query);
+
 		$manager->notify('PostUpdateItem',array('itemid' => $itemid));
 
 		// when needed, move item and comments to new blog
-		if ($moveNeeded) 
+		if ($moveNeeded)
 			ITEM::move($itemid, $catid);
-		
+
 		//update the itemOptions
 		$aOptions = requestArray('plugoption');
 		NucleusPlugin::_applyPluginOptions($aOptions);
 		$manager->notify('PostPluginOptionsUpdate',array('context' => 'item', 'itemid' => $itemid, 'item' => array('title' => $title, 'body' => $body, 'more' => $more, 'closed' => $closed, 'catid' => $catid)));
-		
+
 	}
-	
+
 	// move an item to another blog (no checks, static)
 	function move($itemid, $new_catid) {
 		global $manager;
-		
+
 		$itemid = intval($itemid);
 		$new_catid = intval($new_catid);
-		
+
 		$new_blogid = getBlogIDFromCatID($new_catid);
 
 		$manager->notify(
@@ -253,16 +273,16 @@
 				'destcatid' => $new_catid
 			)
 		);
-	
-	
+
+
 		// update item table
 		$query = 'UPDATE '.sql_table('item')." SET iblog=$new_blogid, icat=$new_catid WHERE inumber=$itemid";
-		sql_query($query);		
-		
+		sql_query($query);
+
 		// update comments
 		$query = 'UPDATE '.sql_table('comment')." SET cblog=" . $new_blogid." WHERE citem=" . $itemid;
-		sql_query($query);	
-		
+		sql_query($query);
+
 		$manager->notify(
 			'PostMoveItem',
 			array(
@@ -270,39 +290,39 @@
 				'destblogid' => $new_blogid,
 				'destcatid' => $new_catid
 			)
-		);		
+		);
 	}
-	
+
 	/**
 	  * Deletes an item
 	  */
 	function delete($itemid) {
 		global $manager;
-		
+
 		$itemid = intval($itemid);
-		
+
 		$manager->notify('PreDeleteItem', array('itemid' => $itemid));
-		
+
 		// delete item
 		$query = 'DELETE FROM '.sql_table('item').' WHERE inumber=' . $itemid;
 		sql_query($query);
 
 		// delete the comments associated with the item
 		$query = 'DELETE FROM '.sql_table('comment').' WHERE citem=' . $itemid;
-		sql_query($query);	  
-		
+		sql_query($query);
+
 		// delete all associated plugin options
 		NucleusPlugin::_deleteOptionValues('item', $itemid);
-		
-		$manager->notify('PostDeleteItem', array('itemid' => $itemid));		
+
+		$manager->notify('PostDeleteItem', array('itemid' => $itemid));
 	}
-	
+
 	// returns true if there is an item with the given ID (static)
 	function exists($id,$future,$draft) {
 		global $manager;
-		
+
 		$id = intval($id);
-		
+
 		$r = 'select * FROM '.sql_table('item').' WHERE inumber='.$id;
 		if (!$future) {
 			$bid = getBlogIDFromItemID($id);
@@ -316,8 +336,83 @@
 		$r = sql_query($r);
 
 		return (mysql_num_rows($r) != 0);
-	}	
-	
+	}
+
+	/**
+	 * Tries to create an draft from the data in the current request (comes from
+	 * bookmarklet or admin area
+	 *
+	 * Returns an array with status info (status = 'added', 'error', 'newcategory')
+	 *
+	 * (static)
+	 *
+	 * Used by xmlHTTPRequest AutoDraft
+	 */
+	function createDraftFromRequest() {
+		global $member, $manager;
+
+		$i_author = $member->getID();
+		$i_body = postVar('body');
+		$i_title = postVar('title');
+		$i_more = postVar('more');
+		//$i_actiontype = postVar('actiontype');
+		$i_closed = intPostVar('closed');
+		//$i_hour = intPostVar('hour');
+		//$i_minutes = intPostVar('minutes');
+		//$i_month = intPostVar('month');
+		//$i_day = intPostVar('day');
+		//$i_year = intPostVar('year');
+		$i_catid = postVar('catid');
+		$i_draft = 1;
+		$type = postVar('type');
+		if ($type == 'edit') {
+			$i_blogid = getBlogIDFromItemID(intPostVar('itemid'));
+		}
+		else {
+			$i_blogid = intPostVar('blogid');
+		}
+		$i_draftid = intPostVar('draftid');
+
+		if (!$member->canAddItem($i_catid)) {
+			return array('status' => 'error', 'message' => _ERROR_DISALLOWED);
+		}
+
+		if (!trim($i_body)) {
+			return array('status' => 'error', 'message' => _ERROR_NOEMPTYITEMS);
+		}
+
+		// create new category if needed
+		if (strstr($i_catid, 'newcat')) {
+			// Set in default category
+			$blog =& $manager->getBlog($i_blogid);
+			$i_catid = $blog->getDefaultCategory();
+		}
+		else {
+			// force blogid (must be same as category id)
+			$i_blogid = getBlogIDFromCatID($i_catid);
+			$blog =& $manager->getBlog($i_blogid);
+		}
+
+		$posttime = 0;
+
+		if ($i_draftid > 0) {
+			ITEM::update($i_draftid, $i_catid, $i_title, $i_body, $i_more, $i_closed, 1, 0, 0);
+			$itemid = $i_draftid;
+		}
+		else {
+			$itemid = $blog->additem($i_catid, $i_title, $i_body, $i_more, $i_blogid, $i_author, $posttime, $i_closed, $i_draft);
+		}
+
+		// No plugin support in AutoSaveDraft yet
+		//Setting the itemOptions
+		//$aOptions = requestArray('plugoption');
+		//NucleusPlugin::_applyPluginOptions($aOptions, $itemid);
+		//$manager->notify('PostPluginOptionsUpdate',array('context' => 'item', 'itemid' => $itemid, 'item' => array('title' => $i_title, 'body' => $i_body, 'more' => $i_more, 'closed' => $i_closed, 'catid' => $i_catid)));
+
+		// success
+		return array('status' => 'added', 'draftid' => $itemid);
+	}
+
 }
 
 ?>
diff -ruN 3.24.src/nucleus/libs/KARMA.php 3.31.src/nucleus/libs/KARMA.php
--- 3.24.src/nucleus/libs/KARMA.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/KARMA.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,45 +1,45 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * Class representing the karma votes for a certain item
-  *
+ * Class representing the karma votes for a certain item
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: KARMA.php,v 1.8.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: KARMA.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 class KARMA {
-	
+
 	// id of item about which this object contains information
 	var $itemid;
-	
+
 	// indicates if the karma vote info has already been intialized from the DB
 	var $inforead;
-	
+
 	// amount of positive/negative votes
 	var $karmapos;
 	var $karmaneg;
-	
-	function KARMA($itemid, $initpos = 0, $initneg = 0, $initread = 0) {	
+
+	function KARMA($itemid, $initpos = 0, $initneg = 0, $initread = 0) {
 		// itemid
 		$this->itemid = intval($itemid);
 
 		// have we read the karma info yet?
-		$this->inforead = intval($initread);	
-		
+		$this->inforead = intval($initread);
+
 		// number of positive and negative votes
 		$this->karmapos = intval($initpos);
 		$this->karmaneg = intval($initneg);
 	}
-	
+
 	function getNbPosVotes() {
 		if (!$this->inforead) $this->readFromDatabase();
 		return $this->karmapos;
@@ -56,7 +56,7 @@
 		if (!$this->inforead) $this->readFromDatabase();
 		return ($this->karmapos - $this->karmaneg);
 	}
-	
+
 	function setNbPosVotes($val) {
 		$this->karmapos = intval($val);
 	}
@@ -72,12 +72,12 @@
 		$this->writeToDatabase();
 		$this->saveIP();
 	}
-	
+
 	// adds a negative vote
 	function voteNegative() {
-		$newKarma = $this->getNbNegVotes() + 1;	
-		$this->setNbNegVotes($newKarma);		
-		$this->writeToDatabase();		
+		$newKarma = $this->getNbNegVotes() + 1;
+		$this->setNbNegVotes($newKarma);
+		$this->writeToDatabase();
 		$this->saveIP();
 	}
 
@@ -88,25 +88,25 @@
 		$query = 'SELECT ikarmapos, ikarmaneg FROM '.sql_table('item').' WHERE inumber=' . $this->itemid;
 		$res = sql_query($query);
 		$obj = mysql_fetch_object($res);
-		
+
 		$this->karmapos = $obj->ikarmapos;
-		$this->karmaneg = $obj->ikarmaneg;		
+		$this->karmaneg = $obj->ikarmaneg;
 		$this->inforead = 1;
 	}
-		
-	
+
+
 	function writeToDatabase() {
 		$query = 'UPDATE '.sql_table('item').' SET ikarmapos=' . $this->karmapos . ', ikarmaneg='.$this->karmaneg.' WHERE inumber=' . $this->itemid;
 		sql_query($query);
 	}
-	
+
 	// checks if a vote is still allowed for an IP
 	function isVoteAllowed($ip) {
 		$query = 'SELECT * FROM '.sql_table('karma')." WHERE itemid=$this->itemid and ip='".addslashes($ip)."'";
 		$res = sql_query($query);
 		return (mysql_num_rows($res) == 0);
 	}
-	
+
 	// save IP in database so no multiple votes are possible
 	function saveIP() {
 		$query = 'INSERT INTO '.sql_table('karma').' (itemid, ip) VALUES ('.$this->itemid.",'".addslashes(serverVar('REMOTE_ADDR'))."')";
diff -ruN 3.24.src/nucleus/libs/MANAGER.php 3.31.src/nucleus/libs/MANAGER.php
--- 3.24.src/nucleus/libs/MANAGER.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/MANAGER.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,32 +1,32 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  *	This class makes sure each item/weblog/comment object gets requested from
-  * the database only once, by keeping them in a cache. The class also acts as 
-  * a dynamic classloader, loading classes _only_ when they are first needed,
-  * hoping to diminish execution time
-  *
-  * The class is a singleton, meaning that there will be only one object of it
-  * active at all times. The object can be requested using MANAGER::instance()
-  *
+ * This class makes sure each item/weblog/comment object gets requested from
+ * the database only once, by keeping them in a cache. The class also acts as
+ * a dynamic classloader, loading classes _only_ when they are first needed,
+ * hoping to diminish execution time
+ *
+ * The class is a singleton, meaning that there will be only one object of it
+ * active at all times. The object can be requested using MANAGER::instance()
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: MANAGER.php,v 1.15.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: MANAGER.php 1150 2007-05-19 23:26:02Z kaigreve $
+ */
 class MANAGER {
 
 	/**
-	 * Cached ITEM, BLOG, PLUGIN and KARMA objects. When these objects are requested 
-	 * through the global $manager object (getItem, getBlog, ...), only the first call 
+	 * Cached ITEM, BLOG, PLUGIN, KARMA and MEMBER objects. When these objects are requested
+	 * through the global $manager object (getItem, getBlog, ...), only the first call
 	 * will create an object. Subsequent calls will return the same object.
 	 *
 	 * The $items, $blogs, ... arrays map an id to an object (for plugins, the name is used
@@ -37,7 +37,8 @@
 	var $plugins;
 	var $karma;
 	var $templates;
-	
+	var $members;
+
 	/**
 	 * cachedInfo to avoid repeated SQL queries (see pidInstalled/pluginInstalled/getPidFromName)
 	 * e.g. which plugins exists?
@@ -45,7 +46,7 @@
 	 * $cachedInfo['installedPlugins'] = array($pid -> $name)
 	 */
 	var $cachedInfo;
-	
+
 	/**
 	  * The plugin subscriptionlist
 	  *
@@ -53,23 +54,24 @@
 	  *		$subscriptions[$EventName] = array containing names of plugin classes to be
 	  *									 notified when that event happens
 	  */
-	var $subscriptions;	
-	
+	var $subscriptions;
+
 	/**
-	  * Returns the only instance of this class. Creates the instance if it 
-	  * does not yet exists. Users should use this function as 
+	  * Returns the only instance of this class. Creates the instance if it
+	  * does not yet exists. Users should use this function as
 	  * $manager =& MANAGER::instance(); to get a reference to the object
 	  * instead of a copy
 	  */
 	function &instance() {
-		static $instance = '';
-		if ($instance == '')
-			$instance =& new MANAGER();
-		return $instance;
+		static $instance = array();
+		if (empty($instance)) {
+			$instance[0] =& new MANAGER();
+		}
+		return $instance[0];
 	}
-	
+
 	/**
-	  * The constructor of this class initializes the object caches 
+	  * The constructor of this class initializes the object caches
 	  */
 	function MANAGER() {
 		$this->items = array();
@@ -79,7 +81,7 @@
 		$this->parserPrefs = array();
 		$this->cachedInfo = array();
 	}
-	
+
 	/**
 	  * Returns the requested item object. If it is not in the cache, it will
 	  * first be loaded and then placed in the cache.
@@ -87,15 +89,15 @@
 	  */
 	function &getItem($itemid, $allowdraft, $allowfuture) {
 		$item =& $this->items[$itemid];
-		
-		// check the draft and future rules if the item was already cached 
+
+		// check the draft and future rules if the item was already cached
 		if ($item) {
 			if ((!$allowdraft) && ($item['draft']))
 				return 0;
 
 			$blog =& $this->getBlog(getBlogIDFromItemID($itemid));
 			if ((!$allowfuture) && ($item['timestamp'] > $blog->getCorrectTime()))
-				return 0;				
+				return 0;
 		}
 		if (!$item) {
 			// load class if needed
@@ -106,29 +108,29 @@
 		}
 		return $item;
 	}
-	
+
 	/**
 	  * Loads a class if it has not yet been loaded
 	  */
 	function loadClass($name) {
 		$this->_loadClass($name, $name . '.php');
 	}
-	
+
 	/**
 	  * Checks if an item exists
 	  */
 	function existsItem($id,$future,$draft) {
-		$this->_loadClass('ITEM','ITEM.php');	
+		$this->_loadClass('ITEM','ITEM.php');
 		return ITEM::exists($id,$future,$draft);
 	}
-	
+
 	/**
 	  * Checks if a category exists
 	  */
 	function existsCategory($id) {
 		return (quickQuery('SELECT COUNT(*) as result FROM '.sql_table('category').' WHERE catid='.intval($id)) > 0);
 	}
-	
+
 	function &getBlog($blogid) {
 		$blog =& $this->blogs[$blogid];
 
@@ -141,7 +143,7 @@
 		}
 		return $blog;
 	}
-	
+
 	function existsBlog($name) {
 		$this->_loadClass('BLOG','BLOG.php');
 		return BLOG::exists($name);
@@ -150,8 +152,8 @@
 	function existsBlogID($id) {
 		$this->_loadClass('BLOG','BLOG.php');
 		return BLOG::existsID($id);
-	}	
-	
+	}
+
 	/**
 	 * Returns a previously read template
 	 */
@@ -163,7 +165,7 @@
 			$this->templates[$templateName] =& $template;
 		}
 		return $template;
-	}	
+	}
 
 	/**
 	 * Returns a KARMA object (karma votes)
@@ -179,8 +181,24 @@
 			$this->karma[$itemid] =& $karma;
 		}
 		return $karma;
-	}	
-	
+	}
+
+	/**
+	 * Returns a MEMBER object
+	 */
+	function &getMember($memberid) {
+		$mem =& $this->members[$memberid];
+
+		if (!$mem) {
+			// load class if needed
+			$this->_loadClass('MEMBER','MEMBER.php');
+			// create MEMBER object
+			$mem =& MEMBER::createFromID($memberid);
+			$this->members[$memberid] =& $mem;
+		}
+		return $mem;
+	}
+
 	/**
 	 * Global parser preferences
 	 */
@@ -198,59 +216,77 @@
 		if (!class_exists($name)) {
 				global $DIR_LIBS;
 				include($DIR_LIBS . $filename);
-		}	
+		}
 	}
-	
+
 	function _loadPlugin($name) {
 		if (!class_exists($name)) {
 				global $DIR_PLUGINS;
-				
+
 				$fileName = $DIR_PLUGINS . $name . '.php';
-				
+
 				if (!file_exists($fileName))
 				{
 					ACTIONLOG::add(WARNING, 'Plugin ' . $name . ' was not loaded (File not found)');
 					return 0;
 				}
-				
+
 				// load plugin
 				include($fileName);
-				
+
 				// check if class exists (avoid errors in eval'd code)
 				if (!class_exists($name))
 				{
-					ACTIONLOG::add(WARNING, 'Plugin ' . $name . ' was not loaded (Class not found in file, possible parse error)');				
+					ACTIONLOG::add(WARNING, 'Plugin ' . $name . ' was not loaded (Class not found in file, possible parse error)');
 					return 0;
 				}
-				
+
 				// add to plugin array
 				eval('$this->plugins[$name] =& new ' . $name . '();');
-				
+
 				// get plugid
 				$this->plugins[$name]->plugid = $this->getPidFromName($name);
-				
+
 				// unload plugin if a prefix is used and the plugin cannot handle this^
 				global $MYSQL_PREFIX;
-				if (($MYSQL_PREFIX != '') && !$this->plugins[$name]->supportsFeature('SqlTablePrefix')) 
+				if (($MYSQL_PREFIX != '') && !$this->plugins[$name]->supportsFeature('SqlTablePrefix'))
 				{
 					unset($this->plugins[$name]);
 					ACTIONLOG::add(WARNING, 'Plugin ' . $name . ' was not loaded (does not support SqlTablePrefix)');
 					return 0;
 				}
-				
+
 				// call init method
 				$this->plugins[$name]->init();
-				
-		}	
+
+		}
 	}
-	
+
 	function &getPlugin($name) {
 		$plugin =& $this->plugins[$name];
 
 		if (!$plugin) {
 			// load class if needed
 			$this->_loadPlugin($name);
-			$plugin =& $this->plugins[$name];			
+			$plugin =& $this->plugins[$name];
+		}
+		return $plugin;
+	}
+
+	/**
+	  * checks if the given plugin IS loaded or not
+	  */
+	function &pluginLoaded($name) {
+		$plugin =& $this->plugins[$name];
+		return $plugin;
+	}
+	function &pidLoaded($pid) {
+		$plugin=false;
+		reset($this->plugins);
+		while (list($name) = each($this->plugins)) {
+			if ($pid!=$this->plugins[$name]->getId()) continue;
+			$plugin= & $this->plugins[$name];
+			break;
 		}
 		return $plugin;
 	}
@@ -278,13 +314,13 @@
 	function clearCachedInfo($what) {
 		unset($this->cachedInfo[$what]);
 	}
-	
+
 	/**
 	 * Loads some info on the first call only
 	 */
 	function _initCacheInfo($what)
 	{
-		if (is_array($this->cachedInfo[$what]))
+		if (isset($this->cachedInfo[$what]) && is_array($this->cachedInfo[$what]))
 			return;
 		switch ($what)
 		{
@@ -299,11 +335,11 @@
 				break;
 		}
 	}
-	
+
 	/**
 	  * A function to notify plugins that something has happened. Only the plugins
 	  * that are subscribed to the event will get notified.
-	  * Upon the first call, the list of subscriptions will be fetched from the 
+	  * Upon the first call, the list of subscriptions will be fetched from the
 	  * database. The plugins itsself will only get loaded when they are first needed
 	  *
 	  * @param $eventName
@@ -314,13 +350,16 @@
 	  */
 	function notify($eventName, $data) {
 		// load subscription list if needed
-		if (!is_array($this->subscriptions)) 
+		if (!is_array($this->subscriptions))
 			$this->_loadSubscriptions();
-			
+
 
 		// get listening objects
-		$listeners = $this->subscriptions[$eventName];
-		
+		$listeners = false;
+		if (isset($this->subscriptions[$eventName])) {
+			$listeners = $this->subscriptions[$eventName];
+		}
+
 		// notify all of them
 		if (is_array($listeners)) {
 			foreach($listeners as $listener) {
@@ -331,9 +370,9 @@
 					call_user_func(array(&$this->plugins[$listener],'event_' . $eventName), $data);
 			}
 		}
-		
+
 	}
-	
+
 	/**
 	  * Loads plugin subscriptions
 	  */
@@ -347,7 +386,7 @@
 			$eventName = $o->event;
 			$this->subscriptions[$eventName][] = $pluginName;
 		}
-		
+
 	}
 
 	/*
@@ -356,7 +395,7 @@
 	*/
 
 	var $currentRequestTicket = '';
-	
+
 	/**
 	 * GET requests: Adds ticket to URL (URL should NOT be html-encoded!, ticket is added at the end)
 	 */
@@ -365,63 +404,73 @@
 		$ticketCode = 'ticket=' . $this->_generateTicket();
 		if (strstr($url, '?'))
 			return $url . '&' . $ticketCode;
-		else 
+		else
 			return $url . '?' . $ticketCode;
 	}
-	
+
 	/**
 	 * POST requests: Adds ticket as hidden formvar
 	 */
 	function addTicketHidden()
 	{
 		$ticket = $this->_generateTicket();
-		
+
 		echo '<input type="hidden" name="ticket" value="', htmlspecialchars($ticket), '" />';
 	}
-	
+
+	/**
+	 * Get a new ticket
+	 * (xmlHTTPRequest AutoSaveDraft uses this to refresh the ticket)
+	 */
+	function getNewTicket()
+	{
+		$this->currentRequestTicket = '';
+		return $this->_generateTicket();
+	}
+
 	/**
 	 * Checks the ticket that was passed along with the current request
 	 */
-	function checkTicket() 
+	function checkTicket()
 	{
 		global $member;
-		
+
 		// get ticket from request
 		$ticket = requestVar('ticket');
-		
+
 		// no ticket -> don't allow
 		if ($ticket == '')
 			return false;
-			
+
 		// remove expired tickets first
 		$this->_cleanUpExpiredTickets();
-		
+
 		// get member id
 		if (!$member->isLoggedIn())
 			$memberId = -1;
 		else
 			$memberId = $member->getID();
-		
+
 		// check if ticket is a valid one
 		$query = 'SELECT COUNT(*) as result FROM ' . sql_table('tickets') . ' WHERE member=' . intval($memberId). ' and ticket=\''.addslashes($ticket).'\'';
 		if (quickQuery($query) == 1)
 		{
 			// [in the original implementation, the checked ticket was deleted. This would lead to invalid
 			//  tickets when using the browsers back button and clicking another link/form
-			//  leaving the keys in the database is not a real problem, since they're member-specific and 
+			//  leaving the keys in the database is not a real problem, since they're member-specific and
 			//  only valid for a period of one hour
 			// ]
 			// sql_query('DELETE FROM '.sql_table('tickets').' WHERE member=' . intval($memberId). ' and ticket=\''.addslashes($ticket).'\'');
-			return true;			
+			return true;
 		} else {
 			// not a valid ticket
 			return false;
 		}
 
 	}
-	
+
 	/**
-	 * (internal method) Removes the expired tickets 
+	 * (internal method) Removes the expired tickets
 	 */
 	function _cleanUpExpiredTickets()
 	{
@@ -439,14 +488,14 @@
 		if ($this->currentRequestTicket == '')
 		{
 			// generate new ticket (only one ticket will be generated per page request)
-			// and store in database 
+			// and store in database
 			global $member;
 			// get member id
 			if (!$member->isLoggedIn())
 				$memberId = -1;
 			else
 				$memberId = $member->getID();
-			
+
 			$ok = false;
 			while (!$ok)
 			{
@@ -460,12 +509,12 @@
 				if (sql_query($query))
 					$ok = true;
 			}
-			
+
 			$this->currentRequestTicket = $ticket;
 		}
 		return $this->currentRequestTicket;
 	}
-	
+
 }
 
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/libs/MEDIA.php 3.31.src/nucleus/libs/MEDIA.php
--- 3.24.src/nucleus/libs/MEDIA.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/MEDIA.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,45 +1,45 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * Media classes for nucleus
-  *
+ * Media classes for nucleus
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: MEDIA.php,v 1.12.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: MEDIA.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 
 
 /**
   * Represents the media objects for a certain member
   */
 class MEDIA {
-	
+
 	/**
 	  * Gets the list of collections available to the currently logged
-	  * in member 
+	  * in member
 	  *
 	  * @returns array of dirname => display name
 	  */
 	function getCollectionList() {
 		global $member, $DIR_MEDIA;
-		
+
 		$collections = array();
-		
+
 		// add private directory for member
 		$collections[$member->getID()] = 'Private Collection';
-		
+
 		// add global collections
 		if (!is_dir($DIR_MEDIA)) return $collections;
-		
+
 		$dirhandle = opendir($DIR_MEDIA);
 		while ($dirname = readdir($dirhandle)) {
 			// only add non-numeric (numeric=private) dirs
@@ -48,9 +48,9 @@
 			}
 		}
 		closedir($dirhandle);
-		
+
 		return $collections;
-		
+
 	}
 
 	/**
@@ -59,20 +59,20 @@
 	  * @param $collection
 	  *		name of the collection
 	  * @param $filter
-	  *		filter on filename (defaults to none)	  
+	  *		filter on filename (defaults to none)
 	  */
 	function getMediaListByCollection($collection, $filter = '') {
 		global $DIR_MEDIA;
 
-		$filelist = array();	
-		
+		$filelist = array();
+
 		// 1. go through all objects and add them to the filelist
 
 		$mediadir = $DIR_MEDIA . $collection . '/';
-		
+
 		// return if dir does not exist
 		if (!is_dir($mediadir)) return $filelist;
-		
+
 		$dirhandle = opendir($mediadir);
 		while ($filename = readdir($dirhandle)) {
 			// only add files that match the filter
@@ -83,28 +83,28 @@
 
 		// sort array so newer files are shown first
 		usort($filelist, 'sort_media');
-		
+
 		return $filelist;
 	}
-	
+
 	function checkFilter($strText, $strFilter) {
 		if ($strFilter == '')
 			return 1;
-		else 
+		else
 			return is_integer(strpos(strtolower($strText), strtolower($strFilter)));
 	}
 
 	/**
-	  * checks if a collection exists with the given name, and if it's 
+	  * checks if a collection exists with the given name, and if it's
 	  * allowed for the currently logged in member to upload files to it
-	  */ 
+	  */
 	function isValidCollection($collectionName) {
 		global $member, $DIR_MEDIA;
-		
+
 		// private collections only accept uploads from their owners
 		if (is_numeric($collectionName))
 			return ($member->getID() == $collectionName);
-			
+
 		// other collections should exists and be writable
 		$collectionDir = $DIR_MEDIA . $collectionName;
 		return (@is_dir($collectionDir) || @is_writable($collectionDir));
@@ -116,14 +116,16 @@
 	  * @param collection
 	  *		collection
 	  * @param uploadfile
-	  *		the postFileInfo(..) array 
+	  *		the postFileInfo(..) array
 	  * @param filename
 	  *		the filename that should be used to save the file as
 	  *		(date prefix should be already added here)
 	  */
 	function addMediaObject($collection, $uploadfile, $filename) {
-		global $DIR_MEDIA;
-		
+		global $DIR_MEDIA, $manager;
+
+		$manager->notify('PreMediaUpload',array('collection' => &$collection, 'uploadfile' => $uploadfile, 'filename' => &$filename));
+
 		// don't allow uploads to unknown or forbidden collections
 		if (!MEDIA::isValidCollection($collection))
 			return _ERROR_DISALLOWED;
@@ -136,19 +138,19 @@
 			$oldumask = umask(0000);
 			if (!@mkdir($mediadir, 0777))
 				return _ERROR_BADPERMISSIONS;
-			umask($oldumask);				
-		} 
-		
+			umask($oldumask);
+		}
+
 		// if dir still not exists, the action is disallowed
 		if (!@is_dir($mediadir))
 			return _ERROR_DISALLOWED;
-		
+
 		if (!is_writeable($mediadir))
 			return _ERROR_BADPERMISSIONS;
-			
+
 		// add trailing slash (don't add it earlier since it causes mkdir to fail on some systems)
 		$mediadir .= '/';
-			
+
 		if (file_exists($mediadir . $filename))
 			return _ERROR_UPLOADDUPLICATE;
 
@@ -160,18 +162,20 @@
 			if (!copy($uploadfile, $mediadir . $filename))
 				return _ERROR_UPLOADCOPY ;
 		}
-		
+
 		// chmod uploaded file
 		$oldumask = umask(0000);
-		@chmod($mediadir . $filename, 0644); 
-		umask($oldumask);		
-		
+		@chmod($mediadir . $filename, 0644);
+		umask($oldumask);
+
+		$manager->notify('PostMediaUpload',array('collection' => $collection, 'mediadir' => $mediadir, 'filename' => $filename));
+
 		return '';
-	
+
 	}
-	
+
 	/**
-	 * Adds an uploaded file to the media dir. 
+	 * Adds an uploaded file to the media dir.
 	 *
 	 * @param $collection
 	 *		collection to use
@@ -185,7 +189,7 @@
 	 */
 	function addMediaObjectRaw($collection, $filename, &$data) {
 		global $DIR_MEDIA;
-		
+
 		// check dir permissions (try to create dir if it does not exist)
 		$mediadir = $DIR_MEDIA . $collection;
 
@@ -194,38 +198,38 @@
 			$oldumask = umask(0000);
 			if (!@mkdir($mediadir, 0777))
 				return _ERROR_BADPERMISSIONS;
-			umask($oldumask);				
-		} 
-		
+			umask($oldumask);
+		}
+
 		// if dir still not exists, the action is disallowed
 		if (!@is_dir($mediadir))
 			return _ERROR_DISALLOWED;
-		
+
 		if (!is_writeable($mediadir))
 			return _ERROR_BADPERMISSIONS;
-			
+
 		// add trailing slash (don't add it earlier since it causes mkdir to fail on some systems)
 		$mediadir .= '/';
-			
+
 		if (file_exists($mediadir . $filename))
 			return _ERROR_UPLOADDUPLICATE;
 
 		// create file
 		$fh = @fopen($mediadir . $filename, 'wb');
-		if (!$fh) 
+		if (!$fh)
 			return _ERROR_UPLOADFAILED;
 		$ok = @fwrite($fh, $data);
 		@fclose($fh);
 		if (!$ok)
 			return _ERROR_UPLOADFAILED;
-		
+
 		// chmod uploaded file
 		$oldumask = umask(0000);
-		@chmod($mediadir . $filename, 0644); 
-		umask($oldumask);		
-		
+		@chmod($mediadir . $filename, 0644);
+		umask($oldumask);
+
 		return '';
-	
+
 	}
 
 }
@@ -252,15 +256,15 @@
 		$this->filename = $filename;
 		$this->timestamp = $timestamp;
 	}
-	
+
 }
 
 /**
   * User-defined sort method to sort an array of MEDIAOBJECTS
   */
 function sort_media($a, $b) {
-    if ($a->timestamp == $b->timestamp) return 0;
-    return ($a->timestamp > $b->timestamp) ? -1 : 1;
+	if ($a->timestamp == $b->timestamp) return 0;
+	return ($a->timestamp > $b->timestamp) ? -1 : 1;
 }
 
-?>
\ No newline at end of file
+?>
diff -ruN 3.24.src/nucleus/libs/MEMBER.php 3.31.src/nucleus/libs/MEMBER.php
--- 3.24.src/nucleus/libs/MEMBER.php	2005-08-19 18:37:26.000000000 -0500
+++ 3.31.src/nucleus/libs/MEMBER.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,30 +1,30 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * A class representing site members
-  *
+ * A class representing site members
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: MEMBER.php,v 1.19.2.2 2005/08/19 16:37:26 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: MEMBER.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 class MEMBER {
 
 	// 1 when authenticated, 0 when not
 	var $loggedin = 0;
-	var $password;		// not the actual password, but rather a MD5 hash	
+	var $password;		// not the actual password, but rather a MD5 hash
 
 	var $cookiekey;		// value that should also be in the client cookie to allow authentication
-	
+
 	// member info
 	var $id = -1;
 	var $realname;
@@ -40,43 +40,43 @@
 	function MEMBER() {
 
 	}
-	
+
 	// (static)
-	function createFromName($displayname) {
+	function &createFromName($displayname) {
 		$mem =& new MEMBER();
 		$mem->readFromName($displayname);
 		return $mem;
 	}
-	
+
 	// (static)
-	function createFromID($id) {
+	function &createFromID($id) {
 		$mem =& new MEMBER();
 		$mem->readFromID($id);
 		return $mem;
 	}
-	
+
 	function readFromName($displayname) {
 		return $this->read("mname='".addslashes($displayname)."'");
 	}
-	
+
 	function readFromID($id) {
 		return $this->read("mnumber=" . intval($id));
 	}
-	
+
 	/**
-	  * Tries to login as a given user. Returns true when succeeded, 
+	  * Tries to login as a given user. Returns true when succeeded,
 	  * returns false when failed
 	  */
 	function login($login, $password) {
 		$this->loggedin = 0;
 		if (!$this->readFromName($login))
 			return 0;
-		if (!$this->checkPassword($password)) 
+		if (!$this->checkPassword($password))
 			return 0;
 		$this->loggedin = 1;
 		return $this->isLoggedIn();
 	}
-	
+
 	// login using cookie key
 	function cookielogin($login, $cookiekey) {
 		$this->loggedin = 0;
@@ -87,72 +87,73 @@
 		$this->loggedin = 1;
 		return $this->isLoggedIn();
 	}
-	
+
 	function logout() {
 		$this->loggedin=0;
 	}
-	
+
 	function isLoggedIn() {
 		return $this->loggedin;
 	}
-	
+
 	function read($where) {
 		// read info
 		$query =  'SELECT * FROM '.sql_table('member') . ' WHERE ' . $where;
-		
+
 		$res = sql_query($query);
 		$obj = mysql_fetch_object($res);
-		
+
 		$this->setRealName($obj->mrealname);
 		$this->setEmail($obj->memail);
 		$this->password = $obj->mpassword;
-		$this->setCookieKey($obj->mcookiekey);		
+		$this->setCookieKey($obj->mcookiekey);
 		$this->setURL($obj->murl);
 		$this->setDisplayName($obj->mname);
 		$this->setAdmin($obj->madmin);
 		$this->id = $obj->mnumber;
 		$this->setCanLogin($obj->mcanlogin);
 		$this->setNotes($obj->mnotes);
-		$this->setLanguage($obj->deflang);		
-			
+		$this->setLanguage($obj->deflang);
+
 		return mysql_num_rows($res);
 	}
-	
-	
+
+
 	/**
 	  * Returns true if member is an admin for the given blog
 	  * (returns false if not a team member)
 	  */
 	function isBlogAdmin($blogid) {
 		$query = 'SELECT tadmin FROM '.sql_table('team').' WHERE'
-		       . ' tblog=' . intval($blogid)
-		       . ' and tmember='. $this->getID();
+			   . ' tblog=' . intval($blogid)
+			   . ' and tmember='. $this->getID();
 		$res = sql_query($query);
 		if (mysql_num_rows($res) == 0)
 			return 0;
 		else
-			return (mysql_result($res,0,0) == 1) ;		       
+			return (mysql_result($res,0,0) == 1) ;
 	}
-	
+
 	function blogAdminRights($blogid) {
 		return ($this->isAdmin() || $this->isBlogAdmin($blogid));
 	}
 
-		
+
 	function teamRights($blogid) {
 		return ($this->isAdmin() || $this->isTeamMember($blogid));
 	}
-	
+
 	/**
 	  * Returns true if this member is a team member of the given blog
 	  */
 	function isTeamMember($blogid) {
 		$query = 'SELECT * FROM '.sql_table('team').' WHERE'
-		       . ' tblog=' . intval($blogid)
-		       . ' and tmember='. $this->getID();
-		return (mysql_num_rows(sql_query($query)) != 0);
+			   . ' tblog=' . intval($blogid)
+			   . ' and tmember='. $this->getID();
+		$res = sql_query($query);
+		return (mysql_num_rows($res) != 0);
 	}
-	
+
 	/**
 	  * Returns true if this member can edit/delete a commentitem. This can be in the
 	  * following cases:
@@ -163,15 +164,16 @@
 	  */
 	function canAlterComment($commentid) {
 		if ($this->isAdmin()) return 1;
-	
+
 		$query =  'SELECT citem as itemid, iblog as blogid, cmember as cauthor, iauthor'
-		       . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog')
-		       . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid);
-		$obj = mysql_fetch_object(sql_query($query));
-		
+			   . ' FROM '.sql_table('comment') .', '.sql_table('item').', '.sql_table('blog')
+			   . ' WHERE citem=inumber and iblog=bnumber and cnumber=' . intval($commentid);
+		$res = sql_query($query);
+		$obj = mysql_fetch_object($res);
+
 		return ($obj->cauthor == $this->getID()) or $this->isBlogAdmin($obj->blogid) or ($obj->iauthor == $this->getID());
-	}	
-	
+	}
+
 	/**
 	  * Returns true if this member can edit/delete an item. This is true in the following
 	  * cases: - member is a super-admin
@@ -180,14 +182,15 @@
 	  */
 	function canAlterItem($itemid) {
 		if ($this->isAdmin()) return 1;
-		
+
 		$query =  'SELECT iblog, iauthor FROM '.sql_table('item').' WHERE inumber=' . intval($itemid);
-		$obj = mysql_fetch_object(sql_query($query));
+		$res = sql_query($query);
+		$obj = mysql_fetch_object($res);
 		return ($obj->iauthor == $this->getID()) or $this->isBlogAdmin($obj->iblog);
 	}
-	
+
 	/**
-	  * returns true if this member can move/update an item to a given category, 
+	  * returns true if this member can move/update an item to a given category,
 	  * false if not (see comments fot the tests that are executed)
 	  *
 	  * @param itemid
@@ -195,66 +198,66 @@
 	  */
 	function canUpdateItem($itemid, $newcat) {
 		global $manager;
-		
+
 		// item does not exists -> NOK
 		if (!$manager->existsItem($itemid,1,1)) return 0;
-		
+
 		// cannot alter item -> NOK
 		if (!$this->canAlterItem($itemid)) return 0;
-		
+
 		// if this is a 'newcat' style newcat
 		// no blog admin of destination blog -> NOK
 		// blog admin of destination blog -> OK
 		if (strstr($newcat,'newcat')) {
-			// get blogid 
+			// get blogid
 			list($blogid) = sscanf($newcat,'newcat-%d');
 			return $this->blogAdminRights($blogid);
-		} 
+		}
 
 		// category does not exist -> NOK
 		if (!$manager->existsCategory($newcat)) return 0;
 
-		
+
 		// get item
 		$item =& $manager->getItem($itemid,1,1);
-		
+
 		// old catid = new catid -> OK
 		if ($item['catid'] == $newcat) return 1;
 
 		// not a valid category -> NOK
 		$validCat = quickQuery('SELECT COUNT(*) AS result FROM '.sql_table('category').' WHERE catid='.intval($newcat));
 		if (!$validCat) return 0;
-		
+
 		// get destination blog
 		$source_blogid = getBlogIDFromItemID($itemid);
 		$dest_blogid = getBlogIDFromCatID($newcat);
-		
+
 		// not a team member of destination blog -> NOK
 		if (!$this->teamRights($dest_blogid)) return 0;
 
 		// if member is author of item -> OK
 		if ($item['authorid'] == $this->getID()) return 1;
-		
+
 		// if member has admin rights on both blogs: OK
 		if (($this->blogAdminRights($dest_blogid)) && ($this->blogAdminRights($source_blogid))) return 1;
-		
+
 		// all other cases: NOK
 		return 0;
-		
+
 	}
-	
+
 	function canAddItem($catid) {
 		global $manager;
-		
+
 		// if this is a 'newcat' style newcat
 		// no blog admin of destination blog -> NOK
 		// blog admin of destination blog -> OK
 		if (strstr($catid,'newcat')) {
-			// get blogid 
+			// get blogid
 			list($blogid) = sscanf($catid,"newcat-%d");
 			return $this->blogAdminRights($blogid);
-		} 
-		
+		}
+
 		// category does not exist -> NOK
 		if (!$manager->existsCategory($catid)) return 0;
 
@@ -266,18 +269,17 @@
 		// all other cases: OK
 		return 1;
 	}
-	
-	/** 
-	  * Return true if member can be deleted. This means that there are no items or comments
-	  * posted by the member
+
+	/**
+	  * Return true if member can be deleted. This means that there are no items
+	  * posted by the member left
 	  */
 	function canBeDeleted() {
 		$res = sql_query('SELECT * FROM '.sql_table('item').' WHERE iauthor=' . $this->getID());
-		$res2 = sql_query('SELECT * FROM '.sql_table('comment').' WHERE cmember=' . $this->getID());
-		return ((mysql_num_rows($res) == 0) and (mysql_num_rows($res2)==0));
+		return (mysql_num_rows($res) == 0);
 	}
 
-	/** 
+	/**
 	  * Sets the cookies for the member
 	  *
 	  * @param shared
@@ -286,12 +288,12 @@
 	  */
 	function setCookies($shared = 0) {
 		global $CONF;
-		
+
 		if ($CONF['SessionCookie'] || $shared)
 			$lifetime = 0;
 		else
 			$lifetime = (time()+2592000);
-			
+
 		setcookie($CONF['CookiePrefix'] .'user',$this->getDisplayName(),$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
 		setcookie($CONF['CookiePrefix'] .'loginkey', $this->getCookieKey(),$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
 
@@ -299,35 +301,35 @@
 		if ($shared)
 			setcookie($CONF['CookiePrefix'] .'sharedpc', '1',$lifetime,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
 	}
-	
-	function sendActivationLink($type, $extra='') 
+
+	function sendActivationLink($type, $extra='')
 	{
 		global $CONF;
-		
+
 		// generate key and URL
 		$key = $this->generateActivationEntry($type, $extra);
 		$url = $CONF['AdminURL'] . 'index.php?action=activate&key=' . $key;
-		
+
 		// choose text to use in mail
 		switch ($type)
 		{
 			case 'register':
-				$message = _ACTIVATE_REGISTER_MAIL;			
+				$message = _ACTIVATE_REGISTER_MAIL;
 				$title = _ACTIVATE_REGISTER_MAILTITLE;
 				break;
 			case 'forgot':
-				$message = _ACTIVATE_FORGOT_MAIL;			
+				$message = _ACTIVATE_FORGOT_MAIL;
 				$title = _ACTIVATE_FORGOT_MAILTITLE;
 				break;
 			case 'addresschange':
 				$message = _ACTIVATE_CHANGE_MAIL;
-				$title = _ACTIVATE_CHANGE_MAILTITLE;				
+				$title = _ACTIVATE_CHANGE_MAILTITLE;
 				break;
 			default;
 		}
 
 		// fill out variables in text
-		
+
 		$aVars = array(
 			'siteName' => $CONF['SiteName'],
 			'siteUrl' => $CONF['IndexURL'],
@@ -335,39 +337,39 @@
 			'activationUrl' => $url
 		);
 
-		$message = TEMPLATE::fill($message, $aVars);		
-		$title = TEMPLATE::fill($title, $aVars);		
-		
+		$message = TEMPLATE::fill($message, $aVars);
+		$title = TEMPLATE::fill($title, $aVars);
+
 		// send mail
-		
+
 		@mail($this->getEmail(), $title ,$message,'From: ' . $CONF['AdminEmail']);
-		
-		ACTIONLOG::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')'); 
-		
+
+		ACTIONLOG::add(INFO, _ACTIONLOG_ACTIVATIONLINK . ' (' . $this->getDisplayName() . ' / type: ' . $type . ')');
+
 
 	}
-	
-	/** 
+
+	/**
 	  * Returns an array of all blogids for which member has admin rights
 	  */
 	function getAdminBlogs() {
 		$blogs = array();
-		
+
 		if ($this->isAdmin())
 			$query = 'SELECT bnumber as blogid from '.sql_table('blog');
 		else
 			$query = 'SELECT tblog as blogid from '.sql_table('team').' where tadmin=1 and tmember=' . $this->getID();
-			
+
 		$res = sql_query($query);
 		if (mysql_num_rows($res) > 0) {
 			while ($obj = mysql_fetch_object($res)) {
 				array_push($blogs, $obj->blogid);
 			}
 		}
-		
+
 		return $blogs;
 	}
-	
+
 	/**
 	  * Returns an email address from which notification of commenting/karma voting can
 	  * be sent. A suggestion can be given for when the member is not logged in
@@ -375,7 +377,7 @@
 	function getNotifyFromMailAddress($suggest = "") {
 		global $CONF;
 		if ($this->isLoggedIn()) {
-			return $this->getDisplayName() . " <" . $this->getEmail() . ">"; 
+			return $this->getDisplayName() . " <" . $this->getEmail() . ">";
 		} else if (isValidMailAddress($suggest)) {
 			return $suggest;
 		} else {
@@ -389,56 +391,56 @@
 	function write() {
 
 		$query =  'UPDATE '.sql_table('member')
-		       . " SET mname='" . addslashes($this->getDisplayName()) . "',"
-		       . "     mrealname='". addslashes($this->getRealName()) . "',"
-		       . "     mpassword='". addslashes($this->getPassword()) . "',"
-		       . "     mcookiekey='". addslashes($this->getCookieKey()) . "',"		       
-		       . "     murl='" . addslashes($this->getURL()) . "',"
-		       . "     memail='" . addslashes($this->getEmail()) . "',"
-		       . "     madmin=" . $this->isAdmin() . ","
-		       . "     mnotes='" . addslashes($this->getNotes()) . "',"
-		       . "     mcanlogin=" . $this->canLogin() . ","
-		       . "	   deflang='" . addslashes($this->getLanguage()) . "'"
-		       . " WHERE mnumber=" . $this->getID();
+			   . " SET mname='" . addslashes($this->getDisplayName()) . "',"
+			   . "     mrealname='". addslashes($this->getRealName()) . "',"
+			   . "     mpassword='". addslashes($this->getPassword()) . "',"
+			   . "     mcookiekey='". addslashes($this->getCookieKey()) . "',"
+			   . "     murl='" . addslashes($this->getURL()) . "',"
+			   . "     memail='" . addslashes($this->getEmail()) . "',"
+			   . "     madmin=" . $this->isAdmin() . ","
+			   . "     mnotes='" . addslashes($this->getNotes()) . "',"
+			   . "     mcanlogin=" . $this->canLogin() . ","
+			   . "	   deflang='" . addslashes($this->getLanguage()) . "'"
+			   . " WHERE mnumber=" . $this->getID();
 		sql_query($query);
 	}
-	
+
 	function checkPassword($pw) {
 		return (md5($pw) == $this->getPassword());
 	}
-	
+
 	function checkCookieKey($key) {
 		return (($key != '') && ($key == $this->getCookieKey()));
 	}
-	
+
 	function getRealName() {
 		return $this->realname;
 	}
-	
+
 	function setRealName($name) {
 		$this->realname = $name;
 	}
-	
+
 	function getEmail() {
 		return $this->email;
 	}
-	
+
 	function setEmail($email) {
 		$this->email = $email;
 	}
-	
+
 	function getPassword() {
 		return $this->password;
 	}
-	
+
 	function setPassword($pwd) {
 		$this->password = md5($pwd);
 	}
-	
+
 	function getCookieKey() {
 		return $this->cookiekey;
 	}
-	
+
 	/**
 	  * Generate new cookiekey, save it, and return it
 	  */
@@ -448,7 +450,7 @@
 		$this->write();
 		return $this->cookiekey;
 	}
-	
+
 	function setCookieKey($val) {
 		$this->cookiekey = $val;
 	}
@@ -456,39 +458,39 @@
 	function getURL() {
 		return $this->url;
 	}
-	
+
 	function setURL($site) {
 		$this->url = $site;
 	}
-	
+
 	function getLanguage() {
 		return $this->language;
 	}
-	
+
 	function setLanguage($lang) {
 		$this->language = $lang;
 	}
-	
+
 	function setDisplayName($nick) {
 		$this->displayname = $nick;
 	}
-	
+
 	function getDisplayName() {
 		return $this->displayname;
 	}
-	
+
 	function isAdmin() {
 		return $this->admin;
 	}
-	
+
 	function setAdmin($val) {
 		$this->admin = $val;
 	}
-	
+
 	function canLogin() {
 		return $this->canlogin;
 	}
-	
+
 	function setCanLogin($val) {
 		$this->canlogin = $val;
 	}
@@ -496,11 +498,11 @@
 	function getNotes() {
 		return $this->notes;
 	}
-	
+
 	function setNotes($val) {
 		$this->notes = $val;
 	}
-	
+
 	function getID() {
 		return $this->id;
 	}
@@ -516,17 +518,17 @@
 		$r = sql_query('select * FROM '.sql_table('member')." WHERE mnumber='".intval($id)."'");
 		return (mysql_num_rows($r) != 0);
 	}
-	
+
 	// checks if a username is protected. If so, it can not be used on anonymous comments
 	function isNameProtected($name) {
-		
+
 		// extract name
-		$name = strip_tags($name);	
-		$name = trim($name);		
-		
+		$name = strip_tags($name);
+		$name = trim($name);
+
 		return MEMBER::exists($name);
 	}
-	
+
 	// adds a new member (static)
 	function create($name, $realname, $password, $email, $url, $admin, $canlogin, $notes) {
 		if (!isValidMailAddress($email))
@@ -536,13 +538,13 @@
 			return _ERROR_BADNAME;
 
 		if (MEMBER::exists($name))
-			return _ERROR_NICKNAMEINUSE;	
+			return _ERROR_NICKNAMEINUSE;
 
 		if (!$realname)
 			return _ERROR_REALNAMEMISSING;
 
 		if (!$password)
-			return _ERROR_PASSWORDMISSING;			
+			return _ERROR_PASSWORDMISSING;
 
 		// Sometimes user didn't prefix the URL with http://, this cause a malformed URL. Let's fix it.
 		if (!eregi("^https?://", $url))
@@ -558,14 +560,14 @@
 		$notes = addslashes($notes);
 
 		$query = 'INSERT INTO '.sql_table('member')." (MNAME,MREALNAME,MPASSWORD,MEMAIL,MURL, MADMIN, MCANLOGIN, MNOTES) "
-		       . "VALUES ('$name','$realname','$password','$email','$url',$admin, $canlogin, '$notes')";
+			   . "VALUES ('$name','$realname','$password','$email','$url',$admin, $canlogin, '$notes')";
 		sql_query($query);
-		
-		ACTIONLOG::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name);		
+
+		ACTIONLOG::add(INFO, _ACTIONLOG_NEWMEMBER . ' ' . $name);
 
 		return 1;
-	}	
-	
+	}
+
 	/**
 	 * Returns activation info for a certain key (an object with properties vkey, vmember, ...)
 	 * (static)
@@ -582,7 +584,7 @@
 		else
 			return mysql_fetch_object($res);
 	}
-	
+
 	/**
 	 * Creates an account activation key
 	 *
@@ -594,16 +596,16 @@
 	 *				  addresschange -> old email address
 	 * @author dekarma
 	 */
-	function generateActivationEntry($type, $extra = '') 
+	function generateActivationEntry($type, $extra = '')
 	{
 		// clean up old entries
 		$this->cleanupActivationTable();
-	
+
 		// kill any existing entries for the current member (delete is ok)
 		// (only one outstanding activation key can be present for a member)
 		sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vmember=' . intval($this->getID()));
 
-		$canLoginWhileActive = false; // indicates if the member can log in while the link is active 
+		$canLoginWhileActive = false; // indicates if the member can log in while the link is active
 		switch ($type)
 		{
 			case 'forgot':
@@ -615,14 +617,14 @@
 				$extra = $extra . '/' . ($this->canLogin() ? '1' : '0');
 				break;
 		}
-		
+
 		$ok = false;
 		while (!$ok)
 		{
 			// generate a random key
 			srand((double)microtime()*1000000);
 			$key = md5(uniqid(rand(), true));
-			
+
 			// attempt to add entry in database
 			// add in database as non-active
 			$query = 'INSERT INTO ' . sql_table('activation'). ' (vkey, vtime, vmember, vtype, vextra) ';
@@ -630,33 +632,33 @@
 			if (sql_query($query))
 				$ok = true;
 		}
-		
+
 		// mark member as not allowed to log in
 		if (!$canLoginWhileActive)
 		{
 			$this->setCanLogin(0);
-			$this->write();	
+			$this->write();
 		}
-		
+
 		// return the key
 		return $key;
 	}
-	
+
 	/**
 	 * Inidicates that an activation link has been clicked and any forms displayed
 	 * there have been successfully filled out.
 	 * @author dekarma
 	 */
-	function activate($key) 
+	function activate($key)
 	{
 		// get activate info
 		$info = MEMBER::getActivationInfo($key);
-		
+
 		// no active key
 		if (!$info)
 			return false;
-			
-		switch ($info->vtype) 
+
+		switch ($info->vtype)
 		{
 			case 'forgot':
 				// nothing to do
@@ -672,27 +674,27 @@
 				sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ' WHERE mnumber=' . intval($info->vmember));
 				break;
 		}
-		
+
 		// delete from activation table
 		sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vkey=\'' . addslashes($key) . '\'');
-		
+
 		// success!
 		return true;
 	}
-	
+
 	/**
 	 * Cleans up entries in the activation table. All entries older than 2 days are removed.
 	 * (static)
 	 *
 	 * @author dekarma
 	 */
-	function cleanupActivationTable() 
+	function cleanupActivationTable()
 	{
 		$boundary = time() - (60 * 60 * 24 * 2);
-		
+
 		// 1. walk over all entries, and see if special actions need to be performed
 		$res = sql_query('SELECT * FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');
-		
+
 		while ($o = mysql_fetch_object($res))
 		{
 			switch ($o->vtype)
@@ -707,14 +709,14 @@
 					// revert the e-mail address of the member back to old address
 					list($oldEmail, $oldCanLogin) = explode('/', $o->vextra);
 					sql_query('UPDATE ' . sql_table('member') . ' SET mcanlogin=' . intval($oldCanLogin). ', memail=\'' . addslashes($oldEmail). '\' WHERE mnumber=' . intval($o->vmember));
-					break;					
+					break;
 				case 'forgot':
-					// delete the activation link and ignore. member can request a new password using the 
+					// delete the activation link and ignore. member can request a new password using the
 					// forgot password link
 					break;
 			}
 		}
-		
+
 		// 2. delete activation entries for real
 		sql_query('DELETE FROM ' . sql_table('activation') . ' WHERE vtime < \'' . date('Y-m-d H:i:s',$boundary) . '\'');
 	}
diff -ruN 3.24.src/nucleus/libs/mysql.php 3.31.src/nucleus/libs/mysql.php
--- 3.24.src/nucleus/libs/mysql.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/libs/mysql.php	2007-10-22 19:36:00.000000000 -0500
@@ -0,0 +1,121 @@
+<?php
+
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+/**
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: mysql.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
+ 
+/*
+ * if no mysql_* functions exist, define wrappers
+ */
+ 
+$MYSQL_CONN = 0;
+
+if (!function_exists('mysql_query'))
+{
+	if (!function_exists('mysqli_query') && function_exists('startUpError'))
+	{
+		startUpError('<p>No suitable mySQL library was found to run Nucleus</p>');
+	}
+	
+	function mysql_query($query) 
+	{
+		global $MYSQL_CONN;
+		return mysqli_query($MYSQL_CONN, $query); 
+	}
+	
+	function mysql_fetch_object($res) 
+	{ 
+		return mysqli_fetch_object($res);
+	}
+	
+	function mysql_fetch_array($res) 
+	{ 
+		return mysqli_fetch_array($res);
+	}	
+	
+	function mysql_fetch_assoc($res) 
+	{ 
+		return mysqli_fetch_assoc($res);
+	}	
+
+	function mysql_fetch_row($res) 
+	{ 
+		return mysqli_fetch_row($res);
+	}	
+
+	function mysql_num_rows($res)
+	{
+		return mysqli_num_rows($res);
+	}
+	
+	function mysql_num_fields($res)
+	{
+		return mysqli_num_fields($res);
+	}
+	
+	function mysql_free_result($res)
+	{
+		return mysqli_free_result($res);
+	}
+	
+	function mysql_result($res, $row, $col) 
+	{ 
+		if (($row != 0) || ($col != 0)) {
+			trigger_error('not implemented', E_USER_ERROR);
+		}
+		
+		$row = mysqli_fetch_row($res);
+		return $row[$col];
+	}	
+	
+	function mysql_connect($host, $username, $pwd)
+	{
+		return mysqli_connect($host, $username, $pwd);
+	}
+	
+	function mysql_error()
+	{
+		global $MYSQL_CONN;
+		return mysqli_error($MYSQL_CONN);
+	}
+	
+	function mysql_select_db($db)
+	{
+		global $MYSQL_CONN;
+		return mysqli_select_db($MYSQL_CONN, $db);
+	}
+	
+	function mysql_close()
+	{
+		global $MYSQL_CONN;
+		return mysqli_close($MYSQL_CONN);
+	}
+	
+	function mysql_insert_id()
+	{
+		global $MYSQL_CONN;
+		return mysqli_insert_id($MYSQL_CONN);
+	}
+	
+	function mysql_affected_rows()
+	{
+		global $MYSQL_CONN;
+		return mysqli_affected_rows($MYSQL_CONN);
+	}
+}
+
+
+
+?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/libs/NOTIFICATION.php 3.31.src/nucleus/libs/NOTIFICATION.php
--- 3.24.src/nucleus/libs/NOTIFICATION.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/NOTIFICATION.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,22 +1,22 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * Class used to represent a collection of e-mail addresses, to which a
-  * message can be sent (e.g. comment or karma vote notification).
-  *
+ * Class used to represent a collection of e-mail addresses, to which a
+ * message can be sent (e.g. comment or karma vote notification).
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: NOTIFICATION.php,v 1.9.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: NOTIFICATION.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 class NOTIFICATION {
 
 	// array of addresses that need to get a notification
@@ -36,28 +36,28 @@
 	  */
 	function validAddresses() {
 		foreach ( $this->addresses as $address ) {
-			if (!isValidMailAddress(trim($address))) 
+			if (!isValidMailAddress(trim($address)))
 				return 0;
 		}
 		return 1;
 	}
-	
+
 	/**
 	  * Sends email messages to all the email addresses
 	  */
 	function notify($title, $message, $from) {
 		global $member;
-			
+
 		foreach ( $this->addresses as $address ) {
 			$address = trim($address);
-			
+
 			if (!$address)
 				continue;
-			
+
 			// don't send messages to yourself
 			if ($member->isLoggedIn() && ($member->getEmail() == $address))
 				continue;
-		
+
 			@mail($address, $title, $message , "From: ". $from . "\nContent-Type: text/plain; charset=utf-8");
 		}
 	}
diff -ruN 3.24.src/nucleus/libs/PAGEFACTORY.php 3.31.src/nucleus/libs/PAGEFACTORY.php
--- 3.24.src/nucleus/libs/PAGEFACTORY.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/PAGEFACTORY.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,22 +1,22 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: PAGEFACTORY.php,v 1.20.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: PAGEFACTORY.php 1187 2007-08-06 14:43:00Z kaigreve $
+ */
 
 /**
- * The formfactory class can be used to insert add/edit item forms into 
+ * The formfactory class can be used to insert add/edit item forms into
  * admin area, bookmarklet, skins or any other places where such a form
  * might be needed
  */
@@ -24,17 +24,17 @@
 
 	// ref to the blog object for which an add:edit form is created
 	var $blog;
-	
+
 	// allowed actions (for parser)
 	var $actions;
-	
+
 	// allowed types of forms (bookmarklet/admin)
 	var $allowedTypes;
 	var $type;		// one of the types in $allowedTypes
-	
+
 	// 'add' or 'edit'
 	var $method;
-	
+
 	// info to fill out in the form (e.g. catid, itemid, ...)
 	var $variables;
 
@@ -43,15 +43,15 @@
 	 */
 	function PAGEFACTORY($blogid) {
 		// call constructor of superclass first
-		$this->BaseActions();			
-		
+		$this->BaseActions();
+
 		global $manager;
 		$this->blog =& $manager->getBlog($blogid);
-		
-		// TODO: move the definition of actions to the createXForm 
+
+		// TODO: move the definition of actions to the createXForm
 		// methods
 		$this->actions = Array(
-			'actionurl', 
+			'actionurl',
 			'title',
 			'body',
 			'more',
@@ -78,39 +78,39 @@
 			'extrahead',
 			'ticket'
 		);
-		
+
 		// TODO: maybe add 'skin' later on?
 		// TODO: maybe add other pages from admin area
-		$this->allowedTypes = Array('bookmarklet','admin');	
+		$this->allowedTypes = Array('bookmarklet','admin');
 	}
 
 	/**
 	 * creates a "add item" form for a given type of page
 	 *
 	 * @param type
-	 *		'admin' or 'bookmarklet' 
+	 *		'admin' or 'bookmarklet'
 	 */
 	function createAddForm($type, $contents = array()) {
 		if (!in_array($type, $this->allowedTypes))
 			return;
 		$this->type = $type;
 		$this->method = 'add';
-		
+
 		global $manager;
 		$manager->notify('PreAddItemForm', array('contents' => &$contents, 'blog' => &$this->blog));
-		
+
 		$this->createForm($contents);
 	}
-	
+
 	/**
 	 * creates a "add item" form for a given type of page
 	 *
 	 * @param type
-	 *		'admin' or 'bookmarklet' 
+	 *		'admin' or 'bookmarklet'
 	 * @param contents
 	 *		An associative array
 	 *			'author' => author
-	 *			'' => 
+	 *			'' =>
 	 */
 	function createEditForm($type, $contents) {
 		if (!in_array($type, $this->allowedTypes))
@@ -119,68 +119,68 @@
 		$this->method = 'edit';
 		$this->createForm($contents);
 	}
-	
+
 	/**
 	 * (private) creates a form for a given type of page
 	 */
 	function createForm($contents) {
 		// save contents
 		$this->variables = $contents;
-		
+
 		// get template to use
 		$template = $this->getTemplateFor($this->type);
-		
+
 		// use the PARSER engine to parse that template
 		$parser =& new PARSER($this->actions, $this);
 		$parser->parse($template);
 	}
-	
+
 	/**
 	 * returns an appropriate template
 	 */
 	function getTemplateFor($type) {
 		global $DIR_LIBS;
-		
+
 		$filename = $DIR_LIBS . 'include/' . $this->type . '-' . $this->method . '.template';
-		
-		if (!file_exists($filename)) 
+
+		if (!file_exists($filename))
 			return '';
 
 		$fsize = filesize($filename);
 		if ($fsize <= 0)
 			return '';
-			
+
 		// read file and return it
 		$fd = fopen ($filename, 'r');
 		$contents = fread ($fd, $fsize);
 		fclose ($fd);
-		
+
 		return $contents;
-		
+
 	}
-	
+
 	// create category dropdown box
 	function parse_categories($startidx = 0) {
-			if ($this->variables['catid']) 
+			if ($this->variables['catid'])
 				$catid = $this->variables['catid'];				// on edit item
 			else
 				$catid = $this->blog->getDefaultCategory();		// on add item
-			
+
 			ADMIN::selectBlogCategory('catid',$catid,$startidx,1,$this->blog->getID());
 	}
-	
+
 	function parse_blogid() {
 		echo $this->blog->getID();
 	}
-	
+
 	function parse_blogname() {
 		echo $this->blog->getName();
 	}
-	
+
 	function parse_bloglink() {
-		echo '<a href="'.htmlspecialchars($this->blog->getURL()).'">'.$this->blog->getName().'</a>';
+		echo '<a href="'.htmlspecialchars($this->blog->getURL()).'">'.htmlspecialchars($this->blog->getName()).'</a>';
 	}
-	
+
 	function parse_authorname() {
 		// don't use on add item?
 		global $member;
@@ -193,7 +193,7 @@
 
 	/**
 	 * Indicates the start of a conditional block of data. It will be added to
-	 * the output only if the blogsetting with the given name equals the 
+	 * the output only if the blogsetting with the given name equals the
 	 * given value (default for value = 1 = true)
 	 *
 	 * the name of the blogsetting is the column name in the nucleus_blog table
@@ -203,97 +203,103 @@
 	function parse_ifblogsetting($name,$value=1) {
 		$this->_addIfCondition(($this->blog->getSetting($name) == $value));
 	}
-	
+
 	function parse_ifitemproperty($name,$value=1) {
 		$this->_addIfCondition(($this->variables[$name] == $value));
 	}
-	
+
 	function parse_helplink($topic) {
 		help($topic);
 	}
-	
+
 	// for future items
 	function parse_currenttime($what) {
 		$nu = getdate($this->blog->getCorrectTime());
 		echo $nu[$what];
 	}
-	
+
 	// date change on edit item
 	function parse_itemtime($what) {
 		$itemtime = getdate($this->variables['timestamp']);
 		echo $itemtime[$what];
 	}
-	
+
 	// some init stuff for all forms
 	function parse_init() {
 		$authorid = ($this->method == 'edit') ? $this->variables['authorid'] : '';
-		$this->blog->insertJavaScriptInfo($authorid);		
+		$this->blog->insertJavaScriptInfo($authorid);
 	}
-	
+
 	// on bookmarklets only: insert extra html header information (by plugins)
 	function parse_extrahead() {
 		global $manager;
-		
+
 		$extrahead = '';
-		
+
 		$manager->notify(
 			'BookmarkletExtraHead',
 			array(
 				'extrahead' => &$extrahead
 			)
 		);
-		
+
 		echo $extrahead;
 	}
-	
+
 	// inserts some localized text
 	function parse_text($which) {
 		// constant($which) only available from 4.0.4 :(
-		if (defined($which)) { 	
+		if (defined($which)) {
 			eval("echo $which;");
 		} else {
 			echo $which;	// this way we see where definitions are missing
 		}
-		
+
 	}
-	
+
 	function parse_contents($which) {
-		echo htmlspecialchars($this->variables[$which]);
+		echo htmlspecialchars($this->variables[$which],ENT_QUOTES);
 	}
-	
+
 	function parse_checkedonval($value, $name) {
 		if ($this->variables[$name] == $value)
 			echo "checked='checked'";
 	}
-	
+
 	// extra javascript for input and textarea fields
 	function parse_jsinput($which) {
 		global $CONF;
 	?>
-			name="<?php echo $which?>" 
-			id="input<?php echo $which?>" 
+			name="<?php echo $which?>"
+			id="input<?php echo $which?>"
 	<?php
 		if ($CONF['DisableJsTools'] != 1) {
 	?>
-			onkeyup="storeCaret(this); updPreview('<?php echo $which?>');"
+			onkeyup="storeCaret(this); updPreview('<?php echo $which?>'); doMonitor();"
 			onclick="storeCaret(this);"
-			onselect="storeCaret(this);" 
+			onselect="storeCaret(this);"
 
-	<?php		
-		} 
-		
-		if ($CONF['DisableJsTools'] == 0) {
+	<?php
+		}
+		else if ($CONF['DisableJsTools'] == 0) {
+	?>
+			onkeyup="doMonitor();"
+			onkeypress="shortCuts();"
+	<?php
+		}
+		else {
 	?>
-	  	    onkeypress="shortCuts();"			
-	<?php		}
+			onkeyup="doMonitor();"
+	<?php
+		}
 	}
-	
+
 	// shows the javascript button bar
 	function parse_jsbuttonbar($extrabuttons = "") {
 		global $CONF;
 		switch($CONF['DisableJsTools'])	{
 
-			case "0":	
+			case "0":
 				echo '<div class="jsbuttonbar">';
 
 					$this->_jsbutton('cut','cutThis()',_ADD_CUT_TT . " (Ctrl + X)");
@@ -303,32 +309,32 @@
 					$this->_jsbutton('bold',"boldThis()",_ADD_BOLD_TT ." (Ctrl + Shift + B)");
 					$this->_jsbutton('italic',"italicThis()",_ADD_ITALIC_TT ." (Ctrl + Shift + I)");
 					$this->_jsbutton('link',"ahrefThis()",_ADD_HREF_TT ." (Ctrl + Shift + A)");
-					$this->_jsbuttonspacer();					
+					$this->_jsbuttonspacer();
 					$this->_jsbutton('alignleft',"alignleftThis()",_ADD_ALIGNLEFT_TT);
 					$this->_jsbutton('alignright',"alignrightThis()",_ADD_ALIGNRIGHT_TT);
 					$this->_jsbutton('aligncenter',"aligncenterThis()",_ADD_ALIGNCENTER_TT);
-					$this->_jsbuttonspacer();					
+					$this->_jsbuttonspacer();
 					$this->_jsbutton('left',"leftThis()",_ADD_LEFT_TT);
 					$this->_jsbutton('right',"rightThis()",_ADD_RIGHT_TT);
 
-				
+
 					if ($extrabuttons) {
 						$btns = explode('+',$extrabuttons);
 						$this->_jsbuttonspacer();
 						foreach ($btns as $button) {
 							switch($button) {
 								case "media":
-									$this->_jsbutton('media',"addMedia()",_ADD_MEDIA_TT .	" (Ctrl + Shift + M)");							
+									$this->_jsbutton('media',"addMedia()",_ADD_MEDIA_TT .	" (Ctrl + Shift + M)");
 									break;
 								case "preview":
 									$this->_jsbutton('preview',"showedit()",_ADD_PREVIEW_TT);
 									break;
 							}
 						}
-					} 
-					
+					}
+
 				echo '</div>';
-				
+
 				break;
 			case "2":
 				echo '<div class="jsbuttonbar">';
@@ -336,14 +342,14 @@
 					$this->_jsbutton('bold',"boldThis()",'');
 					$this->_jsbutton('italic',"italicThis()",'');
 					$this->_jsbutton('link',"ahrefThis()",'');
-					$this->_jsbuttonspacer();										
+					$this->_jsbuttonspacer();
 					$this->_jsbutton('alignleft',"alignleftThis()",_ADD_ALIGNLEFT_TT);
 					$this->_jsbutton('alignright',"alignrightThis()",_ADD_ALIGNRIGHT_TT);
 					$this->_jsbutton('aligncenter',"aligncenterThis()",_ADD_ALIGNCENTER_TT);
-					$this->_jsbuttonspacer();					
+					$this->_jsbuttonspacer();
 					$this->_jsbutton('left',"leftThis()",_ADD_LEFT_TT);
 					$this->_jsbutton('right',"rightThis()",_ADD_RIGHT_TT);
-					
+
 
 					if ($extrabuttons) {
 						$btns = explode('+',$extrabuttons);
@@ -351,34 +357,34 @@
 						foreach ($btns as $button) {
 							switch($button) {
 								case "media":
-									$this->_jsbutton('media',"addMedia()",'');							
+									$this->_jsbutton('media',"addMedia()",'');
 									break;
 							}
 						}
-					} 
-					
+					}
+
 				echo '</div>';
-				
-				break;			
+
+				break;
 		}
 	}
-	
+
 	/**
 	 * Allows plugins to add their own custom fields
 	 */
 	function parse_pluginextras() {
 		global $manager;
-			
+
 		switch ($this->method) {
 			case 'add':
-				$manager->notify('AddItemFormExtras', 
+				$manager->notify('AddItemFormExtras',
 						array(
 							'blog' => &$this->blog
 						)
 				);
 				break;
 			case 'edit':
-				$manager->notify('EditItemFormExtras', 
+				$manager->notify('EditItemFormExtras',
 						array(
 							'variables' => $this->variables,
 							'blog' => &$this->blog,
@@ -388,38 +394,38 @@
 				break;
 		}
 	}
-	
+
 	/**
 	 * Adds the itemOptions of a plugin to a page
 	 * @author TeRanEX
 	 */
-    function parse_itemoptions() {
+	function parse_itemoptions() {
 		global $itemid;
 		ADMIN::_insertPluginOptions('item', $itemid);
-    }
-    
-    function parse_ticket() {
-    	global $manager;
-    	$manager->addTicketHidden();
-    }
-	
+	}
+
+	function parse_ticket() {
+		global $manager;
+		$manager->addTicketHidden();
+	}
+
 	/**
 	 * convenience method
 	 */
 	function _jsbutton($type, $code ,$tooltip) {
 	?>
 			<span class="jsbutton"
-				onmouseover="BtnHighlight(this);" 
-				onmouseout="BtnNormal(this);" 
-				onclick="<?php echo $code?>" >			
+				onmouseover="BtnHighlight(this);"
+				onmouseout="BtnNormal(this);"
+				onclick="<?php echo $code?>" >
 				<img src="images/button-<?php echo $type?>.gif" alt="<?php echo $tooltip?>" width="16" height="16"/>
-			</span>				
+			</span>
 	<?php	}
-	
+
 	function _jsbuttonspacer() {
 		echo '<span class="jsbuttonspacer"></span>';
 	}
-	
+
 }
- 
+
  ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/libs/PARSER.php 3.31.src/nucleus/libs/PARSER.php
--- 3.24.src/nucleus/libs/PARSER.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/PARSER.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,20 +1,23 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: PARSER.php,v 1.14.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
- 
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: PARSER.php 1148 2007-05-19 23:02:46Z kaigreve $
+ */
+
+if ( !function_exists('requestVar') ) exit;
+require_once dirname(__FILE__) . '/BaseActions.php';
+
 /**
  * This is the parser class of Nucleus. It is used for various things (skin parsing,
  * form generation, ...)
@@ -23,27 +26,27 @@
 
 	// array with the names of all allowed actions
 	var $actions;
-	
+
 	// reference to actions handler
 	var $handler;
-	
+
 	// delimiters that can be used for skin/templatevars
 	var $delim;
-	
+
 	// parameter delimiter (to separate skinvar params)
 	var $pdelim;
-	
+
 	// usually set to 0. When set to 1, all skinvars are allowed regardless of $actions
 	var $norestrictions;
-	
+
 	/**
-	 * Creates a new parser object with the given allowed actions 
+	 * Creates a new parser object with the given allowed actions
 	 * and the given handler
 	 *
 	 * @param $allowedActions array
 	 * @param $handler class object with functions for each action (reference)
 	 * @param $delim optional delimiter
-	 * @param $paramdelim optional parameterdelimiter	 
+	 * @param $paramdelim optional parameterdelimiter
 	 */
 	function PARSER($allowedActions, &$handler, $delim = '(<%|%>)', $pdelim = ',') {
 		$this->actions = $allowedActions;
@@ -52,55 +55,57 @@
 		$this->pdelim = $pdelim;
 		$this->norestrictions = 0;	// set this to 1 to disable checking for allowedActions
 	}
-	
+
 	/**
 	 * Parses the given contents and outputs it
 	 */
 	function parse(&$contents) {
-	
+
 		$pieces = preg_split('/'.$this->delim.'/',$contents);
-		
+
 		$maxidx = sizeof($pieces);
-		for ($idx = 0;$idx<$maxidx;$idx++) {
-			echo $pieces[$idx];		
+		for ($idx = 0; $idx < $maxidx; $idx++) {
+			echo $pieces[$idx];
 			$idx++;
-			$this->doAction($pieces[$idx]);
+			if ($idx < $maxidx) {
+				$this->doAction($pieces[$idx]);
+			}
 		}
 	}
-	
+
 
 	/**
-	  * handle an action 
+	  * handle an action
 	  */
 	function doAction($action) {
 		global $manager;
 
 		if (!$action) return;
-		
+
 		// split into action name + arguments
 		if (strstr($action,'(')) {
 			$paramStartPos = strpos($action, '(');
 			$params = substr($action, $paramStartPos + 1, strlen($action) - $paramStartPos - 2);
 			$action = substr($action, 0, $paramStartPos);
 			$params = explode ($this->pdelim, $params);
-			
-			// trim parameters 
+
+			// trim parameters
 			// for PHP versions lower than 4.0.6:
-			//   - add // before '$params = ...' 
+			//   - add // before '$params = ...'
 			//   - remove // before 'foreach'
 			$params = array_map('trim',$params);
-			// foreach ($params as $key => $value) { $params[$key] = trim($value); }			
+			// foreach ($params as $key => $value) { $params[$key] = trim($value); }
 		} else {
 			// no parameters
 			$params = array();
 		}
-	
+
 		$actionlc = strtolower($action);
-		
+
 		// skip execution of skinvars while inside an if condition which hides this part of the page
-		if (!$this->handler->if_currentlevel && ($actionlc != 'else') && ($actionlc != 'endif') && (substr($actionlc,0,2) != 'if'))
+		if (!$this->handler->if_currentlevel && ($actionlc != 'else') && ($actionlc != 'elseif') && ($actionlc != 'endif') && ($actionlc != 'ifnot') && ($actionlc != 'elseifnot') && (substr($actionlc,0,2) != 'if'))
 			return;
-	
+
 		if (in_array($actionlc, $this->actions) || $this->norestrictions ) {
 			// when using PHP versions lower than 4.0.5, uncomment the line before
 			// and comment the call_user_func_array call
@@ -111,11 +116,11 @@
 			if (in_array('plugin', $this->actions) && $manager->pluginInstalled('NP_'.$action))
 				$this->doAction('plugin('.$action.$this->pdelim.implode($this->pdelim,$params).')');
 			else
-				echo '<b>DISALLOWED (' , $action , ')</b>';
+				echo '&lt;%' , $action , '(', implode($this->pdelim, $params), ')%&gt;';
 		}
-		
+
 	}
-	
+
 	/**
 	  * Calls a method using an array of parameters (for use with PHP versions lower than 4.0.5)
 	  * ( = call_user_func_array() function )
@@ -123,7 +128,7 @@
 	function call_using_array($methodname, &$handler, $paramarray) {
 
 		$methodname = 'parse_' . $methodname;
-		
+
 		if (!method_exists($handler, $methodname)) {
 			return;
 		}
@@ -134,230 +139,18 @@
 		$command .= ');';
 		eval($command);	// execute the correct method
 	}
-	
+
 	function setProperty($property, $value) {
 		global $manager;
 		$manager->setParserProperty($property, $value);
 	}
-	
+
 	function getProperty($name) {
 		global $manager;
 		return $manager->getParserProperty($name);
 	}
-	
-	
-}
 
-/**
- * This class contains parse actions that are available in all ACTION classes
- * e.g. include, phpinclude, parsedinclude, skinfile, ...
- *
- * It should never be used on it's own
- */
-class BaseActions {
-	
-	// depth level for includes (max. level is 3)
-	var $level;
-	
-	// array of evaluated conditions (true/false). The element at the end is the one for the most nested
-	// if block.
-	var $if_conditions;
-	
-	// at all times, can be evaluated to either true if the current block needs to be displayed. This 
-	// variable is used to decide to skip skinvars in parts that will never be outputted.
-	var $if_currentlevel;
-	
-	// contains a search string with keywords that need to be highlighted. These get parsed into $aHighlight
-	var $strHighlight;
-	
-	// array of keywords that need to be highlighted in search results (see the highlight() 
-	// and parseHighlight() methods)
-	var $aHighlight;
-	
-
-	// reference to the parser object that is using this object as actions-handler
-
-	var $parser;
-	
-
-	function BaseActions() {
-		$this->level = 0; 
-		
-		// if nesting level
-		$this->if_conditions = array(); // array on which condition values are pushed/popped
-		$this->if_currentlevel = 1;		// 1 = current level is displayed; 0 = current level not displayed
-
-		// highlights		
-		$this->strHighlight = '';			// full highlight
-		$this->aHighlight = array();		// parsed highlight
-		
-	}
-
-	// include file (no parsing of php)
-	function parse_include($filename) {
-		@readfile($this->getIncludeFileName($filename));
-	}
-	
-	// php-include file 
-	function parse_phpinclude($filename) {
-		includephp($this->getIncludeFileName($filename));
-	}	
-	// parsed include
-	function parse_parsedinclude($filename) {
-		// check current level
-		if ($this->level > 3) return;	// max. depth reached (avoid endless loop)
-		$filename = $this->getIncludeFileName($filename);
-		if (!file_exists($filename)) return '';
-		
-		$fsize = filesize($filename);
-		
-		// nothing to include
-		if ($fsize <= 0)
-			return;
-		
-		$this->level = $this->level + 1;
-		
-		// read file 
-		$fd = fopen ($filename, 'r');
-		$contents = fread ($fd, $fsize);
-		fclose ($fd);		
-		
-		// parse file contents
-		$this->parser->parse($contents);
-		
-		$this->level = $this->level - 1;		
-	}
-	
-	/**
-	 * Returns the correct location of the file to be included, according to
-	 * parser properties
-	 *
-	 * IF IncludeMode = 'skindir' => use skindir
-	 */
-	function getIncludeFileName($filename) {
-		// leave absolute filenames and http urls as they are
-		if (
-				(substr($filename,0,1) == '/')
-			||	(substr($filename,0,7) == 'http://')
-			||	(substr($filename,0,6) == 'ftp://')			
-			)
-			return $filename;
-	
-		$filename = PARSER::getProperty('IncludePrefix') . $filename;
-		if (PARSER::getProperty('IncludeMode') == 'skindir') {
-			global $DIR_SKINS;
-			return $DIR_SKINS . $filename;
-		} else {
-			return $filename;
-		}
-	}
-	
-	/**
-	 * Inserts an url relative to the skindir (useful when doing import/export)
-	 *
-	 * e.g. <skinfile(default/myfile.sth)>
-	 */
-	function parse_skinfile($filename) {
-		global $CONF;
-		
-		echo $CONF['SkinsURL'] . PARSER::getProperty('IncludePrefix') . $filename;
-	}
-	
-	/**
-	 * Sets a property for the parser
-	 */
-	function parse_set($property, $value) {
-		PARSER::setProperty($property, $value);
-	}
-	
-	/**
-	 * Helper function: add if condition
-	 */
-	function _addIfCondition($condition) {
-	
-		array_push($this->if_conditions,$condition);
-	
-		$this->_updateTopIfCondition();
-			
-		ob_start();		
-	}
-	
-	function _updateTopIfCondition() {
-		if (sizeof($this->if_conditions) == 0) 
-			$this->if_currentlevel = 1;
-		else
-			$this->if_currentlevel = $this->if_conditions[sizeof($this->if_conditions) - 1];
-	}
-	
-	/**
-	 * returns the currently top if condition
-	 */
-	function _getTopIfCondition() {
-		return $this->if_currentlevel;
-	}
-	
-	/**
-	 * else
-	 */
-	function parse_else() {
-		if (sizeof($this->if_conditions) == 0) return;
-		$old = $this->if_currentlevel;
-		if (array_pop($this->if_conditions)) {
-			ob_end_flush();
-			$this->_addIfCondition(0);
-		} else {
-			ob_end_clean();
-			$this->_addIfCondition(1);
-		}
-	}
-	
-	/**
-	 * Ends a conditional if-block 
-	 * see e.g. ifcat (BLOG), ifblogsetting (PAGEFACTORY)
-	 */
-	function parse_endif() {
-		// we can only close what has been opened
-		if (sizeof($this->if_conditions) == 0) return;
-		
-		if (array_pop($this->if_conditions)) {
-			ob_end_flush();
-		} else {
-			ob_end_clean();
-		}
-		
-		$this->_updateTopIfCondition();
-	}
-	
-	
-	/** 
-	 * Sets the search terms to be highlighted
-	 *
-	 * @param $highlight
-	 *		A series of search terms
-	 */
-	function setHighlight($highlight) {	
-		$this->strHighlight = $highlight;
-		if ($highlight) {
-			$this->aHighlight = parseHighlight($highlight); 
-		}
-	}
-	
-	/**
-	 * Applies the highlight to the given piece of text
-	 *
-	 * @param &$data
-	 *		Data that needs to be highlighted
-	 * @see setHighlight
-	 */
-	function highlight(&$data) {
-		if ($this->aHighlight)
-			return highlight($data,$this->aHighlight,$this->template['SEARCH_HIGHLIGHT']);
-		else
-			return $data;
-	}
-	
-	
 
 }
- 
+
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/libs/PLUGINADMIN.php 3.31.src/nucleus/libs/PLUGINADMIN.php
--- 3.24.src/nucleus/libs/PLUGINADMIN.php	2006-05-23 19:49:54.000000000 -0500
+++ 3.31.src/nucleus/libs/PLUGINADMIN.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,22 +1,22 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * code to make it easier to create plugin admin areas
-  *
+ * code to make it easier to create plugin admin areas
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: PLUGINADMIN.php,v 1.8.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: PLUGINADMIN.php 1151 2007-05-19 23:38:50Z kaigreve $
+ */
 
 global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_SESSION_VARS;
 $aVarsToCheck = array('HTTP_GET_VARS', 'HTTP_POST_VARS', 'HTTP_COOKIE_VARS', 'HTTP_ENV_VARS', 'HTTP_SESSION_VARS', 'HTTP_POST_FILES', 'HTTP_SERVER_VARS', 'GLOBALS', 'argv', 'argc', '_GET', '_POST', '_COOKIE', '_ENV', '_SESSION', '_SERVER', '_FILES', 'DIR_LIBS');
@@ -25,8 +25,8 @@
 {
 	if (phpversion() >= '4.1.0')
 	{
-		if (   isset($_GET[$varName]) 
-			|| isset($_POST[$varName]) 
+		if (   isset($_GET[$varName])
+			|| isset($_POST[$varName])
 			|| isset($_COOKIE[$varName])
 			|| isset($_ENV[$varName])
 			|| isset($_SESSION[$varName])
@@ -35,63 +35,133 @@
 			die('Sorry. An error occurred.');
 		}
 	} else {
-		if (   isset($HTTP_GET_VARS[$varName]) 
-			|| isset($HTTP_POST_VARS[$varName]) 
+		if (   isset($HTTP_GET_VARS[$varName])
+			|| isset($HTTP_POST_VARS[$varName])
 			|| isset($HTTP_COOKIE_VARS[$varName])
 			|| isset($HTTP_ENV_VARS[$varName])
 			|| isset($HTTP_SESSION_VARS[$varName])
 			|| isset($HTTP_POST_FILES[$varName])
 		){
 			die('Sorry. An error occurred.');
-		}		
+		}
 	}
 }
 
-if (!isset($DIR_LIBS))
+if (!isset($DIR_LIBS)) {
 	die('Sorry.');
+}
 
 include($DIR_LIBS . 'ADMIN.php');
 
 class PluginAdmin {
-	
+
 	var $strFullName;		// NP_SomeThing
 	var $plugin;			// ref. to plugin object
 	var $bValid;			// evaluates to true when object is considered valid
 	var $admin;				// ref to an admin object
-	
+
 	function PluginAdmin($pluginName)
 	{
 		global $manager;
-		
+
 		$this->strFullName = 'NP_' . $pluginName;
-		
+
 		// check if plugin exists and is installed
 		if (!$manager->pluginInstalled($this->strFullName))
 			doError('Invalid plugin');
-		
+
 		$this->plugin =& $manager->getPlugin($this->strFullName);
 		$this->bValid = $this->plugin;
-	
+
 		if (!$this->bValid)
 			doError('Invalid plugin');
-		
+
 		$this->admin = new ADMIN();
 		$this->admin->action = 'plugin_' . $pluginName;
 	}
-	
+
 	function start($extraHead = '')
 	{
 		global $CONF;
-		$strBaseHref  = '<base href="' . htmlspecialchars($CONF['AdminURL']) . '" />';	
+		$strBaseHref  = '<base href="' . htmlspecialchars($CONF['AdminURL']) . '" />';
 		$extraHead .= $strBaseHref;
-		
+
 		$this->admin->pagehead($extraHead);
 	}
-	
+
 	function end()
 	{
+		$this->_AddTicketByJS();
 		$this->admin->pagefoot();
-	}	
+	}
+
+/** 
+ * Add ticket when not used in plugin's admin page
+ * to avoid CSRF.
+ */
+	function _AddTicketByJS(){
+		global $CONF,$ticketforplugin;
+		if (!($ticket=$ticketforplugin['ticket'])) {
+			//echo "\n<!--TicketForPlugin skipped-->\n";
+			return;
+		}
+		$ticket=htmlspecialchars($ticket,ENT_QUOTES);
+ 
+?><script type="text/javascript">
+/*<![CDATA[*/
+/* Add tickets for available links (outside blog excluded) */
+for (i=0;document.links[i];i++){
+  if (document.links[i].href.indexOf('<?php echo $CONF['PluginURL']; ?>',0)<0
+    && !(document.links[i].href.indexOf('//',0)<0)) continue;
+  if ((j=document.links[i].href.indexOf('?',0))<0) continue;
+  if (document.links[i].href.indexOf('ticket=',j)>=0) continue;
+  document.links[i].href=document.links[i].href.substring(0,j+1)+'ticket=<?php echo $ticket; ?>&'+document.links[i].href.substring(j+1);
+}
+/* Add tickets for forms (outside blog excluded) */
+for (i=0;document.forms[i];i++){
+  /* check if ticket is already used */
+  for (j=0;document.forms[i].elements[j];j++) {
+    if (document.forms[i].elements[j].name=='ticket') {
+      j=-1;
+      break;
+    }
+  }
+  if (j==-1) continue;
+ 
+  /* check if the modification works */
+  try{document.forms[i].innerHTML+='';}catch(e){
+    /* Modificaion falied: this sometime happens on IE */
+    if (!document.forms[i].action.name && document.forms[i].method.toUpperCase()=="POST") {
+      /* <input name="action"/> is not used for POST method*/
+      if (document.forms[i].action.indexOf('<?php echo $CONF['PluginURL']; ?>',0)<0
+        && !(document.forms[i].action.indexOf('//',0)<0)) continue;
+      if (0<(j=document.forms[i].action.indexOf('?',0))) if (0<document.forms[i].action.indexOf('ticket=',j)) continue;
+      if (j<0) document.forms[i].action+='?'+'ticket=<?php echo $ticket; ?>';
+      else document.forms[i].action+='&'+'ticket=<?php echo $ticket; ?>';
+      continue;
+    }
+    document.write('<p><b>Error occured druing automatic addition of tickets.</b></p>');
+    j=document.forms[i].outerHTML;
+    while (j!=j.replace('<','&lt;')) j=j.replace('<','&lt;');
+    document.write('<p>'+j+'</p>');
+    continue;
+  }
+  /* check the action paramer in form tag */
+  /* note that <input name="action"/> may be used here */
+  j=document.forms[i].innerHTML;
+  document.forms[i].innerHTML='';
+  if ((document.forms[i].action+'').indexOf('<?php echo $CONF['PluginURL']; ?>',0)<0
+      && !((document.forms[i].action+'').indexOf('//',0)<0)) {
+    document.forms[i].innerHTML=j;
+    continue;
+  }
+  /* add ticket */
+  document.forms[i].innerHTML=j+'<input type="hidden" name="ticket" value="<?php echo $ticket; ?>"/>';
+}
+/*]]>*/
+</script><?php
+ 
+	}
 }
 
 
diff -ruN 3.24.src/nucleus/libs/PLUGIN.php 3.31.src/nucleus/libs/PLUGIN.php
--- 3.24.src/nucleus/libs/PLUGIN.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/PLUGIN.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,24 +1,24 @@
 <?php
 	/*
-	  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
-	  * Copyright (C) 2002-2005 The Nucleus Group
-	  *
-	  * 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.
-	  * (see nucleus/documentation/index.html#license for more info)
+	 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+	 * Copyright (C) 2002-2007 The Nucleus Group
+	 *
+	 * 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.
+	 * (see nucleus/documentation/index.html#license for more info)
 	 */
 	/**
-	  * This is an (abstract) class of which all Nucleus Plugins must inherit
-	  *
-	  * for more information on plugins and how to write your own, see the
-	  * plugins.html file that is included with the Nucleus documenation
- 	  *
+	 * This is an (abstract) class of which all Nucleus Plugins must inherit
+	 *
+	 * for more information on plugins and how to write your own, see the
+	 * plugins.html file that is included with the Nucleus documenation
+	 *
 	 * @license http://nucleuscms.org/license.txt GNU General Public License
-	 * @copyright Copyright (C) 2002-2005 The Nucleus Group
-	 * @version $Id: PLUGIN.php,v 1.28.2.1 2005/08/15 10:50:12 dekarma Exp $
-  	  */
+	 * @copyright Copyright (C) 2002-2007 The Nucleus Group
+	 * @version $Id: PLUGIN.php 1196 2007-09-05 07:39:40Z kimitake $
+	 */
 	class NucleusPlugin {
 
 		// these functions _have_ to be redefined in your plugin
@@ -57,6 +57,8 @@
 			call_user_func_array(array(&$this,'doSkinVar'),$args);
 		}
 		function doAction($type) { return 'No Such Action'; }
+		function doIf($key,$value) { return false; }
+		function doItemVar () {}
 
 		/**
 		 * Checks if a plugin supports a certain feature.
@@ -73,7 +75,7 @@
 
 		/**
 		 * Report a list of plugin that is required to function
-		 * 
+		 *
 		 * @returns an array of names of plugin, an empty array indicates no dependency
 		 */
 		function getPluginDep() { return array(); }
@@ -105,7 +107,7 @@
 		function createCategoryOption($name, $desc, $type, $defValue = '', $typeExtras = '') {
 			return $this->_createOption('category', $name, $desc, $type, $defValue, $typeExtras);
 		}
-        function createItemOption($name, $desc, $type, $defValue = '', $typeExtras = '') {
+		function createItemOption($name, $desc, $type, $defValue = '', $typeExtras = '') {
 			return $this->_createOption('item', $name, $desc, $type, $defValue, $typeExtras);
 		}
 
@@ -126,7 +128,7 @@
 		function deleteCategoryOption($name) {
 			return $this->_deleteOption('category', $name);
 		}
-        function deleteItemOption($name) {
+		function deleteItemOption($name) {
 			return $this->_deleteOption('item', $name);
 		}
 
@@ -145,7 +147,7 @@
 		function setCategoryOption($catid, $name, $value) {
 			return $this->_setOption('category', $catid, $name, $value);
 		}
-        function setItemOption($itemid, $name, $value) {
+		function setItemOption($itemid, $name, $value) {
 			return $this->_setOption('item', $itemid, $name, $value);
 		}
 
@@ -158,8 +160,8 @@
 			// the static collection is used to save SQL queries.
 			if ($this->plugin_options == 0)
 			{
-				$this->plugin_options = array();  	
-				$query = mysql_query(
+				$this->plugin_options = array();
+				$query = sql_query(
 					 'SELECT d.oname as name, o.ovalue as value '.
 					 'FROM '.
 					 sql_table('plugin_option').' o, '.
@@ -173,7 +175,7 @@
 				return $this->plugin_options[strtolower($name)];
 		  else
 				return $this->_getOption('global', 0, $name);
-		} 		  
+		}
 
 		function getBlogOption($blogid, $name) {
 			return $this->_getOption('blog', $blogid, $name);
@@ -184,7 +186,7 @@
 		function getCategoryOption($catid, $name) {
 			return $this->_getOption('category', $catid, $name);
 		}
-        function getItemOption($itemid, $name) {
+		function getItemOption($itemid, $name) {
 			return $this->_getOption('item', $itemid, $name);
 		}
 
@@ -201,14 +203,14 @@
 		function getAllCategoryOptions($name) {
 			return $this->_getAllOptions('category', $name);
 		}
-        function getAllItemOptions($name) {
+		function getAllItemOptions($name) {
 			return $this->_getAllOptions('item', $name);
 		}
-		
+
 		/**
-         * Retrieves an indexed array with the top (or bottom) of an option
+		 * Retrieves an indexed array with the top (or bottom) of an option
 		 * (delegates to _getOptionTop())
-         */
+		 */
 		function getBlogOptionTop($name, $amount = 10, $sort = 'desc') {
 			return $this->_getOptionTop('blog', $name, $amount, $sort);
 		}
@@ -221,7 +223,7 @@
 		function getItemOptionTop($name, $amount = 10, $sort = 'desc') {
 			return $this->_getOptionTop('item', $name, $amount, $sort);
 		}
-		
+
 		/**
 		 * Retrieves an array of the top (or bottom) of an option from a plugin.
 		 * @author TeRanEX
@@ -232,7 +234,7 @@
 		 * @return array           array with both values and contextid's
 		 * @access private
 		 */
-        function _getOptionTop($context, $name, $amount = 10, $sort = 'desc') {
+		function _getOptionTop($context, $name, $amount = 10, $sort = 'desc') {
 			if (($sort != 'desc') && ($sort != 'asc')) {
 				$sort= 'desc';
 			}
@@ -241,7 +243,7 @@
 
 			// retrieve the data and return
 			$q = 'SELECT otype, oextra FROM '.sql_table('plugin_option_desc').' WHERE oid = '.$oid;
-			$query = mysql_query($q);
+			$query = sql_query($q);
 
 			$o = mysql_fetch_array($query);
 
@@ -250,16 +252,16 @@
 			} else {
 				$orderby = 'ovalue';
 			}
-			$q = 'SELECT ovalue value, ocontextid id FROM '.sql_table('plugin_option').' WHERE oid = '.$oid.' ORDER BY '.$orderby.' '.$sort.' LIMIT 0,'.$amount;
-			$query = mysql_query($q);
-			
+			$q = 'SELECT ovalue value, ocontextid id FROM '.sql_table('plugin_option').' WHERE oid = '.$oid.' ORDER BY '.$orderby.' '.$sort.' LIMIT 0,'.intval($amount);
+			$query = sql_query($q);
+
 			// create the array
 			$i = 0;
 			$top = array();
 			while($row = mysql_fetch_array($query)) {
 				$top[$i++] = $row;
 			}
-			
+
 			// return the array (duh!)
 			return $top;
 		}
@@ -309,18 +311,22 @@
 			$this->plugin_options = 0;
 		}
 
+		function clearOptionValueCache(){
+			$this->_aOptionValues = array();
+		}
+
 		// private
 		function _createOption($context, $name, $desc, $type, $defValue, $typeExtras = '') {
 			// create in plugin_option_desc
 			$query = 'INSERT INTO ' . sql_table('plugin_option_desc')
-			       .' (opid, oname, ocontext, odesc, otype, odef, oextra)'
-			       .' VALUES ('.intval($this->plugid)
-                             .', \''.addslashes($name).'\''
-                             .', \''.addslashes($context).'\''
-                             .', \''.addslashes($desc).'\''
-                             .', \''.addslashes($type).'\''
-                             .', \''.addslashes($defValue).'\''
-			                 .', \''.addslashes($typeExtras).'\')';
+				   .' (opid, oname, ocontext, odesc, otype, odef, oextra)'
+				   .' VALUES ('.intval($this->plugid)
+							 .', \''.addslashes($name).'\''
+							 .', \''.addslashes($context).'\''
+							 .', \''.addslashes($desc).'\''
+							 .', \''.addslashes($type).'\''
+							 .', \''.addslashes($defValue).'\''
+							 .', \''.addslashes($typeExtras).'\')';
 			sql_query($query);
 			$oid = mysql_insert_id();
 
@@ -368,8 +374,8 @@
 				case 'category':
 					if (!$manager->existsCategory($contextid)) return 0;
 					break;
-                case 'item':
-                    if (!$manager->existsItem($contextid, true, true)) return 0;
+				case 'item':
+					if (!$manager->existsItem($contextid, true, true)) return 0;
 					break;
 				case 'global':
 					if ($contextid != 0) return 0;
@@ -407,7 +413,7 @@
 
 				// fill DB with default value
 				$query = 'INSERT INTO ' . sql_table('plugin_option') . ' (oid,ocontextid,ovalue)'
-				       .' VALUES ('.intval($oid).', '.intval($contextid).', \''.addslashes($defVal).'\')';
+					   .' VALUES ('.intval($oid).', '.intval($contextid).', \''.addslashes($defVal).'\')';
 				sql_query($query);
 			}
 			else {
@@ -438,6 +444,9 @@
 				case 'member':
 					$r = sql_query('SELECT mnumber as contextid FROM ' . sql_table('member'));
 					break;
+				case 'item':
+					$r = sql_query('SELECT inumber as contextid FROM ' . sql_table('item'));
+					break;
 			}
 			if ($r) {
 				while ($o = mysql_fetch_object($r))
@@ -535,7 +544,7 @@
 			//the select list must always be the first part
 			return $meta['select'];
 		}
-		
+
 		/**
 		 * checks if the eventlist in the database is up-to-date
 		 * @return bool if it is up-to-date it return true, else false
@@ -557,14 +566,14 @@
 			}
 			return true;
 		}
-		
+
 		/**
 		 * @param $aOptions: array ( 'oid' => array( 'contextid' => 'value'))
 		 *        (taken from request using requestVar())
-		 * @param $newContextid: integer (accepts a contextid when it is for a new 
+		 * @param $newContextid: integer (accepts a contextid when it is for a new
 		 *        contextid there was no id available at the moment of writing the
 		 *        formcontrols into the page (by ex: itemOptions for new item)
-		 * @static 
+		 * @static
 		 */
 		function _applyPluginOptions(&$aOptions, $newContextid = 0) {
 			global $manager;
@@ -577,15 +586,18 @@
 				$res = sql_query($query);
 				if ($o = mysql_fetch_object($res))
 				{
-					foreach ($values as $contextid => $value) {
+					foreach ($values as $key => $value) {
+						// avoid overriding the key used by foreach statement
+						$contextid=$key;
+
 						// retreive any metadata
 						$meta = NucleusPlugin::getOptionMeta($o->oextra);
-						
+
 						// if the option is readonly or hidden it may not be saved
 						if (($meta['access'] != 'readonly') && ($meta['access'] != 'hidden')) {
-							
+
 							$value = undoMagic($value);	// value comes from request
-	
+
 							switch($o->otype) {
 								case 'yesno':
 									if (($value != 'yes') && ($value != 'no')) $value = 'no';
@@ -593,31 +605,35 @@
 								default:
 									break;
 							}
-							
+
 							// check the validity of numerical options
-							if (($meta['datatype'] == 'numerical') && (!is_numeric($value))) { 
+							if (($meta['datatype'] == 'numerical') && (!is_numeric($value))) {
 								//the option must be numeric, but the it isn't
 								//use the default for this option
 								$value = $o->odef;
 							}
-	
+
 							// decide wether we are using the contextid of newContextid
 							if ($newContextid != 0) {
 								$contextid = $newContextid;
 							}
-							
+
 							//trigger event PrePluginOptionsUpdate to give the plugin the
 							//possibility to change/validate the new value for the option
 							$manager->notify('PrePluginOptionsUpdate',array('context' => $o->ocontext, 'plugid' => $o->opid, 'optionname' => $o->oname, 'contextid' => $contextid, 'value' => &$value));
-							
+
 							// delete the old value for the option
 							sql_query('DELETE FROM '.sql_table('plugin_option').' WHERE oid='.intval($oid).' AND ocontextid='.intval($contextid));
 							sql_query('INSERT INTO '.sql_table('plugin_option')." (oid, ocontextid, ovalue) VALUES (".intval($oid).",".intval($contextid).",'" . addslashes($value) . "')");
 						}
 					}
 				}
+				// clear option value cache if the plugin object is already loaded
+				if (is_object($o)) {
+					$plugin=& $manager->pidLoaded($o->opid);
+					if ($plugin) $plugin->clearOptionValueCache();
+				}
 			}
 		}
-		
 	}
 ?>
diff -ruN 3.24.src/nucleus/libs/SEARCH.php 3.31.src/nucleus/libs/SEARCH.php
--- 3.24.src/nucleus/libs/SEARCH.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/SEARCH.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,186 +1,186 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2003-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2003-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * SEARCH(querystring) offers different functionality to create an
-  * SQL query to find certain items. (and comments)
-  *
-  * based on code by David Altherr:
-  * http://www.evolt.org/article/Boolean_Fulltext_Searching_with_PHP_and_MySQL/18/15665/
-  * http://davidaltherr.net/web/php_functions/boolean/funcs.mysql.boolean.txt
-  * 
+ * SEARCH(querystring) offers different functionality to create an
+ * SQL query to find certain items. (and comments)
+ *
+ * based on code by David Altherr:
+ * http://www.evolt.org/article/Boolean_Fulltext_Searching_with_PHP_and_MySQL/18/15665/
+ * http://davidaltherr.net/web/php_functions/boolean/funcs.mysql.boolean.txt
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: SEARCH.php,v 1.15.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: SEARCH.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 
 
 
 class SEARCH {
-	
+
 	var $querystring;
 	var $marked;
 	var $inclusive;
 	var $blogs;
 
 
-    function SEARCH($text) {
-        global $blogid;
-        $text = preg_replace ("/[<,>,=,?,!,#,^,(,),[,\],:,;,\\\,%]/","",$text);
-        $this->querystring	= $text;
-        $this->marked		= $this->boolean_mark_atoms($text);
-        $this->inclusive	= $this->boolean_inclusive_atoms($text);
-        $this->blogs		= array();
+	function SEARCH($text) {
+		global $blogid;
+		$text = preg_replace ("/[<,>,=,?,!,#,^,(,),[,\],:,;,\\\,%]/","",$text);
+		$this->querystring	= $text;
+		$this->marked		= $this->boolean_mark_atoms($text);
+		$this->inclusive	= $this->boolean_inclusive_atoms($text);
+		$this->blogs		= array();
 
-        // get all public searchable blogs, no matter what, include the current blog allways.
+		// get all public searchable blogs, no matter what, include the current blog allways.
 		$res = sql_query('SELECT bnumber FROM '.sql_table('blog').' WHERE bincludesearch=1 ');
-		while ($obj = mysql_fetch_object($res)) 
-		    $this->blogs[] = intval($obj->bnumber);
-    }
-
-    function  boolean_sql_select($match){
-        if (strlen($this->inclusive) > 0) {
-    	   /* build sql for determining score for each record */
-           $result=explode(" ",$this->inclusive);
-	       for($cth=0;$cth<count($result);$cth++){
-               if(strlen($result[$cth])>=4){
-                   $stringsum_long .=  " $result[$cth] ";
-    		   }else{
-	    	       $stringsum_a[] = ' '.$this->boolean_sql_select_short($result[$cth],$match).' ';
-    		   }
-	       }
-
-    	   if(strlen($stringsum_long)>0){
-    	   		$stringsum_long = addslashes($stringsum_long);
-	    		$stringsum_a[] = " match ($match) against ('$stringsum_long') ";
-    	   }
-
-	       $stringsum .= implode("+",$stringsum_a);
-    	   return $stringsum;
-   	    }
-    }
-
-    function boolean_inclusive_atoms($string){
-    	$result=trim($string);
-    	$result=preg_replace("/([[:space:]]{2,})/",' ',$result);
-
-    	/* convert normal boolean operators to shortened syntax */
-    	$result=eregi_replace(' not ',' -',$result);
-    	$result=eregi_replace(' and ',' ',$result);
-    	$result=eregi_replace(' or ',',',$result);
-
-    	/* drop unnecessary spaces */
-    	$result=str_replace(' ,',',',$result);
-    	$result=str_replace(', ',',',$result);
-    	$result=str_replace('- ','-',$result);
-    	$result=str_replace('+','',$result);
-
-    	/* strip exlusive atoms */
-    	$result=preg_replace(
-    		"(\-\([A-Za-z0-9]{1,}[A-Za-z0-9\-\.\_\,]{0,}\))",
-    		'',
-    		$result);
-
-    	$result=str_replace('(',' ',$result);
-    	$result=str_replace(')',' ',$result);
-    	$result=str_replace(',',' ',$result);
-
-    	return $result;
-    }
-   
-    function boolean_sql_where($match){
-        $result = $this->marked;
-    	$result = preg_replace(
-    		"/foo\[\(\'([^\)]{4,})\'\)\]bar/e",
-    		" 'match ('.\$match.') against (\''.\$this->copyvalue(\"$1\").'\') > 0 ' ",
-    		$result);
-
-    	$result = preg_replace(     		
-            "/foo\[\(\'([^\)]{1,3})\'\)\]bar/e",
-            " '('.\$this->boolean_sql_where_short(\"$1\",\"$match\").')' ",    		
-            $result);
-    	return $result;
-    }
-    
-    // there must be a simple way to simply copy a value with backslashes in it through
-    // the preg_replace, but I cannot currently find it (karma 2003-12-30)
-    function copyvalue($foo) {
-    	return $foo;
-    }
-
-
-    function boolean_mark_atoms($string){
-    	$result=trim($string);
-    	$result=preg_replace("/([[:space:]]{2,})/",' ',$result);
-
-    	/* convert normal boolean operators to shortened syntax */
-    	$result=eregi_replace(' not ',' -',$result);
-    	$result=eregi_replace(' and ',' ',$result);
-    	$result=eregi_replace(' or ',',',$result);
-
-
-    	/* strip excessive whitespace */
-    	$result=str_replace('( ','(',$result);
-    	$result=str_replace(' )',')',$result);
-    	$result=str_replace(', ',',',$result);
-    	$result=str_replace(' ,',',',$result);
-    	$result=str_replace('- ','-',$result);
-    	$result=str_replace('+','',$result);
-    	
-    	// remove double spaces (we might have introduced some new ones above)
-    	$result=trim($result);
-    	$result=preg_replace("/([[:space:]]{2,})/",' ',$result);
-    	
-    	/* apply arbitrary function to all 'word' atoms */
-
-        $result_a = explode(" ",$result);
-        for($word=0;$word<count($result_a);$word++){
-            $result_a[$word] = "foo[('".$result_a[$word]."')]bar";
-        }
-        $result = implode(" ",$result_a);
-        
-    	/* dispatch ' ' to ' AND ' */
-    	$result=str_replace(' ',' AND ',$result);
-
-    	/* dispatch ',' to ' OR ' */
-    	$result=str_replace(',',' OR ',$result);
-
-    	/* dispatch '-' to ' NOT ' */
-    	$result=str_replace(' -',' NOT ',$result);
-    	return $result;
-    }
-    
-    function boolean_sql_where_short($string,$match){
-    	$match_a = explode(',',$match);
-    	for($ith=0;$ith<count($match_a);$ith++){
-    		$like_a[$ith] = " $match_a[$ith] LIKE '% $string %' ";
-    	}
-    	$like = implode(" OR ",$like_a);
-
-    	return $like;
-    }
-    function boolean_sql_select_short($string,$match){
-        $match_a = explode(',',$match);
-        $score_unit_weight = .2;
-        for($ith=0;$ith<count($match_a);$ith++){
-            $score_a[$ith] =
-                           " $score_unit_weight*(
-                           LENGTH(" . addslashes($match_a[$ith]) . ") -
-                           LENGTH(REPLACE(LOWER(" . addslashes($match_a[$ith]) . "),LOWER('" . addslashes($string) . "'),'')))
-			               /LENGTH('" . addslashes($string) . "') ";
-        }
-	    $score = implode(" + ",$score_a);
+		while ($obj = mysql_fetch_object($res))
+			$this->blogs[] = intval($obj->bnumber);
+	}
+
+	function  boolean_sql_select($match){
+		if (strlen($this->inclusive) > 0) {
+		   /* build sql for determining score for each record */
+		   $result=explode(" ",$this->inclusive);
+		   for($cth=0;$cth<count($result);$cth++){
+			   if(strlen($result[$cth])>=4){
+				   $stringsum_long .=  " $result[$cth] ";
+			   }else{
+				   $stringsum_a[] = ' '.$this->boolean_sql_select_short($result[$cth],$match).' ';
+			   }
+		   }
+
+		   if(strlen($stringsum_long)>0){
+				$stringsum_long = addslashes($stringsum_long);
+				$stringsum_a[] = " match ($match) against ('$stringsum_long') ";
+		   }
+
+		   $stringsum .= implode("+",$stringsum_a);
+		   return $stringsum;
+		}
+	}
+
+	function boolean_inclusive_atoms($string){
+		$result=trim($string);
+		$result=preg_replace("/([[:space:]]{2,})/",' ',$result);
+
+		/* convert normal boolean operators to shortened syntax */
+		$result=eregi_replace(' not ',' -',$result);
+		$result=eregi_replace(' and ',' ',$result);
+		$result=eregi_replace(' or ',',',$result);
+
+		/* drop unnecessary spaces */
+		$result=str_replace(' ,',',',$result);
+		$result=str_replace(', ',',',$result);
+		$result=str_replace('- ','-',$result);
+		$result=str_replace('+','',$result);
+
+		/* strip exlusive atoms */
+		$result=preg_replace(
+			"(\-\([A-Za-z0-9]{1,}[A-Za-z0-9\-\.\_\,]{0,}\))",
+			'',
+			$result);
+
+		$result=str_replace('(',' ',$result);
+		$result=str_replace(')',' ',$result);
+		$result=str_replace(',',' ',$result);
+
+		return $result;
+	}
+
+	function boolean_sql_where($match){
+		$result = $this->marked;
+		$result = preg_replace(
+			"/foo\[\(\'([^\)]{4,})\'\)\]bar/e",
+			" 'match ('.\$match.') against (\''.\$this->copyvalue(\"$1\").'\') > 0 ' ",
+			$result);
+
+		$result = preg_replace(
+			"/foo\[\(\'([^\)]{1,3})\'\)\]bar/e",
+			" '('.\$this->boolean_sql_where_short(\"$1\",\"$match\").')' ",
+			$result);
+		return $result;
+	}
+
+	// there must be a simple way to simply copy a value with backslashes in it through
+	// the preg_replace, but I cannot currently find it (karma 2003-12-30)
+	function copyvalue($foo) {
+		return $foo;
+	}
+
+
+	function boolean_mark_atoms($string){
+		$result=trim($string);
+		$result=preg_replace("/([[:space:]]{2,})/",' ',$result);
+
+		/* convert normal boolean operators to shortened syntax */
+		$result=eregi_replace(' not ',' -',$result);
+		$result=eregi_replace(' and ',' ',$result);
+		$result=eregi_replace(' or ',',',$result);
+
+
+		/* strip excessive whitespace */
+		$result=str_replace('( ','(',$result);
+		$result=str_replace(' )',')',$result);
+		$result=str_replace(', ',',',$result);
+		$result=str_replace(' ,',',',$result);
+		$result=str_replace('- ','-',$result);
+		$result=str_replace('+','',$result);
+
+		// remove double spaces (we might have introduced some new ones above)
+		$result=trim($result);
+		$result=preg_replace("/([[:space:]]{2,})/",' ',$result);
+
+		/* apply arbitrary function to all 'word' atoms */
+
+		$result_a = explode(" ",$result);
+		for($word=0;$word<count($result_a);$word++){
+			$result_a[$word] = "foo[('".$result_a[$word]."')]bar";
+		}
+		$result = implode(" ",$result_a);
+
+		/* dispatch ' ' to ' AND ' */
+		$result=str_replace(' ',' AND ',$result);
+
+		/* dispatch ',' to ' OR ' */
+		$result=str_replace(',',' OR ',$result);
+
+		/* dispatch '-' to ' NOT ' */
+		$result=str_replace(' -',' NOT ',$result);
+		return $result;
+	}
+
+	function boolean_sql_where_short($string,$match){
+		$match_a = explode(',',$match);
+		for($ith=0;$ith<count($match_a);$ith++){
+			$like_a[$ith] = " $match_a[$ith] LIKE '% $string %' ";
+		}
+		$like = implode(" OR ",$like_a);
+
+		return $like;
+	}
+	function boolean_sql_select_short($string,$match){
+		$match_a = explode(',',$match);
+		$score_unit_weight = .2;
+		for($ith=0;$ith<count($match_a);$ith++){
+			$score_a[$ith] =
+						   " $score_unit_weight*(
+						   LENGTH(" . addslashes($match_a[$ith]) . ") -
+						   LENGTH(REPLACE(LOWER(" . addslashes($match_a[$ith]) . "),LOWER('" . addslashes($string) . "'),'')))
+						   /LENGTH('" . addslashes($string) . "') ";
+		}
+		$score = implode(" + ",$score_a);
 
-        return $score;
-    }
+		return $score;
+	}
 }
 ?>
diff -ruN 3.24.src/nucleus/libs/showlist.php 3.31.src/nucleus/libs/showlist.php
--- 3.24.src/nucleus/libs/showlist.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/libs/showlist.php	2007-10-22 19:36:00.000000000 -0500
@@ -0,0 +1,631 @@
+<?php
+/*
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+/**
+ * Functions to create lists of things inside the admin are
+ *
+ * @license http://nucleuscms.org/license.txt GNU General Public License
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: showlist.php 1197 2007-09-05 07:42:15Z kimitake $
+ */
+
+
+// can take either an array of objects, or an SQL query
+function showlist($query, $type, $template) {
+
+	if (is_array($query)) {
+		if (sizeof($query) == 0)
+			return 0;
+
+		call_user_func('listplug_' . $type, $template, 'HEAD');
+
+		foreach ($query as $currentObj) {
+			$template['current'] = $currentObj;
+			call_user_func('listplug_' . $type, $template, 'BODY');
+		}
+
+		call_user_func('listplug_' . $type, $template, 'FOOT');
+
+		return sizeof($query);
+
+	} else {
+		$res = sql_query($query);
+
+		// don't do anything if there are no results
+		$numrows = mysql_num_rows($res);
+		if ($numrows == 0)
+			return 0;
+
+		call_user_func('listplug_' . $type, $template, 'HEAD');
+
+		while($template['current'] = mysql_fetch_object($res))
+			call_user_func('listplug_' . $type, $template, 'BODY');
+
+		call_user_func('listplug_' . $type, $template, 'FOOT');
+
+		mysql_free_result($res);
+
+		// return amount of results
+		return $numrows;
+	}
+}
+
+function listplug_select($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo '<select name="' . ifset($template['name']) . '" tabindex="' . ifset($template['tabindex']) . '" ' . ifset($template['javascript']) . '>';
+
+			// add extra row if needed
+			if (ifset($template['extra'])) {
+				echo '<option value="', ifset($template['extraval']), '">', $template['extra'], '</option>';
+			}
+
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<option value="' . htmlspecialchars($current->value) . '"';
+			if ($template['selected'] == $current->value)
+				echo ' selected="selected" ';
+			if (isset($template['shorten']) && $template['shorten'] > 0) {
+				echo ' title="'. htmlspecialchars($current->text).'"';
+				$current->text = shorten($current->text, $template['shorten'], $template['shortenel']);
+			}
+			echo '>' . htmlspecialchars($current->text) . '</option>';
+			break;
+		case 'FOOT':
+			echo '</select>';
+			break;
+	}
+}
+
+function listplug_table($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo "<table>";
+			echo "<thead><tr>";
+			// print head
+			call_user_func("listplug_table_" . $template['content'] , $template, 'HEAD');
+			echo "</tr></thead><tbody>";
+			break;
+		case 'BODY':
+			// print tabletype specific thingies
+			echo "<tr onmouseover='focusRow(this);' onmouseout='blurRow(this);'>";
+			call_user_func("listplug_table_" . $template['content'] , $template,  'BODY');
+			echo "</tr>";
+			break;
+		case 'FOOT':
+			call_user_func("listplug_table_" . $template['content'] , $template,  'FOOT');
+			echo "</tbody></table>";
+			break;
+	}
+}
+
+function listplug_table_memberlist($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo '<th>' . _LIST_MEMBER_NAME . '</th><th>' . _LIST_MEMBER_RNAME . '</th><th>' . _LIST_MEMBER_URL . '</th><th>' . _LIST_MEMBER_ADMIN;
+			help('superadmin');
+			echo "</th><th>" . _LIST_MEMBER_LOGIN;
+			help('canlogin');
+			echo "</th><th colspan='2'>" . _LISTS_ACTIONS. "</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>';
+			$id = listplug_nextBatchId();
+			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->mnumber,'" />';
+			echo '<label for="batch',$id,'">';
+			echo "<a href='mailto:", htmlspecialchars($current->memail), "' tabindex='".$template['tabindex']."'>", htmlspecialchars($current->mname), "</a>";
+			echo '</label>';
+			echo '</td>';
+			echo '<td>', htmlspecialchars($current->mrealname), '</td>';
+			echo "<td><a href='", htmlspecialchars($current->murl), "' tabindex='", $template['tabindex'] , "'>", htmlspecialchars($current->murl), "</a></td>";
+			echo '<td>', ($current->madmin ? _YES : _NO),'</td>';
+			echo '<td>', ($current->mcanlogin ? _YES : _NO), '</td>';
+			echo "<td><a href='index.php?action=memberedit&amp;memberid=$current->mnumber' tabindex='".$template['tabindex']."'>"._LISTS_EDIT."</a></td>";
+			echo "<td><a href='index.php?action=memberdelete&amp;memberid=$current->mnumber' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
+			break;
+	}
+}
+
+function listplug_table_teamlist($template, $type) {
+	global $manager;
+	switch($type) {
+		case 'HEAD':
+			echo "<th>"._LIST_MEMBER_NAME."</th><th>"._LIST_MEMBER_RNAME."</th><th>"._LIST_TEAM_ADMIN;
+			help('teamadmin');
+			echo "</th><th colspan='2'>"._LISTS_ACTIONS."</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>';
+			$id = listplug_nextBatchId();
+			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->tmember,'" />';
+			echo '<label for="batch',$id,'">';
+			echo "<a href='mailto:", htmlspecialchars($current->memail), "' tabindex='".$template['tabindex']."'>", htmlspecialchars($current->mname), "</a>";
+			echo '</label>';
+			echo '</td>';
+			echo '<td>', htmlspecialchars($current->mrealname), '</td>';
+			echo '<td>', ($current->tadmin ? _YES : _NO) , '</td>';
+			echo "<td><a href='index.php?action=teamdelete&amp;memberid=$current->tmember&amp;blogid=$current->tblog' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
+
+			$url = 'index.php?action=teamchangeadmin&memberid=' . intval($current->tmember) . '&blogid=' . intval($current->tblog);
+			$url = $manager->addTicketToUrl($url);
+			echo "<td><a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>"._LIST_TEAM_CHADMIN."</a></td>";
+			break;
+	}
+}
+
+function listplug_table_pluginlist($template, $type) {
+	global $manager;
+	switch($type) {
+		case 'HEAD':
+			echo '<th>'._LISTS_INFO.'</th><th>'._LISTS_DESC.'</th>';
+			echo '<th style="white-space:nowrap">'._LISTS_ACTIONS.'</th>';
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			$plug =& $manager->getPlugin($current->pfile);
+			if ($plug) {
+				echo '<td>';
+					echo '<strong>' , htmlspecialchars($plug->getName()) , '</strong><br />';
+					echo _LIST_PLUGS_AUTHOR, ' ' , htmlspecialchars($plug->getAuthor()) , '<br />';
+					echo _LIST_PLUGS_VER, ' ' , htmlspecialchars($plug->getVersion()) , '<br />';
+					if ($plug->getURL())
+					echo '<a href="',htmlspecialchars($plug->getURL()),'" tabindex="'.$template['tabindex'].'">',_LIST_PLUGS_SITE,'</a><br />';
+				echo '</td>';
+				echo '<td>';
+					echo _LIST_PLUGS_DESC .'<br/>'. encode_desc($plug->getDescription());
+					if (sizeof($plug->getEventList()) > 0) {
+						echo '<br /><br />',_LIST_PLUGS_SUBS,'<br />',htmlspecialchars(implode($plug->getEventList(),', '));
+						// check the database to see if it is up-to-date and notice the user if not
+					}
+					if (!$plug->subscribtionListIsUptodate()) {
+						echo '<br /><br /><strong>',_LIST_PLUG_SUBS_NEEDUPDATE,'</strong>';
+					}
+					if (sizeof($plug->getPluginDep()) > 0)
+						echo '<br /><br />',_LIST_PLUGS_DEP,'<br />',htmlspecialchars(implode($plug->getPluginDep(),', '));
+				echo '</td>';
+			} else {
+				echo '<td colspan="2">Error: plugin file <b>',htmlspecialchars($current->pfile),'.php</b> could not be loaded, or it has been set inactive because it does not support some features (check the <a href="?action=actionlog">actionlog</a> for more info)</td>';
+			}
+			echo '<td>';
+
+				$baseUrl = 'index.php?plugid=' . intval($current->pid) . '&action=';
+				$url = $manager->addTicketToUrl($baseUrl . 'pluginup');
+				echo "<a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>",_LIST_PLUGS_UP,"</a>";
+				$url = $manager->addTicketToUrl($baseUrl . 'plugindown');
+				echo "<br /><a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>",_LIST_PLUGS_DOWN,"</a>";
+				echo "<br /><a href='index.php?action=plugindelete&amp;plugid=$current->pid' tabindex='".$template['tabindex']."'>",_LIST_PLUGS_UNINSTALL,"</a>";
+				if ($plug && ($plug->hasAdminArea() > 0))
+					echo "<br /><a href='".htmlspecialchars($plug->getAdminURL())."'  tabindex='".$template['tabindex']."'>",_LIST_PLUGS_ADMIN,"</a>";
+				if ($plug && ($plug->supportsFeature('HelpPage') > 0))
+					echo "<br /><a href='index.php?action=pluginhelp&amp;plugid=$current->pid'  tabindex='".$template['tabindex']."'>",_LIST_PLUGS_HELP,"</a>";
+				if (quickQuery('SELECT COUNT(*) AS result FROM '.sql_table('plugin_option_desc').' WHERE ocontext=\'global\' and opid='.$current->pid) > 0)
+					echo "<br /><a href='index.php?action=pluginoptions&amp;plugid=$current->pid'  tabindex='".$template['tabindex']."'>",_LIST_PLUGS_OPTIONS,"</a>";
+			echo '</td>';
+			break;
+	}
+}
+
+function listplug_table_plugoptionlist($template, $type) {
+	global $manager;
+	switch($type) {
+		case 'HEAD':
+			echo '<th>'._LISTS_INFO.'</th><th>'._LISTS_VALUE.'</th>';
+			break;
+		case 'BODY':
+			$current = $template['current'];
+			listplug_plugOptionRow($current);
+			break;
+		case 'FOOT':
+			?>
+			<tr>
+				<th colspan="2"><?php echo _PLUGS_SAVE?></th>
+			</tr><tr>
+				<td><?php echo _PLUGS_SAVE?></td>
+				<td><input type="submit" value="<?php echo _PLUGS_SAVE?>" /></td>
+			</tr>
+			<?php			break;
+	}
+}
+
+function listplug_plugOptionRow($current) {
+	$varname = 'plugoption['.$current['oid'].']['.$current['contextid'].']';
+	// retreive the optionmeta
+	$meta = NucleusPlugin::getOptionMeta($current['typeinfo']);
+
+	// only if it is not a hidden option write the controls to the page
+	if ($meta['access'] != 'hidden') {
+		echo '<td>',htmlspecialchars($current['description']?$current['description']:$current['name']),'</td>';
+		echo '<td>';
+		switch($current['type']) {
+			case 'yesno':
+				ADMIN::input_yesno($varname, $current['value'], 0, 'yes', 'no');
+				break;
+			case 'password':
+				echo '<input type="password" size="40" maxlength="128" name="',htmlspecialchars($varname),'" value="',htmlspecialchars($current['value']),'" />';
+				break;
+			case 'select':
+				echo '<select name="'.htmlspecialchars($varname).'">';
+				$aOptions = NucleusPlugin::getOptionSelectValues($current['typeinfo']);
+				$aOptions = explode('|', $aOptions);
+				for ($i=0; $i<(count($aOptions)-1); $i+=2) {
+					echo '<option value="'.htmlspecialchars($aOptions[$i+1]).'"';
+					if ($aOptions[$i+1] == $current['value'])
+						echo ' selected="selected"';
+					echo '>'.htmlspecialchars($aOptions[$i]).'</option>';
+				}
+				echo '</select>';
+				break;
+			case 'textarea':
+				//$meta = NucleusPlugin::getOptionMeta($current['typeinfo']);
+				echo '<textarea class="pluginoption" cols="30" rows="5" name="',htmlspecialchars($varname),'"';
+				if ($meta['access'] == 'readonly') {
+					echo ' readonly="readonly"';
+				}
+				echo '>',htmlspecialchars($current['value']),'</textarea>';
+				break;
+			case 'text':
+			default:
+				//$meta = NucleusPlugin::getOptionMeta($current['typeinfo']);
+
+				echo '<input type="text" size="40" maxlength="128" name="',htmlspecialchars($varname),'" value="',htmlspecialchars($current['value']),'"';
+				if ($meta['datatype'] == 'numerical') {
+					echo ' onkeyup="checkNumeric(this)" onblur="checkNumeric(this)"';
+				}
+				if ($meta['access'] == 'readonly') {
+					echo ' readonly="readonly"';
+				}
+				echo ' />';
+		}
+		echo $current['extra'];
+		echo '</td>';
+	}
+}
+
+function listplug_table_itemlist($template, $type) {
+	$cssclass = null;
+
+	switch($type) {
+		case 'HEAD':
+			echo "<th>"._LIST_ITEM_INFO."</th><th>"._LIST_ITEM_CONTENT."</th><th style=\"white-space:nowrap\" colspan='1'>"._LISTS_ACTIONS."</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+			$current->itime = strtotime($current->itime);	// string -> unix timestamp
+
+			if ($current->idraft == 1)
+				$cssclass = "class='draft'";
+
+			// (can't use offset time since offsets might vary between blogs)
+			if ($current->itime > $template['now'])
+				$cssclass = "class='future'";
+
+			echo "<td $cssclass>",_LIST_ITEM_BLOG,' ', htmlspecialchars($current->bshortname);
+			echo "    <br />",_LIST_ITEM_CAT,' ', htmlspecialchars($current->cname);
+			echo "    <br />",_LIST_ITEM_AUTHOR, ' ', htmlspecialchars($current->mname);
+			echo "    <br />",_LIST_ITEM_DATE," " . date("Y-m-d",$current->itime);
+			echo "<br />",_LIST_ITEM_TIME," " . date("H:i",$current->itime);
+			echo "</td>";
+			echo "<td $cssclass>";
+
+			$id = listplug_nextBatchId();
+
+			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->inumber,'" />';
+			echo '<label for="batch',$id,'">';
+			echo "<b>" . htmlspecialchars(strip_tags($current->ititle)) . "</b>";
+			echo '</label>';
+			echo "<br />";
+
+
+			$current->ibody = strip_tags($current->ibody);
+			$current->ibody = htmlspecialchars(shorten($current->ibody,300,'...'));
+
+			echo "$current->ibody</td>";
+			echo "<td  style=\"white-space:nowrap\" $cssclass>";
+			echo 	"<a href='index.php?action=itemedit&amp;itemid=$current->inumber'>"._LISTS_EDIT."</a>";
+			echo    "<br /><a href='index.php?action=itemcommentlist&amp;itemid=$current->inumber'>"._LISTS_COMMENTS."</a>";
+			echo    "<br /><a href='index.php?action=itemmove&amp;itemid=$current->inumber'>"._LISTS_MOVE."</a>";
+			echo    "<br /><a href='index.php?action=itemdelete&amp;itemid=$current->inumber'>"._LISTS_DELETE."</a>";
+			echo "</td>";
+			break;
+	}
+}
+
+// for batch operations: generates the index numbers for checkboxes
+function listplug_nextBatchId() {
+	static $id = 0;
+	return $id++;
+}
+
+function listplug_table_commentlist($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo "<th>"._LISTS_INFO."</th><th>"._LIST_COMMENT."</th><th colspan='3'>"._LISTS_ACTIONS."</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+			$current->ctime = strtotime($current->ctime);	// string -> unix timestamp
+
+			echo '<td>';
+			echo date("Y-m-d@H:i",$current->ctime);
+			echo '<br />';
+			if ($current->mname)
+				echo htmlspecialchars($current->mname) ,' ', _LIST_COMMENTS_MEMBER;
+			else
+				echo htmlspecialchars($current->cuser);
+			if ($current->cmail != '') {
+                                echo '<br />';
+                                echo htmlspecialchars($current->cmail);
+                        }
+			if ($current->cemail != '') {
+                                echo '<br />';
+                                echo htmlspecialchars($current->cemail);
+                        }
+			echo '</td>';
+
+			$current->cbody = strip_tags($current->cbody);
+			$current->cbody = htmlspecialchars(shorten($current->cbody, 300, '...'));
+
+			echo '<td>';
+			$id = listplug_nextBatchId();
+			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->cnumber,'" />';
+			echo '<label for="batch',$id,'">';
+			echo $current->cbody;
+			echo '</label>';
+			echo '</td>';
+
+			echo "<td style=\"white-space:nowrap\"><a href='index.php?action=commentedit&amp;commentid=$current->cnumber'>"._LISTS_EDIT."</a></td>";
+			echo "<td style=\"white-space:nowrap\"><a href='index.php?action=commentdelete&amp;commentid=$current->cnumber'>"._LISTS_DELETE."</a></td>";
+			if ($template['canAddBan'])
+				echo "<td style=\"white-space:nowrap\"><a href='index.php?action=banlistnewfromitem&amp;itemid=$current->citem&amp;ip=", htmlspecialchars($current->cip), "' title='", htmlspecialchars($current->chost), "'>"._LIST_COMMENT_BANIP."</a></td>";
+			break;
+	}
+}
+
+
+function listplug_table_bloglist($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo "<th>" . _NAME . "</th><th colspan='7'>" ._LISTS_ACTIONS. "</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo "<td title='blogid:$current->bnumber shortname:$current->bshortname'><a href='$current->burl'><img src='images/globe.gif' width='13' height='13' alt='". _BLOGLIST_TT_VISIT."' /></a> " . htmlspecialchars($current->bname) . "</td>";
+			echo "<td><a href='index.php?action=createitem&amp;blogid=$current->bnumber' title='" . _BLOGLIST_TT_ADD ."'>" . _BLOGLIST_ADD . "</a></td>";
+			echo "<td><a href='index.php?action=itemlist&amp;blogid=$current->bnumber' title='". _BLOGLIST_TT_EDIT."'>". _BLOGLIST_EDIT."</a></td>";
+			echo "<td><a href='index.php?action=blogcommentlist&amp;blogid=$current->bnumber' title='". _BLOGLIST_TT_COMMENTS."'>". _BLOGLIST_COMMENTS."</a></td>";
+			echo "<td><a href='index.php?action=bookmarklet&amp;blogid=$current->bnumber' title='". _BLOGLIST_TT_BMLET."'>". _BLOGLIST_BMLET . "</a></td>";
+
+			if ($current->tadmin == 1) {
+				echo "<td><a href='index.php?action=blogsettings&amp;blogid=$current->bnumber' title='" . _BLOGLIST_TT_SETTINGS . "'>" ._BLOGLIST_SETTINGS. "</a></td>";
+				echo "<td><a href='index.php?action=banlist&amp;blogid=$current->bnumber' title='" . _BLOGLIST_TT_BANS. "'>". _BLOGLIST_BANS."</a></td>";
+			}
+
+			if ($template['superadmin']) {
+				echo "<td><a href='index.php?action=deleteblog&amp;blogid=$current->bnumber' title='". _BLOGLIST_TT_DELETE."'>" ._BLOGLIST_DELETE. "</a></td>";
+			}
+
+
+
+			break;
+	}
+}
+
+function listplug_table_shortblognames($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo "<th>" . _NAME . "</th><th>" . _NAME. "</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>' , htmlspecialchars($current->bshortname) , '</td>';
+			echo '<td>' , htmlspecialchars($current->bname) , '</td>';
+
+			break;
+	}
+}
+
+function listplug_table_shortnames($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo "<th>" . _NAME . "</th><th>" . _LISTS_DESC. "</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>' , htmlspecialchars($current->name) , '</td>';
+			echo '<td>' , htmlspecialchars($current->description) , '</td>';
+
+			break;
+	}
+}
+
+
+function listplug_table_categorylist($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo "<th>"._LISTS_NAME."</th><th>"._LISTS_DESC."</th><th colspan='2'>"._LISTS_ACTIONS."</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>';
+			$id = listplug_nextBatchId();
+			echo '<input type="checkbox" id="batch',$id,'" name="batch[',$id,']" value="',$current->catid,'" />';
+			echo '<label for="batch',$id,'">';
+			echo htmlspecialchars($current->cname);
+			echo '</label>';
+			echo '</td>';
+
+			echo '<td>', htmlspecialchars($current->cdesc), '</td>';
+			echo "<td><a href='index.php?action=categorydelete&amp;blogid=$current->cblog&amp;catid=$current->catid' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
+			echo "<td><a href='index.php?action=categoryedit&amp;blogid=$current->cblog&amp;catid=$current->catid' tabindex='".$template['tabindex']."'>"._LISTS_EDIT."</a></td>";
+
+			break;
+	}
+}
+
+
+function listplug_table_templatelist($template, $type) {
+	global $manager;
+	switch($type) {
+		case 'HEAD':
+			echo "<th>"._LISTS_NAME."</th><th>"._LISTS_DESC."</th><th colspan='3'>"._LISTS_ACTIONS."</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo "<td>" , htmlspecialchars($current->tdname), "</td>";
+			echo "<td>" , htmlspecialchars($current->tddesc), "</td>";
+			echo "<td style=\"white-space:nowrap\"><a href='index.php?action=templateedit&amp;templateid=$current->tdnumber' tabindex='".$template['tabindex']."'>"._LISTS_EDIT."</a></td>";
+
+			$url = $manager->addTicketToUrl('index.php?action=templateclone&templateid=' . intval($current->tdnumber));
+			echo "<td style=\"white-space:nowrap\"><a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>"._LISTS_CLONE."</a></td>";
+			echo "<td style=\"white-space:nowrap\"><a href='index.php?action=templatedelete&amp;templateid=$current->tdnumber' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
+
+			break;
+	}
+}
+
+function listplug_table_skinlist($template, $type) {
+	global $CONF, $DIR_SKINS, $manager;
+	switch($type) {
+		case 'HEAD':
+			echo "<th>"._LISTS_NAME."</th><th>"._LISTS_DESC."</th><th colspan='3'>"._LISTS_ACTIONS."</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>';
+
+			// use a special style for the default skin
+			if ($current->sdnumber == $CONF['BaseSkin']) {
+				echo '<strong>',htmlspecialchars($current->sdname),'</strong>';
+			} else {
+				echo htmlspecialchars($current->sdname);
+			}
+
+			echo '<br /><br />';
+			echo _LISTS_TYPE ,': ' , htmlspecialchars($current->sdtype);
+			echo '<br />', _LIST_SKINS_INCMODE , ' ' , (($current->sdincmode=='skindir') ?_PARSER_INCMODE_SKINDIR:_PARSER_INCMODE_NORMAL);
+			if ($current->sdincpref) echo '<br />' , _LIST_SKINS_INCPREFIX , ' ', htmlspecialchars($current->sdincpref);
+
+			// add preview image when present
+			if ($current->sdincpref && @file_exists($DIR_SKINS . $current->sdincpref . 'preview.png'))
+			{
+				echo '<br /><br />';
+
+				$hasEnlargement = @file_exists($DIR_SKINS . $current->sdincpref . 'preview-large.png');
+				if ($hasEnlargement)
+					echo '<a href="',$CONF['SkinsURL'], htmlspecialchars($current->sdincpref),'preview-large.png" title="View larger">';
+
+				echo '<img class="skinpreview" src="',$CONF['SkinsURL'], htmlspecialchars($current->sdincpref),'preview.png" width="100" height="75" alt="Preview for \'',htmlspecialchars($current->sdname),'\' skin" />';
+
+				if ($hasEnlargement)
+					echo '</a>';
+
+				if (@file_exists($DIR_SKINS . $current->sdincpref . 'readme.html'))
+				{
+					echo '<br /><a href="',$CONF['SkinsURL'], htmlspecialchars($current->sdincpref),'readme.html" title="More info on the \'',htmlspecialchars($current->sdname),'\' skin">Readme</a>';
+				}
+
+
+			}
+
+			echo "</td>";
+
+
+			echo "<td>" , htmlspecialchars($current->sddesc);
+				// show list of defined parts
+				$r = sql_query('SELECT stype FROM '.sql_table('skin').' WHERE sdesc='.$current->sdnumber . ' ORDER BY stype');
+				$types = array();
+				while ($o = mysql_fetch_object($r))
+					array_push($types,$o->stype);
+				if (sizeof($types) > 0) {
+					$friendlyNames = SKIN::getFriendlyNames();
+					for ($i=0;$i<sizeof($types);$i++) {
+						$type = $types[$i];
+						if (in_array($type, array('index', 'item', 'archivelist', 'archive', 'search', 'error', 'member', 'imagepopup'))) {
+							$types[$i] = '<li>' . helpHtml('skinpart'.$type) . ' <a href="index.php?action=skinedittype&amp;skinid='.$current->sdnumber.'&amp;type='.$type.'" tabindex="'.$template['tabindex'].'">' . htmlspecialchars($friendlyNames[$type]) . "</a></li>";
+						} else {
+							$types[$i] = '<li>' . helpHtml('skinpartspecial') . ' <a href="index.php?action=skinedittype&amp;skinid='.$current->sdnumber.'&amp;type='.$type.'" tabindex="'.$template['tabindex'].'">' . htmlspecialchars($friendlyNames[$type]) . "</a></li>";
+						}
+					}
+					echo '<br /><br />',_LIST_SKINS_DEFINED,' <ul>',implode($types,'') ,'</ul>';
+				}
+			echo "</td>";
+			echo "<td style=\"white-space:nowrap\"><a href='index.php?action=skinedit&amp;skinid=$current->sdnumber' tabindex='".$template['tabindex']."'>"._LISTS_EDIT."</a></td>";
+
+			$url = $manager->addTicketToUrl('index.php?action=skinclone&skinid=' . intval($current->sdnumber));
+			echo "<td style=\"white-space:nowrap\"><a href='",htmlspecialchars($url),"' tabindex='".$template['tabindex']."'>"._LISTS_CLONE."</a></td>";
+			echo "<td style=\"white-space:nowrap\"><a href='index.php?action=skindelete&amp;skinid=$current->sdnumber' tabindex='".$template['tabindex']."'>"._LISTS_DELETE."</a></td>";
+
+			break;
+	}
+}
+
+function listplug_table_draftlist($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo "<th>"._LISTS_BLOG."</th><th>"._LISTS_TITLE."</th><th colspan='2'>"._LISTS_ACTIONS."</th>";
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>', htmlspecialchars($current->bshortname) , '</td>';
+			echo '<td>', htmlspecialchars(strip_tags($current->ititle)) , '</td>';
+			echo "<td><a href='index.php?action=itemedit&amp;itemid=$current->inumber'>"._LISTS_EDIT."</a></td>";
+			echo "<td><a href='index.php?action=itemdelete&amp;itemid=$current->inumber'>"._LISTS_DELETE."</a></td>";
+
+			break;
+	}
+}
+
+
+function listplug_table_actionlist($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo '<th>'._LISTS_TIME.'</th><th>'._LIST_ACTION_MSG.'</th>';
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>' , htmlspecialchars($current->timestamp), '</td>';
+			echo '<td>' , htmlspecialchars($current->message), '</td>';
+
+			break;
+	}
+}
+
+function listplug_table_banlist($template, $type) {
+	switch($type) {
+		case 'HEAD':
+			echo '<th>'._LIST_BAN_IPRANGE.'</th><th>'. _LIST_BAN_REASON.'</th><th>'._LISTS_ACTIONS.'</th>';
+			break;
+		case 'BODY':
+			$current = $template['current'];
+
+			echo '<td>' , htmlspecialchars($current->iprange) , '</td>';
+			echo '<td>' , htmlspecialchars($current->reason) , '</td>';
+			echo "<td><a href='index.php?action=banlistdelete&amp;blogid=", intval($current->blogid) , "&amp;iprange=" , htmlspecialchars($current->iprange) , "'>",_LISTS_DELETE,"</a></td>";
+			break;
+	}
+}
+
+?>
diff -ruN 3.24.src/nucleus/libs/skinie.php 3.31.src/nucleus/libs/skinie.php
--- 3.24.src/nucleus/libs/skinie.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/skinie.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,42 +1,42 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  *	This class contains two classes that can be used for importing and 
-  *	exporting Nucleus skins: SKINIMPORT and SKINEXPORT
-  *
+ *	This class contains two classes that can be used for importing and
+ *	exporting Nucleus skins: SKINIMPORT and SKINEXPORT
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: skinie.php,v 1.18.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: skinie.php 1159 2007-05-24 14:37:56Z kaigreve $
+ */
 
 class SKINIMPORT {
 
 	// hardcoded value (see constructor). When 1, interesting info about the
 	// parsing process is sent to the output
 	var $debug;
-	
+
 	// parser/file pointer
 	var $parser;
 	var $fp;
-	
+
 	// which data has been read?
 	var $metaDataRead;
-	var $allRead;	
-	
+	var $allRead;
+
 	// extracted data
 	var $skins;
 	var $templates;
 	var $info;
-	
+
 	// to maintain track of where we are inside the XML file
 	var $inXml;
 	var $inData;
@@ -45,31 +45,31 @@
 	var $inTemplate;
 	var $currentName;
 	var $currentPartName;
-	var $cdata;	
-	
-	
-	
+	var $cdata;
+
+
+
 	/**
 	 * constructor initializes data structures
 	 */
 	function SKINIMPORT() {
 		// disable magic_quotes_runtime if it's turned on
 		set_magic_quotes_runtime(0);
-	
+
 		// debugging mode?
 		$this->debug = 0;
-	
+
 		$this->reset();
-		
+
 	}
-	
+
 	function reset() {
-    	if ($this->parser)
-    		xml_parser_free($this->parser);
-    		
+		if ($this->parser)
+			xml_parser_free($this->parser);
+
 		// XML file pointer
-		$this->fp = 0;		
-		
+		$this->fp = 0;
+
 		// which data has been read?
 		$this->metaDataRead = 0;
 		$this->allRead = 0;
@@ -82,17 +82,17 @@
 		$this->inTemplate = 0;
 		$this->currentName = '';
 		$this->currentPartName = '';
-		
+
 		// character data pile
 		$this->cdata = '';
-		
+
 		// list of skinnames and templatenames (will be array of array)
 		$this->skins = array();
 		$this->templates = array();
-		
+
 		// extra info included in the XML files (e.g. installation notes)
 		$this->info = '';
-		
+
 		// init XML parser
 		$this->parser = xml_parser_create();
 		xml_set_object($this->parser, $this);
@@ -100,8 +100,8 @@
 		xml_set_character_data_handler($this->parser, 'characterData');
 		xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
 
-	}	
-	
+	}
+
 	/**
 	 * Reads an XML file into memory
 	 *
@@ -118,6 +118,8 @@
 		// here we go!
 		$this->inXml = 1;
 
+		$tempbuffer = null;
+
 		while (!feof($this->fp)) {
 			$tempbuffer .= fread($this->fp, 4096);
 		}
@@ -125,9 +127,9 @@
 
 /*
 	[2004-08-04] dekarma - Took this out since it messes up good XML if it has skins/templates
-	                       with CDATA sections. need to investigate consequences.
-	                       see bug [ 999914 ] Import fails (multiple skins in XML/one of them with CDATA)
-	
+						   with CDATA sections. need to investigate consequences.
+						   see bug [ 999914 ] Import fails (multiple skins in XML/one of them with CDATA)
+
 		// backwards compatibility with the non-wellformed skinbackup.xml files
 		// generated by v2/v3 (when CDATA sections were present in skins)
 		// split up those CDATA sections into multiple ones
@@ -138,7 +140,7 @@
 				'return $matches[1] . preg_replace("/(\]\])(.*?<!\[CDATA)/ms","]]]]><![CDATA[$2",$matches[2])."]]]]><![CDATA[".$matches[4];'
 			),
 			$tempbuffer
-		);		
+		);
 */
 		$temp = tmpfile();
 		fwrite($temp, $tempbuffer);
@@ -153,8 +155,8 @@
 		// all done
 		$this->inXml = 0;
 		fclose($temp);
-	}	
-	
+	}
+
 	/**
 	 * Returns the list of skin names
 	 */
@@ -167,17 +169,17 @@
 	 */
 	function getTemplateNames() {
 		return array_keys($this->templates);
-	}	
-	
+	}
+
 	/**
 	 * Returns the extra information included in the XML file
 	 */
 	function getInfo() {
 		return $this->info;
 	}
-	
+
 	/**
-	 * Writes the skins and templates to the database 
+	 * Writes the skins and templates to the database
 	 *
 	 * @param $allowOverwrite
 	 *		set to 1 when allowed to overwrite existing skins with the same name
@@ -186,95 +188,97 @@
 	function writeToDatabase($allowOverwrite = 0) {
 		$existingSkins = $this->checkSkinNameClashes();
 		$existingTemplates = $this->checkTemplateNameClashes();
-		
+
 		// if not allowed to overwrite, check if any nameclashes exists
 		if (!$allowOverwrite) {
 			if ((sizeof($existingSkins) > 0) || (sizeof($existingTemplates) > 0))
 				return 'Name clashes detected, re-run with allowOverwrite = 1 to force overwrite';
 		}
-		
+
 		foreach ($this->skins as $skinName => $data) {
 			// 1. if exists: delete all part data, update desc data
 			//    if not exists: create desc
 			if (in_array($skinName, $existingSkins)) {
 				$skinObj = SKIN::createFromName($skinName);
-				
+
 				// delete all parts of the skin
 				$skinObj->deleteAllParts();
-				
+
 				// update general info
 				$skinObj->updateGeneralInfo($skinName, $data['description'], $data['type'], $data['includeMode'], $data['includePrefix']);
 			} else {
 				$skinid = SKIN::createNew($skinName, $data['description'], $data['type'], $data['includeMode'], $data['includePrefix']);
 				$skinObj = new SKIN($skinid);
 			}
-			
+
 			// 2. add parts
 			foreach ($data['parts'] as $partName => $partContent) {
 				$skinObj->update($partName, $partContent);
 			}
 		}
-		
+
 		foreach ($this->templates as $templateName => $data) {
 			// 1. if exists: delete all part data, update desc data
 			//    if not exists: create desc
 			if (in_array($templateName, $existingTemplates)) {
 				$templateObj = TEMPLATE::createFromName($templateName);
-				
+
 				// delete all parts of the template
 				$templateObj->deleteAllParts();
-				
+
 				// update general info
 				$templateObj->updateGeneralInfo($templateName, $data['description']);
 			} else {
 				$templateid = TEMPLATE::createNew($templateName, $data['description']);
 				$templateObj = new TEMPLATE($templateid);
 			}
-			
+
 			// 2. add parts
 			foreach ($data['parts'] as $partName => $partContent) {
 				$templateObj->update($partName, $partContent);
-			}			
+			}
 		}
-	
-			
+
+
 	}
-	
+
 	/**
 	  * returns an array of all the skin nameclashes (empty array when no name clashes)
 	  */
 	function checkSkinNameClashes() {
 		$clashes = array();
-		
+
 		foreach ($this->skins as $skinName => $data) {
 			if (SKIN::exists($skinName))
 				array_push($clashes, $skinName);
 		}
-		
+
 		return $clashes;
 	}
-	
+
 	/**
-	  * returns an array of all the template nameclashes 
+	  * returns an array of all the template nameclashes
 	  * (empty array when no name clashes)
 	  */
 	function checkTemplateNameClashes() {
 		$clashes = array();
-		
+
 		foreach ($this->templates as $templateName => $data) {
 			if (TEMPLATE::exists($templateName))
 				array_push($clashes, $templateName);
 		}
-		
+
 		return $clashes;
 	}
-		
+
 	/**
 	 * Called by XML parser for each new start element encountered
 	 */
 	function startElement($parser, $name, $attrs) {
-		if ($this->debug) echo 'START: ', $name, '<br />';
-		
+		foreach($attrs as $key=>$value) $attrs[$key]=htmlspecialchars($value,ENT_QUOTES);
+
+		if ($this->debug) echo 'START: ', htmlspecialchars($name), '<br />';
+
 		switch ($name) {
 			case 'nucleusskin':
 				$this->inData = 1;
@@ -291,21 +295,21 @@
 					$this->currentName = $attrs['name'];
 					$this->skins[$this->currentName]['type'] = $attrs['type'];
 					$this->skins[$this->currentName]['includeMode'] = $attrs['includeMode'];
-					$this->skins[$this->currentName]['includePrefix'] = $attrs['includePrefix'];					
-					$this->skins[$this->currentName]['parts'] = array();										
+					$this->skins[$this->currentName]['includePrefix'] = $attrs['includePrefix'];
+					$this->skins[$this->currentName]['parts'] = array();
 				} else {
-					$this->skins[$attrs['name']] = array();				
-					$this->skins[$attrs['name']]['parts'] = array();									
+					$this->skins[$attrs['name']] = array();
+					$this->skins[$attrs['name']]['parts'] = array();
 				}
 				break;
 			case 'template':
 				if (!$this->inMeta) {
 					$this->inTemplate = 1;
 					$this->currentName = $attrs['name'];
-					$this->templates[$this->currentName]['parts'] = array();															
+					$this->templates[$this->currentName]['parts'] = array();
 				} else {
-					$this->templates[$attrs['name']] = array();				
-					$this->templates[$attrs['name']]['parts'] = array();									
+					$this->templates[$attrs['name']] = array();
+					$this->templates[$attrs['name']]['parts'] = array();
 				}
 				break;
 			case 'description':
@@ -315,21 +319,21 @@
 				$this->currentPartName = $attrs['name'];
 				break;
 			default:
-				echo 'UNEXPECTED TAG: ' , $name , '<br />';
+				echo 'UNEXPECTED TAG: ' , htmlspecialchars($name) , '<br />';
 				break;
 		}
-		
+
 		// character data never contains other tags
-		$this->clearCharacterData(); 
-		
+		$this->clearCharacterData();
+
 	}
 
 	/**
 	  * Called by the XML parser for each closing tag encountered
 	  */
 	function endElement($parser, $name) {
-		if ($this->debug) echo 'END: ', $name, '<br />';
-		
+		if ($this->debug) echo 'END: ', htmlspecialchars($name), '<br />';
+
 		switch ($name) {
 			case 'nucleusskin':
 				$this->inData = 0;
@@ -345,30 +349,30 @@
 				if (!$this->inMeta) $this->inSkin = 0;
 				break;
 			case 'template':
-				if (!$this->inMeta) $this->inTemplate = 0;			
+				if (!$this->inMeta) $this->inTemplate = 0;
 				break;
 			case 'description':
 				if ($this->inSkin) {
 					$this->skins[$this->currentName]['description'] = $this->getCharacterData();
 				} else {
-					$this->templates[$this->currentName]['description'] = $this->getCharacterData();				
+					$this->templates[$this->currentName]['description'] = $this->getCharacterData();
 				}
 				break;
 			case 'part':
 				if ($this->inSkin) {
 					$this->skins[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();
 				} else {
-					$this->templates[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();				
+					$this->templates[$this->currentName]['parts'][$this->currentPartName] = $this->getCharacterData();
 				}
 				break;
 			default:
-				echo 'UNEXPECTED TAG: ' , $name, '<br />';
+				echo 'UNEXPECTED TAG: ' , htmlspecialchars($name), '<br />';
 				break;
 		}
 		$this->clearCharacterData();
 
 	}
-	
+
 	/**
 	 * Called by XML parser for data inside elements
 	 */
@@ -376,21 +380,21 @@
 		if ($this->debug) echo 'NEW DATA: ', htmlspecialchars($data), '<br />';
 		$this->cdata .= $data;
 	}
-	
+
 	/**
 	 * Returns the data collected so far
 	 */
 	function getCharacterData() {
 		return $this->cdata;
 	}
-	
+
 	/**
 	 * Clears the data buffer
 	 */
 	function clearCharacterData() {
 		$this->cdata = '';
 	}
-	
+
 	/**
 	 * Static method that looks for importable XML files in subdirs of the given dir
 	 */
@@ -403,22 +407,22 @@
 				$xml_file = $dir . $filename . '/skinbackup.xml';
 				if (file_exists($xml_file) && is_readable($xml_file)) {
 					$candidates[$filename] = $filename; //$xml_file;
-				} 
+				}
 
-				// backwards compatibility			
+				// backwards compatibility
 				$xml_file = $dir . $filename . '/skindata.xml';
 				if (file_exists($xml_file) && is_readable($xml_file)) {
 					$candidates[$filename] = $filename; //$xml_file;
-				} 
+				}
 			}
 		}
 		closedir($dirhandle);
-		
+
 		return $candidates;
-	
+
 	}
-	 
-	
+
+
 }
 
 
@@ -427,21 +431,21 @@
 	var $templates;
 	var $skins;
 	var $info;
-	
+
 	/**
 	 * Constructor initializes data structures
 	 */
 	function SKINEXPORT() {
 		// list of templateIDs to export
 		$this->templates = array();
-		
+
 		// list of skinIDs to export
 		$this->skins = array();
-		
+
 		// extra info to be in XML file
 		$this->info = '';
 	}
-	
+
 	/**
 	 * Adds a template to be exported
 	 *
@@ -451,35 +455,35 @@
 	 */
 	function addTemplate($id) {
 		if (!TEMPLATE::existsID($id)) return 0;
-	
+
 		$this->templates[$id] = TEMPLATE::getNameFromId($id);
-		
+
 		return 1;
 	}
-	
+
 	/**
 	 * Adds a skin to be exported
 	 *
-	 * @param id 
+	 * @param id
 	 *		skin ID
 	 * @result false when no such ID exists
-	 */	
+	 */
 	function addSkin($id) {
 		if (!SKIN::existsID($id)) return 0;
-		
+
 		$this->skins[$id] = SKIN::getNameFromId($id);
-		
+
 		return 1;
 	}
-	
+
 	/**
 	 * Sets the extra info to be included in the exported file
 	 */
 	function setInfo($info) {
 		$this->info = $info;
 	}
-	
-	
+
+
 	/**
 	 * Outputs the XML contents of the export file
 	 *
@@ -489,16 +493,16 @@
 	 */
 	function export($setHeaders = 1) {
 		if ($setHeaders) {
-			// make sure the mimetype is correct, and that the data does not show up 
+			// make sure the mimetype is correct, and that the data does not show up
 			// in the browser, but gets saved into and XML file (popup download window)
 			header('Content-Type: text/xml');
 			header('Content-Disposition: attachment; filename="skinbackup.xml"');
 			header('Expires: 0');
 			header('Pragma: no-cache');
 		}
-	
+
 		echo "<nucleusskin>\n";
-	
+
 		// meta
 		echo "\t<meta>\n";
 			// skins
@@ -513,54 +517,54 @@
 			if ($this->info)
 				echo "\t\t<info><![CDATA[",$this->info,"]]></info>\n";
 		echo "\t</meta>\n\n\n";
-		
+
 		// contents skins
 		foreach ($this->skins as $skinId => $skinName) {
 			$skinId = intval($skinId);
 			$skinObj = new SKIN($skinId);
-			
+
 			echo "\t", '<skin name="',htmlspecialchars($skinName),'" type="',htmlspecialchars($skinObj->getContentType()),'" includeMode="',htmlspecialchars($skinObj->getIncludeMode()),'" includePrefix="',htmlspecialchars($skinObj->getIncludePrefix()),'">',"\n";
-			
+
 			echo "\t\t", '<description>',htmlspecialchars($skinObj->getDescription()),'</description>',"\n";
-			
+
 			$res = sql_query('SELECT stype, scontent FROM '.sql_table('skin').' WHERE sdesc='.$skinId);
 			while ($partObj = mysql_fetch_object($res)) {
 				echo "\t\t",'<part name="',htmlspecialchars($partObj->stype),'">';
 				echo '<![CDATA[', $this->escapeCDATA($partObj->scontent),']]>';
 				echo "</part>\n\n";
 			}
-			
+
 			echo "\t</skin>\n\n\n";
 		}
-		
+
 		// contents templates
 		foreach ($this->templates as $templateId => $templateName) {
 			$templateId = intval($templateId);
-			
+
 			echo "\t",'<template name="',htmlspecialchars($templateName),'">',"\n";
-			
-			echo "\t\t",'<description>',htmlspecialchars(TEMPLATE::getDesc($templateId)),'</description>',"\n";			
-			
+
+			echo "\t\t",'<description>',htmlspecialchars(TEMPLATE::getDesc($templateId)),'</description>',"\n";
+
 			$res = sql_query('SELECT tpartname, tcontent FROM '.sql_table('template').' WHERE tdesc='.$templateId);
 			while ($partObj = mysql_fetch_object($res)) {
 				echo "\t\t",'<part name="',htmlspecialchars($partObj->tpartname),'">';
 				echo '<![CDATA[', $this->escapeCDATA($partObj->tcontent) ,']]>';
 				echo '</part>',"\n\n";
 			}
-			
+
 			echo "\t</template>\n\n\n";
-		}		
-		
+		}
+
 		echo '</nucleusskin>';
 	}
-	
+
 	/**
 	 * Escapes CDATA content so it can be included in another CDATA section
 	 */
 	function escapeCDATA($cdata)
 	{
 		return preg_replace('/]]>/', ']]]]><![CDATA[>', $cdata);
-		
+
 	}
 }
 
diff -ruN 3.24.src/nucleus/libs/SKIN.php 3.31.src/nucleus/libs/SKIN.php
--- 3.24.src/nucleus/libs/SKIN.php	2006-11-29 15:23:33.000000000 -0600
+++ 3.31.src/nucleus/libs/SKIN.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,28 +1,30 @@
 <?php
-
-
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * Class representing a skin
-  *
+ * Class representing a skin
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: SKIN.php 1104 2006-11-11 10:21:45Z dekarma $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: SKIN.php 1198 2007-09-05 07:44:35Z kimitake $
+ */
+
+if ( !function_exists('requestVar') ) exit;
+require_once dirname(__FILE__) . '/ACTIONS.php';
+
 class SKIN {
 
 	// after creating a SKIN object, evaluates to true when the skin exists
 	var $isValid;
-	
+
 	// skin characteristics. Use the getXXX methods rather than accessing directly
 	var $id;
 	var $description;
@@ -30,7 +32,7 @@
 	var $includeMode;		// either 'normal' or 'skindir'
 	var $includePrefix;
 	var $name;
-	
+
 	function SKIN($id) {
 		$this->id = intval($id);
 
@@ -40,7 +42,7 @@
 		$this->isValid = (mysql_num_rows($res) > 0);
 		if (!$this->isValid)
 			return;
-			
+
 		$this->name = $obj->sdname;
 		$this->description = $obj->sddesc;
 		$this->contentType = $obj->sdtype;
@@ -48,52 +50,77 @@
 		$this->includePrefix = $obj->sdincpref;
 
 	}
-	
+
 	function getID() {				return $this->id; }
 	function getName() { 			return $this->name; }
 	function getDescription() { 	return $this->description; }
 	function getContentType() { 	return $this->contentType; }
 	function getIncludeMode() { 	return $this->includeMode; }
 	function getIncludePrefix() { 	return $this->includePrefix; }
-	
-	// returns true if there is a skin with the given shortname (static)
+
+	/**
+	 * Checks if a skin with a given shortname exists
+	 * @param string $name Skin short name
+	 * @return int number of skins with the given ID
+	 * @static
+	 */
 	function exists($name) {
 		return quickQuery('select count(*) as result FROM '.sql_table('skin_desc').' WHERE sdname="'.addslashes($name).'"') > 0;
 	}
 
-	// returns true if there is a skin with the given ID (static)
+	/**
+	 * Checks if a skin with a given ID exists
+	 * @param string $id Skin ID
+	 * @return int number of skins with the given ID
+	 * @static
+	 */
 	function existsID($id) {
 		return quickQuery('select COUNT(*) as result FROM '.sql_table('skin_desc').' WHERE sdnumber='.intval($id)) > 0;
-	}	
-	
-	// (static)
+	}
+
+	/**
+	 * Returns a skin given its shortname
+	 * @param string $name Skin shortname
+	 * @return object SKIN
+	 * @static
+	 */
 	function createFromName($name) {
 		return new SKIN(SKIN::getIdFromName($name));
-	}	
-	
-	// (static)
+	}
+
+	/**
+	 * Returns a skin ID given its shortname
+	 * @param string $name Skin shortname
+	 * @return int Skin ID
+	 * @static
+	 */
 	function getIdFromName($name) {
 		$query =  'SELECT sdnumber'
-		       . ' FROM '.sql_table('skin_desc')
-		       . ' WHERE sdname="'.addslashes($name).'"';
+			   . ' FROM '.sql_table('skin_desc')
+			   . ' WHERE sdname="'.addslashes($name).'"';
 		$res = sql_query($query);
 		$obj = mysql_fetch_object($res);
-		return $obj->sdnumber;	
+		return $obj->sdnumber;
 	}
-	
-	// (static)
+
+	/**
+	 * Returns a skin shortname given its ID
+	 * @param string $name
+	 * @return string Skin short name
+	 * @static
+	 */
 	function getNameFromId($id) {
 		return quickQuery('SELECT sdname as result FROM '.sql_table('skin_desc').' WHERE sdnumber=' . intval($id));
 	}
-	
+
 	/**
 	 * Creates a new skin, with the given characteristics.
 	 *
-	 * (static)
+	 * @static
 	 */
 	function createNew($name, $desc, $type = 'text/html', $includeMode = 'normal', $includePrefix = '') {
 		global $manager;
-		
+
 		$manager->notify(
 			'PreAddSkin',
 			array(
@@ -107,7 +134,7 @@
 
 		sql_query('INSERT INTO '.sql_table('skin_desc')." (sdname, sddesc, sdtype, sdincmode, sdincpref) VALUES ('" . addslashes($name) . "','" . addslashes($desc) . "','".addslashes($type)."','".addslashes($includeMode)."','".addslashes($includePrefix)."')");
 		$newid = mysql_insert_id();
-		
+
 		$manager->notify(
 			'PostAddSkin',
 			array(
@@ -119,10 +146,10 @@
 				'includePrefix' => $includePrefix
 			)
 		);
-		
+
 		return $newid;
 	}
-	
+
 	function parse($type) {
 		global $manager, $CONF;
 
@@ -188,35 +215,35 @@
 		// write new thingie
 		if ($content) {
 			sql_query('INSERT INTO '.sql_table('skin')." SET scontent='" . addslashes($content) . "', stype='" . addslashes($type) . "', sdesc=" . intval($skinid));
-		}	
+		}
 	}
-	
+
 	/**
 	 * Deletes all skin parts from the database
 	 */
 	function deleteAllParts() {
 		sql_query('DELETE FROM '.sql_table('skin').' WHERE sdesc='.$this->getID());
 	}
-	
+
 	/**
 	 * Updates the general information about the skin
 	 */
 	function updateGeneralInfo($name, $desc, $type = 'text/html', $includeMode = 'normal', $includePrefix = '') {
 		$query =  'UPDATE '.sql_table('skin_desc').' SET'
-		       . " sdname='" . addslashes($name) . "',"
-		       . " sddesc='" . addslashes($desc) . "',"
-		       . " sdtype='" . addslashes($type) . "',"
+			   . " sdname='" . addslashes($name) . "',"
+			   . " sddesc='" . addslashes($desc) . "',"
+			   . " sdtype='" . addslashes($type) . "',"
 			   . " sdincmode='" . addslashes($includeMode) . "',"
-			   . " sdincpref='" . addslashes($includePrefix) . "'"		       
-		       . " WHERE sdnumber=" . $this->getID();
-		sql_query($query);		
+			   . " sdincpref='" . addslashes($includePrefix) . "'"
+			   . " WHERE sdnumber=" . $this->getID();
+		sql_query($query);
 	}
-	
+
 	/**
 	 * static: returns an array of friendly names
 	 */
 	function getFriendlyNames() {
-		return array(
+		$skintypes = array(
 			'index' => _SKIN_PART_MAIN,
 			'item' => _SKIN_PART_ITEM,
 			'archivelist' => _SKIN_PART_ALIST,
@@ -225,10 +252,20 @@
 			'error' => _SKIN_PART_ERROR,
 			'member' => _SKIN_PART_MEMBER,
 			'imagepopup' => _SKIN_PART_POPUP
-		);	
+		);
+
+		$query = "SELECT stype FROM " . sql_table('skin') . " WHERE stype NOT IN ('index', 'item', 'error', 'search', 'archive', 'archivelist', 'imagepopup', 'member')";
+		$res = sql_query($query);
+		while ($row = mysql_fetch_array($res)) {
+			$skintypes[strtolower($row['stype'])] = ucfirst($row['stype']);
+		}
+
+		return $skintypes;
 	}
-	
+
 	function getAllowedActionsForType($type) {
+		global $blogid;
+
 		// some actions that can be performed at any time, from anywhere
 		$defaultActions = array('otherblog',
 								'plugin',
@@ -256,53 +293,57 @@
 								'if',
 								'else',
 								'endif',
-								'charset'
+								'elseif',
+								'ifnot',
+								'elseifnot',
+								'charset',
+								'bloglist'
 								);
-		
+
 		// extra actions specific for a certain skin type
 		$extraActions = array();
 
 		switch ($type) {
 			case 'index':
-				$extraActions = array('blog', 
-					            'blogsetting',
-					            'preview',
-					            'additemform',
-								'categorylist',					            
-					            'archivelist',
-					            'archivedaylist',
-					            'nextlink',
-					            'prevlink'
-					            );				
+				$extraActions = array('blog',
+								'blogsetting',
+								'preview',
+								'additemform',
+								'categorylist',
+								'archivelist',
+								'archivedaylist',
+								'nextlink',
+								'prevlink'
+								);
 				break;
 			case 'archive':
 				$extraActions = array('blog',
 								'archive',
 								'otherarchive',
-								'categorylist',								
+								'categorylist',
 								'archivelist',
-					            'archivedaylist',								
+								'archivedaylist',
 								'blogsetting',
 								'archivedate',
-							    'nextarchive',
-							    'prevarchive',
-							    'nextlink',
-							    'prevlink',
-							    'archivetype'
+								'nextarchive',
+								'prevarchive',
+								'nextlink',
+								'prevlink',
+								'archivetype'
 				);
 				break;
 			case 'archivelist':
 				$extraActions = array('blog',
-							    'archivelist',
+								'archivelist',
 								'archivedaylist',
 								'categorylist',
-							    'blogsetting',
+								'blogsetting',
 							   );
 				break;
 			case 'search':
 				$extraActions = array('blog',
 								'archivelist',
-					            'archivedaylist',
+								'archivedaylist',
 								'categorylist',
 								'searchresults',
 								'othersearchresults',
@@ -326,1077 +367,52 @@
 				break;
 			case 'item':
 				$extraActions = array('blog',
-							    'item',
-							    'comments',
-							    'commentform',
-							    'vars',
-							    'blogsetting',
-							    'nextitem',
-							    'previtem',
-							    'nextlink',
-							    'prevlink',
-							    'nextitemtitle',
-							    'previtemtitle',
-								'categorylist',							    
-							    'archivelist',
-					            'archivedaylist',							    
-							    'itemtitle',
-							    'itemid',
-							    'itemlink',
-							    );
+								'item',
+								'comments',
+								'commentform',
+								'vars',
+								'blogsetting',
+								'nextitem',
+								'previtem',
+								'nextlink',
+								'prevlink',
+								'nextitemtitle',
+								'previtemtitle',
+								'categorylist',
+								'archivelist',
+								'archivedaylist',
+								'itemtitle',
+								'itemid',
+								'itemlink',
+								);
 				break;
 			case 'error':
 				$extraActions = array(
 								'errormessage'
 				);
 				break;
-		}
-		return array_merge($defaultActions, $extraActions);
-	}
-	
-}
-
-
-/*
- * This class contains the functions that get called by using
- * the special tags in the skins
- *
- * The allowed tags for a type of skinpart are defined by the 
- * SKIN::getAllowedActionsForType($type) method
- */
-class ACTIONS extends BaseActions {
-
-	// part of the skin currently being parsed ('index', 'item', 'archive',
-	// 'archivelist', 'member', 'search', 'error', 'imagepopup')
-	var $skintype;
-	
-	// contains an assoc array with parameters that need to be included when
-	// generating links to items/archives/... (e.g. catid)	
-	var $linkparams;
-	
-	// reference to the skin object for which a part is being parsed
-	var $skin;
-	
-
-	// used when including templated forms from the include/ dir. The $formdata var 
-	// contains the values to fill out in there (assoc array name -> value)
-	var $formdata;
-	
-
-	// filled out with the number of displayed items after calling one of the 
-
-	// (other)blog/(other)searchresults skinvars.
-
-	var $amountfound;
-
-	function ACTIONS($type) {
-		// call constructor of superclass first
-		$this->BaseActions();
-
-		$this->skintype = $type;
-
-		global $catid;
-		if ($catid) 
-			$this->linkparams = array('catid' => $catid);
-	}
-
-	function setSkin(&$skin) {
-		$this->skin =& $skin;
-	}
-	
-	function setParser(&$parser) {
-		$this->parser =& $parser;
-	}
-	
-	/*
-		Forms get parsedincluded now, using an extra <formdata> skinvar
-	*/
-	function doForm($filename) {
-		global $DIR_NUCLEUS;
-		array_push($this->parser->actions,'formdata','text','callback','errordiv','ticket');
-		$oldIncludeMode = PARSER::getProperty('IncludeMode');
-		$oldIncludePrefix = PARSER::getProperty('IncludePrefix');
-		PARSER::setProperty('IncludeMode','normal');
-		PARSER::setProperty('IncludePrefix','');
-		$this->parse_parsedinclude($DIR_NUCLEUS . 'forms/' . $filename . '.template');
-		PARSER::setProperty('IncludeMode',$oldIncludeMode);
-		PARSER::setProperty('IncludePrefix',$oldIncludePrefix);
-		array_pop($this->parser->actions);		// errordiv
-		array_pop($this->parser->actions);		// callback
-		array_pop($this->parser->actions);		// text
-		array_pop($this->parser->actions);		// formdata
-		array_pop($this->parser->actions);		// ticket
-	}
-
-	function parse_ticket() {
-		global $manager;
-		$manager->addTicketHidden();
-	}
-
-	function parse_formdata($what) {
-		echo $this->formdata[$what];
-	}
-	function parse_text($which) {
-		// constant($which) only available from 4.0.4 :(
-		if (defined($which)) { 	
-			eval("echo $which;");
-		}
-	}
-	function parse_callback($eventName, $type)
-	{
-		global $manager;
-		$manager->notify($eventName, array('type' => $type));
-	}
-	function parse_errordiv() {
-		global $errormessage;
-		if ($errormessage)
-	  		echo '<div class="error">', htmlspecialchars($errormessage),'</div>';
-	}
-	
-	function parse_skinname() {
-		echo $this->skin->getName();
-	}
-	
-	function parse_if($field, $name='', $value = '') {
-		global $catid, $blog, $member, $itemidnext, $itemidprev, $manager;
-
-		$condition = 0;
-		switch($field) {
-			case 'category':
-				$condition = ($blog && $this->_ifCategory($name,$value));
-				break;
-			case 'blogsetting':
-				$condition = ($blog && ($blog->getSetting($name) == $value));
-				break;
-			case 'loggedin':
-				$condition = $member->isLoggedIn();
-				break;
-			case 'onteam':
-				$condition = $member->isLoggedIn() && $this->_ifOnTeam($name);
-				break;
-			case 'admin':
-				$condition = $member->isLoggedIn() && $this->_ifAdmin($name);
-				break;				
-			case 'nextitem':
-				$condition = ($itemidnext != '');
-				break;
-			case 'previtem':
-				$condition = ($itemidprev != ''); 
-				break;
-			case 'skintype':
-				$condition = ($name == $this->skintype);
-				break;
-			/*
-				hasplugin,PlugName
-					-> checks if plugin exists
-				hasplugin,PlugName,OptionName
-					-> checks if the option OptionName from plugin PlugName is not set to 'no'
-				hasplugin,PlugName,OptionName=value
-					-> checks if the option OptionName from plugin PlugName is set to value
-			*/
-		  	case 'hasplugin':
-                $condition = false;
-                // (pluginInstalled method won't write a message in the actionlog on failure)
-                if ($manager->pluginInstalled('NP_'.$name)) 
-                {
-					$plugin =& $manager->getPlugin('NP_' . $name);
-					if ($plugin != NULL){
-						if ($value == "") {
-							$condition = true;
-						} else {
-							list($name2, $value2) = explode('=', $value, 2);
-							if ($value2 == "" && $plugin->getOption($name2) != 'no') {
-								$condition = true;
-							} else if ($plugin->getOption($name2) == $value2) {
-								$condition = true;
-							}
-						}
-					}
-                }
-                break;				
-			default:	
-				return;
-		}
-		$this->_addIfCondition($condition);
-	}
-	
-	function _ifCategory($name = '', $value='') {
-		global $blog, $catid;
-
-		// when no parameter is defined, just check if a category is selected
-		if (($name != 'catname' && $name != 'catid') || ($value == ''))
-			return $blog->isValidCategory($catid);
-
-		// check category name
-		if ($name == 'catname') {
-			$value = $blog->getCategoryIdFromName($value);
-			if ($value == $catid)
-				return $blog->isValidCategory($catid);
-		}
-
-		// check category id
-		if (($name == 'catid') && ($value == $catid))
-			return $blog->isValidCategory($catid);
-		
-		return false;
-	}
-   
-	function _ifOnTeam($blogName = '') {
-		global $blog, $member, $manager;
-		
-		// when no blog found
-		if (($blogName == '') && (!is_object($blog)))
-			return 0;
-		
-		// explicit blog selection
-		if ($blogName != '') 
-			$blogid = getBlogIDFromName($blogName); 
-		
-		if (($blogName == '') || !$manager->existsBlogID($blogid))
-			// use current blog
-			$blogid = $blog->getID();
-			
-		return $member->teamRights($blogid);
-	}
-	
-	function _ifAdmin($blogName = '') {
-		global $blog, $member, $manager;
-
-		// when no blog found
-		if (($blogName == '') && (!is_object($blog)))
-			return 0;
-
-		// explicit blog selection
-		if ($blogName != '')
-			$blogid = getBlogIDFromName($blogName);
-
-		if (($blogName == '') || !$manager->existsBlogID($blogid))
-			// use current blog
-			$blogid = $blog->getID();
-
-		return $member->isBlogAdmin($blogid);
-	}	
-	
-	function parse_ifcat($text = '') {
-		if ($text == '') {
-			// new behaviour
-			$this->parse_if('category');
-		} else {
-			// old behaviour
-			global $catid, $blog;
-			if ($blog->isValidCategory($catid))
-				echo $text;
-		}
-	}
-	
-	// a link to the today page (depending on selected blog, etc...)
-	function parse_todaylink($linktext = '') {
-		global $blog, $CONF;
-		if ($blog)
-			echo $this->_link(createBlogidLink($blog->getID(),$this->linkparams), $linktext);
-		else
-			echo $this->_link($CONF['SiteUrl'], $linktext);
-	}
-	
-	// a link to the archives for the current blog (or for default blog)
-	function parse_archivelink($linktext = '') {
-		global $blog, $CONF;
-		if ($blog)
-			echo $this->_link(createArchiveListLink($blog->getID(),$this->linkparams), $linktext);
-		else
-			echo $this->_link(createArchiveListLink(), $linktext);
-	}
-
-	// include itemid of prev item
-	function parse_previtem() {
-		global $itemidprev;
-		echo $itemidprev;
-	}
-
-	// include itemtitle of prev item
-	function parse_previtemtitle($format = '') {
-		global $itemtitleprev;
-		
-		switch ($format) {
-			case 'xml':
-				echo stringToXML ($itemtitleprev);
-				break;
-			case 'attribute':
-				echo stringToAttribute ($itemtitleprev);
-				break;
-			case 'raw':
-				echo $itemtitleprev;
-				break;
-			default:
-		echo htmlspecialchars($itemtitleprev);
-				break;
-		}
-	}
-
-	// include itemid of next item
-	function parse_nextitem() {
-		global $itemidnext;
-		echo $itemidnext;
-	}
-
-	// include itemtitle of next item
-	function parse_nextitemtitle($format = '') {
-		global $itemtitlenext;
-
-		switch ($format) {
-			case 'xml':
-				echo stringToXML ($itemtitlenext);
-				break;
-			case 'attribute':
-				echo stringToAttribute ($itemtitlenext);
-				break;
-			case 'raw':
-				echo $itemtitlenext;
-				break;
-			default:
-		echo htmlspecialchars($itemtitlenext);
-				break;
-		}
-	}
-
-	function parse_prevarchive() {
-		global $archiveprev;
-		echo $archiveprev;
-	}
-
-	function parse_nextarchive() {
-		global $archivenext;
-		echo $archivenext;
-	}
-
-	function parse_archivetype() {
-		global $archivetype;
-		echo $archivetype;
-	}
-
-	function parse_prevlink($linktext = '', $amount = 10) {
-		global $itemidprev, $archiveprev, $startpos;
-
-		if ($this->skintype == 'item')
-			$this->_itemlink($itemidprev, $linktext);
-	    else if ($this->skintype == 'search' || $this->skintype == 'index')
-	        $this->_searchlink($amount, $startpos, 'prev', $linktext);
-		else
-			$this->_archivelink($archiveprev, $linktext);
-	}
-	
-	function parse_nextlink($linktext = '', $amount = 10) {
-		global $itemidnext, $archivenext, $startpos;
-		if ($this->skintype == 'item')
-			$this->_itemlink($itemidnext, $linktext);
-	    else if ($this->skintype == 'search' || $this->skintype == 'index')
-	        $this->_searchlink($amount, $startpos, 'next', $linktext);
-		else
-			$this->_archivelink($archivenext, $linktext);
-	}
-	
-	/**
-	 * returns either
-	 *		- a raw link (html/xml encoded) when no linktext is provided
-	 *		- a (x)html <a href... link when a text is present (text htmlencoded)
-	 */
-	function _link($url, $linktext = '')
-	{
-		$u = htmlspecialchars($url);
-		$u = preg_replace("/&amp;amp;/",'&amp;',$u); // fix URLs that already had encoded ampersands
-		if ($linktext != '')
-			$l = '<a href="' . $u .'">'.htmlspecialchars($linktext).'</a>';
-		else
-			$l = $u;
-		return $l; 	
-	}
-
-	/**
-	 * Outputs a next/prev link
-	 *
-	 * @param $maxresults
-	 *		The maximum amount of items shown per page (e.g. 10)
-	 * @param $startpos
-	 *		Current start position (requestVar('startpos'))
-	 * @param $direction
-	 *		either 'prev' or 'next'
-	 * @param $linktext
-	 *		When present, the output will be a full <a href...> link. When empty,
-	 *		only a raw link will be outputted
-	 */
-    function _searchlink($maxresults, $startpos, $direction, $linktext = '') {
-        global $CONF, $blog, $query, $amount;
-        // TODO: Move request uri to linkparams. this is ugly. sorry for that.
-        $startpos	= intval($startpos);		// will be 0 when empty. 
-        $parsed		= parse_url(serverVar('REQUEST_URI'));
-        $parsed		= $parsed['query'];
-		$url		= '';
-        
-        switch ($direction) {
-            case 'prev':
-                if ( intval($startpos) - intval($maxresults) >= 0) {
-                    $startpos 	= intval($startpos) - intval($maxresults);
-                    $url		= $CONF['SearchURL'].'?'.alterQueryStr($parsed,'startpos',$startpos);
-                }
-                break;
-            case 'next':
-                $iAmountOnPage = $this->amountfound;
-                if ($iAmountOnPage == 0)
-                {
-                	// [%nextlink%] or [%prevlink%] probably called before [%blog%] or [%searchresults%]
-                	// try a count query
-                	switch ($this->skintype)
-                	{
-                		case 'index':
-                			$sqlquery = $blog->getSqlBlog('', 'count');
-                			break;
-                		case 'search':
-                			$sqlquery = $blog->getSqlSearch($query, $amount, $unused_highlight, 'count');
-                			break;
-                	}
-                	if ($sqlquery) 
-                		$iAmountOnPage = intval(quickQuery($sqlquery)) - intval($startpos);
-                }
-                if (intval($iAmountOnPage) >= intval($maxresults)) {
-                	$startpos 	= intval($startpos) + intval($maxresults);                
-                	$url		= $CONF['SearchURL'].'?'.alterQueryStr($parsed,'startpos',$startpos);
-                }
-                break;
-            default:
-                break;
-        } // switch($direction)
-
-		if ($url != '')
-			echo $this->_link($url, $linktext);        
-    }
-
-	function _itemlink($id, $linktext = '') {
-		global $CONF;
-		if ($id)
-			echo $this->_link(createItemLink($id, $this->linkparams), $linktext);
-		else
-			$this->parse_todaylink($linktext);
-	}
-
-	function _archivelink($id, $linktext = '') {
-		global $CONF, $blog;
-		if ($id)
-			echo $this->_link(createArchiveLink($blog->getID(), $id, $this->linkparams), $linktext);
-		else
-			$this->parse_todaylink($linktext);
-	}
-	
-	
-	function parse_itemlink($linktext = '') {	
-		global $itemid;
-		$this->_itemlink($itemid, $linktext);
-	}
-	
-	/**
-	  * %archivedate(locale,date format)%
-	  */
-	function parse_archivedate($locale = '-def-') {
-		global $archive;
-		
-		if ($locale == '-def-')
-			setlocale(LC_TIME,$template['LOCALE']);
-		else
-			setlocale(LC_TIME,$locale);
-		
-		// get archive date
-		sscanf($archive,'%d-%d-%d',$y,$m,$d);
-
-		// get format		
-		$args = func_get_args();
-		// format can be spread over multiple parameters
-		if (sizeof($args) > 1) {
-			// take away locale
-			array_shift($args);
-			// implode
-			$format=implode(',',$args);
-		} elseif ($d == 0) {
-			$format = '%B %Y';	
-		} else {
-			$format = '%d %B %Y';	
-		}
-		
-		echo strftime($format,mktime(0,0,0,$m,$d?$d:1,$y));		
-	}
-	
-	function parse_blog($template, $amount = 10, $category = '') {
-		global $blog, $startpos;
-		
-		list($limit, $offset) = sscanf($amount, '%d(%d)');
-		$this->_setBlogCategory($blog, $category);
-		$this->_preBlogContent('blog',$blog);
-		$this->amountfound = $blog->readLog($template, $limit, $offset, $startpos);
-		$this->_postBlogContent('blog',$blog);
-	}
-
-	function parse_otherblog($blogname, $template, $amount = 10, $category = '') {
-		global $manager;
-
-		list($limit, $offset) = sscanf($amount, '%d(%d)');
-
-		$b =& $manager->getBlog(getBlogIDFromName($blogname));
-		$this->_setBlogCategory($b, $category);
-		$this->_preBlogContent('otherblog',$b);
-		$this->amountfound = $b->readLog($template, $limit, $offset);
-		$this->_postBlogContent('otherblog',$b);
-	}
-
-	// include one item (no comments)
-	function parse_item($template) {
-		global $blog, $itemid, $highlight;
-		$this->_setBlogCategory($blog, '');	// need this to select default category
-		$this->_preBlogContent('item',$blog);
-		$r = $blog->showOneitem($itemid, $template, $highlight);
-		if ($r == 0)
-			echo _ERROR_NOSUCHITEM;
-		$this->_postBlogContent('item',$blog);
-	}
-
-	function parse_itemid() {
-		global $itemid;
-		echo $itemid;
-	}
-
-
-	// include comments for one item
-	function parse_comments($template) {
-		global $itemid, $manager, $blog, $highlight;
-		$template =& $manager->getTemplate($template);
-
-		// create parser object & action handler
-		$actions =& new ITEMACTIONS($blog);
-		$parser =& new PARSER($actions->getDefinedActions(),$actions);
-		$actions->setTemplate($template);
-		$actions->setParser($parser);
-		$item = ITEM::getitem($itemid, 0, 0);
-		$actions->setCurrentItem($item);
-
-		$comments =& new COMMENTS($itemid);
-		$comments->setItemActions($actions);
-		$comments->showComments($template, -1, 1, $highlight);	// shows ALL comments
-	}
-
-	function parse_archive($template, $category = '') {
-		global $blog, $archive;
-		// can be used with either yyyy-mm or yyyy-mm-dd
-		sscanf($archive,'%d-%d-%d',$y,$m,$d);
-		$this->_setBlogCategory($blog, $category);
-		$this->_preBlogContent('achive',$blog);
-		$blog->showArchive($template, $y, $m, $d);
-		$this->_postBlogContent('achive',$blog);
-
-	}
-
-	function parse_otherarchive($blogname, $template, $category = '') {
-		global $archive, $manager;
-		sscanf($archive,'%d-%d-%d',$y,$m,$d);
-		$b =& $manager->getBlog(getBlogIDFromName($blogname));
-		$this->_setBlogCategory($b, $category);
-		$this->_preBlogContent('otherachive',$b);
-		$b->showArchive($template, $y, $m, $d);
-		$this->_postBlogContent('otherachive',$b);
-	}
-
-	function parse_archivelist($template, $category = 'all', $limit = 0) {
-		global $blog;
-		if ($category == 'all') $category = '';
-		$this->_preBlogContent('archivelist',$blog);
-		$this->_setBlogCategory($blog, $category);
-		$blog->showArchiveList($template, 'month', $limit);
-		$this->_postBlogContent('archivelist',$blog);
-	}
-
-	function parse_archivedaylist($template, $category = 'all', $limit = 0) {
-		global $blog;
-		if ($category == 'all') $category = '';
-		$this->_preBlogContent('archivelist',$blog);
-		$this->_setBlogCategory($blog, $category);
-		$blog->showArchiveList($template, 'day', $limit);
-		$this->_postBlogContent('archivelist',$blog);
-	}
-
-	function parse_itemtitle($format = '') {
-		global $manager, $itemid;
-		$item =& $manager->getItem($itemid,0,0);
-		
-		switch ($format) {
-			case 'xml':
-				echo stringToXML ($item['title']);
-				break;
-			case 'attribute':
-				echo stringToAttribute ($item['title']);
-				break;
-			case 'raw':
-				echo $item['title'];
-				break;
-			default:
-		echo htmlspecialchars(strip_tags($item['title']));
-				break;
-		}
-	}
-
-	function parse_categorylist($template, $blogname = '') {
-		global $blog, $manager;
-
-		if ($blogname == '') {
-			$this->_preBlogContent('categorylist',$blog);
-			$blog->showCategoryList($template);
-			$this->_postBlogContent('categorylist',$blog);
-		} else {
-			$b =& $manager->getBlog(getBlogIDFromName($blogname));
-			$this->_preBlogContent('categorylist',$b);
-			$b->showCategoryList($template);
-			$this->_postBlogContent('categorylist',$b);
-		}
-	}
-
-	function parse_category($type = 'name') {
-		global $catid, $blog;
-		if (!$blog->isValidCategory($catid))
-			return;
-
-		switch($type) {
-			case 'name':
-				echo $blog->getCategoryName($catid);
-				break;
-			case 'desc':
-				echo $blog->getCategoryDesc($catid);
-				break;
-			case 'id':
-				echo $catid;
-				break;
-		}
-	}
-
-	function parse_otherarchivelist($blogname, $template, $category = 'all', $limit = 0) {
-		global $manager;
-		if ($category == 'all') $category = '';
-		$b =& $manager->getBlog(getBlogIDFromName($blogname));
-		$this->_setBlogCategory($b, $category);
-		$this->_preBlogContent('otherarchivelist',$b);
-		$b->showArchiveList($template, 'month', $limit);
-		$this->_postBlogContent('otherarchivelist',$b);
-	}
-
-	function parse_otherarchivedaylist($blogname, $template, $category = 'all', $limit = 0) {
-		global $manager;
-		if ($category == 'all') $category = '';
-		$b =& $manager->getBlog(getBlogIDFromName($blogname));
-		$this->_setBlogCategory($b, $category);
-		$this->_preBlogContent('otherarchivelist',$b);
-		$b->showArchiveList($template, 'day', $limit);
-		$this->_postBlogContent('otherarchivelist',$b);
-	}
-
-	function parse_searchresults($template, $maxresults = 50 ) {
-		global $blog, $query, $amount, $startpos;
-
-		$this->_setBlogCategory($blog, '');	// need this to select default category
-		$this->_preBlogContent('searchresults',$blog);
-		$this->amountfound = $blog->search($query, $template, $amount, $maxresults, $startpos);
-		$this->_postBlogContent('searchresults',$blog);
-	}
-
-	function parse_othersearchresults($blogname, $template, $maxresults = 50) {
-		global $query, $amount, $manager, $startpos;
-		$b =& $manager->getBlog(getBlogIDFromName($blogname));
-		$this->_setBlogCategory($b, '');	// need this to select default category
-		$this->_preBlogContent('othersearchresults',$b);
-		$b->search($query, $template, $amount, $maxresults, $startpos);
-		$this->_postBlogContent('othersearchresults',$b);
-	}
-
-	// includes the search query
-	function parse_query() {
-		global $query;
-		echo htmlspecialchars($query);
-	}
-			
-	// include nucleus versionnumber
-	function parse_version() {
-		global $nucleus;
-		echo 'Nucleus CMS ' . $nucleus['version'];
-	}
-	
-
-	function parse_errormessage() {
-		global $errormessage;
-		echo $errormessage;
-	}
-
-
-	function parse_imagetext() {			
-		echo htmlspecialchars(requestVar('imagetext'));
-	}
-	
-	function parse_image($what = 'imgtag') {
-		global $CONF;
-
-		$imagetext 	= htmlspecialchars(requestVar('imagetext'));
-		$imagepopup = requestVar('imagepopup');
-		$width 		= intRequestVar('width');
-		$height 	= intRequestVar('height');
-		$fullurl 	= htmlspecialchars($CONF['MediaURL'] . $imagepopup);
-		
-		switch($what)
-		{
-			case 'url':
-				echo $fullurl;
-				break;
-			case 'width':
-				echo $width;
-				break;
-			case 'height':
-				echo $height;
-				break;
-			case 'caption':
-			case 'text':			
-				echo $imagetext;
-				break;
-			case 'imgtag':
 			default:
-				echo "<img src=\"$fullurl\" width=\"$width\" height=\"$height\" alt=\"$imagetext\" title=\"$imagetext\" />";
-				break;
-		}
-	}
-	
-	// When commentform is not used, to include a hidden field with itemid
-	function parse_vars() {
-		global $itemid;
-		echo '<input type="hidden" name="itemid" value="'.$itemid.'" />';
-	}
-	
-	// include a sitevar
-	function parse_sitevar($which) {
-		global $CONF;
-		switch($which) {
-			case 'url':
-				echo $CONF['IndexURL'];
-				break;
-			case 'name':
-				echo $CONF['SiteName'];
-				break;
-			case 'admin':
-				echo $CONF['AdminEmail'];
+				if ($blogid && $blogid > 0) {
+					$extraActions = array(
+						'blog',
+						'blogsetting',
+						'preview',
+						'additemform',
+						'categorylist',
+						'archivelist',
+						'archivedaylist',
+						'nextlink',
+						'archivelist',
+						'archivedaylist',
+						'prevlink',
+						'membermailform',
+						'nucleusbutton'
+					);
+				}
 				break;
-			case 'adminurl':
-				echo $CONF['AdminURL'];
-		}			
-	}
-	
-	// shortcut for admin url
-	function parse_adminurl() { $this->parse_sitevar('adminurl'); }
-	
-	function parse_blogsetting($which) {
-		global $blog;
-		switch($which) {
-			case 'id':
-				echo htmlspecialchars($blog->getID());
-				break;
-			case 'url':
-				echo htmlspecialchars($blog->getURL());
-				break;
-			case 'name':
-				echo htmlspecialchars($blog->getName());
-				break;
-			case 'desc':
-				echo htmlspecialchars($blog->getDescription());
-				break;
-			case 'short':
-				echo htmlspecialchars($blog->getShortName());
-				break; 				
-		}	
-	}
-	
-	// includes a member info thingie
-	function parse_member($what) {
-		global $memberinfo, $member;
-		
-		// 1. only allow the member-details-page specific variables on member pages
-		if ($this->skintype == 'member') {
-
-			switch($what) {
-				case 'name':
-					echo htmlspecialchars($memberinfo->getDisplayName());
-					break;
-				case 'realname':
-					echo htmlspecialchars($memberinfo->getRealName());
-					break;
-				case 'notes':
-					echo htmlspecialchars($memberinfo->getNotes());
-					break;
-				case 'url':
-					echo htmlspecialchars($memberinfo->getURL());
-					break;
-				case 'email':
-					echo htmlspecialchars($memberinfo->getEmail());
-					break;
-				case 'id':
-					echo htmlspecialchars($memberinfo->getID());
-					break;					
-			}	
-		}
-		
-		// 2. the next bunch of options is available everywhere, as long as the user is logged in
-		if ($member->isLoggedIn())
-		{
-			switch($what) {
-				case 'yourname':
-					echo htmlspecialchars($member->getDisplayName());
-					break;
-				case 'yourrealname':
-					echo htmlspecialchars($member->getRealName());
-					break;
-				case 'yournotes':
-					echo htmlspecialchars($member->getNotes());
-					break;
-				case 'yoururl':
-					echo htmlspecialchars($member->getURL());
-					break;
-				case 'youremail':
-					echo htmlspecialchars($member->getEmail());
-					break;
-				case 'yourid':
-					echo htmlspecialchars($member->getID());
-					break;									
-			}	
 		}
 
-	}
-	
-	function parse_preview($template) {
-		global $blog, $CONF, $manager;
-		
-		$template =& $manager->getTemplate($template);
-		$row['body'] = '<span id="prevbody"></span>';
-		$row['title'] = '<span id="prevtitle"></span>';
-		$row['more'] = '<span id="prevmore"></span>';
-		$row['itemlink'] = '';
-		$row['itemid'] = 0; $row['blogid'] = $blog->getID();
-		echo TEMPLATE::fill($template['ITEM_HEADER'],$row);
-		echo TEMPLATE::fill($template['ITEM'],$row);
-		echo TEMPLATE::fill($template['ITEM_FOOTER'],$row);
-	}
-	
-	function parse_additemform() {
-		global $blog, $CONF;
-		$this->formdata = array(
-			'adminurl' => htmlspecialchars($CONF['AdminURL']),
-			'catid' => $blog->getDefaultCategory()
-		);
-		$blog->InsertJavaScriptInfo(); 
-		$this->doForm('additemform');
-	}
-
-	/**
-	  * Executes a plugin skinvar
-	  *
-	  * @param pluginName name of plugin (without the NP_)
-	  * 
-	  * extra parameters can be added
-	  */
-	function parse_plugin($pluginName) {
-		global $manager;
-		
-		// only continue when the plugin is really installed
-		if (!$manager->pluginInstalled('NP_' . $pluginName))
-			return;
-		
-		$plugin =& $manager->getPlugin('NP_' . $pluginName);
-		if (!$plugin) return;
-
-		// get arguments
-		$params = func_get_args();
-		
-		// remove plugin name 
-		array_shift($params);
-		
-		// add skin type on front
-		array_unshift($params, $this->skintype);
-		
-		call_user_func_array(array(&$plugin,'doSkinVar'), $params);
-	}
-
-			
-	function parse_commentform($destinationurl = '') {
-		global $blog, $itemid, $member, $CONF, $manager, $DIR_LIBS, $errormessage;
-		
-		// warn when trying to provide a actionurl (used to be a parameter in Nucleus <2.0)
-		if (stristr($destinationurl, 'action.php')) {
-			$args = func_get_args();
-			$destinationurl = $args[1];
-			ACTIONLOG::add(WARNING,'actionurl is not longer a parameter on commentform skinvars. Moved to be a global setting instead.');
-		}
-		
-		$actionurl = $CONF['ActionURL'];
-		
-		// if item is closed, show message and do nothing
-		$item =& $manager->getItem($itemid,0,0);
-		if ($item['closed'] || !$blog->commentsEnabled()) {
-			$this->doForm('commentform-closed');
-			return;
-		}
-		
-		if (!$destinationurl)
-		{
-			$destinationurl = createLink(
-				'item', 
-				array(
-					'itemid' => $itemid,
-					'title' => $item['title'],
-					'timestamp' => $item['timestamp'],
-					'extra' => $this->linkparams
-				)
-			);
-		}
-
-		// values to prefill
-		$user = cookieVar($CONF['CookiePrefix'] .'comment_user');
-		if (!$user) $user = postVar('user');
-		$userid = cookieVar($CONF['CookiePrefix'] .'comment_userid');
-		if (!$userid) $userid = postVar('userid');
-		$body = postVar('body');
-		
-		$this->formdata = array(
-			'destinationurl' => htmlspecialchars($destinationurl),
-			'actionurl' => htmlspecialchars($actionurl),
-			'itemid' => $itemid,
-			'user' => htmlspecialchars($user),
-			'userid' => htmlspecialchars($userid),			
-			'body' => htmlspecialchars($body),			
-			'membername' => $member->getDisplayName(),
-			'rememberchecked' => cookieVar($CONF['CookiePrefix'] .'comment_user')?'checked="checked"':''
-		);
-		
-		if (!$member->isLoggedIn()) {
-			$this->doForm('commentform-notloggedin');
-		} else {
-			$this->doForm('commentform-loggedin');		
-		}
-	}
-
-	function parse_loginform() {
-		global $member, $CONF;
-		if (!$member->isLoggedIn()) {
-			$filename = 'loginform-notloggedin';
-			$this->formdata = array();
-		} else {
-			$filename = 'loginform-loggedin';
-			$this->formdata = array(
-				'membername' => $member->getDisplayName(),
-			);
-		}
-		$this->doForm($filename);
-	}	
-	
-	
-	function parse_membermailform($rows = 10, $cols = 40, $desturl = '') {
-		global $member, $CONF, $memberid;
-		
-		if ($desturl == '') {
-			if ($CONF['URLMode'] == 'pathinfo')
-				$desturl = createMemberLink($memberid);
-			else
-				$desturl = $CONF['IndexURL'] . createMemberLink($memberid);				
-		}
-			
-		$message = postVar('message');
-		$frommail = postVar('frommail');
-		
-		$this->formdata = array(
-			'url' => htmlspecialchars($desturl),
-			'actionurl' => htmlspecialchars($CONF['ActionURL']),
-			'memberid' => $memberid,
-			'rows' => $rows,
-			'cols' => $cols,
-			'message' => htmlspecialchars($message),
-			'frommail' => htmlspecialchars($frommail)
-		);
-		if ($member->isLoggedIn()) {
-			$this->doForm('membermailform-loggedin');
-		} else if ($CONF['NonmemberMail']) {
-			$this->doForm('membermailform-notloggedin');		
-		} else {
-			$this->doForm('membermailform-disallowed');		
-		}
-
-	}
-
-	function parse_searchform($blogname = '') {
-		global $CONF, $manager, $maxresults;
-		if ($blogname) {
-			$blog =& $manager->getBlog(getBlogIDFromName($blogname));
-		} else {
-			global $blog;
-		}
-		// use default blog when no blog is selected
-		$this->formdata = array(
-			'id' => $blog?$blog->getID():$CONF['DefaultBlog'],
-			'query' => htmlspecialchars(getVar('query')),
-		);
-		$this->doForm('searchform');
-	}
-
-	function parse_nucleusbutton($imgurl = '',
-							     $imgwidth = '85',
-							     $imgheight = '31') {
-		global $CONF;
-		if ($imgurl == '') {
-			$imgurl = $CONF['AdminURL'] . 'nucleus.gif';
-		} else if (PARSER::getProperty('IncludeMode') == 'skindir'){
-			// when skindit IncludeMode is used: start from skindir
-			$imgurl = $CONF['SkinsURL'] . PARSER::getProperty('IncludePrefix') . $imgurl;
-		}
-
-		$this->formdata = array(
-			'imgurl' => $imgurl,
-			'imgwidth' => $imgwidth,
-			'imgheight' => $imgheight,
-		);
-		$this->doForm('nucleusbutton');
-	}
-	
-	function parse_self() {
-		global $CONF;
-		echo $CONF['Self'];
-	}
-	
-	function parse_referer() {
-		echo htmlspecialchars(serverVar('HTTP_REFERER'));
-	}
-	
-	function parse_charset() {
-		echo _CHARSET;
-	}
-
-	/**
-	  * Helper function that sets the category that a blog will need to use 
-	  *
-	  * @param $blog
-	  *		An object of the blog class, passed by reference (we want to make changes to it)
-	  * @param $catname
-	  *		The name of the category to use
-	  */
-	function _setBlogCategory(&$blog, $catname) {
-		global $catid;
-		if ($catname != '')
-			$blog->setSelectedCategoryByName($catname);
-		else
-			$blog->setSelectedCategory($catid);
-	}
-	
-	function _preBlogContent($type, &$blog) {
-		global $manager;
-		$manager->notify('PreBlogContent',array('blog' => &$blog, 'type' => $type));
-	}
-
-	function _postBlogContent($type, &$blog) {
-		global $manager;
-		$manager->notify('PostBlogContent',array('blog' => &$blog, 'type' => $type));
+		return array_merge($defaultActions, $extraActions);
 	}
 
 }
diff -ruN 3.24.src/nucleus/libs/TEMPLATE.php 3.31.src/nucleus/libs/TEMPLATE.php
--- 3.24.src/nucleus/libs/TEMPLATE.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/TEMPLATE.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,47 +1,47 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * A class representing a template
-  *
+ * A class representing a template
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: TEMPLATE.php,v 1.10.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: TEMPLATE.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 class TEMPLATE {
 
 	var $id;
-	
+
 	function TEMPLATE($templateid) {
 		$this->id = intval($templateid);
 	}
-	
+
 	function getID() {
 		return intval($this->id);
 	}
-	
+
 	// (static)
 	function createFromName($name) {
 		return new TEMPLATE(TEMPLATE::getIdFromName($name));
 	}
-	
+
 	// (static)
 	function getIdFromName($name) {
 		$query =  'SELECT tdnumber'
-		       . ' FROM '.sql_table('template_desc')
-		       . ' WHERE tdname="'.addslashes($name).'"';
+			   . ' FROM '.sql_table('template_desc')
+			   . ' WHERE tdname="'.addslashes($name).'"';
 		$res = sql_query($query);
 		$obj = mysql_fetch_object($res);
-		return $obj->tdnumber;	
+		return $obj->tdnumber;
 	}
 
 	/**
@@ -49,27 +49,27 @@
 	 */
 	function updateGeneralInfo($name, $desc) {
 		$query =  'UPDATE '.sql_table('template_desc').' SET'
-		       . " tdname='" . addslashes($name) . "',"
-		       . " tddesc='" . addslashes($desc) . "'"
-		       . " WHERE tdnumber=" . $this->getID();
-		sql_query($query);		
+			   . " tdname='" . addslashes($name) . "',"
+			   . " tddesc='" . addslashes($desc) . "'"
+			   . " WHERE tdnumber=" . $this->getID();
+		sql_query($query);
 	}
-	
+
 	/**
 	 * Updates the contents of one part of the template
 	 */
 	function update($type, $content) {
 		$id = $this->getID();
-	
+
 		// delete old thingie
 		sql_query('DELETE FROM '.sql_table('template')." WHERE tpartname='". addslashes($type) ."' and tdesc=" . intval($id));
-		
+
 		// write new thingie
 		if ($content) {
 			sql_query('INSERT INTO '.sql_table('template')." SET tcontent='" . addslashes($content) . "', tpartname='" . addslashes($type) . "', tdesc=" . intval($id));
-		}	
+		}
 	}
-		
+
 
 	/**
 	 * Deletes all template parts from the database
@@ -85,7 +85,7 @@
 	 */
 	function createNew($name, $desc) {
 		global $manager;
-		
+
 		$manager->notify(
 			'PreAddTemplate',
 			array(
@@ -93,10 +93,10 @@
 				'description' => &$desc
 			)
 		);
-		
+
 		sql_query('INSERT INTO '.sql_table('template_desc')." (tdname, tddesc) VALUES ('" . addslashes($name) . "','" . addslashes($desc) . "')");
 		$newId = mysql_insert_id();
-		
+
 		$manager->notify(
 			'PostAddTemplate',
 			array(
@@ -104,12 +104,12 @@
 				'name' => $name,
 				'description' => $desc
 			)
-		);		
-		
+		);
+
 		return $newId;
 	}
 
-	
+
 
 	/**
 	 * Reads a template and returns an array with the parts.
@@ -119,29 +119,29 @@
 	 */
 	function read($name) {
 		$query = 'SELECT tpartname, tcontent'
-		       . ' FROM '.sql_table('template_desc').', '.sql_table('template')
-		       . ' WHERE tdesc=tdnumber and tdname="' . addslashes($name) . '"';
+			   . ' FROM '.sql_table('template_desc').', '.sql_table('template')
+			   . ' WHERE tdesc=tdnumber and tdname="' . addslashes($name) . '"';
 		$res = sql_query($query);
-		while ($obj = mysql_fetch_object($res)) 
+		while ($obj = mysql_fetch_object($res))
 			$template[$obj->tpartname] = $obj->tcontent;
-		
+
 		// set locale according to template:
 		if ($template['LOCALE'])
 			setlocale(LC_TIME,$template['LOCALE']);
 		else
-			setlocale(LC_TIME,'');	
-			
+			setlocale(LC_TIME,'');
+
 		return $template;
 	}
-	
+
 	/**
 	  * fills a template with values
 	  * (static)
 	  *
-	  * @param $template 
+	  * @param $template
 	  *		Template to be used
 	  * @param $values
-	  *		Array of all the values 
+	  *		Array of all the values
 	  */
 	function fill($template, $values) {
 
@@ -154,36 +154,37 @@
 
 		// remove non matched template-tags
 		return preg_replace('/<%[a-zA-Z]+%>/','',$template);
-	}	
-	
+	}
+
 	// returns true if there is a template with the given shortname
 	// (static)
 	function exists($name) {
 		$r = sql_query('select * FROM '.sql_table('template_desc').' WHERE tdname="'.addslashes($name).'"');
 		return (mysql_num_rows($r) != 0);
 	}
-	
+
 	// returns true if there is a template with the given ID
 	// (static)
 	function existsID($id) {
 		$r = sql_query('select * FROM '.sql_table('template_desc').' WHERE tdnumber='.intval($id));
 		return (mysql_num_rows($r) != 0);
 	}
-	
+
 	// (static)
 	function getNameFromId($id) {
 		return quickQuery('SELECT tdname as result FROM '.sql_table('template_desc').' WHERE tdnumber=' . intval($id));
 	}
-	
+
 	// (static)
 	function getDesc($id) {
 		$query = 'SELECT tddesc FROM '.sql_table('template_desc').' WHERE tdnumber='. intval($id);
-		$obj = mysql_fetch_object(sql_query($query));
+		$res = sql_query($query);
+		$obj = mysql_fetch_object($res);
 		return $obj->tddesc;
 	}
-	
 
-	
+
+
 }
 
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/libs/vars4.0.6.php 3.31.src/nucleus/libs/vars4.0.6.php
--- 3.24.src/nucleus/libs/vars4.0.6.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/vars4.0.6.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,21 +1,21 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: vars4.0.6.php,v 1.8.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
-  
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: vars4.0.6.php 1153 2007-05-20 23:18:22Z kaigreve $
+ */
+
 /**
   * The purpose of the functions below is to avoid declaring HTTP_ vars to be global
   * everywhere, plus to offer support for php versions before 4.1.0, that do not
@@ -23,16 +23,31 @@
   */
 function getVar($name) {
 	global $HTTP_GET_VARS;
+
+	if (!isset($HTTP_GET_VARS[$name])) {
+		return;
+	}
+
 	return undoMagic($HTTP_GET_VARS[$name]);
 }
 
 function postVar($name) {
 	global $HTTP_POST_VARS;
+
+	if (!isset($HTTP_POST_VARS[$name])) {
+		return;
+	}
+
 	return undoMagic($HTTP_POST_VARS[$name]);
 }
 
-function cookieVar($name) {	
+function cookieVar($name) {
 	global $HTTP_COOKIE_VARS;
+
+	if (!isset($HTTP_COOKIE_VARS[$name])) {
+		return;
+	}
+
 	return undoMagic($HTTP_COOKIE_VARS[$name]);
 }
 
@@ -43,28 +58,56 @@
 
 function serverVar($name) {
 	global $HTTP_SERVER_VARS;
+
+	if (!isset($HTTP_SERVER_VARS[$name])) {
+		return;
+	}
+
 	return $HTTP_SERVER_VARS[$name];
 }
 
 // removes magic quotes if that option is enabled
 function undoMagic($data) {
-	return get_magic_quotes_gpc() ? stripslashes_array($data) : $data;
+	if (!get_magic_quotes_gpc())
+		return $data;
+	if (ini_get('magic_quotes_sybase') != 1)
+		return stripslashes_array($data);
+	else
+		return undoSybaseQuotes_array($data);
 }
 
 function stripslashes_array($data) {
-	return is_array($data) ? array_map('stripslashes', $data) : stripslashes($data);
+	return is_array($data) ? array_map('stripslashes_array', $data) : stripslashes($data);
+}
+
+function undoSybaseQuotes_array($data) {
+	return is_array($data) ? array_map('undoSybaseQuotes', $data) : stripslashes($data);
+}
+
+function undoSybaseQuotes($data) {
+	return str_replace("''", "'", $data);
 }
 
 // integer array from request
 function requestIntArray($name) {
 	global $HTTP_POST_VARS;
-	return $HTTP_POST_VARS[$name];	
+
+	if (!isset($HTTP_POST_VARS[$name])) {
+		return;
+	}
+
+	return $HTTP_POST_VARS[$name];
 }
 
 // array from request. Be sure to call undoMagic on the strings inside
 function requestArray($name) {
 	global $HTTP_POST_VARS;
-	return $HTTP_POST_VARS[$name];	
+
+	if (!isset($HTTP_POST_VARS[$name])) {
+		return;
+	}
+
+	return $HTTP_POST_VARS[$name];
 }
 
 
@@ -94,12 +137,17 @@
 
 function postFileInfo($name) {
 	global $HTTP_POST_FILES;
+
+	if (!isset($HTTP_POST_FILES[$name])) {
+		return;
+	}
+
 	return $HTTP_POST_FILES[$name];
 }
 
 function setOldAction($value) {
 	global $HTTP_POST_VARS;
-	$HTTP_POST_VARS['oldaction'] = $value;	
+	$HTTP_POST_VARS['oldaction'] = $value;
 }
 
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/libs/vars4.1.0.php 3.31.src/nucleus/libs/vars4.1.0.php
--- 3.24.src/nucleus/libs/vars4.1.0.php	2005-08-15 12:50:12.000000000 -0500
+++ 3.31.src/nucleus/libs/vars4.1.0.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,65 +1,102 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: vars4.1.0.php,v 1.10.2.1 2005/08/15 10:50:12 dekarma Exp $
-  */
-  
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: vars4.1.0.php 1153 2007-05-20 23:18:22Z kaigreve $
+ */
+
 function getVar($name) {
+	if (!isset($_GET[$name])) {
+		return;
+	}
+
 	return undoMagic($_GET[$name]);
 }
 
 function postVar($name) {
+	if (!isset($_POST[$name])) {
+		return;
+	}
+
 	return undoMagic($_POST[$name]);
 }
 
-function cookieVar($name) {	
+function cookieVar($name) {
+	if (!isset($_COOKIE[$name])) {
+		return;
+	}
+
 	return undoMagic($_COOKIE[$name]);
 }
 
 function requestVar($name) {
 	if(array_key_exists($name,$_REQUEST))
 		return undoMagic($_REQUEST[$name]);
-	elseif( array_key_exists($name,$_GET))   
+	elseif( array_key_exists($name,$_GET))
 		return undoMagic($_GET[$name]);
-	elseif( array_key_exists($name,$_POST))   
+	elseif( array_key_exists($name,$_POST))
 		return undoMagic($_POST[$name]);
 	else
 		return;
 }
 
 function serverVar($name) {
+	if (!isset($_SERVER[$name])) {
+		return false;
+	}
+
 	return $_SERVER[$name];
 }
 
 // removes magic quotes if that option is enabled
 function undoMagic($data) {
-	return get_magic_quotes_gpc() ? stripslashes_array($data) : $data;
+	if (!get_magic_quotes_gpc())
+		return $data;
+	if (ini_get('magic_quotes_sybase') != 1)
+		return stripslashes_array($data);
+	else
+		return undoSybaseQuotes_array($data);
 }
 
 function stripslashes_array($data) {
-	return is_array($data) ? array_map('stripslashes', $data) : stripslashes($data);
+	return is_array($data) ? array_map('stripslashes_array', $data) : stripslashes($data);
+}
+
+function undoSybaseQuotes_array($data) {
+	return is_array($data) ? array_map('undoSybaseQuotes', $data) : stripslashes($data);
+}
+
+function undoSybaseQuotes($data) {
+	return str_replace("''", "'", $data);
 }
 
 // integer array from request
 function requestIntArray($name) {
-	return $_REQUEST[$name];	
+	if (!isset($_REQUEST[$name])) {
+		return;
+	}
+
+	return $_REQUEST[$name];
 }
 
 // array from request. Be sure to call undoMagic on the strings inside
 function requestArray($name) {
-	return $_REQUEST[$name];	
+	if (!isset($_REQUEST[$name])) {
+		return;
+	}
+
+	return $_REQUEST[$name];
 }
 
 // add all the variables from the request as hidden input field
@@ -68,22 +105,27 @@
 	foreach ($_REQUEST as $key => $value) {
 		if (($key == 'action') && ($value != requestVar('nextaction')))
 			$key = 'nextaction';
-			
+
 		// a nextaction of 'showlogin' makes no sense
 		if (($key == 'nextaction') && ($value == 'showlogin'))
 			continue;
-			
+
 		if (($key != 'login') && ($key != 'password'))
 			passVar($key, $value);
 	}
 }
 
 function postFileInfo($name) {
+	if (!isset($_FILES[$name])) {
+		return;
+	}
+
 	return $_FILES[$name];
 }
 
 function setOldAction($value) {
-	$_POST['oldaction'] = $value;	
+	$_POST['oldaction'] = $value;
 }
 
+
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/libs/xmlrpc.inc.php 3.31.src/nucleus/libs/xmlrpc.inc.php
--- 3.24.src/nucleus/libs/xmlrpc.inc.php	2005-08-15 20:10:38.000000000 -0500
+++ 3.31.src/nucleus/libs/xmlrpc.inc.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,7 +1,8 @@
-<?php					// -*-c++-*-
+<?php
 // by Edd Dumbill (C) 1999-2002
 // <edd@usefulinc.com>
-// $Id: xmlrpc.inc.php,v 1.6.6.3 2005/08/15 18:10:37 dekarma Exp $
+// $Original: xmlrpc.inc,v 1.158 2007/03/01 21:21:02 ggiunta Exp $
+// $Id: xmlrpc.inc.php 1199 2007-09-07 07:03:41Z kimitake $
 
 
 // Copyright (c) 1999,2000,2002 Edd Dumbill.
@@ -36,71 +37,67 @@
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 // OF THE POSSIBILITY OF SUCH DAMAGE.
 
-	if (!function_exists('xml_parser_create'))
+	if(!function_exists('xml_parser_create'))
 	{
-		// Win 32 fix. From: 'Leo West' <lwest@imaginet.fr>
-		if($WINDIR)
+		// For PHP 4 onward, XML functionality is always compiled-in on windows:
+		// no more need to dl-open it. It might have been compiled out on *nix...
+		if(strtoupper(substr(PHP_OS, 0, 3) != 'WIN'))
 		{
-			dl('php3_xml.dll');
+			dl('xml.so');
 		}
-		else
+	}
+
+	// Try to be backward compat with php < 4.2 (are we not being nice ?)
+	$phpversion = phpversion();
+	if($phpversion[0] == '4' && $phpversion[2] < 2)
+	{
+		// give an opportunity to user to specify where to include other files from
+		if(!defined('PHP_XMLRPC_COMPAT_DIR'))
 		{
-			dl('xml.so');
+			define('PHP_XMLRPC_COMPAT_DIR',dirname(__FILE__).'/compat/');
 		}
+		if($phpversion[2] == '0')
+		{
+			if($phpversion[4] < 6)
+			{
+				include(PHP_XMLRPC_COMPAT_DIR.'is_callable.php');
+			}
+			include(PHP_XMLRPC_COMPAT_DIR.'is_scalar.php');
+			include(PHP_XMLRPC_COMPAT_DIR.'array_key_exists.php');
+			include(PHP_XMLRPC_COMPAT_DIR.'version_compare.php');
+		}
+		include(PHP_XMLRPC_COMPAT_DIR.'var_export.php');
+		include(PHP_XMLRPC_COMPAT_DIR.'is_a.php');
 	}
 
 	// G. Giunta 2005/01/29: declare global these variables,
 	// so that xmlrpc.inc will work even if included from within a function
-	// NB: it will give warnings in PHP3, so we comment it out
-	// Milosch: Next round, maybe we should explicitly request these via $GLOBALS where used.
-	if (phpversion() >= '4')
-	{
-		global $xmlrpcI4;
-		global $xmlrpcInt;
-		global $xmlrpcDouble;
-		global $xmlrpcBoolean;
-		global $xmlrpcString;
-		global $xmlrpcDateTime;
-		global $xmlrpcBase64;
-		global $xmlrpcArray;
-		global $xmlrpcStruct;
-
-		global $xmlrpcTypes;
-		global $xmlEntities;
-		global $xmlrpcerr;
-		global $xmlrpcstr;
-		global $xmlrpc_defencoding;
-		global $xmlrpc_internalencoding;
-		global $xmlrpcName;
-		global $xmlrpcVersion;
-		global $xmlrpcerruser;
-		global $xmlrpcerrxml;
-		global $xmlrpc_backslash;
-		global $_xh;
-	}
-	$xmlrpcI4='i4';
-	$xmlrpcInt='int';
-	$xmlrpcBoolean='boolean';
-	$xmlrpcDouble='double';
-	$xmlrpcString='string';
-	$xmlrpcDateTime='dateTime.iso8601';
-	$xmlrpcBase64='base64';
-	$xmlrpcArray='array';
-	$xmlrpcStruct='struct';
-
-	$xmlrpcTypes=array(
-		$xmlrpcI4       => 1,
-		$xmlrpcInt      => 1,
-		$xmlrpcBoolean  => 1,
-		$xmlrpcString   => 1,
-		$xmlrpcDouble   => 1,
-		$xmlrpcDateTime => 1,
-		$xmlrpcBase64   => 1,
-		$xmlrpcArray    => 2,
-		$xmlrpcStruct   => 3
+	// Milosch: 2005/08/07 - explicitly request these via $GLOBALS where used.
+	$GLOBALS['xmlrpcI4']='i4';
+	$GLOBALS['xmlrpcInt']='int';
+	$GLOBALS['xmlrpcBoolean']='boolean';
+	$GLOBALS['xmlrpcDouble']='double';
+	$GLOBALS['xmlrpcString']='string';
+	$GLOBALS['xmlrpcDateTime']='dateTime.iso8601';
+	$GLOBALS['xmlrpcBase64']='base64';
+	$GLOBALS['xmlrpcArray']='array';
+	$GLOBALS['xmlrpcStruct']='struct';
+	$GLOBALS['xmlrpcValue']='undefined';
+
+	$GLOBALS['xmlrpcTypes']=array(
+		$GLOBALS['xmlrpcI4']       => 1,
+		$GLOBALS['xmlrpcInt']      => 1,
+		$GLOBALS['xmlrpcBoolean']  => 1,
+		$GLOBALS['xmlrpcString']   => 1,
+		$GLOBALS['xmlrpcDouble']   => 1,
+		$GLOBALS['xmlrpcDateTime'] => 1,
+		$GLOBALS['xmlrpcBase64']   => 1,
+		$GLOBALS['xmlrpcArray']    => 2,
+		$GLOBALS['xmlrpcStruct']   => 3
 	);
 
-	$xmlrpc_valid_parents = array(
+	$GLOBALS['xmlrpc_valid_parents'] = array(
+		'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
 		'BOOLEAN' => array('VALUE'),
 		'I4' => array('VALUE'),
 		'INT' => array('VALUE'),
@@ -108,19 +105,25 @@
 		'DOUBLE' => array('VALUE'),
 		'DATETIME.ISO8601' => array('VALUE'),
 		'BASE64' => array('VALUE'),
+		'MEMBER' => array('STRUCT'),
+		'NAME' => array('MEMBER'),
+		'DATA' => array('ARRAY'),
 		'ARRAY' => array('VALUE'),
 		'STRUCT' => array('VALUE'),
 		'PARAM' => array('PARAMS'),
-		'METHODNAME' => array('METHODCALL'),		
+		'METHODNAME' => array('METHODCALL'),
 		'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
-		'MEMBER' => array('STRUCT'),
-		'NAME' => array('MEMBER'),
-		'DATA' => array('ARRAY'),
 		'FAULT' => array('METHODRESPONSE'),
-		'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
+		'NIL' => array('VALUE') // only used when extension activated
 	);
 
-	$xmlEntities=array(
+	// define extra types for supporting NULL (useful for json or <NIL/>)
+	$GLOBALS['xmlrpcNull']='null';
+	$GLOBALS['xmlrpcTypes']['null']=1;
+
+	// Not in use anymore since 2.0. Shall we remove it?
+	/// @deprecated
+	$GLOBALS['xmlEntities']=array(
 		'amp'  => '&',
 		'quot' => '"',
 		'lt'   => '<',
@@ -128,1227 +131,1897 @@
 		'apos' => "'"
 	);
 
-	$xmlrpcerr['unknown_method']=1;
-	$xmlrpcstr['unknown_method']='Unknown method';
-	$xmlrpcerr['invalid_return']=2;
-	$xmlrpcstr['invalid_return']='Invalid return payload: enable debugging to examine incoming payload';
-	$xmlrpcerr['incorrect_params']=3;
-	$xmlrpcstr['incorrect_params']='Incorrect parameters passed to method';
-	$xmlrpcerr['introspect_unknown']=4;
-	$xmlrpcstr['introspect_unknown']="Can't introspect: method unknown";
-	$xmlrpcerr['http_error']=5;
-	$xmlrpcstr['http_error']="Didn't receive 200 OK from remote server.";
-	$xmlrpcerr['no_data']=6;
-	$xmlrpcstr['no_data']='No data received from server.';
-	$xmlrpcerr['no_ssl']=7;
-	$xmlrpcstr['no_ssl']='No SSL support compiled in.';
-	$xmlrpcerr['curl_fail']=8;
-	$xmlrpcstr['curl_fail']='CURL error';
-	$xmlrpcerr['invalid_request']=15;
-	$xmlrpcstr['invalid_request']='Invalid request payload';
-
-	$xmlrpcerr['multicall_notstruct'] = 9;
-	$xmlrpcstr['multicall_notstruct'] = 'system.multicall expected struct';
-	$xmlrpcerr['multicall_nomethod']  = 10;
-	$xmlrpcstr['multicall_nomethod']  = 'missing methodName';
-	$xmlrpcerr['multicall_notstring'] = 11;
-	$xmlrpcstr['multicall_notstring'] = 'methodName is not a string';
-	$xmlrpcerr['multicall_recursion'] = 12;
-	$xmlrpcstr['multicall_recursion'] = 'recursive system.multicall forbidden';
-	$xmlrpcerr['multicall_noparams']  = 13;
-	$xmlrpcstr['multicall_noparams']  = 'missing params';
-	$xmlrpcerr['multicall_notarray']  = 14;
-	$xmlrpcstr['multicall_notarray']  = 'params is not an array';
-
-	// The charset encoding expected by the server for received messages and
-	// by the client for received responses
-	$xmlrpc_defencoding='UTF-8';
-	// The encoding used by PHP.
-	// String values received will be converted to this.
-	$xmlrpc_internalencoding='ISO-8859-1';
+	// tables used for transcoding different charsets into us-ascii xml
+
+	$GLOBALS['xml_iso88591_Entities']=array();
+	$GLOBALS['xml_iso88591_Entities']['in'] = array();
+	$GLOBALS['xml_iso88591_Entities']['out'] = array();
+	for ($i = 0; $i < 32; $i++)
+	{
+		$GLOBALS['xml_iso88591_Entities']['in'][] = chr($i);
+		$GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';';
+	}
+	for ($i = 160; $i < 256; $i++)
+	{
+		$GLOBALS['xml_iso88591_Entities']['in'][] = chr($i);
+		$GLOBALS['xml_iso88591_Entities']['out'][] = '&#'.$i.';';
+	}
+
+	/// @todo add to iso table the characters from cp_1252 range, i.e. 128 to 159.
+	/// These will NOT be present in true ISO-8859-1, but will save the unwary
+	/// windows user from sending junk.
+/*
+$cp1252_to_xmlent =
+  array(
+   '\x80'=>'&#x20AC;', '\x81'=>'?', '\x82'=>'&#x201A;', '\x83'=>'&#x0192;',
+   '\x84'=>'&#x201E;', '\x85'=>'&#x2026;', '\x86'=>'&#x2020;', \x87'=>'&#x2021;',
+   '\x88'=>'&#x02C6;', '\x89'=>'&#x2030;', '\x8A'=>'&#x0160;', '\x8B'=>'&#x2039;',
+   '\x8C'=>'&#x0152;', '\x8D'=>'?', '\x8E'=>'&#x017D;', '\x8F'=>'?',
+   '\x90'=>'?', '\x91'=>'&#x2018;', '\x92'=>'&#x2019;', '\x93'=>'&#x201C;',
+   '\x94'=>'&#x201D;', '\x95'=>'&#x2022;', '\x96'=>'&#x2013;', '\x97'=>'&#x2014;',
+   '\x98'=>'&#x02DC;', '\x99'=>'&#x2122;', '\x9A'=>'&#x0161;', '\x9B'=>'&#x203A;',
+   '\x9C'=>'&#x0153;', '\x9D'=>'?', '\x9E'=>'&#x017E;', '\x9F'=>'&#x0178;'
+  );
+*/
+
+	$GLOBALS['xmlrpcerr']['unknown_method']=1;
+	$GLOBALS['xmlrpcstr']['unknown_method']='Unknown method';
+	$GLOBALS['xmlrpcerr']['invalid_return']=2;
+	$GLOBALS['xmlrpcstr']['invalid_return']='Invalid return payload: enable debugging to examine incoming payload';
+	$GLOBALS['xmlrpcerr']['incorrect_params']=3;
+	$GLOBALS['xmlrpcstr']['incorrect_params']='Incorrect parameters passed to method';
+	$GLOBALS['xmlrpcerr']['introspect_unknown']=4;
+	$GLOBALS['xmlrpcstr']['introspect_unknown']="Can't introspect: method unknown";
+	$GLOBALS['xmlrpcerr']['http_error']=5;
+	$GLOBALS['xmlrpcstr']['http_error']="Didn't receive 200 OK from remote server.";
+	$GLOBALS['xmlrpcerr']['no_data']=6;
+	$GLOBALS['xmlrpcstr']['no_data']='No data received from server.';
+	$GLOBALS['xmlrpcerr']['no_ssl']=7;
+	$GLOBALS['xmlrpcstr']['no_ssl']='No SSL support compiled in.';
+	$GLOBALS['xmlrpcerr']['curl_fail']=8;
+	$GLOBALS['xmlrpcstr']['curl_fail']='CURL error';
+	$GLOBALS['xmlrpcerr']['invalid_request']=15;
+	$GLOBALS['xmlrpcstr']['invalid_request']='Invalid request payload';
+	$GLOBALS['xmlrpcerr']['no_curl']=16;
+	$GLOBALS['xmlrpcstr']['no_curl']='No CURL support compiled in.';
+	$GLOBALS['xmlrpcerr']['server_error']=17;
+	$GLOBALS['xmlrpcstr']['server_error']='Internal server error';
+	$GLOBALS['xmlrpcerr']['multicall_error']=18;
+	$GLOBALS['xmlrpcstr']['multicall_error']='Received from server invalid multicall response';
+
+	$GLOBALS['xmlrpcerr']['multicall_notstruct'] = 9;
+	$GLOBALS['xmlrpcstr']['multicall_notstruct'] = 'system.multicall expected struct';
+	$GLOBALS['xmlrpcerr']['multicall_nomethod']  = 10;
+	$GLOBALS['xmlrpcstr']['multicall_nomethod']  = 'missing methodName';
+	$GLOBALS['xmlrpcerr']['multicall_notstring'] = 11;
+	$GLOBALS['xmlrpcstr']['multicall_notstring'] = 'methodName is not a string';
+	$GLOBALS['xmlrpcerr']['multicall_recursion'] = 12;
+	$GLOBALS['xmlrpcstr']['multicall_recursion'] = 'recursive system.multicall forbidden';
+	$GLOBALS['xmlrpcerr']['multicall_noparams']  = 13;
+	$GLOBALS['xmlrpcstr']['multicall_noparams']  = 'missing params';
+	$GLOBALS['xmlrpcerr']['multicall_notarray']  = 14;
+	$GLOBALS['xmlrpcstr']['multicall_notarray']  = 'params is not an array';
+
+	$GLOBALS['xmlrpcerr']['cannot_decompress']=103;
+	$GLOBALS['xmlrpcstr']['cannot_decompress']='Received from server compressed HTTP and cannot decompress';
+	$GLOBALS['xmlrpcerr']['decompress_fail']=104;
+	$GLOBALS['xmlrpcstr']['decompress_fail']='Received from server invalid compressed HTTP';
+	$GLOBALS['xmlrpcerr']['dechunk_fail']=105;
+	$GLOBALS['xmlrpcstr']['dechunk_fail']='Received from server invalid chunked HTTP';
+	$GLOBALS['xmlrpcerr']['server_cannot_decompress']=106;
+	$GLOBALS['xmlrpcstr']['server_cannot_decompress']='Received from client compressed HTTP request and cannot decompress';
+	$GLOBALS['xmlrpcerr']['server_decompress_fail']=107;
+	$GLOBALS['xmlrpcstr']['server_decompress_fail']='Received from client invalid compressed HTTP request';
+
+	// The charset encoding used by the server for received messages and
+	// by the client for received responses when received charset cannot be determined
+	// or is not supported
+	$GLOBALS['xmlrpc_defencoding']='UTF-8';
+
+	// The encoding used internally by PHP.
+	// String values received as xml will be converted to this, and php strings will be converted to xml
+	// as if having been coded with this
+	$GLOBALS['xmlrpc_internalencoding']='ISO-8859-1';
 
-	$xmlrpcName='XML-RPC for PHP';
-	$xmlrpcVersion='1.2';
+	$GLOBALS['xmlrpcName']='XML-RPC for PHP';
+	$GLOBALS['xmlrpcVersion']='2.2';
 
 	// let user errors start at 800
-	$xmlrpcerruser=800;
+	$GLOBALS['xmlrpcerruser']=800;
 	// let XML parse errors start at 100
-	$xmlrpcerrxml=100;
+	$GLOBALS['xmlrpcerrxml']=100;
 
 	// formulate backslashes for escaping regexp
-	$xmlrpc_backslash=chr(92).chr(92);
+	// Not in use anymore since 2.0. Shall we remove it?
+	/// @deprecated
+	$GLOBALS['xmlrpc_backslash']=chr(92).chr(92);
+
+	// set to TRUE to enable correct decoding of <NIL/> values
+	$GLOBALS['xmlrpc_null_extension']=false;
 
 	// used to store state during parsing
 	// quick explanation of components:
 	//   ac - used to accumulate values
-	//   isf - used to indicate a fault
+	//   isf - used to indicate a parsing fault (2) or xmlrpcresp fault (1)
+	//   isf_reason - used for storing xmlrpcresp fault string
 	//   lv - used to indicate "looking for a value": implements
 	//        the logic to allow values with no types to be strings
 	//   params - used to store parameters in method calls
 	//   method - used to store method name
 	//   stack - array with genealogy of xml elements names:
 	//           used to validate nesting of xmlrpc elements
-
-	$_xh=array();
+	$GLOBALS['_xh']=null;
 
 	/**
+	* Convert a string to the correct XML representation in a target charset
 	* To help correct communication of non-ascii chars inside strings, regardless
 	* of the charset used when sending requests, parsing them, sending responses
-	* and parsing responses, convert all non-ascii chars present in the message
+	* and parsing responses, an option is to convert all non-ascii chars present in the message
 	* into their equivalent 'charset entity'. Charset entities enumerated this way
 	* are independent of the charset encoding used to transmit them, and all XML
 	* parsers are bound to understand them.
+	* Note that in the std case we are not sending a charset encoding mime type
+	* along with http headers, so we are bound by RFC 3023 to emit strict us-ascii.
+	*
+	* @todo do a bit of basic benchmarking (strtr vs. str_replace)
+	* @todo	make usage of iconv() or recode_string() or mb_string() where available
 	*/
-	function xmlrpc_entity_decode($string)
+	function xmlrpc_encode_entitites($data, $src_encoding='', $dest_encoding='')
 	{
-		$top=split('&', $string);
-		$op='';
-		$i=0;
-		while($i<sizeof($top))
+		if ($src_encoding == '')
 		{
-			if (ereg("^([#a-zA-Z0-9]+);", $top[$i], $regs))
-			{
-				$op.=ereg_replace("^[#a-zA-Z0-9]+;",
-				xmlrpc_lookup_entity($regs[1]),
-				$top[$i]);
-			}
-			else
-			{
-				if ($i==0)
-				{
-					$op=$top[$i];
-				}
-				else
-				{
-					$op.='&' . $top[$i];
-				}
-			}
-			$i++;
+			// lame, but we know no better...
+			$src_encoding = $GLOBALS['xmlrpc_internalencoding'];
 		}
-		return $op;
-	}
 
-	function xmlrpc_lookup_entity($ent)
-	{
-		global $xmlEntities;
-
-		if (isset($xmlEntities[strtolower($ent)]))
-		{
-			return $xmlEntities[strtolower($ent)];
-		}
-		if (ereg("^#([0-9]+)$", $ent, $regs))
+		switch(strtoupper($src_encoding.'_'.$dest_encoding))
+		{
+			case 'ISO-8859-1_':
+			case 'ISO-8859-1_US-ASCII':
+				$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&amp;', '&quot;', '&apos;', '&lt;', '&gt;'), $data);
+				$escaped_data = str_replace($GLOBALS['xml_iso88591_Entities']['in'], $GLOBALS['xml_iso88591_Entities']['out'], $escaped_data);
+				break;
+			case 'ISO-8859-1_UTF-8':
+				$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&amp;', '&quot;', '&apos;', '&lt;', '&gt;'), $data);
+				$escaped_data = utf8_encode($escaped_data);
+				break;
+			case 'ISO-8859-1_ISO-8859-1':
+			case 'US-ASCII_US-ASCII':
+			case 'US-ASCII_UTF-8':
+			case 'US-ASCII_':
+			case 'US-ASCII_ISO-8859-1':
+			case 'UTF-8_UTF-8':
+				$escaped_data = str_replace(array('&', '"', "'", '<', '>'), array('&amp;', '&quot;', '&apos;', '&lt;', '&gt;'), $data);
+				break;
+			case 'UTF-8_':
+			case 'UTF-8_US-ASCII':
+			case 'UTF-8_ISO-8859-1':
+	// NB: this will choke on invalid UTF-8, going most likely beyond EOF
+	$escaped_data = '';
+	// be kind to users creating string xmlrpcvals out of different php types
+	$data = (string) $data;
+	$ns = strlen ($data);
+	for ($nn = 0; $nn < $ns; $nn++)
+	{
+		$ch = $data[$nn];
+		$ii = ord($ch);
+		//1 7 0bbbbbbb (127)
+		if ($ii < 128)
 		{
-			return chr($regs[1]);
-		}
-		return '?';
-	}
-
-	/**
-	 * These entities originate from HTML specs (1.1, proposed 2.0, etc),
-	 * and are taken directly from php-4.3.1/ext/mbstring/html_entities.c.
-	 * Until php provides functionality to translate these entities in its
-	 * core library, use this function.
-	 */
-	function xmlrpc_html_entity_xlate($data = '')
-	{
-		$entities = array(
-			"&nbsp;" => "&#160;",
-			"&iexcl;" => "&#161;",
-			"&cent;" => "&#162;",
-			"&pound;" => "&#163;",
-			"&curren;" => "&#164;",
-			"&yen;" => "&#165;",
-			"&brvbar;" => "&#166;",
-			"&sect;" => "&#167;",
-			"&uml;" => "&#168;",
-			"&copy;" => "&#169;",
-			"&ordf;" => "&#170;",
-			"&laquo;" => "&#171;",
-			"&not;" => "&#172;",
-			"&shy;" => "&#173;",
-			"&reg;" => "&#174;",
-			"&macr;" => "&#175;",
-			"&deg;" => "&#176;",
-			"&plusmn;" => "&#177;",
-			"&sup2;" => "&#178;",
-			"&sup3;" => "&#179;",
-			"&acute;" => "&#180;",
-			"&micro;" => "&#181;",
-			"&para;" => "&#182;",
-			"&middot;" => "&#183;",
-			"&cedil;" => "&#184;",
-			"&sup1;" => "&#185;",
-			"&ordm;" => "&#186;",
-			"&raquo;" => "&#187;",
-			"&frac14;" => "&#188;",
-			"&frac12;" => "&#189;",
-			"&frac34;" => "&#190;",
-			"&iquest;" => "&#191;",
-			"&Agrave;" => "&#192;",
-			"&Aacute;" => "&#193;",
-			"&Acirc;" => "&#194;",
-			"&Atilde;" => "&#195;",
-			"&Auml;" => "&#196;",
-			"&Aring;" => "&#197;",
-			"&AElig;" => "&#198;",
-			"&Ccedil;" => "&#199;",
-			"&Egrave;" => "&#200;",
-			"&Eacute;" => "&#201;",
-			"&Ecirc;" => "&#202;",
-			"&Euml;" => "&#203;",
-			"&Igrave;" => "&#204;",
-			"&Iacute;" => "&#205;",
-			"&Icirc;" => "&#206;",
-			"&Iuml;" => "&#207;",
-			"&ETH;" => "&#208;",
-			"&Ntilde;" => "&#209;",
-			"&Ograve;" => "&#210;",
-			"&Oacute;" => "&#211;",
-			"&Ocirc;" => "&#212;",
-			"&Otilde;" => "&#213;",
-			"&Ouml;" => "&#214;",
-			"&times;" => "&#215;",
-			"&Oslash;" => "&#216;",
-			"&Ugrave;" => "&#217;",
-			"&Uacute;" => "&#218;",
-			"&Ucirc;" => "&#219;",
-			"&Uuml;" => "&#220;",
-			"&Yacute;" => "&#221;",
-			"&THORN;" => "&#222;",
-			"&szlig;" => "&#223;",
-			"&agrave;" => "&#224;",
-			"&aacute;" => "&#225;",
-			"&acirc;" => "&#226;",
-			"&atilde;" => "&#227;",
-			"&auml;" => "&#228;",
-			"&aring;" => "&#229;",
-			"&aelig;" => "&#230;",
-			"&ccedil;" => "&#231;",
-			"&egrave;" => "&#232;",
-			"&eacute;" => "&#233;",
-			"&ecirc;" => "&#234;",
-			"&euml;" => "&#235;",
-			"&igrave;" => "&#236;",
-			"&iacute;" => "&#237;",
-			"&icirc;" => "&#238;",
-			"&iuml;" => "&#239;",
-			"&eth;" => "&#240;",
-			"&ntilde;" => "&#241;",
-			"&ograve;" => "&#242;",
-			"&oacute;" => "&#243;",
-			"&ocirc;" => "&#244;",
-			"&otilde;" => "&#245;",
-			"&ouml;" => "&#246;",
-			"&divide;" => "&#247;",
-			"&oslash;" => "&#248;",
-			"&ugrave;" => "&#249;",
-			"&uacute;" => "&#250;",
-			"&ucirc;" => "&#251;",
-			"&uuml;" => "&#252;",
-			"&yacute;" => "&#253;",
-			"&thorn;" => "&#254;",
-			"&yuml;" => "&#255;",
-			"&OElig;" => "&#338;",
-			"&oelig;" => "&#339;",
-			"&Scaron;" => "&#352;",
-			"&scaron;" => "&#353;",
-			"&Yuml;" => "&#376;",
-			"&fnof;" => "&#402;",
-			"&circ;" => "&#710;",
-			"&tilde;" => "&#732;",
-			"&Alpha;" => "&#913;",
-			"&Beta;" => "&#914;",
-			"&Gamma;" => "&#915;",
-			"&Delta;" => "&#916;",
-			"&Epsilon;" => "&#917;",
-			"&Zeta;" => "&#918;",
-			"&Eta;" => "&#919;",
-			"&Theta;" => "&#920;",
-			"&Iota;" => "&#921;",
-			"&Kappa;" => "&#922;",
-			"&Lambda;" => "&#923;",
-			"&Mu;" => "&#924;",
-			"&Nu;" => "&#925;",
-			"&Xi;" => "&#926;",
-			"&Omicron;" => "&#927;",
-			"&Pi;" => "&#928;",
-			"&Rho;" => "&#929;",
-			"&Sigma;" => "&#931;",
-			"&Tau;" => "&#932;",
-			"&Upsilon;" => "&#933;",
-			"&Phi;" => "&#934;",
-			"&Chi;" => "&#935;",
-			"&Psi;" => "&#936;",
-			"&Omega;" => "&#937;",
-			"&beta;" => "&#946;",
-			"&gamma;" => "&#947;",
-			"&delta;" => "&#948;",
-			"&epsilon;" => "&#949;",
-			"&zeta;" => "&#950;",
-			"&eta;" => "&#951;",
-			"&theta;" => "&#952;",
-			"&iota;" => "&#953;",
-			"&kappa;" => "&#954;",
-			"&lambda;" => "&#955;",
-			"&mu;" => "&#956;",
-			"&nu;" => "&#957;",
-			"&xi;" => "&#958;",
-			"&omicron;" => "&#959;",
-			"&pi;" => "&#960;",
-			"&rho;" => "&#961;",
-			"&sigmaf;" => "&#962;",
-			"&sigma;" => "&#963;",
-			"&tau;" => "&#964;",
-			"&upsilon;" => "&#965;",
-			"&phi;" => "&#966;",
-			"&chi;" => "&#967;",
-			"&psi;" => "&#968;",
-			"&omega;" => "&#969;",
-			"&thetasym;" => "&#977;",
-			"&upsih;" => "&#978;",
-			"&piv;" => "&#982;",
-			"&ensp;" => "&#8194;",
-			"&emsp;" => "&#8195;",
-			"&thinsp;" => "&#8201;",
-			"&zwnj;" => "&#8204;",
-			"&zwj;" => "&#8205;",
-			"&lrm;" => "&#8206;",
-			"&rlm;" => "&#8207;",
-			"&ndash;" => "&#8211;",
-			"&mdash;" => "&#8212;",
-			"&lsquo;" => "&#8216;",
-			"&rsquo;" => "&#8217;",
-			"&sbquo;" => "&#8218;",
-			"&ldquo;" => "&#8220;",
-			"&rdquo;" => "&#8221;",
-			"&bdquo;" => "&#8222;",
-			"&dagger;" => "&#8224;",
-			"&Dagger;" => "&#8225;",
-			"&bull;" => "&#8226;",
-			"&hellip;" => "&#8230;",
-			"&permil;" => "&#8240;",
-			"&prime;" => "&#8242;",
-			"&Prime;" => "&#8243;",
-			"&lsaquo;" => "&#8249;",
-			"&rsaquo;" => "&#8250;",
-			"&oline;" => "&#8254;",
-			"&frasl;" => "&#8260;",
-			"&euro;" => "&#8364;",
-			"&weierp;" => "&#8472;",
-			"&image;" => "&#8465;",
-			"&real;" => "&#8476;",
-			"&trade;" => "&#8482;",
-			"&alefsym;" => "&#8501;",
-			"&larr;" => "&#8592;",
-			"&uarr;" => "&#8593;",
-			"&rarr;" => "&#8594;",
-			"&darr;" => "&#8595;",
-			"&harr;" => "&#8596;",
-			"&crarr;" => "&#8629;",
-			"&lArr;" => "&#8656;",
-			"&uArr;" => "&#8657;",
-			"&rArr;" => "&#8658;",
-			"&dArr;" => "&#8659;",
-			"&hArr;" => "&#8660;",
-			"&forall;" => "&#8704;",
-			"&part;" => "&#8706;",
-			"&exist;" => "&#8707;",
-			"&empty;" => "&#8709;",
-			"&nabla;" => "&#8711;",
-			"&isin;" => "&#8712;",
-			"&notin;" => "&#8713;",
-			"&ni;" => "&#8715;",
-			"&prod;" => "&#8719;",
-			"&sum;" => "&#8721;",
-			"&minus;" => "&#8722;",
-			"&lowast;" => "&#8727;",
-			"&radic;" => "&#8730;",
-			"&prop;" => "&#8733;",
-			"&infin;" => "&#8734;",
-			"&ang;" => "&#8736;",
-			"&and;" => "&#8743;",
-			"&or;" => "&#8744;",
-			"&cap;" => "&#8745;",
-			"&cup;" => "&#8746;",
-			"&int;" => "&#8747;",
-			"&there4;" => "&#8756;",
-			"&sim;" => "&#8764;",
-			"&cong;" => "&#8773;",
-			"&asymp;" => "&#8776;",
-			"&ne;" => "&#8800;",
-			"&equiv;" => "&#8801;",
-			"&le;" => "&#8804;",
-			"&ge;" => "&#8805;",
-			"&sub;" => "&#8834;",
-			"&sup;" => "&#8835;",
-			"&nsub;" => "&#8836;",
-			"&sube;" => "&#8838;",
-			"&supe;" => "&#8839;",
-			"&oplus;" => "&#8853;",
-			"&otimes;" => "&#8855;",
-			"&perp;" => "&#8869;",
-			"&sdot;" => "&#8901;",
-			"&lceil;" => "&#8968;",
-			"&rceil;" => "&#8969;",
-			"&lfloor;" => "&#8970;",
-			"&rfloor;" => "&#8971;",
-			"&lang;" => "&#9001;",
-			"&rang;" => "&#9002;",
-			"&loz;" => "&#9674;",
-			"&spades;" => "&#9824;",
-			"&clubs;" => "&#9827;",
-			"&hearts;" => "&#9829;",
-			"&diams;" => "&#9830;");
-		return strtr($data, $entities);
-	}
-
-	function xmlrpc_encode_entitites($data) 
-	{
-		$length = strlen($data);
-		$escapeddata = "";
-		for($position = 0; $position < $length; $position++)
-		{
-			$character = substr($data, $position, 1);
-			$code = Ord($character);
-			switch($code) {
+			/// @todo shall we replace this with a (supposedly) faster str_replace?
+			switch($ii){
 				case 34:
-				$character = "&quot;";
-				break;
+					$escaped_data .= '&quot;';
+					break;
 				case 38:
-				$character = "&amp;";
-				break;
+					$escaped_data .= '&amp;';
+					break;
 				case 39:
-				$character = "&apos;";
-				break;
+					$escaped_data .= '&apos;';
+					break;
 				case 60:
-				$character = "&lt;";
-				break;
+					$escaped_data .= '&lt;';
+					break;
 				case 62:
-				$character = "&gt;";
-				break;
+					$escaped_data .= '&gt;';
+					break;
 				default:
-				if ($code < 32 || $code > 159)
-					$character = ("&#".strval($code).";");
+					$escaped_data .= $ch;
+			} // switch
+		}
+		//2 11 110bbbbb 10bbbbbb (2047)
+		else if ($ii>>5 == 6)
+		{
+			$b1 = ($ii & 31);
+			$ii = ord($data[$nn+1]);
+			$b2 = ($ii & 63);
+			$ii = ($b1 * 64) + $b2;
+			$ent = sprintf ('&#%d;', $ii);
+			$escaped_data .= $ent;
+			$nn += 1;
+		}
+		//3 16 1110bbbb 10bbbbbb 10bbbbbb
+		else if ($ii>>4 == 14)
+		{
+			$b1 = ($ii & 31);
+			$ii = ord($data[$nn+1]);
+			$b2 = ($ii & 63);
+			$ii = ord($data[$nn+2]);
+			$b3 = ($ii & 63);
+			$ii = ((($b1 * 64) + $b2) * 64) + $b3;
+			$ent = sprintf ('&#%d;', $ii);
+			$escaped_data .= $ent;
+			$nn += 2;
+		}
+		//4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+		else if ($ii>>3 == 30)
+		{
+			$b1 = ($ii & 31);
+			$ii = ord($data[$nn+1]);
+			$b2 = ($ii & 63);
+			$ii = ord($data[$nn+2]);
+			$b3 = ($ii & 63);
+			$ii = ord($data[$nn+3]);
+			$b4 = ($ii & 63);
+			$ii = ((((($b1 * 64) + $b2) * 64) + $b3) * 64) + $b4;
+			$ent = sprintf ('&#%d;', $ii);
+			$escaped_data .= $ent;
+			$nn += 3;
+		}
+	}
 				break;
-			}
-			$escapeddata .= $character;
+			default:
+				$escaped_data = '';
+				error_log("Converting from $src_encoding to $dest_encoding: not supported...");
 		}
-		return $escapeddata;
+		return $escaped_data;
 	}
 
-	function xmlrpc_se($parser, $name, $attrs)
+	/// xml parser handler function for opening element tags
+	function xmlrpc_se($parser, $name, $attrs, $accept_single_vals=false)
 	{
-		global $_xh, $xmlrpcDateTime, $xmlrpcString, $xmlrpc_valid_parents;
-
 		// if invalid xmlrpc already detected, skip all processing
-		if ($_xh[$parser]['isf'] < 2)
+		if ($GLOBALS['_xh']['isf'] < 2)
 		{
-
-		// check for correct element nesting
-		// top level element can only be of 2 types
-		if (count($_xh[$parser]['stack']) == 0)
-		{
-			if ($name != 'METHODRESPONSE' && $name != 'METHODCALL')
+			// check for correct element nesting
+			// top level element can only be of 2 types
+			/// @todo optimization creep: save this check into a bool variable, instead of using count() every time:
+			///       there is only a single top level element in xml anyway
+			if (count($GLOBALS['_xh']['stack']) == 0)
 			{
-				$_xh[$parser]['isf'] = 2;
-				$_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
-				return;
+				if ($name != 'METHODRESPONSE' && $name != 'METHODCALL' && (
+					$name != 'VALUE' && !$accept_single_vals))
+				{
+					$GLOBALS['_xh']['isf'] = 2;
+					$GLOBALS['_xh']['isf_reason'] = 'missing top level xmlrpc element';
+					return;
+				}
+				else
+				{
+					$GLOBALS['_xh']['rt'] = strtolower($name);
+				}
 			}
-		}
-		else
-		{
-			// not top level element: see if parent is OK
-			if (!in_array($_xh[$parser]['stack'][0], $xmlrpc_valid_parents[$name]))
+			else
 			{
-				$_xh[$parser]['isf'] = 2;
-				$_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$_xh[$parser]['stack'][0]}";
-				return;
-			}
-		}
-
-		switch($name)
-		{
-			case 'STRUCT':
-			case 'ARRAY':
-				//$_xh[$parser]['st'].='array(';
-				//$_xh[$parser]['cm']++;
-				// this last line turns quoting off
-				// this means if we get an empty array we'll
-				// simply get a bit of whitespace in the eval
-				//$_xh[$parser]['qt']=0;
-
-				// create an empty array to hold child values, and push it onto appropriate stack
-				$cur_val = array();
-				$cur_val['values'] = array();
-				$cur_val['type'] = $name;
-				array_unshift($_xh[$parser]['valuestack'], $cur_val);
-				break;
-			case 'METHODNAME':
-			case 'NAME':
-				//$_xh[$parser]['st'].='"';
-				$_xh[$parser]['ac']='';
-				break;
-			case 'FAULT':
-				$_xh[$parser]['isf']=1;
-				break;
-			case 'PARAM':
-				//$_xh[$parser]['st']='';
-				// clear value, so we can check later if no value will passed for this param/member
-				$_xh[$parser]['value']=null;
-				break;
-			case 'VALUE':
-				//$_xh[$parser]['st'].='new xmlrpcval(';
-				// look for a value: if this is still true by the
-				// time we reach the end tag for value then the type is string
-				// by implication
-				$_xh[$parser]['vt']='value';
-				$_xh[$parser]['ac']='';
-				//$_xh[$parser]['qt']=0;
-				$_xh[$parser]['lv']=1;
-				break;
-			case 'I4':
-			case 'INT':
-			case 'STRING':
-			case 'BOOLEAN':
-			case 'DOUBLE':
-			case 'DATETIME.ISO8601':
-			case 'BASE64':
-				if ($_xh[$parser]['vt']!='value')
-				{
-					//two data elements inside a value: an error occurred!
-					$_xh[$parser]['isf'] = 2;
-					$_xh[$parser]['isf_reason'] = "$name element following a {$_xh[$parser]['vt']} element inside a single value";
+				// not top level element: see if parent is OK
+				$parent = end($GLOBALS['_xh']['stack']);
+				if (!array_key_exists($name, $GLOBALS['xmlrpc_valid_parents']) || !in_array($parent, $GLOBALS['xmlrpc_valid_parents'][$name]))
+				{
+					$GLOBALS['_xh']['isf'] = 2;
+					$GLOBALS['_xh']['isf_reason'] = "xmlrpc element $name cannot be child of $parent";
 					return;
 				}
+			}
 
-				// reset the accumulator
-				$_xh[$parser]['ac']='';
-
-				/*if ($name=='DATETIME.ISO8601' || $name=='STRING')
-				{
-					$_xh[$parser]['qt']=1;
-					if ($name=='DATETIME.ISO8601')
+			switch($name)
+			{
+				// optimize for speed switch cases: most common cases first
+				case 'VALUE':
+					/// @todo we could check for 2 VALUE elements inside a MEMBER or PARAM element
+					$GLOBALS['_xh']['vt']='value'; // indicator: no value found yet
+					$GLOBALS['_xh']['ac']='';
+					$GLOBALS['_xh']['lv']=1;
+					$GLOBALS['_xh']['php_class']=null;
+					break;
+				case 'I4':
+				case 'INT':
+				case 'STRING':
+				case 'BOOLEAN':
+				case 'DOUBLE':
+				case 'DATETIME.ISO8601':
+				case 'BASE64':
+					if ($GLOBALS['_xh']['vt']!='value')
 					{
-						$_xh[$parser]['vt']=$xmlrpcDateTime;
+						//two data elements inside a value: an error occurred!
+						$GLOBALS['_xh']['isf'] = 2;
+						$GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value";
+						return;
 					}
-				}
-				elseif ($name=='BASE64')
-				{
-					$_xh[$parser]['qt']=2;
-				}
-				else
-				{
-					// No quoting is required here -- but
-					// at the end of the element we must check
-					// for data format errors.
-					$_xh[$parser]['qt']=0;
-				}*/
-				break;
-			case 'MEMBER':
-				//$_xh[$parser]['ac']='';
-				// avoid warnings later on if no NAME is found before VALUE inside
-				// a struct member predefining member name as NULL
-				$_xh[$parser]['valuestack'][0]['name'] = '';
-				// clear value, so we can check later if no value will passed for this param/member
-				$_xh[$parser]['value']=null;
-				break;
-			case 'DATA':
-			case 'METHODCALL':
-			case 'METHODRESPONSE':
-			case 'PARAMS':
-				// valid elements that add little to processing
-				break;
-			default:
-				/// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!
-				$_xh[$parser]['isf'] = 2;
-				$_xh[$parser]['isf_reason'] = "found not-xmlrpc xml element $name";
-				break;
-		}
+					$GLOBALS['_xh']['ac']=''; // reset the accumulator
+					break;
+				case 'STRUCT':
+				case 'ARRAY':
+					if ($GLOBALS['_xh']['vt']!='value')
+					{
+						//two data elements inside a value: an error occurred!
+						$GLOBALS['_xh']['isf'] = 2;
+						$GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value";
+						return;
+					}
+					// create an empty array to hold child values, and push it onto appropriate stack
+					$cur_val = array();
+					$cur_val['values'] = array();
+					$cur_val['type'] = $name;
+					// check for out-of-band information to rebuild php objs
+					// and in case it is found, save it
+					if (@isset($attrs['PHP_CLASS']))
+					{
+						$cur_val['php_class'] = $attrs['PHP_CLASS'];
+					}
+					$GLOBALS['_xh']['valuestack'][] = $cur_val;
+					$GLOBALS['_xh']['vt']='data'; // be prepared for a data element next
+					break;
+				case 'DATA':
+					if ($GLOBALS['_xh']['vt']!='data')
+					{
+						//two data elements inside a value: an error occurred!
+						$GLOBALS['_xh']['isf'] = 2;
+						$GLOBALS['_xh']['isf_reason'] = "found two data elements inside an array element";
+						return;
+					}
+				case 'METHODCALL':
+				case 'METHODRESPONSE':
+				case 'PARAMS':
+					// valid elements that add little to processing
+					break;
+				case 'METHODNAME':
+				case 'NAME':
+					/// @todo we could check for 2 NAME elements inside a MEMBER element
+					$GLOBALS['_xh']['ac']='';
+					break;
+				case 'FAULT':
+					$GLOBALS['_xh']['isf']=1;
+					break;
+				case 'MEMBER':
+					$GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name']=''; // set member name to null, in case we do not find in the xml later on
+					//$GLOBALS['_xh']['ac']='';
+					// Drop trough intentionally
+				case 'PARAM':
+					// clear value type, so we can check later if no value has been passed for this param/member
+					$GLOBALS['_xh']['vt']=null;
+					break;
+				case 'NIL':
+					if ($GLOBALS['xmlrpc_null_extension'])
+					{
+						if ($GLOBALS['_xh']['vt']!='value')
+						{
+							//two data elements inside a value: an error occurred!
+							$GLOBALS['_xh']['isf'] = 2;
+							$GLOBALS['_xh']['isf_reason'] = "$name element following a {$GLOBALS['_xh']['vt']} element inside a single value";
+							return;
+						}
+						$GLOBALS['_xh']['ac']=''; // reset the accumulator
+						break;
+					}
+					// we do not support the <NIL/> extension, so
+					// drop through intentionally
+				default:
+					/// INVALID ELEMENT: RAISE ISF so that it is later recognized!!!
+					$GLOBALS['_xh']['isf'] = 2;
+					$GLOBALS['_xh']['isf_reason'] = "found not-xmlrpc xml element $name";
+					break;
+			}
 
-		// Save current element name to stack, to validate nesting
-		array_unshift($_xh[$parser]['stack'], $name);
+			// Save current element name to stack, to validate nesting
+			$GLOBALS['_xh']['stack'][] = $name;
 
-		if ($name!='VALUE')
-		{
-			$_xh[$parser]['lv']=0;
+			/// @todo optimization creep: move this inside the big switch() above
+			if($name!='VALUE')
+			{
+				$GLOBALS['_xh']['lv']=0;
+			}
 		}
 	}
-	}
 
-	function xmlrpc_ee($parser, $name)
+	/// Used in decoding xml chunks that might represent single xmlrpc values
+	function xmlrpc_se_any($parser, $name, $attrs)
 	{
-		global $_xh,$xmlrpcTypes,$xmlrpcString,$xmlrpcDateTime;
-
-		if ($_xh[$parser]['isf'] < 2)
-		{
-
-		// push this element name from stack
-		// NB: if XML validates, correct opening/closing is guaranteed and
-		// we do not have to check for $name == $curr_elem.
-		// we also checked for proper nesting at start of elements...
-		$curr_elem = array_shift($_xh[$parser]['stack']);		
+		xmlrpc_se($parser, $name, $attrs, true);
+	}
 
-		switch($name)
+	/// xml parser handler function for close element tags
+	function xmlrpc_ee($parser, $name, $rebuild_xmlrpcvals = true)
+	{
+		if ($GLOBALS['_xh']['isf'] < 2)
 		{
-			case 'STRUCT':
-			case 'ARRAY':
-				//if ($_xh[$parser]['cm'] && substr($_xh[$parser]['st'], -1) ==',')
-				//{
-				//	$_xh[$parser]['st']=substr($_xh[$parser]['st'],0,-1);
-				//}
-				//$_xh[$parser]['st'].=')';
+			// push this element name from stack
+			// NB: if XML validates, correct opening/closing is guaranteed and
+			// we do not have to check for $name == $curr_elem.
+			// we also checked for proper nesting at start of elements...
+			$curr_elem = array_pop($GLOBALS['_xh']['stack']);
 
-				// fetch out of stack array of values, and promote it to current value
-				$cur_val = array_shift($_xh[$parser]['valuestack']);
-				$_xh[$parser]['value'] = $cur_val['values'];
+			switch($name)
+			{
+				case 'VALUE':
+					// This if() detects if no scalar was inside <VALUE></VALUE>
+					if ($GLOBALS['_xh']['vt']=='value')
+					{
+						$GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac'];
+						$GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcString'];
+					}
 
-				$_xh[$parser]['vt']=strtolower($name);
-				//$_xh[$parser]['cm']--;
-				break;
-			case 'NAME':
-				//$_xh[$parser]['st'].= $_xh[$parser]['ac'] . '" => ';
-				$_xh[$parser]['valuestack'][0]['name'] = $_xh[$parser]['ac'];
-				break;
-			case 'BOOLEAN':
-			case 'I4':
-			case 'INT':
-			case 'STRING':
-			case 'DOUBLE':
-			case 'DATETIME.ISO8601':
-			case 'BASE64':
-				$_xh[$parser]['vt']=strtolower($name);
-				//if ($_xh[$parser]['qt']==1)			
-				if ($name=='STRING')
-				{
-					// we use double quotes rather than single so backslashification works OK
-					//$_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
-					$_xh[$parser]['value']=$_xh[$parser]['ac'];
-				}
-				elseif ($name=='DATETIME.ISO8601')
-				{
-					$_xh[$parser]['vt']=$xmlrpcDateTime;
-					$_xh[$parser]['value']=$_xh[$parser]['ac'];
-				}
-				elseif ($name=='BASE64')
-				{
-					//$_xh[$parser]['st'].='base64_decode("'. $_xh[$parser]['ac'] . '")';
-
-					///@todo check for failure of base64 decoding / catch warnings
-					$_xh[$parser]['value']=base64_decode($_xh[$parser]['ac']);
-				}
-				elseif ($name=='BOOLEAN')
-				{
-					// special case here: we translate boolean 1 or 0 into PHP
-					// constants true or false
-					// NB: this simple checks helps a lot sanitizing input, ie no
-					// security problems around here
-					if ($_xh[$parser]['ac']=='1')
+					if ($rebuild_xmlrpcvals)
 					{
-						//$_xh[$parser]['ac']='true';	
-						$_xh[$parser]['value']=true;
+						// build the xmlrpc val out of the data received, and substitute it
+						$temp =& new xmlrpcval($GLOBALS['_xh']['value'], $GLOBALS['_xh']['vt']);
+						// in case we got info about underlying php class, save it
+						// in the object we're rebuilding
+						if (isset($GLOBALS['_xh']['php_class']))
+							$temp->_php_class = $GLOBALS['_xh']['php_class'];
+						// check if we are inside an array or struct:
+						// if value just built is inside an array, let's move it into array on the stack
+						$vscount = count($GLOBALS['_xh']['valuestack']);
+						if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY')
+						{
+							$GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $temp;
+						}
+						else
+						{
+							$GLOBALS['_xh']['value'] = $temp;
+						}
 					}
 					else
 					{
-						//$_xh[$parser]['ac']='false';
-						// log if receiveing something strange, even though we set the value to false anyway
-						if ($_xh[$parser]['ac']!='0')
-							error_log('XML-RPC: invalid value received in BOOLEAN: '.$_xh[$parser]['ac']);
-						$_xh[$parser]['value']=false;
-					}
-					//$_xh[$parser]['st'].=$_xh[$parser]['ac'];
-				}
-				elseif ($name=='DOUBLE')
-				{
-					// we have a DOUBLE
-					// we must check that only 0123456789-.<space> are characters here
-					if (!ereg("^[+-]?[eE0123456789 \\t\\.]+$", $_xh[$parser]['ac']))
-					{
-						// TODO: find a better way of throwing an error
-						// than this!
-						error_log('XML-RPC: non numeric value received in DOUBLE: '.$_xh[$parser]['ac']);
-						//$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";
-						$_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';
+						/// @todo this needs to treat correctly php-serialized objects,
+						/// since std deserializing is done by php_xmlrpc_decode,
+						/// which we will not be calling...
+						if (isset($GLOBALS['_xh']['php_class']))
+						{
+						}
+
+						// check if we are inside an array or struct:
+						// if value just built is inside an array, let's move it into array on the stack
+						$vscount = count($GLOBALS['_xh']['valuestack']);
+						if ($vscount && $GLOBALS['_xh']['valuestack'][$vscount-1]['type']=='ARRAY')
+						{
+							$GLOBALS['_xh']['valuestack'][$vscount-1]['values'][] = $GLOBALS['_xh']['value'];
+						}
+					}
+					break;
+				case 'BOOLEAN':
+				case 'I4':
+				case 'INT':
+				case 'STRING':
+				case 'DOUBLE':
+				case 'DATETIME.ISO8601':
+				case 'BASE64':
+					$GLOBALS['_xh']['vt']=strtolower($name);
+        			/// @todo: optimization creep - remove the if/elseif cycle below
+                    /// since the case() in which we are already did that
+					if ($name=='STRING')
+					{
+						$GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac'];
+					}
+					elseif ($name=='DATETIME.ISO8601')
+					{
+						if (!preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $GLOBALS['_xh']['ac']))
+						{
+							error_log('XML-RPC: invalid value received in DATETIME: '.$GLOBALS['_xh']['ac']);
+						}
+						$GLOBALS['_xh']['vt']=$GLOBALS['xmlrpcDateTime'];
+						$GLOBALS['_xh']['value']=$GLOBALS['_xh']['ac'];
+					}
+					elseif ($name=='BASE64')
+					{
+						/// @todo check for failure of base64 decoding / catch warnings
+						$GLOBALS['_xh']['value']=base64_decode($GLOBALS['_xh']['ac']);
+					}
+					elseif ($name=='BOOLEAN')
+					{
+						// special case here: we translate boolean 1 or 0 into PHP
+						// constants true or false.
+						// Strings 'true' and 'false' are accepted, even though the
+						// spec never mentions them (see eg. Blogger api docs)
+						// NB: this simple checks helps a lot sanitizing input, ie no
+						// security problems around here
+						if ($GLOBALS['_xh']['ac']=='1' || strcasecmp($GLOBALS['_xh']['ac'], 'true') == 0)
+						{
+							$GLOBALS['_xh']['value']=true;
+						}
+						else
+						{
+							// log if receiveing something strange, even though we set the value to false anyway
+							if ($GLOBALS['_xh']['ac']!='0' && strcasecmp($_xh[$parser]['ac'], 'false') != 0)
+								error_log('XML-RPC: invalid value received in BOOLEAN: '.$GLOBALS['_xh']['ac']);
+							$GLOBALS['_xh']['value']=false;
+						}
+					}
+					elseif ($name=='DOUBLE')
+					{
+						// we have a DOUBLE
+						// we must check that only 0123456789-.<space> are characters here
+						if (!preg_match('/^[+-]?[eE0123456789 \t.]+$/', $GLOBALS['_xh']['ac']))
+						{
+							/// @todo: find a better way of throwing an error
+							// than this!
+							error_log('XML-RPC: non numeric value received in DOUBLE: '.$GLOBALS['_xh']['ac']);
+							$GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND';
+						}
+						else
+						{
+							// it's ok, add it on
+							$GLOBALS['_xh']['value']=(double)$GLOBALS['_xh']['ac'];
+						}
 					}
 					else
 					{
-						// it's ok, add it on
-						//$_xh[$parser]['st'].=(double)$_xh[$parser]['ac'];
-						$_xh[$parser]['value']=(double)$_xh[$parser]['ac'];
+						// we have an I4/INT
+						// we must check that only 0123456789-<space> are characters here
+						if (!preg_match('/^[+-]?[0123456789 \t]+$/', $GLOBALS['_xh']['ac']))
+						{
+							/// @todo find a better way of throwing an error
+							// than this!
+							error_log('XML-RPC: non numeric value received in INT: '.$GLOBALS['_xh']['ac']);
+							$GLOBALS['_xh']['value']='ERROR_NON_NUMERIC_FOUND';
+						}
+						else
+						{
+							// it's ok, add it on
+							$GLOBALS['_xh']['value']=(int)$GLOBALS['_xh']['ac'];
+						}
 					}
-				}
-				else
-				{
-					// we have an I4/INT
-					// we must check that only 0123456789-<space> are characters here
-					if (!ereg("^[+-]?[0123456789 \\t]+$", $_xh[$parser]['ac']))
-					{
-						// TODO: find a better way of throwing an error
-						// than this!
-						error_log('XML-RPC: non numeric value received in INT: '.$_xh[$parser]['ac']);
-						//$_xh[$parser]['st'].="'ERROR_NON_NUMERIC_FOUND'";
-						$_xh[$parser]['value']='ERROR_NON_NUMERIC_FOUND';
+					//$GLOBALS['_xh']['ac']=''; // is this necessary?
+					$GLOBALS['_xh']['lv']=3; // indicate we've found a value
+					break;
+				case 'NAME':
+					$GLOBALS['_xh']['valuestack'][count($GLOBALS['_xh']['valuestack'])-1]['name'] = $GLOBALS['_xh']['ac'];
+					break;
+				case 'MEMBER':
+					//$GLOBALS['_xh']['ac']=''; // is this necessary?
+					// add to array in the stack the last element built,
+					// unless no VALUE was found
+					if ($GLOBALS['_xh']['vt'])
+					{
+						$vscount = count($GLOBALS['_xh']['valuestack']);
+						$GLOBALS['_xh']['valuestack'][$vscount-1]['values'][$GLOBALS['_xh']['valuestack'][$vscount-1]['name']] = $GLOBALS['_xh']['value'];
+					} else
+						error_log('XML-RPC: missing VALUE inside STRUCT in received xml');
+					break;
+				case 'DATA':
+					//$GLOBALS['_xh']['ac']=''; // is this necessary?
+					$GLOBALS['_xh']['vt']=null; // reset this to check for 2 data elements in a row - even if they're empty
+					break;
+				case 'STRUCT':
+				case 'ARRAY':
+					// fetch out of stack array of values, and promote it to current value
+					$curr_val = array_pop($GLOBALS['_xh']['valuestack']);
+					$GLOBALS['_xh']['value'] = $curr_val['values'];
+					$GLOBALS['_xh']['vt']=strtolower($name);
+					if (isset($curr_val['php_class']))
+					{
+						$GLOBALS['_xh']['php_class'] = $curr_val['php_class'];
+					}
+					break;
+				case 'PARAM':
+					// add to array of params the current value,
+					// unless no VALUE was found
+					if ($GLOBALS['_xh']['vt'])
+					{
+						$GLOBALS['_xh']['params'][]=$GLOBALS['_xh']['value'];
+						$GLOBALS['_xh']['pt'][]=$GLOBALS['_xh']['vt'];
 					}
 					else
+						error_log('XML-RPC: missing VALUE inside PARAM in received xml');
+					break;
+				case 'METHODNAME':
+					$GLOBALS['_xh']['method']=preg_replace('/^[\n\r\t ]+/', '', $GLOBALS['_xh']['ac']);
+					break;
+				case 'NIL':
+					if ($GLOBALS['xmlrpc_null_extension'])
 					{
-						// it's ok, add it on
-						//$_xh[$parser]['st'].=(int)$_xh[$parser]['ac'];
-						$_xh[$parser]['value']=(int)$_xh[$parser]['ac'];
+						$GLOBALS['_xh']['vt']='null';
+						$GLOBALS['_xh']['value']=null;
+						$GLOBALS['_xh']['lv']=3;
+						break;
 					}
-				}
-				$_xh[$parser]['ac']='';
-				//$_xh[$parser]['qt']=0;
-				$_xh[$parser]['lv']=3; // indicate we've found a value
-				break;
-			case 'VALUE':
-				// This if() detects if no scalar was inside <VALUE></VALUE>
-				if ($_xh[$parser]['vt']=='value')
-				{
-					$_xh[$parser]['value']=$_xh[$parser]['ac'];
-					$_xh[$parser]['vt']=$xmlrpcString;
-				}
-				/*if (strlen($_xh[$parser]['ac'])>0 &&
-					$_xh[$parser]['vt']==$xmlrpcString)
-				{
-					$_xh[$parser]['st'].='"'. $_xh[$parser]['ac'] . '"';
-				}
-				// This if() detects if no scalar was inside <VALUE></VALUE>
-				// and pads an empty ''.
-				if($_xh[$parser]['st'][strlen($_xh[$parser]['st'])-1] == '(')
-				{
-					$_xh[$parser]['st'].= '""';
-				}
-				// G. Giunta 2005/03/12 save some chars in the reconstruction of string vals...
-				if ($_xh[$parser]['vt'] != $xmlrpcString)
-					$_xh[$parser]['st'].=", '" . $_xh[$parser]['vt'] . "')";
-				else
-					$_xh[$parser]['st'].=")";
-				if ($_xh[$parser]['cm'])
-				{
-					$_xh[$parser]['st'].=',';
-				}*/
-
-				// build the xmlrpc val out of the data received, and substitute it
-				$temp = new xmlrpcval($_xh[$parser]['value'], $_xh[$parser]['vt']);
-				// check if we are inside an array or struct:
-				// if value just built is inside an array, let's move it into array on the stack
-				if (count($_xh[$parser]['valuestack']) && $_xh[$parser]['valuestack'][0]['type']=='ARRAY')
-				{
-					$_xh[$parser]['valuestack'][0]['values'][] = $temp;
-				}
-				else
-				{
-	    			$_xh[$parser]['value'] = $temp;
-				}
-				break;
-			case 'MEMBER':
-				$_xh[$parser]['ac']='';
-				//$_xh[$parser]['qt']=0;
-				// add to array in the stack the last element built
-				// unless no VALUE was found
-				if ($_xh[$parser]['value'])
-					$_xh[$parser]['valuestack'][0]['values'][$_xh[$parser]['valuestack'][0]['name']] = $_xh[$parser]['value'];
-				else
-					error_log('XML-RPC: missing VALUE inside STRUCT in received xml');
-				break;
-			case 'DATA':
-				$_xh[$parser]['ac']='';
-				//$_xh[$parser]['qt']=0;
-				break;
-			case 'PARAM':
-				//$_xh[$parser]['params'][]=$_xh[$parser]['st'];
-				if ($_xh[$parser]['value'])
-					$_xh[$parser]['params'][]=$_xh[$parser]['value'];
-				else
-					error_log('XML-RPC: missing VALUE inside PARAM in received xml');
-				break;
-			case 'METHODNAME':
-				$_xh[$parser]['method']=ereg_replace("^[\n\r\t ]+", '', $_xh[$parser]['ac']);
-				break;
-			case 'PARAMS':
-			case 'FAULT':
-			case 'METHODCALL':
-			case 'METHORESPONSE':
-				break;
-			default:
-				// End of INVALID ELEMENT!
-				// shall we add an assert here for unreachable code???
-				break;
+					// drop through intentionally if nil extension not enabled
+				case 'PARAMS':
+				case 'FAULT':
+				case 'METHODCALL':
+				case 'METHORESPONSE':
+					break;
+				default:
+					// End of INVALID ELEMENT!
+					// shall we add an assert here for unreachable code???
+					break;
+			}
 		}
-		// if it's a valid type name, set the type
-		/*if (isset($xmlrpcTypes[strtolower($name)]))
-		{
-			$_xh[$parser]['vt']=strtolower($name);
-		}*/
+	}
 
-		}
+	/// Used in decoding xmlrpc requests/responses without rebuilding xmlrpc values
+	function xmlrpc_ee_fast($parser, $name)
+	{
+		xmlrpc_ee($parser, $name, false);
 	}
 
+	/// xml parser handler function for character data
 	function xmlrpc_cd($parser, $data)
 	{
-		global $_xh, $xmlrpc_backslash;
-
-		//if (ereg("^[\n\r \t]+$", $data)) return;
-		// print "adding [${data}]\n";
-
 		// skip processing if xml fault already detected
-		if ($_xh[$parser]['isf'] < 2)
-		{
-		if ($_xh[$parser]['lv']!=3)
+		if ($GLOBALS['_xh']['isf'] < 2)
 		{
 			// "lookforvalue==3" means that we've found an entire value
 			// and should discard any further character data
-			if ($_xh[$parser]['lv']==1)
+			if($GLOBALS['_xh']['lv']!=3)
 			{
-				// if we've found text and we're just in a <value> then
-				// turn quoting on, as this will be a string
-					//$_xh[$parser]['qt']=1;
-				// and say we've found a value
-				$_xh[$parser]['lv']=2;
-			}
-			if(!@isset($_xh[$parser]['ac']))
-			{
-				$_xh[$parser]['ac'] = '';
-			}
-				//$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
-				$_xh[$parser]['ac'].=$data;
+				// G. Giunta 2006-08-23: useless change of 'lv' from 1 to 2
+				//if($GLOBALS['_xh']['lv']==1)
+				//{
+					// if we've found text and we're just in a <value> then
+					// say we've found a value
+					//$GLOBALS['_xh']['lv']=2;
+				//}
+				// we always initialize the accumulator before starting parsing, anyway...
+				//if(!@isset($GLOBALS['_xh']['ac']))
+				//{
+				//	$GLOBALS['_xh']['ac'] = '';
+				//}
+				$GLOBALS['_xh']['ac'].=$data;
 			}
 		}
 	}
 
+	/// xml parser handler function for 'other stuff', ie. not char data or
+	/// element start/end tag. In fact it only gets called on unknown entities...
 	function xmlrpc_dh($parser, $data)
 	{
-		global $_xh, $xmlrpc_backslash;
-
 		// skip processing if xml fault already detected
-		if ($parser[$_xh]['isf'] < 2)
-		{
-		if (substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
+		if ($GLOBALS['_xh']['isf'] < 2)
 		{
-			if ($_xh[$parser]['lv']==1)
+			if(substr($data, 0, 1) == '&' && substr($data, -1, 1) == ';')
 			{
-					//$_xh[$parser]['qt']=1;
-				$_xh[$parser]['lv']=2;
-			}
-				//$_xh[$parser]['ac'].=str_replace('$', '\$', str_replace('"', '\"', str_replace(chr(92),$xmlrpc_backslash, $data)));
-				$_xh[$parser]['ac'].=$data;
+				// G. Giunta 2006-08-25: useless change of 'lv' from 1 to 2
+				//if($GLOBALS['_xh']['lv']==1)
+				//{
+				//	$GLOBALS['_xh']['lv']=2;
+				//}
+				$GLOBALS['_xh']['ac'].=$data;
 			}
 		}
+		return true;
 	}
 
 	class xmlrpc_client
 	{
 		var $path;
 		var $server;
-		var $port;
+		var $port=0;
+		var $method='http';
 		var $errno;
 		var $errstr;
 		var $debug=0;
 		var $username='';
 		var $password='';
+		var $authtype=1;
 		var $cert='';
 		var $certpass='';
-		var $verifypeer=1;
+		var $cacert='';
+		var $cacertdir='';
+		var $key='';
+		var $keypass='';
+		var $verifypeer=true;
 		var $verifyhost=1;
 		var $no_multicall=false;
-
-		function xmlrpc_client($path, $server, $port=0)
-		{
-			$this->port=$port; $this->server=$server; $this->path=$path;
-		}
-
-		function setDebug($in)
-		{
-			if ($in)
+		var $proxy='';
+		var $proxyport=0;
+		var $proxy_user='';
+		var $proxy_pass='';
+		var $proxy_authtype=1;
+		var $cookies=array();
+		/**
+		* List of http compression methods accepted by the client for responses.
+		* NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
+		*
+		* NNB: you can set it to any non-empty array for HTTP11 and HTTPS, since
+		* in those cases it will be up to CURL to decide the compression methods
+		* it supports. You might check for the presence of 'zlib' in the output of
+		* curl_version() to determine wheter compression is supported or not
+		*/
+		var $accepted_compression = array();
+		/**
+		* Name of compression scheme to be used for sending requests.
+		* Either null, gzip or deflate
+		*/
+		var $request_compression = '';
+		/**
+		* CURL handle: used for keep-alive connections (PHP 4.3.8 up, see:
+		* http://curl.haxx.se/docs/faq.html#7.3)
+		*/
+		var $xmlrpc_curl_handle = null;
+		/// Wheter to use persistent connections for http 1.1 and https
+		var $keepalive = false;
+		/// Charset encodings that can be decoded without problems by the client
+		var $accepted_charset_encodings = array();
+		/// Charset encoding to be used in serializing request. NULL = use ASCII
+		var $request_charset_encoding = '';
+		/**
+		* Decides the content of xmlrpcresp objects returned by calls to send()
+		* valid strings are 'xmlrpcvals', 'phpvals' or 'xml'
+		*/
+		var $return_type = 'xmlrpcvals';
+
+		/**
+		* @param string $path either the complete server URL or the PATH part of the xmlrc server URL, e.g. /xmlrpc/server.php
+		* @param string $server the server name / ip address
+		* @param integer $port the port the server is listening on, defaults to 80 or 443 depending on protocol used
+		* @param string $method the http protocol variant: defaults to 'http', 'https' and 'http11' can be used if CURL is installed
+		*/
+		function xmlrpc_client($path, $server='', $port='', $method='')
+		{
+			// allow user to specify all params in $path
+			if($server == '' and $port == '' and $method == '')
+			{
+				$parts = parse_url($path);
+				$server = $parts['host'];
+				$path = $parts['path'];
+				if(isset($parts['query']))
+				{
+					$path .= '?'.$parts['query'];
+				}
+				if(isset($parts['fragment']))
+				{
+					$path .= '#'.$parts['fragment'];
+				}
+				if(isset($parts['port']))
+				{
+					$port = $parts['port'];
+				}
+				if(isset($parts['scheme']))
+				{
+					$method = $parts['scheme'];
+				}
+				if(isset($parts['user']))
+				{
+					$this->username = $parts['user'];
+				}
+				if(isset($parts['pass']))
+				{
+					$this->password = $parts['pass'];
+				}
+			}
+			if($path == '' || $path[0] != '/')
 			{
-				$this->debug=1;
+				$this->path='/'.$path;
 			}
 			else
 			{
-				$this->debug=0;
+				$this->path=$path;
 			}
+			$this->server=$server;
+			if($port != '')
+			{
+				$this->port=$port;
+			}
+			if($method != '')
+			{
+				$this->method=$method;
+			}
+
+			// if ZLIB is enabled, let the client by default accept compressed responses
+			if(function_exists('gzinflate') || (
+				function_exists('curl_init') && (($info = curl_version()) &&
+				((is_string($info) && strpos($info, 'zlib') !== null) || isset($info['libz_version'])))
+			))
+			{
+				$this->accepted_compression = array('gzip', 'deflate');
+			}
+
+			// keepalives: enabled by default ONLY for PHP >= 4.3.8
+			// (see http://curl.haxx.se/docs/faq.html#7.3)
+			if(version_compare(phpversion(), '4.3.8') >= 0)
+			{
+				$this->keepalive = true;
+			}
+
+			// by default the xml parser can support these 3 charset encodings
+			$this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
 		}
 
-		function setCredentials($u, $p)
+		/**
+		* Enables/disables the echoing to screen of the xmlrpc responses received
+		* @param integer $debug values 0, 1 and 2 are supported (2 = echo sent msg too, before received response)
+		* @access public
+		*/
+		function setDebug($in)
+		{
+			$this->debug=$in;
+		}
+
+		/**
+		* Add some http BASIC AUTH credentials, used by the client to authenticate
+		* @param string $u username
+		* @param string $p password
+		* @param integer $t auth type. See curl_setopt man page for supported auth types. Defaults to CURLAUTH_BASIC (basic auth)
+		* @access public
+		*/
+		function setCredentials($u, $p, $t=1)
 		{
 			$this->username=$u;
 			$this->password=$p;
+			$this->authtype=$t;
 		}
 
+		/**
+		* Add a client-side https certificate
+		* @param string $cert
+		* @param string $certpass
+		* @access public
+		*/
 		function setCertificate($cert, $certpass)
 		{
 			$this->cert = $cert;
 			$this->certpass = $certpass;
 		}
 
+		/**
+		* Add a CA certificate to verify server with (see man page about
+		* CURLOPT_CAINFO for more details
+		* @param string $cacert certificate file name (or dir holding certificates)
+		* @param bool $is_dir set to true to indicate cacert is a dir. defaults to false
+		* @access public
+		*/
+		function setCaCertificate($cacert, $is_dir=false)
+		{
+			if ($is_dir)
+			{
+				$this->cacert = $cacert;
+			}
+			else
+			{
+				$this->cacertdir = $cacert;
+			}
+		}
+
+		/**
+		* Set attributes for SSL communication: private SSL key
+		* @param string $key The name of a file containing a private SSL key
+		* @param string $keypass The secret password needed to use the private SSL key
+		* @access public
+		* NB: does not work in older php/curl installs
+		* Thanks to Daniel Convissor
+		*/
+		function setKey($key, $keypass)
+		{
+			$this->key = $key;
+			$this->keypass = $keypass;
+		}
+
+		/**
+		* Set attributes for SSL communication: verify server certificate
+		* @param bool $i enable/disable verification of peer certificate
+		* @access public
+		*/
 		function setSSLVerifyPeer($i)
 		{
 			$this->verifypeer = $i;
 		}
 
+		/**
+		* Set attributes for SSL communication: verify match of server cert w. hostname
+		* @param int $i
+		* @access public
+		*/
 		function setSSLVerifyHost($i)
 		{
 			$this->verifyhost = $i;
 		}
 
-		function send($msg, $timeout=0, $method='http')
+		/**
+		* Set proxy info
+		* @param string $proxyhost
+		* @param string $proxyport Defaults to 8080 for HTTP and 443 for HTTPS
+		* @param string $proxyusername Leave blank if proxy has public access
+		* @param string $proxypassword Leave blank if proxy has public access
+		* @param int $proxyauthtype set to constant CURLAUTH_NTLM to use NTLM auth with proxy
+		* @access public
+		*/
+		function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 1)
+		{
+			$this->proxy = $proxyhost;
+			$this->proxyport = $proxyport;
+			$this->proxy_user = $proxyusername;
+			$this->proxy_pass = $proxypassword;
+			$this->proxy_authtype = $proxyauthtype;
+		}
+
+		/**
+		* Enables/disables reception of compressed xmlrpc responses.
+		* Note that enabling reception of compressed responses merely adds some standard
+		* http headers to xmlrpc requests. It is up to the xmlrpc server to return
+		* compressed responses when receiving such requests.
+		* @param string $compmethod either 'gzip', 'deflate', 'any' or ''
+		* @access public
+		*/
+		function setAcceptedCompression($compmethod)
 		{
-			if (is_array($msg))
+			if ($compmethod == 'any')
+				$this->accepted_compression = array('gzip', 'deflate');
+			else
+				$this->accepted_compression = array($compmethod);
+		}
+
+		/**
+		* Enables/disables http compression of xmlrpc request.
+		* Take care when sending compressed requests: servers might not support them
+		* (and automatic fallback to uncompressed requests is not yet implemented)
+		* @param string $compmethod either 'gzip', 'deflate' or ''
+		* @access public
+		*/
+		function setRequestCompression($compmethod)
+		{
+			$this->request_compression = $compmethod;
+		}
+
+		/**
+		* Adds a cookie to list of cookies that will be sent to server.
+		* NB: setting any param but name and value will turn the cookie into a 'version 1' cookie:
+		* do not do it unless you know what you are doing
+		* @param string $name
+		* @param string $value
+		* @param string $path
+		* @param string $domain
+		* @param int $port
+		* @access public
+		*
+		* @todo check correctness of urlencoding cookie value (copied from php way of doing it...)
+		*/
+		function setCookie($name, $value='', $path='', $domain='', $port=null)
+		{
+			$this->cookies[$name]['value'] = urlencode($value);
+			if ($path || $domain || $port)
+			{
+				$this->cookies[$name]['path'] = $path;
+				$this->cookies[$name]['domain'] = $domain;
+				$this->cookies[$name]['port'] = $port;
+				$this->cookies[$name]['version'] = 1;
+			}
+			else
+			{
+				$this->cookies[$name]['version'] = 0;
+			}
+		}
+
+		/**
+		* Send an xmlrpc request
+		* @param mixed $msg The message object, or an array of messages for using multicall, or the complete xml representation of a request
+		* @param integer $timeout Connection timeout, in seconds, If unspecified, a platform specific timeout will apply
+		* @param string $method if left unspecified, the http protocol chosen during creation of the object will be used
+		* @return xmlrpcresp
+		* @access public
+		*/
+		function& send($msg, $timeout=0, $method='')
+		{
+			// if user deos not specify http protocol, use native method of this client
+			// (i.e. method set during call to constructor)
+			if($method == '')
+			{
+				$method = $this->method;
+			}
+
+			if(is_array($msg))
 			{
 				// $msg is an array of xmlrpcmsg's
-				return $this->multicall($msg, $timeout, $method);
+				$r = $this->multicall($msg, $timeout, $method);
+				return $r;
+			}
+			elseif(is_string($msg))
+			{
+				$n =& new xmlrpcmsg('');
+				$n->payload = $msg;
+				$msg = $n;
 			}
 
 			// where msg is an xmlrpcmsg
 			$msg->debug=$this->debug;
 
-			if ($method == 'https')
+			if($method == 'https')
 			{
-				return $this->sendPayloadHTTPS($msg,
-				$this->server,
-				$this->port, $timeout,
-				$this->username, $this->password,
-				$this->cert,
-				$this->certpass);
+				$r =& $this->sendPayloadHTTPS(
+					$msg,
+					$this->server,
+					$this->port,
+					$timeout,
+					$this->username,
+					$this->password,
+					$this->authtype,
+					$this->cert,
+					$this->certpass,
+					$this->cacert,
+					$this->cacertdir,
+					$this->proxy,
+					$this->proxyport,
+					$this->proxy_user,
+					$this->proxy_pass,
+					$this->proxy_authtype,
+					$this->keepalive,
+					$this->key,
+					$this->keypass
+				);
+			}
+			elseif($method == 'http11')
+			{
+				$r =& $this->sendPayloadCURL(
+					$msg,
+					$this->server,
+					$this->port,
+					$timeout,
+					$this->username,
+					$this->password,
+					$this->authtype,
+					null,
+					null,
+					null,
+					null,
+					$this->proxy,
+					$this->proxyport,
+					$this->proxy_user,
+					$this->proxy_pass,
+					$this->proxy_authtype,
+					'http',
+					$this->keepalive
+				);
 			}
 			else
 			{
-				return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
-				$timeout, $this->username, 
-				$this->password);
+				$r =& $this->sendPayloadHTTP10(
+					$msg,
+					$this->server,
+					$this->port,
+					$timeout,
+					$this->username,
+					$this->password,
+					$this->authtype,
+					$this->proxy,
+					$this->proxyport,
+					$this->proxy_user,
+					$this->proxy_pass,
+					$this->proxy_authtype
+				);
 			}
+
+			return $r;
 		}
 
-		function sendPayloadHTTP10($msg, $server, $port, $timeout=0,$username='', $password='')
+		/**
+		* @access private
+		*/
+		function &sendPayloadHTTP10($msg, $server, $port, $timeout=0,
+			$username='', $password='', $authtype=1, $proxyhost='',
+			$proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1)
 		{
-			global $xmlrpcerr, $xmlrpcstr, $xmlrpcName, $xmlrpcVersion, $xmlrpc_defencoding;
-			if ($port==0)
+			if($port==0)
 			{
 				$port=80;
 			}
-			if($timeout>0)
+
+			// Only create the payload if it was not created previously
+			if(empty($msg->payload))
 			{
-				$fp=@fsockopen($server, $port,$this->errno, $this->errstr, $timeout);
+				$msg->createPayload($this->request_charset_encoding);
 			}
-			else
+
+			$payload = $msg->payload;
+			// Deflate request body and set appropriate request headers
+			if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
 			{
-				$fp=@fsockopen($server, $port,$this->errno, $this->errstr);
+				if($this->request_compression == 'gzip')
+				{
+					$a = @gzencode($payload);
+					if($a)
+					{
+						$payload = $a;
+						$encoding_hdr = "Content-Encoding: gzip\r\n";
+					}
+				}
+				else
+				{
+					$a = @gzcompress($payload);
+					if($a)
+					{
+						$payload = $a;
+						$encoding_hdr = "Content-Encoding: deflate\r\n";
+					}
+				}
 			}
-			if ($fp)
+			else
 			{
-				if ($timeout>0 && function_exists('stream_set_timeout'))
-					stream_set_timeout($fp, $timeout);
+				$encoding_hdr = '';
 			}
-			else
+
+			// thanks to Grant Rauscher <grant7@firstworld.net> for this
+			$credentials='';
+			if($username!='')
 			{
-				$this->errstr='Connect error';
-				$r=new xmlrpcresp(0, $xmlrpcerr['http_error'],$xmlrpcstr['http_error']);
-				return $r;
+				$credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
+				if ($authtype != 1)
+				{
+					error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported with HTTP 1.0');
+				}
 			}
-			// Only create the payload if it was not created previously
-			if(empty($msg->payload))
+
+			$accepted_encoding = '';
+			if(is_array($this->accepted_compression) && count($this->accepted_compression))
 			{
-				$msg->createPayload();
+				$accepted_encoding = 'Accept-Encoding: ' . implode(', ', $this->accepted_compression) . "\r\n";
 			}
 
-			// thanks to Grant Rauscher <grant7@firstworld.net>
-			// for this
-			$credentials='';
-			if ($username!='')
+			$proxy_credentials = '';
+			if($proxyhost)
 			{
-				$credentials='Authorization: Basic ' . base64_encode($username . ':' . $password) . "\r\n";
+				if($proxyport == 0)
+				{
+					$proxyport = 8080;
+				}
+				$connectserver = $proxyhost;
+				$connectport = $proxyport;
+				$uri = 'http://'.$server.':'.$port.$this->path;
+				if($proxyusername != '')
+				{
+					if ($proxyauthtype != 1)
+					{
+						error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported with HTTP 1.0');
+					}
+					$proxy_credentials = 'Proxy-Authorization: Basic ' . base64_encode($proxyusername.':'.$proxypassword) . "\r\n";
+				}
+			}
+			else
+			{
+				$connectserver = $server;
+				$connectport = $port;
+				$uri = $this->path;
+			}
+
+			// Cookie generation, as per rfc2965 (version 1 cookies) or
+			// netscape's rules (version 0 cookies)
+			$cookieheader='';
+			foreach ($this->cookies as $name => $cookie)
+			{
+				if ($cookie['version'])
+				{
+					$cookieheader .= 'Cookie: $Version="' . $cookie['version'] . '"; ';
+					$cookieheader .= $name . '="' . $cookie['value'] . '";';
+					if ($cookie['path'])
+						$cookieheader .= ' $Path="' . $cookie['path'] . '";';
+					if ($cookie['domain'])
+						$cookieheader .= ' $Domain="' . $cookie['domain'] . '";';
+					if ($cookie['port'])
+						$cookieheader .= ' $Port="' . $cookie['domain'] . '";';
+					$cookieheader = substr($cookieheader, 0, -1) . "\r\n";
+				}
+				else
+				{
+					$cookieheader .= 'Cookie: ' . $name . '=' . $cookie['value'] . "\r\n";
+				}
 			}
 
-			$op= "POST " . $this->path. " HTTP/1.0\r\n" .
-				"User-Agent: " . $xmlrpcName . " " . $xmlrpcVersion . "\r\n" .
-				"Host: ". $server . "\r\n" .
-				$credentials . 
-				"Accept-Charset: " . $xmlrpc_defencoding . "\r\n" .
-				"Content-Type: text/xml\r\nContent-Length: " .
-				strlen($msg->payload) . "\r\n\r\n" .
-				$msg->payload;
+			$op= 'POST ' . $uri. " HTTP/1.0\r\n" .
+				'User-Agent: ' . $GLOBALS['xmlrpcName'] . ' ' . $GLOBALS['xmlrpcVersion'] . "\r\n" .
+				'Host: '. $server . ':' . $port . "\r\n" .
+				$credentials .
+				$proxy_credentials .
+				$accepted_encoding .
+				$encoding_hdr .
+				'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings) . "\r\n" .
+				$cookieheader .
+				'Content-Type: ' . $msg->content_type . "\r\nContent-Length: " .
+				strlen($payload) . "\r\n\r\n" .
+				$payload;
+
+			if($this->debug > 1)
+			{
+				print "<PRE>\n---SENDING---\n" . htmlentities($op) . "\n---END---\n</PRE>";
+				// let the client see this now in case http times out...
+				flush();
+			}
 
-			if (!fputs($fp, $op, strlen($op)))
+			if($timeout>0)
+			{
+				$fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr, $timeout);
+			}
+			else
+			{
+				$fp=@fsockopen($connectserver, $connectport, $this->errno, $this->errstr);
+			}
+			if($fp)
+			{
+				if($timeout>0 && function_exists('stream_set_timeout'))
+				{
+					stream_set_timeout($fp, $timeout);
+				}
+			}
+			else
+			{
+				$this->errstr='Connect error: '.$this->errstr;
+				$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr . ' (' . $this->errno . ')');
+				return $r;
+			}
+
+			if(!fputs($fp, $op, strlen($op)))
 			{
 				$this->errstr='Write error';
-				$r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']);
+				$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $this->errstr);
 				return $r;
 			}
-			$resp=$msg->parseResponseFile($fp);
+			else
+			{
+				// reset errno and errstr on succesful socket connection
+				$this->errstr = '';
+			}
+			// G. Giunta 2005/10/24: close socket before parsing.
+			// should yeld slightly better execution times, and make easier recursive calls (e.g. to follow http redirects)
+			$ipd='';
+			while($data=fread($fp, 32768))
+			{
+				// shall we check for $data === FALSE?
+				// as per the manual, it signals an error
+				$ipd.=$data;
+			}
 			fclose($fp);
-			return $resp;
+			$r =& $msg->parseResponse($ipd, false, $this->return_type);
+			return $r;
+
 		}
 
-		// contributed by Justin Miller <justin@voxel.net>
-		// requires curl to be built into PHP
-		function sendPayloadHTTPS($msg, $server, $port, $timeout=0,$username='', $password='', $cert='',$certpass='')
+		/**
+		* @access private
+		*/
+		function &sendPayloadHTTPS($msg, $server, $port, $timeout=0, $username='',
+			$password='', $authtype=1, $cert='',$certpass='', $cacert='', $cacertdir='',
+			$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1,
+			$keepalive=false, $key='', $keypass='')
+		{
+			$r =& $this->sendPayloadCURL($msg, $server, $port, $timeout, $username,
+				$password, $authtype, $cert, $certpass, $cacert, $cacertdir, $proxyhost, $proxyport,
+				$proxyusername, $proxypassword, $proxyauthtype, 'https', $keepalive, $key, $keypass);
+			return $r;
+		}
+
+		/**
+		* Contributed by Justin Miller <justin@voxel.net>
+		* Requires curl to be built into PHP
+		* NB: CURL versions before 7.11.10 cannot use proxy to talk to https servers!
+		* @access private
+		*/
+		function &sendPayloadCURL($msg, $server, $port, $timeout=0, $username='',
+			$password='', $authtype=1, $cert='', $certpass='', $cacert='', $cacertdir='',
+			$proxyhost='', $proxyport=0, $proxyusername='', $proxypassword='', $proxyauthtype=1, $method='https',
+			$keepalive=false, $key='', $keypass='')
 		{
-			global $xmlrpcerr, $xmlrpcstr, $xmlrpcVersion, $xmlrpc_internalencoding;
-			if ($port == 0)
+			if(!function_exists('curl_init'))
+			{
+				$this->errstr='CURL unavailable on this install';
+				$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_curl'], $GLOBALS['xmlrpcstr']['no_curl']);
+				return $r;
+			}
+			if($method == 'https')
 			{
-				$port = 443;
+				if(($info = curl_version()) &&
+					((is_string($info) && strpos($info, 'OpenSSL') === null) || (is_array($info) && !isset($info['ssl_version']))))
+				{
+					$this->errstr='SSL unavailable on this install';
+					$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_ssl'], $GLOBALS['xmlrpcstr']['no_ssl']);
+					return $r;
+				}
+			}
+
+			if($port == 0)
+			{
+				if($method == 'http')
+				{
+					$port = 80;
+				}
+				else
+				{
+					$port = 443;
+				}
 			}
 
 			// Only create the payload if it was not created previously
 			if(empty($msg->payload))
 			{
-				$msg->createPayload();
+				$msg->createPayload($this->request_charset_encoding);
 			}
 
-			if (!function_exists('curl_init'))
+			// Deflate request body and set appropriate request headers
+			$payload = $msg->payload;
+			if(function_exists('gzdeflate') && ($this->request_compression == 'gzip' || $this->request_compression == 'deflate'))
 			{
-				$this->errstr='SSL unavailable on this install';
-				$r=new xmlrpcresp(0, $xmlrpcerr['no_ssl'], $xmlrpcstr['no_ssl']);
-				return $r;
+				if($this->request_compression == 'gzip')
+				{
+					$a = @gzencode($payload);
+					if($a)
+					{
+						$payload = $a;
+						$encoding_hdr = 'Content-Encoding: gzip';
+					}
+				}
+				else
+				{
+					$a = @gzcompress($payload);
+					if($a)
+					{
+						$payload = $a;
+						$encoding_hdr = 'Content-Encoding: deflate';
+					}
+				}
+			}
+			else
+			{
+				$encoding_hdr = '';
 			}
 
-			$curl = curl_init('https://' . $server . ':' . $port . $this->path);
+			if($this->debug > 1)
+			{
+				print "<PRE>\n---SENDING---\n" . htmlentities($payload) . "\n---END---\n</PRE>";
+				// let the client see this now in case http times out...
+				flush();
+			}
+
+			if(!$keepalive || !$this->xmlrpc_curl_handle)
+			{
+				$curl = curl_init($method . '://' . $server . ':' . $port . $this->path);
+				if($keepalive)
+				{
+					$this->xmlrpc_curl_handle = $curl;
+				}
+			}
+			else
+			{
+				$curl = $this->xmlrpc_curl_handle;
+			}
 
-			curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 			// results into variable
-			if ($this->debug)
+			curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+
+			if($this->debug)
 			{
 				curl_setopt($curl, CURLOPT_VERBOSE, 1);
 			}
-			curl_setopt($curl, CURLOPT_USERAGENT, 'PHP XMLRPC '.$xmlrpcVersion);
-			// required for XMLRPC
+			curl_setopt($curl, CURLOPT_USERAGENT, $GLOBALS['xmlrpcName'].' '.$GLOBALS['xmlrpcVersion']);
+			// required for XMLRPC: post the data
 			curl_setopt($curl, CURLOPT_POST, 1);
-			// post the data
-			curl_setopt($curl, CURLOPT_POSTFIELDS, $msg->payload);
 			// the data
-			curl_setopt($curl, CURLOPT_HEADER, 1);
+			curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
+
 			// return the header too
-			curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: text/xml', 'Accept-Charset: '.$xmlrpc_internalencoding));
-			// whether to verify remote host's cert
-			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
-			// whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used
-			curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
-			// required for XMLRPC
-			if ($timeout)
+			curl_setopt($curl, CURLOPT_HEADER, 1);
+
+			// will only work with PHP >= 5.0
+			// NB: if we set an empty string, CURL will add http header indicating
+			// ALL methods it is supporting. This is possibly a better option than
+			// letting the user tell what curl can / cannot do...
+			if(is_array($this->accepted_compression) && count($this->accepted_compression))
+			{
+				//curl_setopt($curl, CURLOPT_ENCODING, implode(',', $this->accepted_compression));
+				// empty string means 'any supported by CURL' (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
+				if (count($this->accepted_compression) == 1)
+				{
+					curl_setopt($curl, CURLOPT_ENCODING, $this->accepted_compression[0]);
+				}
+				else
+					curl_setopt($curl, CURLOPT_ENCODING, '');
+			}
+			// extra headers
+			$headers = array('Content-Type: ' . $msg->content_type , 'Accept-Charset: ' . implode(',', $this->accepted_charset_encodings));
+			// if no keepalive is wanted, let the server know it in advance
+			if(!$keepalive)
+			{
+				$headers[] = 'Connection: close';
+			}
+			// request compression header
+			if($encoding_hdr)
+			{
+				$headers[] = $encoding_hdr;
+			}
+
+			curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+			// timeout is borked
+			if($timeout)
 			{
 				curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
 			}
-			// timeout is borked
-			if ($username && $password)
+
+			if($username && $password)
+			{
+				curl_setopt($curl, CURLOPT_USERPWD, $username.':'.$password);
+				if (defined('CURLOPT_HTTPAUTH'))
+				{
+					curl_setopt($curl, CURLOPT_HTTPAUTH, $authtype);
+				}
+				else if ($authtype != 1)
+				{
+					error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth is supported by the current PHP/curl install');
+				}
+			}
+
+			if($method == 'https')
 			{
-				curl_setopt($curl, CURLOPT_USERPWD,"$username:$password");
+				// set cert file
+				if($cert)
+				{
+					curl_setopt($curl, CURLOPT_SSLCERT, $cert);
+				}
+				// set cert password
+				if($certpass)
+				{
+					curl_setopt($curl, CURLOPT_SSLCERTPASSWD, $certpass);
+				}
+				// whether to verify remote host's cert
+				curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verifypeer);
+				// set ca certificates file/dir
+				if($cacert)
+				{
+					curl_setopt($curl, CURLOPT_CAINFO, $cacert);
+				}
+				if($cacertdir)
+				{
+					curl_setopt($curl, CURLOPT_CAPATH, $cacertdir);
+				}
+				// set key file (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
+				if($key)
+				{
+					curl_setopt($curl, CURLOPT_SSLKEY, $key);
+				}
+				// set key password (shall we catch errors in case CURLOPT_SSLKEY undefined ?)
+				if($keypass)
+				{
+					curl_setopt($curl, CURLOPT_SSLKEYPASSWD, $keypass);
+				}
+				// whether to verify cert's common name (CN); 0 for no, 1 to verify that it exists, and 2 to verify that it matches the hostname used
+				curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $this->verifyhost);
 			}
-			// set auth stuff
-			if ($cert)
+
+			// proxy info
+			if($proxyhost)
 			{
-				curl_setopt($curl, CURLOPT_SSLCERT, $cert);
+				if($proxyport == 0)
+				{
+					$proxyport = 8080; // NB: even for HTTPS, local connection is on port 8080
+				}
+				curl_setopt($curl, CURLOPT_PROXY,$proxyhost.':'.$proxyport);
+				//curl_setopt($curl, CURLOPT_PROXYPORT,$proxyport);
+				if($proxyusername)
+				{
+					curl_setopt($curl, CURLOPT_PROXYUSERPWD, $proxyusername.':'.$proxypassword);
+					if (defined('CURLOPT_PROXYAUTH'))
+					{
+						curl_setopt($curl, CURLOPT_PROXYAUTH, $proxyauthtype);
+					}
+					else if ($proxyauthtype != 1)
+					{
+						error_log('XML-RPC: xmlrpc_client::send: warning. Only Basic auth to proxy is supported by the current PHP/curl install');
+					}
+				}
 			}
-			// set cert file
-			if ($certpass)
+
+			// NB: should we build cookie http headers by hand rather than let CURL do it?
+			// the following code does not honour 'expires', 'path' and 'domain' cookie attributes
+			// set to clint obj the the user...
+			if (count($this->cookies))
 			{
-				curl_setopt($curl, CURLOPT_SSLCERTPASSWD,$certpass);
+				$cookieheader = '';
+				foreach ($this->cookies as $name => $cookie)
+				{
+					$cookieheader .= $name . '=' . $cookie['value'] . ', ';
+				}
+				curl_setopt($curl, CURLOPT_COOKIE, substr($cookieheader, 0, -2));
 			}
-			// set cert password
 
 			$result = curl_exec($curl);
 
-			if (!$result)
+			if(!$result)
 			{
 				$this->errstr='no response';
-				$resp=new xmlrpcresp(0, $xmlrpcerr['curl_fail'], $xmlrpcstr['curl_fail']. ': '. curl_error($curl));
-				curl_close($curl);
+				$resp=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['curl_fail'], $GLOBALS['xmlrpcstr']['curl_fail']. ': '. curl_error($curl));
+				if(!$keepalive)
+				{
+					curl_close($curl);
+				}
 			}
 			else
 			{
-				curl_close($curl);
-				$resp = $msg->parseResponse($result);
+				if(!$keepalive)
+				{
+					curl_close($curl);
+				}
+				$resp =& $msg->parseResponse($result, true, $this->return_type);
 			}
 			return $resp;
 		}
 
-		function multicall($msgs, $timeout=0, $method='http')
+		/**
+		* Send an array of request messages and return an array of responses.
+		* Unless $this->no_multicall has been set to true, it will try first
+		* to use one single xmlrpc call to server method system.multicall, and
+		* revert to sending many successive calls in case of failure.
+		* This failure is also stored in $this->no_multicall for subsequent calls.
+		* Unfortunately, there is no server error code universally used to denote
+		* the fact that multicall is unsupported, so there is no way to reliably
+		* distinguish between that and a temporary failure.
+		* If you are sure that server supports multicall and do not want to
+		* fallback to using many single calls, set the fourth parameter to FALSE.
+		*
+		* NB: trying to shoehorn extra functionality into existing syntax has resulted
+		* in pretty much convoluted code...
+		*
+		* @param array $msgs an array of xmlrpcmsg objects
+		* @param integer $timeout connection timeout (in seconds)
+		* @param string $method the http protocol variant to be used
+		* @param boolean fallback When true, upon receiveing an error during multicall, multiple single calls will be attempted
+		* @return array
+		* @access public
+		*/
+		function multicall($msgs, $timeout=0, $method='', $fallback=true)
 		{
-			$results = false;
-
-			if (! $this->no_multicall)
+			if ($method == '')
+			{
+				$method = $this->method;
+			}
+			if(!$this->no_multicall)
 			{
 				$results = $this->_try_multicall($msgs, $timeout, $method);
-				/* TODO - this is not php3-friendly */
-				// if($results !== false)
 				if(is_array($results))
 				{
-					// Either the system.multicall succeeded, or the send
-					// failed (e.g. due to HTTP timeout). In either case,
-					// we're done for now.
+					// System.multicall succeeded
 					return $results;
 				}
 				else
 				{
-					// system.multicall unsupported by server,
-					// don't try it next time...
-					$this->no_multicall = true;
+					// either system.multicall is unsupported by server,
+					// or call failed for some other reason.
+					if ($fallback)
+					{
+						// Don't try it next time...
+						$this->no_multicall = true;
+					}
+					else
+					{
+						if (is_a($results, 'xmlrpcresp'))
+						{
+							$result = $results;
+						}
+						else
+						{
+							$result =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['multicall_error'], $GLOBALS['xmlrpcstr']['multicall_error']);
+						}
+					}
 				}
 			}
+			else
+			{
+				// override fallback, in case careless user tries to do two
+				// opposite things at the same time
+				$fallback = true;
+			}
 
-			// system.multicall is unupported by server:
-			//   Emulate multicall via multiple requests
 			$results = array();
-			//foreach($msgs as $msg)
-			@reset($msgs);
-			while(list(,$msg) = @each($msgs))
+			if ($fallback)
+			{
+				// system.multicall is (probably) unsupported by server:
+				// emulate multicall via multiple requests
+				foreach($msgs as $msg)
+				{
+					$results[] =& $this->send($msg, $timeout, $method);
+				}
+			}
+			else
 			{
-				$results[] = $this->send($msg, $timeout, $method);
+				// user does NOT want to fallback on many single calls:
+				// since we should always return an array of responses,
+				// return an array with the same error repeated n times
+				foreach($msgs as $msg)
+				{
+					$results[] = $result;
+				}
 			}
 			return $results;
 		}
 
-		// Attempt to boxcar $msgs via system.multicall.
+		/**
+		* Attempt to boxcar $msgs via system.multicall.
+		* Returns either an array of xmlrpcreponses, an xmlrpc error response
+		* or false (when received response does not respect valid multicall syntax)
+		* @access private
+		*/
 		function _try_multicall($msgs, $timeout, $method)
 		{
 			// Construct multicall message
 			$calls = array();
-			//foreach($msgs as $msg)
-			@reset($msgs);
-			while(list(,$msg) = @each($msgs))
+			foreach($msgs as $msg)
 			{
-				$call['methodName'] = new xmlrpcval($msg->method(),'string');
+				$call['methodName'] =& new xmlrpcval($msg->method(),'string');
 				$numParams = $msg->getNumParams();
 				$params = array();
-				for ($i = 0; $i < $numParams; $i++)
+				for($i = 0; $i < $numParams; $i++)
 				{
 					$params[$i] = $msg->getParam($i);
 				}
-				$call['params'] = new xmlrpcval($params, 'array');
-				$calls[] = new xmlrpcval($call, 'struct');
+				$call['params'] =& new xmlrpcval($params, 'array');
+				$calls[] =& new xmlrpcval($call, 'struct');
 			}
-			$multicall = new xmlrpcmsg('system.multicall');
+			$multicall =& new xmlrpcmsg('system.multicall');
 			$multicall->addParam(new xmlrpcval($calls, 'array'));
 
 			// Attempt RPC call
-			$result = $this->send($multicall, $timeout, $method);
-			if(!is_object($result))
-			{
-				return ($result || 0); // transport failed
-			}
+			$result =& $this->send($multicall, $timeout, $method);
 
 			if($result->faultCode() != 0)
 			{
-				return false;		// system.multicall failed
+				// call to system.multicall failed
+				return $result;
 			}
 
 			// Unpack responses.
 			$rets = $result->value();
-			if($rets->kindOf() != 'array')
+
+			if ($this->return_type == 'xml')
 			{
-				return false;		// bad return type from system.multicall
+					return $rets;
 			}
-			$numRets = $rets->arraysize();
-			if($numRets != count($msgs))
+			else if ($this->return_type == 'phpvals')
 			{
-				return false;		// wrong number of return values.
-			}
+				///@todo test this code branch...
+				$rets = $result->value();
+				if(!is_array($rets))
+				{
+					return false;		// bad return type from system.multicall
+				}
+				$numRets = count($rets);
+				if($numRets != count($msgs))
+				{
+					return false;		// wrong number of return values.
+				}
 
-			$response = array();
-			for ($i = 0; $i < $numRets; $i++)
-			{
-				$val = $rets->arraymem($i);
-				switch ($val->kindOf())
+				$response = array();
+				for($i = 0; $i < $numRets; $i++)
 				{
-				case 'array':
-					if($val->arraysize() != 1)
-					{
-						return false;		// Bad value
+					$val = $rets[$i];
+					if (!is_array($val)) {
+						return false;
 					}
-					// Normal return value
-					$response[$i] = new xmlrpcresp($val->arraymem(0));
-					break;
-				case 'struct':
-					$code = $val->structmem('faultCode');
-					if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
+					switch(count($val))
 					{
-						return false;
+						case 1:
+							if(!isset($val[0]))
+							{
+								return false;		// Bad value
+							}
+							// Normal return value
+							$response[$i] =& new xmlrpcresp($val[0], 0, '', 'phpvals');
+							break;
+						case 2:
+							///	@todo remove usage of @: it is apparently quite slow
+							$code = @$val['faultCode'];
+							if(!is_int($code))
+							{
+								return false;
+							}
+							$str = @$val['faultString'];
+							if(!is_string($str))
+							{
+								return false;
+							}
+							$response[$i] =& new xmlrpcresp(0, $code, $str);
+							break;
+						default:
+							return false;
 					}
-					$str = $val->structmem('faultString');
-					if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
+				}
+				return $response;
+			}
+			else // return type == 'xmlrpcvals'
+			{
+				$rets = $result->value();
+				if($rets->kindOf() != 'array')
+				{
+					return false;		// bad return type from system.multicall
+				}
+				$numRets = $rets->arraysize();
+				if($numRets != count($msgs))
+				{
+					return false;		// wrong number of return values.
+				}
+
+				$response = array();
+				for($i = 0; $i < $numRets; $i++)
+				{
+					$val = $rets->arraymem($i);
+					switch($val->kindOf())
 					{
-						return false;
+						case 'array':
+							if($val->arraysize() != 1)
+							{
+								return false;		// Bad value
+							}
+							// Normal return value
+							$response[$i] =& new xmlrpcresp($val->arraymem(0));
+							break;
+						case 'struct':
+							$code = $val->structmem('faultCode');
+							if($code->kindOf() != 'scalar' || $code->scalartyp() != 'int')
+							{
+								return false;
+							}
+							$str = $val->structmem('faultString');
+							if($str->kindOf() != 'scalar' || $str->scalartyp() != 'string')
+							{
+								return false;
+							}
+							$response[$i] =& new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
+							break;
+						default:
+							return false;
 					}
-					$response[$i] = new xmlrpcresp(0, $code->scalarval(), $str->scalarval());
-					break;
-				default:
-					return false;
 				}
+				return $response;
 			}
-			return $response;
 		}
 	} // end class xmlrpc_client
 
 	class xmlrpcresp
 	{
 		var $val = 0;
+		var $valtyp;
 		var $errno = 0;
 		var $errstr = '';
+		var $payload;
 		var $hdrs = array();
-
-		function xmlrpcresp($val, $fcode = 0, $fstr = '')
+		var $_cookies = array();
+		var $content_type = 'text/xml';
+		var $raw_data = '';
+
+		/**
+		* @param mixed $val either an xmlrpcval obj, a php value or the xml serialization of an xmlrpcval (a string)
+		* @param integer $fcode set it to anything but 0 to create an error response
+		* @param string $fstr the error string, in case of an error response
+		* @param string $valtyp either 'xmlrpcvals', 'phpvals' or 'xml'
+		*
+		* @todo add check that $val / $fcode / $fstr is of correct type???
+		* NB: as of now we do not do it, since it might be either an xmlrpcval or a plain
+		* php val, or a complete xml chunk, depending on usage of xmlrpc_client::send() inside which creator is called...
+		*/
+		function xmlrpcresp($val, $fcode = 0, $fstr = '', $valtyp='')
 		{
-			if ($fcode != 0)
+			if($fcode != 0)
 			{
-				// error
+				// error response
 				$this->errno = $fcode;
 				$this->errstr = $fstr;
 				//$this->errstr = htmlspecialchars($fstr); // XXX: encoding probably shouldn't be done here; fix later.
 			}
-			elseif (!is_object($val))
-			{
-				// programmer error
-				error_log("Invalid type '" . gettype($val) . "' (value: $val) passed to xmlrpcresp. Defaulting to empty value.");
-				$this->val = new xmlrpcval();
-			}
 			else
 			{
-				// success
+				// successful response
 				$this->val = $val;
+				if ($valtyp == '')
+				{
+					// user did not declare type of response value: try to guess it
+					if (is_object($this->val) && is_a($this->val, 'xmlrpcval'))
+					{
+						$this->valtyp = 'xmlrpcvals';
+					}
+					else if (is_string($this->val))
+					{
+						$this->valtyp = 'xml';
+
+					}
+					else
+					{
+						$this->valtyp = 'phpvals';
+					}
+				}
+				else
+				{
+					// user declares type of resp value: believe him
+					$this->valtyp = $valtyp;
+				}
 			}
 		}
 
+		/**
+		* Returns the error code of the response.
+		* @return integer the error code of this response (0 for not-error responses)
+		* @access public
+		*/
 		function faultCode()
 		{
 			return $this->errno;
 		}
 
+		/**
+		* Returns the error code of the response.
+		* @return string the error string of this response ('' for not-error responses)
+		* @access public
+		*/
 		function faultString()
 		{
 			return $this->errstr;
 		}
 
+		/**
+		* Returns the value received by the server.
+		* @return mixed the xmlrpcval object returned by the server. Might be an xml string or php value if the response has been created by specially configured xmlrpc_client objects
+		* @access public
+		*/
 		function value()
 		{
 			return $this->val;
 		}
 
-		function serialize()
+		/**
+		* Returns an array with the cookies received from the server.
+		* Array has the form: $cookiename => array ('value' => $val, $attr1 => $val1, $attr2 = $val2, ...)
+		* with attributes being e.g. 'expires', 'path', domain'.
+		* NB: cookies sent as 'expired' by the server (i.e. with an expiry date in the past)
+		* are still present in the array. It is up to the user-defined code to decide
+		* how to use the received cookies, and wheter they have to be sent back with the next
+		* request to the server (using xmlrpc_client::setCookie) or not
+		* @return array array of cookies received from the server
+		* @access public
+		*/
+		function cookies()
+		{
+			return $this->_cookies;
+		}
+
+		/**
+		* Returns xml representation of the response. XML prologue not included
+		* @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
+		* @return string the xml representation of the response
+		* @access public
+		*/
+		function serialize($charset_encoding='')
 		{
+			if ($charset_encoding != '')
+				$this->content_type = 'text/xml; charset=' . $charset_encoding;
+			else
+				$this->content_type = 'text/xml';
 			$result = "<methodResponse>\n";
-			if ($this->errno)
+			if($this->errno)
 			{
 				// G. Giunta 2005/2/13: let non-ASCII response messages be tolerated by clients
-				$result .= '<fault>
-<value>
-<struct>
-<member>
-<name>faultCode</name>
-<value><int>' . $this->errno . '</int></value>
-</member>
-<member>
-<name>faultString</name>
-<value><string>' . xmlrpc_encode_entitites($this->errstr) . '</string></value>
-</member>
-</struct>
-</value>
-</fault>';
+				// by xml-encoding non ascii chars
+				$result .= "<fault>\n" .
+"<value>\n<struct><member><name>faultCode</name>\n<value><int>" . $this->errno .
+"</int></value>\n</member>\n<member>\n<name>faultString</name>\n<value><string>" .
+xmlrpc_encode_entitites($this->errstr, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "</string></value>\n</member>\n" .
+"</struct>\n</value>\n</fault>";
 			}
 			else
 			{
-				$result .= "<params>\n<param>\n" .
-					$this->val->serialize() . 
-					"</param>\n</params>";
+				if(!is_object($this->val) || !is_a($this->val, 'xmlrpcval'))
+				{
+					if (is_string($this->val) && $this->valtyp == 'xml')
+					{
+						$result .= "<params>\n<param>\n" .
+							$this->val .
+							"</param>\n</params>";
+					}
+					else
+					{
+						/// @todo try to build something serializable?
+						die('cannot serialize xmlrpcresp objects whose content is native php values');
+					}
+				}
+				else
+				{
+					$result .= "<params>\n<param>\n" .
+						$this->val->serialize($charset_encoding) .
+						"</param>\n</params>";
+				}
 			}
 			$result .= "\n</methodResponse>";
+			$this->payload = $result;
 			return $result;
 		}
 	}
@@ -1359,218 +2032,514 @@
 		var $methodname;
 		var $params=array();
 		var $debug=0;
+		var $content_type = 'text/xml';
 
+		/**
+		* @param string $meth the name of the method to invoke
+		* @param array $pars array of parameters to be paased to the method (xmlrpcval objects)
+		*/
 		function xmlrpcmsg($meth, $pars=0)
 		{
 			$this->methodname=$meth;
-			if (is_array($pars) && sizeof($pars)>0)
+			if(is_array($pars) && count($pars)>0)
 			{
-				for($i=0; $i<sizeof($pars); $i++)
+				for($i=0; $i<count($pars); $i++)
 				{
 					$this->addParam($pars[$i]);
 				}
 			}
 		}
 
-		function xml_header()
+		/**
+		* @access private
+		*/
+		function xml_header($charset_encoding='')
 		{
-			return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
+			if ($charset_encoding != '')
+			{
+				return "<?xml version=\"1.0\" encoding=\"$charset_encoding\" ?" . ">\n<methodCall>\n";
+			}
+			else
+			{
+				return "<?xml version=\"1.0\"?" . ">\n<methodCall>\n";
+			}
 		}
 
+		/**
+		* @access private
+		*/
 		function xml_footer()
 		{
-			return "</methodCall>\n";
+			return '</methodCall>';
+		}
+
+		/**
+		* @access private
+		*/
+		function kindOf()
+		{
+			return 'msg';
 		}
 
-		function createPayload()
+		/**
+		* @access private
+		*/
+		function createPayload($charset_encoding='')
 		{
-			$this->payload=$this->xml_header();
+			if ($charset_encoding != '')
+				$this->content_type = 'text/xml; charset=' . $charset_encoding;
+			else
+				$this->content_type = 'text/xml';
+			$this->payload=$this->xml_header($charset_encoding);
 			$this->payload.='<methodName>' . $this->methodname . "</methodName>\n";
-			//	if (sizeof($this->params)) {
 			$this->payload.="<params>\n";
-			for($i=0; $i<sizeof($this->params); $i++)
+			for($i=0; $i<count($this->params); $i++)
 			{
 				$p=$this->params[$i];
-				$this->payload.="<param>\n" . $p->serialize() .
+				$this->payload.="<param>\n" . $p->serialize($charset_encoding) .
 				"</param>\n";
 			}
 			$this->payload.="</params>\n";
-			// }
 			$this->payload.=$this->xml_footer();
-			//$this->payload=str_replace("\n", "\r\n", $this->payload);
 		}
 
+		/**
+		* Gets/sets the xmlrpc method to be invoked
+		* @param string $meth the method to be set (leave empty not to set it)
+		* @return string the method that will be invoked
+		* @access public
+		*/
 		function method($meth='')
 		{
-			if ($meth!='')
+			if($meth!='')
 			{
 				$this->methodname=$meth;
 			}
 			return $this->methodname;
 		}
 
-		function serialize()
+		/**
+		* Returns xml representation of the message. XML prologue included
+		* @return string the xml representation of the message, xml prologue included
+		* @access public
+		*/
+		function serialize($charset_encoding='')
 		{
-			$this->createPayload();
+			$this->createPayload($charset_encoding);
 			return $this->payload;
 		}
 
-		function addParam($par) { $this->params[]=$par; }
+		/**
+		* Add a parameter to the list of parameters to be used upon method invocation
+		* @param xmlrpcval $par
+		* @return boolean false on failure
+		* @access public
+		*/
+		function addParam($par)
+		{
+			// add check: do not add to self params which are not xmlrpcvals
+			if(is_object($par) && is_a($par, 'xmlrpcval'))
+			{
+				$this->params[]=$par;
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		/**
+		* Returns the nth parameter in the message. The index zero-based.
+		* @param integer $i the index of the parameter to fetch (zero based)
+		* @return xmlrpcval the i-th parameter
+		* @access public
+		*/
 		function getParam($i) { return $this->params[$i]; }
-		function getNumParams() { return sizeof($this->params); }
 
-		function parseResponseFile($fp)
+		/**
+		* Returns the number of parameters in the messge.
+		* @return integer the number of parameters currently set
+		* @access public
+		*/
+		function getNumParams() { return count($this->params); }
+
+		/**
+		* Given an open file handle, read all data available and parse it as axmlrpc response.
+		* NB: the file handle is not closed by this function.
+		* @access public
+		* @return xmlrpcresp
+		* @todo add 2nd & 3rd param to be passed to ParseResponse() ???
+		*/
+		function &parseResponseFile($fp)
 		{
 			$ipd='';
 			while($data=fread($fp, 32768))
 			{
 				$ipd.=$data;
 			}
-			return $this->parseResponse($ipd);
+			//fclose($fp);
+			$r =& $this->parseResponse($ipd);
+			return $r;
 		}
 
-		function parseResponse($data='')
-		{
-			global $_xh,$xmlrpcerr,$xmlrpcstr;
-			global $xmlrpc_defencoding, $xmlrpc_internalencoding;
-
-			$hdrfnd = 0;
-			if($this->debug)
-			{
-				//by maHo, replaced htmlspecialchars with htmlentities
-				print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
-			}
+		/**
+		* Parses HTTP headers and separates them from data.
+		* @access private
+		*/
+		function &parseResponseHeaders(&$data, $headers_processed=false)
+		{
+				// Support "web-proxy-tunelling" connections for https through proxies
+				if(preg_match('/^HTTP\/1\.[0-1] 200 Connection established/', $data))
+				{
+					// Look for CR/LF or simple LF as line separator,
+					// (even though it is not valid http)
+					$pos = strpos($data,"\r\n\r\n");
+					if($pos || is_int($pos))
+					{
+						$bd = $pos+4;
+					}
+					else
+					{
+						$pos = strpos($data,"\n\n");
+						if($pos || is_int($pos))
+						{
+							$bd = $pos+2;
+						}
+						else
+						{
+							// No separation between response headers and body: fault?
+							$bd = 0;
+						}
+					}
+					if ($bd)
+					{
+						// this filters out all http headers from proxy.
+						// maybe we could take them into account, too?
+						$data = substr($data, $bd);
+					}
+					else
+					{
+						error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTPS via proxy error, tunnel connection possibly failed');
+						$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (HTTPS via proxy error, tunnel connection possibly failed)');
+						return $r;
+					}
+				}
 
-			if($data == '')
-			{
-				error_log('No response received from server.');
-				$r = new xmlrpcresp(0, $xmlrpcerr['no_data'], $xmlrpcstr['no_data']);
-				return $r;
-			}
-			// see if we got an HTTP 200 OK, else bomb
-			// but only do this if we're using the HTTP protocol.
-			if(ereg("^HTTP",$data))
-			{
 				// Strip HTTP 1.1 100 Continue header if present
-				while (ereg('^HTTP/1.1 1[0-9]{2}', $data))
+				while(preg_match('/^HTTP\/1\.1 1[0-9]{2} /', $data))
 				{
 					$pos = strpos($data, 'HTTP', 12);
 					// server sent a Continue header without any (valid) content following...
 					// give the client a chance to know it
-					if (!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
+					if(!$pos && !is_int($pos)) // works fine in php 3, 4 and 5
+					{
 						break;
+					}
 					$data = substr($data, $pos);
 				}
-				if (!ereg("^HTTP/[0-9\\.]+ 200 ", $data))
+				if(!preg_match('/^HTTP\/[0-9.]+ 200 /', $data))
 				{
 					$errstr= substr($data, 0, strpos($data, "\n")-1);
-					error_log('HTTP error, got response: ' .$errstr);
-					$r=new xmlrpcresp(0, $xmlrpcerr['http_error'], $xmlrpcstr['http_error']. ' (' . $errstr . ')');
+					error_log('XML-RPC: xmlrpcmsg::parseResponse: HTTP error, got response: ' .$errstr);
+					$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['http_error'], $GLOBALS['xmlrpcstr']['http_error']. ' (' . $errstr . ')');
 					return $r;
 				}
-			}
-			$parser = xml_parser_create($xmlrpc_defencoding);
 
-			// G. Giunta 2004/04/06
-			// Clean up the accumulator, or it will grow indefinitely long
-			// if making xmlrpc calls for a while
-			$_xh=array();
-			$_xh[$parser]=array();
-			$_xh[$parser]['headers'] = array();
-			$_xh[$parser]['stack'] = array();
-			$_xh[$parser]['valuestack'] = array();
+				$GLOBALS['_xh']['headers'] = array();
+				$GLOBALS['_xh']['cookies'] = array();
 
-			// separate HTTP headers from data
-			if (ereg("^HTTP", $data))
-			{
 				// be tolerant to usage of \n instead of \r\n to separate headers and data
 				// (even though it is not valid http)
 				$pos = strpos($data,"\r\n\r\n");
 				if($pos || is_int($pos))
+				{
 					$bd = $pos+4;
+				}
 				else
 				{
 					$pos = strpos($data,"\n\n");
 					if($pos || is_int($pos))
+					{
 						$bd = $pos+2;
+					}
 					else
 					{
 						// No separation between response headers and body: fault?
+						// we could take some action here instead of going on...
 						$bd = 0;
 					}
 				}
 				// be tolerant to line endings, and extra empty lines
 				$ar = split("\r?\n", trim(substr($data, 0, $pos)));
-				while (list(,$line) = @each($ar))
+				while(list(,$line) = @each($ar))
 				{
-					// take care of multi-line headers
-					$arr = explode(':',$line);
+					// take care of multi-line headers and cookies
+					$arr = explode(':',$line,2);
 					if(count($arr) > 1)
 					{
-						$header_name = trim($arr[0]);
-						// TO DO: some headers (the ones that allow a CSV list of values)
-						// do allow many values to be passed using multiple header lines.
-						// We should add content to $_xh[$parser]['headers'][$header_name]
-						// instead of replacing it for those...
-						$_xh[$parser]['headers'][$header_name] = $arr[1];
-						for ($i = 2; $i < count($arr); $i++)
+						$header_name = strtolower(trim($arr[0]));
+						/// @todo some other headers (the ones that allow a CSV list of values)
+						/// do allow many values to be passed using multiple header lines.
+						/// We should add content to $GLOBALS['_xh']['headers'][$header_name]
+						/// instead of replacing it for those...
+						if ($header_name == 'set-cookie' || $header_name == 'set-cookie2')
 						{
-							$_xh[$parser]['headers'][$header_name] .= ':'.$arr[$i];
-						} // while
-						$_xh[$parser]['headers'][$header_name] = trim($_xh[$parser]['headers'][$header_name]);
-					} else if (isset($header_name))
+							if ($header_name == 'set-cookie2')
+							{
+								// version 2 cookies:
+								// there could be many cookies on one line, comma separated
+								$cookies = explode(',', $arr[1]);
+							}
+							else
+							{
+								$cookies = array($arr[1]);
+							}
+							foreach ($cookies as $cookie)
+							{
+								// glue together all received cookies, using a comma to separate them
+								// (same as php does with getallheaders())
+								if (isset($GLOBALS['_xh']['headers'][$header_name]))
+									$GLOBALS['_xh']['headers'][$header_name] .= ', ' . trim($cookie);
+								else
+									$GLOBALS['_xh']['headers'][$header_name] = trim($cookie);
+								// parse cookie attributes, in case user wants to correctly honour them
+								// feature creep: only allow rfc-compliant cookie attributes?
+								$cookie = explode(';', $cookie);
+								foreach ($cookie as $pos => $val)
+								{
+									$val = explode('=', $val, 2);
+									$tag = trim($val[0]);
+									$val = trim(@$val[1]);
+									/// @todo with version 1 cookies, we should strip leading and trailing " chars
+									if ($pos == 0)
+									{
+										$cookiename = $tag;
+										$GLOBALS['_xh']['cookies'][$tag] = array();
+										$GLOBALS['_xh']['cookies'][$cookiename]['value'] = urldecode($val);
+									}
+									else
+									{
+										$GLOBALS['_xh']['cookies'][$cookiename][$tag] = $val;
+									}
+								}
+							}
+						}
+						else
+						{
+							$GLOBALS['_xh']['headers'][$header_name] = trim($arr[1]);
+						}
+					}
+					elseif(isset($header_name))
 					{
-						$_xh[$parser]['headers'][$header_name] .= ' ' . trim($line);
+						///	@todo version1 cookies might span multiple lines, thus breaking the parsing above
+						$GLOBALS['_xh']['headers'][$header_name] .= ' ' . trim($line);
 					}
 				}
+
 				$data = substr($data, $bd);
 
-				if ($this->debug && count($_xh[$parser]['headers']))
+				if($this->debug && count($GLOBALS['_xh']['headers']))
 				{
 					print '<PRE>';
-					//foreach ($_xh[$parser]['headers'] as $header)
-					@reset($_xh[$parser]['headers']);
-					while(list($header, $value) = @each($_xh[$parser]['headers']))
+					foreach($GLOBALS['_xh']['headers'] as $header => $value)
+					{
+						print htmlentities("HEADER: $header: $value\n");
+					}
+					foreach($GLOBALS['_xh']['cookies'] as $header => $value)
 					{
-						print "HEADER: $header: $value\n";
+						print htmlentities("COOKIE: $header={$value['value']}\n");
 					}
 					print "</PRE>\n";
 				}
+
+				// if CURL was used for the call, http headers have been processed,
+				// and dechunking + reinflating have been carried out
+				if(!$headers_processed)
+				{
+					// Decode chunked encoding sent by http 1.1 servers
+					if(isset($GLOBALS['_xh']['headers']['transfer-encoding']) && $GLOBALS['_xh']['headers']['transfer-encoding'] == 'chunked')
+					{
+						if(!$data = decode_chunked($data))
+						{
+							error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to rebuild the chunked data received from server');
+							$r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['dechunk_fail'], $GLOBALS['xmlrpcstr']['dechunk_fail']);
+							return $r;
+						}
+					}
+
+					// Decode gzip-compressed stuff
+					// code shamelessly inspired from nusoap library by Dietrich Ayala
+					if(isset($GLOBALS['_xh']['headers']['content-encoding']))
+					{
+						$GLOBALS['_xh']['headers']['content-encoding'] = str_replace('x-', '', $GLOBALS['_xh']['headers']['content-encoding']);
+						if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' || $GLOBALS['_xh']['headers']['content-encoding'] == 'gzip')
+						{
+							// if decoding works, use it. else assume data wasn't gzencoded
+							if(function_exists('gzinflate'))
+							{
+								if($GLOBALS['_xh']['headers']['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data))
+								{
+									$data = $degzdata;
+									if($this->debug)
+									print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
+								}
+								elseif($GLOBALS['_xh']['headers']['content-encoding'] == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
+								{
+									$data = $degzdata;
+									if($this->debug)
+									print "<PRE>---INFLATED RESPONSE---[".strlen($data)." chars]---\n" . htmlentities($data) . "\n---END---</PRE>";
+								}
+								else
+								{
+									error_log('XML-RPC: xmlrpcmsg::parseResponse: errors occurred when trying to decode the deflated data received from server');
+									$r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['decompress_fail'], $GLOBALS['xmlrpcstr']['decompress_fail']);
+									return $r;
+								}
+							}
+							else
+							{
+								error_log('XML-RPC: xmlrpcmsg::parseResponse: the server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
+								$r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['cannot_decompress'], $GLOBALS['xmlrpcstr']['cannot_decompress']);
+								return $r;
+							}
+						}
+					}
+				} // end of 'if needed, de-chunk, re-inflate response'
+
+				// real stupid hack to avoid PHP 4 complaining about returning NULL by ref
+				$r = null;
+				$r =& $r;
+				return $r;
+		}
+
+		/**
+		* Parse the xmlrpc response contained in the string $data and return an xmlrpcresp object.
+		* @param string $data the xmlrpc response, eventually including http headers
+		* @param bool $headers_processed when true prevents parsing HTTP headers for interpretation of content-encoding and consequent decoding
+		* @param string $return_type decides return type, i.e. content of response->value(). Either 'xmlrpcvals', 'xml' or 'phpvals'
+		* @return xmlrpcresp
+		* @access public
+		*/
+		function &parseResponse($data='', $headers_processed=false, $return_type='xmlrpcvals')
+		{
+			if($this->debug)
+			{
+				//by maHo, replaced htmlspecialchars with htmlentities
+				print "<PRE>---GOT---\n" . htmlentities($data) . "\n---END---\n</PRE>";
+			}
+
+			if($data == '')
+			{
+				error_log('XML-RPC: xmlrpcmsg::parseResponse: no response received from server.');
+				$r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['no_data'], $GLOBALS['xmlrpcstr']['no_data']);
+				return $r;
+			}
+
+			$GLOBALS['_xh']=array();
+
+			$raw_data = $data;
+			// parse the HTTP headers of the response, if present, and separate them from data
+			if(substr($data, 0, 4) == 'HTTP')
+			{
+				$r =& $this->parseResponseHeaders($data, $headers_processed);
+				if ($r)
+				{
+					// failed processing of HTTP response headers
+					// save into response obj the full payload received, for debugging
+					$r->raw_data = $data;
+					return $r;
+				}
+			}
+			else
+			{
+				$GLOBALS['_xh']['headers'] = array();
+				$GLOBALS['_xh']['cookies'] = array();
+			}
+
+			if($this->debug)
+			{
+				$start = strpos($data, '<!-- SERVER DEBUG INFO (BASE64 ENCODED):');
+				if ($start)
+				{
+					$start += strlen('<!-- SERVER DEBUG INFO (BASE64 ENCODED):');
+					$end = strpos($data, '-->', $start);
+					$comments = substr($data, $start, $end-$start);
+					print "<PRE>---SERVER DEBUG INFO (DECODED) ---\n\t".htmlentities(str_replace("\n", "\n\t", base64_decode($comments)))."\n---END---\n</PRE>";
+				}
 			}
 
 			// be tolerant of extra whitespace in response body
 			$data = trim($data);
 
-			// be tolerant of junk after methodResponse (e.g. javascript automatically inserted by free hosts)
+			/// @todo return an error msg if $data=='' ?
+
+			// be tolerant of junk after methodResponse (e.g. javascript ads automatically inserted by free hosts)
 			// idea from Luca Mariano <luca.mariano@email.it> originally in PEARified version of the lib
 			$bd = false;
-			$pos = strpos($data, "</methodResponse>");
-			while ($pos || is_int($pos))
+			// Poor man's version of strrpos for php 4...
+			$pos = strpos($data, '</methodResponse>');
+			while($pos || is_int($pos))
 			{
 				$bd = $pos+17;
-				$pos = strpos($data, "</methodResponse>", $bd);
+				$pos = strpos($data, '</methodResponse>', $bd);
 			}
-			if ($bd)
+			if($bd)
+			{
 				$data = substr($data, 0, $bd);
+			}
+
+			// if user wants back raw xml, give it to him
+			if ($return_type == 'xml')
+			{
+				$r =& new xmlrpcresp($data, 0, '', 'xml');
+				$r->hdrs = $GLOBALS['_xh']['headers'];
+				$r->_cookies = $GLOBALS['_xh']['cookies'];
+				$r->raw_data = $raw_data;
+				return $r;
+			}
 
-			//$_xh[$parser]['st']='';
-			//$_xh[$parser]['cm']=0;
-			$_xh[$parser]['isf']=0;
-			$_xh[$parser]['isf_reason']=0;
-			$_xh[$parser]['ac']='';
-			//$_xh[$parser]['qt']='';
+			// try to 'guestimate' the character encoding of the received response
+			$resp_encoding = guess_encoding(@$GLOBALS['_xh']['headers']['content-type'], $data);
 
+			$GLOBALS['_xh']['ac']='';
+			//$GLOBALS['_xh']['qt']=''; //unused...
+			$GLOBALS['_xh']['stack'] = array();
+			$GLOBALS['_xh']['valuestack'] = array();
+			$GLOBALS['_xh']['isf']=0; // 0 = OK, 1 for xmlrpc fault responses, 2 = invalid xmlrpc
+			$GLOBALS['_xh']['isf_reason']='';
+			$GLOBALS['_xh']['rt']=''; // 'methodcall or 'methodresponse'
+
+			// if response charset encoding is not known / supported, try to use
+			// the default encoding and parse the xml anyway, but log a warning...
+			if (!in_array($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+			// the following code might be better for mb_string enabled installs, but
+			// makes the lib about 200% slower...
+			//if (!is_valid_charset($resp_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+			{
+				error_log('XML-RPC: xmlrpcmsg::parseResponse: invalid charset encoding of received response: '.$resp_encoding);
+				$resp_encoding = $GLOBALS['xmlrpc_defencoding'];
+			}
+			$parser = xml_parser_create($resp_encoding);
 			xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
 			// G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
 			// the xml parser to give us back data in the expected charset
-			xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding);
+			xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
+
+			if ($return_type == 'phpvals')
+			{
+				xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast');
+			}
+			else
+			{
+				xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
+			}
 
-			xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
 			xml_set_character_data_handler($parser, 'xmlrpc_cd');
 			xml_set_default_handler($parser, 'xmlrpc_dh');
-			//$xmlrpc_value=new xmlrpcval;
 
-			if (!xml_parse($parser, $data, sizeof($data)))
+			// first error check: xml not well formed
+			if(!xml_parse($parser, $data, count($data)))
 			{
 				// thanks to Peter Kocks <peter.kocks@baygate.com>
 				if((xml_get_current_line_number($parser)) == 1)
@@ -1579,81 +2548,92 @@
 				}
 				else
 				{
-					$errstr = sprintf('XML error: %s at line %d',
+					$errstr = sprintf('XML error: %s at line %d, column %d',
 						xml_error_string(xml_get_error_code($parser)),
-						xml_get_current_line_number($parser));
+						xml_get_current_line_number($parser), xml_get_current_column_number($parser));
 				}
 				error_log($errstr);
-				$r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return'].' ('.$errstr.')');
+				$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'], $GLOBALS['xmlrpcstr']['invalid_return'].' ('.$errstr.')');
 				xml_parser_free($parser);
-				if ($this->debug)
-					echo $errstr;
-				$r->hdrs = $_xh[$parser]['headers'];
+				if($this->debug)
+				{
+					print $errstr;
+				}
+				$r->hdrs = $GLOBALS['_xh']['headers'];
+				$r->_cookies = $GLOBALS['_xh']['cookies'];
+				$r->raw_data = $raw_data;
 				return $r;
 			}
 			xml_parser_free($parser);
-
-			if ($_xh[$parser]['isf'] > 1)
-			{
-			if ($this->debug)
+			// second error check: xml well formed but not xml-rpc compliant
+			if ($GLOBALS['_xh']['isf'] > 1)
 			{
-					///@todo echo something for user?
+				if ($this->debug)
+				{
+					/// @todo echo something for user?
 				}
 
-				$r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'],
-				$xmlrpcstr['invalid_return'] . ' ' . $_xh[$parser]['isf_reason']);
+				$r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'],
+				$GLOBALS['xmlrpcstr']['invalid_return'] . ' ' . $GLOBALS['_xh']['isf_reason']);
 			}
-			//else if (strlen($_xh[$parser]['st'])==0)
-			else if (!is_object($_xh[$parser]['value']))
+			// third error check: parsing of the response has somehow gone boink.
+			// NB: shall we omit this check, since we trust the parsing code?
+			elseif ($return_type == 'xmlrpcvals' && !is_object($GLOBALS['_xh']['value']))
 			{
-				// then something odd has happened
+				// something odd has happened
 				// and it's time to generate a client side error
 				// indicating something odd went on
-				$r=new xmlrpcresp(0, $xmlrpcerr['invalid_return'],
-				$xmlrpcstr['invalid_return']);
+				$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['invalid_return'],
+					$GLOBALS['xmlrpcstr']['invalid_return']);
 			}
 			else
 			{
-
 				if ($this->debug)
 				{
-					//print "<PRE>---EVALING---[" .
-					//strlen($_xh[$parser]['st']) . " chars]---\n" .
-					//htmlspecialchars($_xh[$parser]['st']) . ";\n---END---</PRE>";
-					print "<PRE>---PARSED---\n" ;
-					var_dump($_xh[$parser]['value']);
+					print "<PRE>---PARSED---\n";
+					// somehow htmlentities chokes on var_export, and some full html string...
+					//print htmlentitites(var_export($GLOBALS['_xh']['value'], true));
+					print htmlspecialchars(var_export($GLOBALS['_xh']['value'], true));
 					print "\n---END---</PRE>";
 				}
 
-				//$allOK=0;
-				//@eval('$v=' . $_xh[$parser]['st'] . '; $allOK=1;');
-				//if (!$allOK)
-				//{
-				//	$r = new xmlrpcresp(0, $xmlrpcerr['invalid_return'], $xmlrpcstr['invalid_return']);
-				//}
-				//else
-				$v = $_xh[$parser]['value'];
-				if ($_xh[$parser]['isf'])
-				{
-					$errno_v = $v->structmem('faultCode');
-					$errstr_v = $v->structmem('faultString');
-					$errno = $errno_v->scalarval();
+				// note that using =& will raise an error if $GLOBALS['_xh']['st'] does not generate an object.
+				$v =& $GLOBALS['_xh']['value'];
+
+				if($GLOBALS['_xh']['isf'])
+				{
+					/// @todo we should test here if server sent an int and a string,
+					/// and/or coerce them into such...
+					if ($return_type == 'xmlrpcvals')
+					{
+						$errno_v = $v->structmem('faultCode');
+						$errstr_v = $v->structmem('faultString');
+						$errno = $errno_v->scalarval();
+						$errstr = $errstr_v->scalarval();
+					}
+					else
+					{
+						$errno = $v['faultCode'];
+						$errstr = $v['faultString'];
+					}
 
-					if ($errno == 0)
+					if($errno == 0)
 					{
 						// FAULT returned, errno needs to reflect that
 						$errno = -1;
 					}
 
-					$r = new xmlrpcresp($v, $errno, $errstr_v->scalarval());
+					$r =& new xmlrpcresp(0, $errno, $errstr);
 				}
 				else
 				{
-					$r=new xmlrpcresp($v);
+					$r=&new xmlrpcresp($v, 0, '', $return_type);
 				}
 			}
 
-			$r->hdrs = $_xh[$parser]['headers'];
+			$r->hdrs = $GLOBALS['_xh']['headers'];
+			$r->_cookies = $GLOBALS['_xh']['cookies'];
+			$r->raw_data = $raw_data;
 			return $r;
 		}
 	}
@@ -1662,120 +2642,200 @@
 	{
 		var $me=array();
 		var $mytype=0;
+		var $_php_class=null;
 
+		/**
+		* @param mixed $val
+		* @param string $type any valid xmlrpc type name (lowercase). If null, 'string' is assumed
+		*/
 		function xmlrpcval($val=-1, $type='')
 		{
-			global $xmlrpcTypes;
-			$this->me=array();
-			$this->mytype=0;
-			if ($val!=-1 || !is_int($val) || $type!='')
-			{
-				if ($type=='')
+			/// @todo: optimization creep - do not call addXX, do it all inline.
+			/// downside: booleans will not be coerced anymore
+			if($val!==-1 || $type!='')
+			{
+				// optimization creep: inlined all work done by constructor
+				switch($type)
+				{
+					case '':
+						$this->mytype=1;
+						$this->me['string']=$val;
+						break;
+					case 'i4':
+					case 'int':
+					case 'double':
+					case 'string':
+					case 'boolean':
+					case 'dateTime.iso8601':
+					case 'base64':
+					case 'null':
+						$this->mytype=1;
+						$this->me[$type]=$val;
+						break;
+					case 'array':
+						$this->mytype=2;
+						$this->me['array']=$val;
+						break;
+					case 'struct':
+						$this->mytype=3;
+						$this->me['struct']=$val;
+						break;
+					default:
+						error_log("XML-RPC: xmlrpcval::xmlrpcval: not a known type ($type)");
+				}
+				/*if($type=='')
 				{
 					$type='string';
 				}
-				if ($xmlrpcTypes[$type]==1)
+				if($GLOBALS['xmlrpcTypes'][$type]==1)
 				{
 					$this->addScalar($val,$type);
 				}
-				elseif ($xmlrpcTypes[$type]==2)
+				elseif($GLOBALS['xmlrpcTypes'][$type]==2)
 				{
 					$this->addArray($val);
 				}
-				elseif ($xmlrpcTypes[$type]==3)
+				elseif($GLOBALS['xmlrpcTypes'][$type]==3)
 				{
 					$this->addStruct($val);
-				}
+				}*/
 			}
 		}
 
+		/**
+		* Add a single php value to an (unitialized) xmlrpcval
+		* @param mixed $val
+		* @param string $type
+		* @return int 1 or 0 on failure
+		*/
 		function addScalar($val, $type='string')
 		{
-			global $xmlrpcTypes, $xmlrpcBoolean;
-
-			if ($this->mytype==1)
-			{
-				echo '<B>xmlrpcval</B>: scalar can have only one value<BR>';
-				return 0;
-			}
-			$typeof=$xmlrpcTypes[$type];
-			if ($typeof!=1)
+			$typeof=@$GLOBALS['xmlrpcTypes'][$type];
+			if($typeof!=1)
 			{
-				echo '<B>xmlrpcval</B>: not a scalar type (${typeof})<BR>';
+				error_log("XML-RPC: xmlrpcval::addScalar: not a scalar type ($type)");
 				return 0;
 			}
 
-			if ($type==$xmlrpcBoolean)
+			// coerce booleans into correct values
+			// NB: we should iether do it for datetimes, integers and doubles, too,
+			// or just plain remove this check, implemnted on booleans only...
+			if($type==$GLOBALS['xmlrpcBoolean'])
 			{
-				if (strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
+				if(strcasecmp($val,'true')==0 || $val==1 || ($val==true && strcasecmp($val,'false')))
 				{
-					$val=1;
+					$val=true;
 				}
 				else
 				{
-					$val=0;
+					$val=false;
 				}
 			}
 
-			if ($this->mytype==2)
-			{
-				// we're adding to an array here
-				$ar=$this->me['array'];
-				$ar[]=new xmlrpcval($val, $type);
-				$this->me['array']=$ar;
-			}
-			else
+			switch($this->mytype)
 			{
-				// a scalar, so set the value and remember we're scalar
-				$this->me[$type]=$val;
-				$this->mytype=$typeof;
+				case 1:
+					error_log('XML-RPC: xmlrpcval::addScalar: scalar xmlrpcval can have only one value');
+					return 0;
+				case 3:
+					error_log('XML-RPC: xmlrpcval::addScalar: cannot add anonymous scalar to struct xmlrpcval');
+					return 0;
+				case 2:
+					// we're adding a scalar value to an array here
+					//$ar=$this->me['array'];
+					//$ar[]=&new xmlrpcval($val, $type);
+					//$this->me['array']=$ar;
+					// Faster (?) avoid all the costly array-copy-by-val done here...
+					$this->me['array'][]=&new xmlrpcval($val, $type);
+					return 1;
+				default:
+					// a scalar, so set the value and remember we're scalar
+					$this->me[$type]=$val;
+					$this->mytype=$typeof;
+					return 1;
 			}
-			return 1;
 		}
 
+		/**
+		* Add an array of xmlrpcval objects to an xmlrpcval
+		* @param array $vals
+		* @return int 1 or 0 on failure
+		* @access public
+		*
+		* @todo add some checking for $vals to be an array of xmlrpcvals?
+		*/
 		function addArray($vals)
 		{
-			global $xmlrpcTypes;
-			if ($this->mytype!=0)
+			if($this->mytype==0)
+			{
+				$this->mytype=$GLOBALS['xmlrpcTypes']['array'];
+				$this->me['array']=$vals;
+				return 1;
+			}
+			elseif($this->mytype==2)
+			{
+				// we're adding to an array here
+				$this->me['array'] = array_merge($this->me['array'], $vals);
+				return 1;
+			}
+			else
 			{
-				echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
+				error_log('XML-RPC: xmlrpcval::addArray: already initialized as a [' . $this->kindOf() . ']');
 				return 0;
 			}
-
-			$this->mytype=$xmlrpcTypes['array'];
-			$this->me['array']=$vals;
-			return 1;
 		}
 
+		/**
+		* Add an array of named xmlrpcval objects to an xmlrpcval
+		* @param array $vals
+		* @return int 1 or 0 on failure
+		* @access public
+		*
+		* @todo add some checking for $vals to be an array?
+		*/
 		function addStruct($vals)
 		{
-			global $xmlrpcTypes;
-			if ($this->mytype!=0)
+			if($this->mytype==0)
+			{
+				$this->mytype=$GLOBALS['xmlrpcTypes']['struct'];
+				$this->me['struct']=$vals;
+				return 1;
+			}
+			elseif($this->mytype==3)
 			{
-				echo '<B>xmlrpcval</B>: already initialized as a [' . $this->kindOf() . ']<BR>';
+				// we're adding to a struct here
+				$this->me['struct'] = array_merge($this->me['struct'], $vals);
+				return 1;
+			}
+			else
+			{
+				error_log('XML-RPC: xmlrpcval::addStruct: already initialized as a [' . $this->kindOf() . ']');
 				return 0;
 			}
-			$this->mytype=$xmlrpcTypes['struct'];
-			$this->me['struct']=$vals;
-			return 1;
 		}
 
+		// poor man's version of print_r ???
+		// DEPRECATED!
 		function dump($ar)
 		{
-			reset($ar);
-			while ( list( $key, $val ) = each( $ar ) )
+			foreach($ar as $key => $val)
 			{
-				echo "$key => $val<br>";
-				if ($key == 'array')
+				echo "$key => $val<br />";
+				if($key == 'array')
 				{
-					while ( list( $key2, $val2 ) = each( $val ) )
+					while(list($key2, $val2) = each($val))
 					{
-						echo "-- $key2 => $val2<br>";
+						echo "-- $key2 => $val2<br />";
 					}
 				}
 			}
 		}
 
+		/**
+		* Returns a string containing "struct", "array" or "scalar" describing the base type of the value
+		* @return string
+		* @access public
+		*/
 		function kindOf()
 		{
 			switch($this->mytype)
@@ -1794,21 +2854,59 @@
 			}
 		}
 
-		function serializedata($typ, $val)
+		/**
+		* @access private
+		*/
+		function serializedata($typ, $val, $charset_encoding='')
 		{
 			$rs='';
-			global $xmlrpcTypes, $xmlrpcBase64, $xmlrpcString,
-			$xmlrpcBoolean;
-			switch(@$xmlrpcTypes[$typ])
+			switch(@$GLOBALS['xmlrpcTypes'][$typ])
 			{
+				case 1:
+					switch($typ)
+					{
+						case $GLOBALS['xmlrpcBase64']:
+							$rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
+							break;
+						case $GLOBALS['xmlrpcBoolean']:
+							$rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
+							break;
+						case $GLOBALS['xmlrpcString']:
+							// G. Giunta 2005/2/13: do NOT use htmlentities, since
+							// it will produce named html entities, which are invalid xml
+							$rs.="<${typ}>" . xmlrpc_encode_entitites($val, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding). "</${typ}>";
+							break;
+						case $GLOBALS['xmlrpcInt']:
+						case $GLOBALS['xmlrpcI4']:
+							$rs.="<${typ}>".(int)$val."</${typ}>";
+							break;
+						case $GLOBALS['xmlrpcDouble']:
+							$rs.="<${typ}>".(double)$val."</${typ}>";
+							break;
+						case $GLOBALS['xmlrpcNull']:
+							$rs.="<nil/>";
+							break;
+						default:
+							// no standard type value should arrive here, but provide a possibility
+							// for xmlrpcvals of unknown type...
+							$rs.="<${typ}>${val}</${typ}>";
+					}
+					break;
 				case 3:
 					// struct
-					$rs.="<struct>\n";
-					reset($val);
-					while(list($key2, $val2)=each($val))
+					if ($this->_php_class)
+					{
+						$rs.='<struct php_class="' . $this->_php_class . "\">\n";
+					}
+					else
+					{
+						$rs.="<struct>\n";
+					}
+					foreach($val as $key2 => $val2)
 					{
-						$rs.="<member><name>${key2}</name>\n";
-						$rs.=$this->serializeval($val2);
+						$rs.='<member><name>'.xmlrpc_encode_entitites($key2, $GLOBALS['xmlrpc_internalencoding'], $charset_encoding)."</name>\n";
+						//$rs.=$this->serializeval($val2);
+						$rs.=$val2->serialize($charset_encoding);
 						$rs.="</member>\n";
 					}
 					$rs.='</struct>';
@@ -1816,78 +2914,97 @@
 				case 2:
 					// array
 					$rs.="<array>\n<data>\n";
-					for($i=0; $i<sizeof($val); $i++)
+					for($i=0; $i<count($val); $i++)
 					{
-						$rs.=$this->serializeval($val[$i]);
+						//$rs.=$this->serializeval($val[$i]);
+						$rs.=$val[$i]->serialize($charset_encoding);
 					}
 					$rs.="</data>\n</array>";
 					break;
-				case 1:
-					switch ($typ)
-					{
-						case $xmlrpcBase64:
-							$rs.="<${typ}>" . base64_encode($val) . "</${typ}>";
-							break;
-						case $xmlrpcBoolean:
-							$rs.="<${typ}>" . ($val ? '1' : '0') . "</${typ}>";
-							break;
-						case $xmlrpcString:
-							// G. Giunta 2005/2/13: do NOT use htmlentities, since
-							// it will produce named html entities, which are invalid xml
-							// $rs.="<${typ}>" . xmlrpc_encode_entitites($val). "</${typ}>";
-							// $rs.="<${typ}>" . htmlentities($val). "</${typ}>";
-							
-							// N. Leenheer 2005/6/30: Use CDATA instead... 
-							$rs.="<${typ}><![CDATA[" . $val. "]]></${typ}>";
-							break;
-						default:
-							$rs.="<${typ}>${val}</${typ}>";
-					}
-					break;
 				default:
 					break;
 			}
 			return $rs;
 		}
 
-		function serialize()
-		{
-			return $this->serializeval($this);
+		/**
+		* Returns xml representation of the value. XML prologue not included
+		* @param string $charset_encoding the charset to be used for serialization. if null, US-ASCII is assumed
+		* @return string
+		* @access public
+		*/
+		function serialize($charset_encoding='')
+		{
+			// add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
+			//if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
+			//{
+				reset($this->me);
+				list($typ, $val) = each($this->me);
+				return '<value>' . $this->serializedata($typ, $val, $charset_encoding) . "</value>\n";
+			//}
 		}
 
+		// DEPRECATED
 		function serializeval($o)
 		{
-			//global $xmlrpcTypes;
-			$rs='';
-			$ar=$o->me;
-			reset($ar);
-			list($typ, $val) = each($ar);
-			$rs.='<value>';
-			$rs.=$this->serializedata($typ, $val);
-			$rs.="</value>\n";
-			return $rs;
-		}
-
+			// add check? slower, but helps to avoid recursion in serializing broken xmlrpcvals...
+			//if (is_object($o) && (get_class($o) == 'xmlrpcval' || is_subclass_of($o, 'xmlrpcval')))
+			//{
+				$ar=$o->me;
+				reset($ar);
+				list($typ, $val) = each($ar);
+				return '<value>' . $this->serializedata($typ, $val) . "</value>\n";
+			//}
+		}
+
+		/**
+		* Checks wheter a struct member with a given name is present.
+		* Works only on xmlrpcvals of type struct.
+		* @param string $m the name of the struct member to be looked up
+		* @return boolean
+		* @access public
+		*/
+		function structmemexists($m)
+		{
+			return array_key_exists($m, $this->me['struct']);
+		}
+
+		/**
+		* Returns the value of a given struct member (an xmlrpcval object in itself).
+		* Will raise a php warning if struct member of given name does not exist
+		* @param string $m the name of the struct member to be looked up
+		* @return xmlrpcval
+		* @access public
+		*/
 		function structmem($m)
 		{
-			$nv=$this->me['struct'][$m];
-			return $nv;
+			return $this->me['struct'][$m];
 		}
 
+		/**
+		* Reset internal pointer for xmlrpcvals of type struct.
+		* @access public
+		*/
 		function structreset()
 		{
 			reset($this->me['struct']);
 		}
 
+		/**
+		* Return next member element for xmlrpcvals of type struct.
+		* @return xmlrpcval
+		* @access public
+		*/
 		function structeach()
 		{
 			return each($this->me['struct']);
 		}
 
+		// DEPRECATED! this code looks like it is very fragile and has not been fixed
+		// for a long long time. Shall we remove it for 2.0?
 		function getval()
 		{
 			// UNSTABLE
-			global $xmlrpcBoolean, $xmlrpcBase64;
 			reset($this->me);
 			list($a,$b)=each($this->me);
 			// contributed by I Sofer, 2001-03-24
@@ -1895,7 +3012,7 @@
 			// i've created a new method here, so as to
 			// preserve back compatibility
 
-			if (is_array($b))
+			if(is_array($b))
 			{
 				@reset($b);
 				while(list($id,$cont) = @each($b))
@@ -1905,7 +3022,7 @@
 			}
 
 			// add support for structures directly encoding php objects
-			if (is_object($b))
+			if(is_object($b))
 			{
 				$t = get_object_vars($b);
 				@reset($t);
@@ -1916,7 +3033,6 @@
 				@reset($t);
 				while(list($id,$cont) = @each($t))
 				{
-					//eval('$b->'.$id.' = $cont;');
 					@$b->$id = $cont;
 				}
 			}
@@ -1924,60 +3040,96 @@
 			return $b;
 		}
 
+		/**
+		* Returns the value of a scalar xmlrpcval
+		* @return mixed
+		* @access public
+		*/
 		function scalarval()
 		{
-			//global $xmlrpcBoolean, $xmlrpcBase64;
 			reset($this->me);
-			list($a,$b)=each($this->me);
+			list(,$b)=each($this->me);
 			return $b;
 		}
 
+		/**
+		* Returns the type of the xmlrpcval.
+		* For integers, 'int' is always returned in place of 'i4'
+		* @return string
+		* @access public
+		*/
 		function scalartyp()
 		{
-			global $xmlrpcI4, $xmlrpcInt;
 			reset($this->me);
-			list($a,$b)=each($this->me);
-			if ($a==$xmlrpcI4)
+			list($a,)=each($this->me);
+			if($a==$GLOBALS['xmlrpcI4'])
 			{
-				$a=$xmlrpcInt;
+				$a=$GLOBALS['xmlrpcInt'];
 			}
 			return $a;
 		}
 
+		/**
+		* Returns the m-th member of an xmlrpcval of struct type
+		* @param integer $m the index of the value to be retrieved (zero based)
+		* @return xmlrpcval
+		* @access public
+		*/
 		function arraymem($m)
 		{
-			$nv=$this->me['array'][$m];
-			return $nv;
+			return $this->me['array'][$m];
 		}
 
+		/**
+		* Returns the number of members in an xmlrpcval of array type
+		* @return integer
+		* @access public
+		*/
 		function arraysize()
 		{
-			reset($this->me);
-			list($a,$b)=each($this->me);
-			return sizeof($b);
+			return count($this->me['array']);
+		}
+
+		/**
+		* Returns the number of members in an xmlrpcval of struct type
+		* @return integer
+		* @access public
+		*/
+		function structsize()
+		{
+			return count($this->me['struct']);
 		}
 	}
 
+
 	// date helpers
+
+	/**
+	* Given a timestamp, return the corresponding ISO8601 encoded string.
+	*
+	* Really, timezones ought to be supported
+	* but the XML-RPC spec says:
+	*
+	* "Don't assume a timezone. It should be specified by the server in its
+	* documentation what assumptions it makes about timezones."
+	*
+	* These routines always assume localtime unless
+	* $utc is set to 1, in which case UTC is assumed
+	* and an adjustment for locale is made when encoding
+	*
+	* @param int $timet (timestamp)
+	* @param int $utc (0 or 1)
+	* @return string
+	*/
 	function iso8601_encode($timet, $utc=0)
 	{
-		// return an ISO8601 encoded string
-		// really, timezones ought to be supported
-		// but the XML-RPC spec says:
-		//
-		// "Don't assume a timezone. It should be specified by the server in its
-		// documentation what assumptions it makes about timezones."
-		// 
-		// these routines always assume localtime unless 
-		// $utc is set to 1, in which case UTC is assumed
-		// and an adjustment for locale is made when encoding
-		if (!$utc)
+		if(!$utc)
 		{
 			$t=strftime("%Y%m%dT%H:%M:%S", $timet);
 		}
 		else
 		{
-			if (function_exists('gmstrftime'))
+			if(function_exists('gmstrftime'))
 			{
 				// gmstrftime doesn't exist in some versions
 				// of PHP
@@ -1991,13 +3143,18 @@
 		return $t;
 	}
 
+	/**
+	* Given an ISO8601 date string, return a timet in the localtime, or UTC
+	* @param string $idate
+	* @param int $utc either 0 or 1
+	* @return int (datetime)
+	*/
 	function iso8601_decode($idate, $utc=0)
 	{
-		// return a timet in the localtime, or UTC
 		$t=0;
-		if (ereg("([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})", $idate, $regs))
+		if(preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})/', $idate, $regs))
 		{
-			if ($utc)
+			if($utc)
 			{
 				$t=gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
 			}
@@ -2005,199 +3162,481 @@
 			{
 				$t=mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
 			}
-		} 
-		return $t;
-	}
-
-	/****************************************************************
-	* xmlrpc_decode takes a message in PHP xmlrpc object format and *
-	* tranlates it into native PHP types.                           *
-	*                                                               *
-	* author: Dan Libby (dan@libby.com)                             *
-	****************************************************************/
-	function php_xmlrpc_decode($xmlrpc_val)
-	{
-		$kind = $xmlrpc_val->kindOf();
-
-		if($kind == 'scalar')
-		{
-			return $xmlrpc_val->scalarval();
-		}
-		elseif($kind == 'array')
-		{
-			$size = $xmlrpc_val->arraysize();
-			$arr = array();
-
-			for($i = 0; $i < $size; $i++)
-			{
-				$arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i));
-			}
-			return $arr;
-		}
-		elseif($kind == 'struct')
-		{
-			$xmlrpc_val->structreset();
-			$arr = array();
-
-			while(list($key,$value)=$xmlrpc_val->structeach())
-			{
-				$arr[$key] = php_xmlrpc_decode($value);
-			}
-			return $arr;
 		}
+		return $t;
 	}
 
-	if(function_exists('xmlrpc_decode'))
-	{
-		define('XMLRPC_EPI_ENABLED','1');
-	}
-	else
+	/**
+	* Takes an xmlrpc value in PHP xmlrpcval object format and translates it into native PHP types.
+	*
+	* Works with xmlrpc message objects as input, too.
+	*
+	* Given proper options parameter, can rebuild generic php object instances
+	* (provided those have been encoded to xmlrpc format using a corresponding
+	* option in php_xmlrpc_encode())
+	* PLEASE NOTE that rebuilding php objects involves calling their constructor function.
+	* This means that the remote communication end can decide which php code will
+	* get executed on your server, leaving the door possibly open to 'php-injection'
+	* style of attacks (provided you have some classes defined on your server that
+	* might wreak havoc if instances are built outside an appropriate context).
+	* Make sure you trust the remote server/client before eanbling this!
+	*
+	* @author Dan Libby (dan@libby.com)
+	*
+	* @param xmlrpcval $xmlrpc_val
+	* @param array $options if 'decode_php_objs' is set in the options array, xmlrpc structs can be decoded into php objects
+	* @return mixed
+	*/
+	function php_xmlrpc_decode($xmlrpc_val, $options=array())
 	{
-		define('XMLRPC_EPI_ENABLED','0');
-		function xmlrpc_decode($xmlrpc_val)
+		switch($xmlrpc_val->kindOf())
 		{
-			$kind = $xmlrpc_val->kindOf();
-
-			if($kind == 'scalar')
-			{
+			case 'scalar':
+				if (in_array('extension_api', $options))
+				{
+					reset($xmlrpc_val->me);
+					list($typ,$val) = each($xmlrpc_val->me);
+					switch ($typ)
+					{
+						case 'dateTime.iso8601':
+							$xmlrpc_val->scalar = $val;
+							$xmlrpc_val->xmlrpc_type = 'datetime';
+							$xmlrpc_val->timestamp = iso8601_decode($val);
+							return $xmlrpc_val;
+						case 'base64':
+							$xmlrpc_val->scalar = $val;
+							$xmlrpc_val->type = $typ;
+							return $xmlrpc_val;
+						default:
+							return $xmlrpc_val->scalarval();
+					}
+				}
 				return $xmlrpc_val->scalarval();
-			}
-			elseif($kind == 'array')
-			{
+			case 'array':
 				$size = $xmlrpc_val->arraysize();
 				$arr = array();
-
 				for($i = 0; $i < $size; $i++)
 				{
-					$arr[]=xmlrpc_decode($xmlrpc_val->arraymem($i));
+					$arr[] = php_xmlrpc_decode($xmlrpc_val->arraymem($i), $options);
 				}
 				return $arr;
-			}
-			elseif($kind == 'struct')
-			{
+			case 'struct':
 				$xmlrpc_val->structreset();
+				// If user said so, try to rebuild php objects for specific struct vals.
+				/// @todo should we raise a warning for class not found?
+				// shall we check for proper subclass of xmlrpcval instead of
+				// presence of _php_class to detect what we can do?
+				if (in_array('decode_php_objs', $options) && $xmlrpc_val->_php_class != ''
+					&& class_exists($xmlrpc_val->_php_class))
+				{
+					$obj = @new $xmlrpc_val->_php_class;
+					while(list($key,$value)=$xmlrpc_val->structeach())
+					{
+						$obj->$key = php_xmlrpc_decode($value, $options);
+					}
+					return $obj;
+				}
+				else
+				{
+					$arr = array();
+					while(list($key,$value)=$xmlrpc_val->structeach())
+					{
+						$arr[$key] = php_xmlrpc_decode($value, $options);
+					}
+					return $arr;
+				}
+			case 'msg':
+				$paramcount = $xmlrpc_val->getNumParams();
 				$arr = array();
-
-				while(list($key,$value)=$xmlrpc_val->structeach())
+				for($i = 0; $i < $paramcount; $i++)
 				{
-					$arr[$key] = xmlrpc_decode($value);
+					$arr[] = php_xmlrpc_decode($xmlrpc_val->getParam($i));
 				}
 				return $arr;
 			}
-		}
 	}
 
-	/****************************************************************
-	* xmlrpc_encode takes native php types and encodes them into    *
-	* xmlrpc PHP object format.                                     *
-	* BUG: All sequential arrays are turned into structs.  I don't  *
-	* know of a good way to determine if an array is sequential     *
-	* only.                                                         *
-	*                                                               *
-	* feature creep -- could support more types via optional type   *
-	* argument.                                                     *
-	*                                                               *
-	* author: Dan Libby (dan@libby.com)                             *
-	****************************************************************/
-	function php_xmlrpc_encode($php_val)
-	{
-		global $xmlrpcInt;
-		global $xmlrpcDouble;
-		global $xmlrpcString;
-		global $xmlrpcArray;
-		global $xmlrpcStruct;
-		global $xmlrpcBoolean;
+	// This constant left here only for historical reasons...
+	// it was used to decide if we have to define xmlrpc_encode on our own, but
+	// we do not do it anymore
+	if(function_exists('xmlrpc_decode'))
+	{
+		define('XMLRPC_EPI_ENABLED','1');
+	}
+	else
+	{
+		define('XMLRPC_EPI_ENABLED','0');
+	}
 
+	/**
+	* Takes native php types and encodes them into xmlrpc PHP object format.
+	* It will not re-encode xmlrpcval objects.
+	*
+	* Feature creep -- could support more types via optional type argument
+	* (string => datetime support has been added, ??? => base64 not yet)
+	*
+	* If given a proper options parameter, php object instances will be encoded
+	* into 'special' xmlrpc values, that can later be decoded into php objects
+	* by calling php_xmlrpc_decode() with a corresponding option
+	*
+	* @author Dan Libby (dan@libby.com)
+	*
+	* @param mixed $php_val the value to be converted into an xmlrpcval object
+	* @param array $options	can include 'encode_php_objs', 'auto_dates', 'null_extension' or 'extension_api'
+	* @return xmlrpcval
+	*/
+	function &php_xmlrpc_encode($php_val, $options=array())
+	{
 		$type = gettype($php_val);
-		$xmlrpc_val = new xmlrpcval;
-
 		switch($type)
 		{
-			case 'array':
-			case 'object':
-				$arr = array();
-				while (list($k,$v) = each($php_val))
-				{
-					$arr[$k] = php_xmlrpc_encode($v);
-				}
-				$xmlrpc_val->addStruct($arr);
+			case 'string':
+				if (in_array('auto_dates', $options) && preg_match('/^[0-9]{8}T[0-9]{2}:[0-9]{2}:[0-9]{2}$/', $php_val))
+					$xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcDateTime']);
+				else
+					$xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcString']);
 				break;
 			case 'integer':
-				$xmlrpc_val->addScalar($php_val, $xmlrpcInt);
+				$xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcInt']);
 				break;
 			case 'double':
-				$xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
-				break;
-			case 'string':
-				$xmlrpc_val->addScalar($php_val, $xmlrpcString);
+				$xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcDouble']);
 				break;
 				// <G_Giunta_2001-02-29>
 				// Add support for encoding/decoding of booleans, since they are supported in PHP
 			case 'boolean':
-				$xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
+				$xmlrpc_val =& new xmlrpcval($php_val, $GLOBALS['xmlrpcBoolean']);
 				break;
 				// </G_Giunta_2001-02-29>
-			// catch "resource", "NULL", "user function", "unknown type"
-			//case 'unknown type':
+			case 'array':
+				// PHP arrays can be encoded to either xmlrpc structs or arrays,
+				// depending on wheter they are hashes or plain 0..n integer indexed
+				// A shorter one-liner would be
+				// $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1));
+				// but execution time skyrockets!
+				$j = 0;
+				$arr = array();
+				$ko = false;
+				foreach($php_val as $key => $val)
+				{
+					$arr[$key] =& php_xmlrpc_encode($val, $options);
+					if(!$ko && $key !== $j)
+					{
+						$ko = true;
+					}
+					$j++;
+				}
+				if($ko)
+				{
+					$xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']);
+				}
+				else
+				{
+					$xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcArray']);
+				}
+				break;
+			case 'object':
+				if(is_a($php_val, 'xmlrpcval'))
+				{
+					$xmlrpc_val = $php_val;
+				}
+				else
+				{
+					$arr = array();
+					while(list($k,$v) = each($php_val))
+					{
+						$arr[$k] = php_xmlrpc_encode($v, $options);
+					}
+					$xmlrpc_val =& new xmlrpcval($arr, $GLOBALS['xmlrpcStruct']);
+					if (in_array('encode_php_objs', $options))
+					{
+						// let's save original class name into xmlrpcval:
+						// might be useful later on...
+						$xmlrpc_val->_php_class = get_class($php_val);
+					}
+				}
+				break;
+			case 'NULL':
+				if (in_array('extension_api', $options))
+				{
+					$xmlrpc_val =& new xmlrpcval('', $GLOBALS['xmlrpcString']);
+				}
+				if (in_array('null_extension', $options))
+				{
+					$xmlrpc_val =& new xmlrpcval('', $GLOBALS['xmlrpcNull']);
+				}
+				else
+				{
+					$xmlrpc_val =& new xmlrpcval();
+				}
+				break;
+			case 'resource':
+				if (in_array('extension_api', $options))
+				{
+					$xmlrpc_val =& new xmlrpcval((int)$php_val, $GLOBALS['xmlrpcInt']);
+				}
+				else
+				{
+					$xmlrpc_val =& new xmlrpcval();
+				}
+			// catch "user function", "unknown type"
 			default:
 				// giancarlo pinerolo <ping@alt.it>
-				// it has to return 
-				// an empty object in case (which is already
-				// at this point), not a boolean. 
+				// it has to return
+				// an empty object in case, not a boolean.
+				$xmlrpc_val =& new xmlrpcval();
 				break;
 			}
 			return $xmlrpc_val;
 	}
 
-	if(XMLRPC_EPI_ENABLED == '0')
+	/**
+	* Convert the xml representation of a method response, method request or single
+	* xmlrpc value into the appropriate object (a.k.a. deserialize)
+	* @param string $xml_val
+	* @param array $options
+	* @return mixed false on error, or an instance of either xmlrpcval, xmlrpcmsg or xmlrpcresp
+	*/
+	function php_xmlrpc_decode_xml($xml_val, $options=array())
+	{
+		$GLOBALS['_xh'] = array();
+		$GLOBALS['_xh']['ac'] = '';
+		$GLOBALS['_xh']['stack'] = array();
+		$GLOBALS['_xh']['valuestack'] = array();
+		$GLOBALS['_xh']['params'] = array();
+		$GLOBALS['_xh']['pt'] = array();
+		$GLOBALS['_xh']['isf'] = 0;
+		$GLOBALS['_xh']['isf_reason'] = '';
+		$GLOBALS['_xh']['method'] = false;
+		$GLOBALS['_xh']['rt'] = '';
+		/// @todo 'guestimate' encoding
+		$parser = xml_parser_create();
+		xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
+		xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
+		xml_set_element_handler($parser, 'xmlrpc_se_any', 'xmlrpc_ee');
+		xml_set_character_data_handler($parser, 'xmlrpc_cd');
+		xml_set_default_handler($parser, 'xmlrpc_dh');
+		if(!xml_parse($parser, $xml_val, 1))
+		{
+			$errstr = sprintf('XML error: %s at line %d, column %d',
+						xml_error_string(xml_get_error_code($parser)),
+						xml_get_current_line_number($parser), xml_get_current_column_number($parser));
+			error_log($errstr);
+			xml_parser_free($parser);
+			return false;
+		}
+		xml_parser_free($parser);
+		if ($GLOBALS['_xh']['isf'] > 1) // test that $GLOBALS['_xh']['value'] is an obj, too???
+		{
+			error_log($GLOBALS['_xh']['isf_reason']);
+			return false;
+		}
+		switch ($GLOBALS['_xh']['rt'])
+		{
+			case 'methodresponse':
+				$v =& $GLOBALS['_xh']['value'];
+				if ($GLOBALS['_xh']['isf'] == 1)
+				{
+					$vc = $v->structmem('faultCode');
+					$vs = $v->structmem('faultString');
+					$r =& new xmlrpcresp(0, $vc->scalarval(), $vs->scalarval());
+				}
+				else
+				{
+					$r =& new xmlrpcresp($v);
+				}
+				return $r;
+			case 'methodcall':
+				$m =& new xmlrpcmsg($GLOBALS['_xh']['method']);
+				for($i=0; $i < count($GLOBALS['_xh']['params']); $i++)
+				{
+					$m->addParam($GLOBALS['_xh']['params'][$i]);
+				}
+				return $m;
+			case 'value':
+				return $GLOBALS['_xh']['value'];
+			default:
+				return false;
+		}
+	}
+
+	/**
+	* decode a string that is encoded w/ "chunked" transfer encoding
+	* as defined in rfc2068 par. 19.4.6
+	* code shamelessly stolen from nusoap library by Dietrich Ayala
+	*
+	* @param string $buffer the string to be decoded
+	* @return string
+	*/
+	function decode_chunked($buffer)
 	{
-		function xmlrpc_encode($php_val)
+		// length := 0
+		$length = 0;
+		$new = '';
+
+		// read chunk-size, chunk-extension (if any) and crlf
+		// get the position of the linebreak
+		$chunkend = strpos($buffer,"\r\n") + 2;
+		$temp = substr($buffer,0,$chunkend);
+		$chunk_size = hexdec( trim($temp) );
+		$chunkstart = $chunkend;
+		while($chunk_size > 0)
 		{
-			global $xmlrpcInt;
-			global $xmlrpcDouble;
-			global $xmlrpcString;
-			global $xmlrpcArray;
-			global $xmlrpcStruct;
-			global $xmlrpcBoolean;
+			$chunkend = strpos($buffer, "\r\n", $chunkstart + $chunk_size);
 
-			$type = gettype($php_val);
-			$xmlrpc_val = new xmlrpcval;
+			// just in case we got a broken connection
+			if($chunkend == false)
+			{
+				$chunk = substr($buffer,$chunkstart);
+				// append chunk-data to entity-body
+				$new .= $chunk;
+				$length += strlen($chunk);
+				break;
+			}
+
+			// read chunk-data and crlf
+			$chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
+			// append chunk-data to entity-body
+			$new .= $chunk;
+			// length := length + chunk-size
+			$length += strlen($chunk);
+			// read chunk-size and crlf
+			$chunkstart = $chunkend + 2;
 
-			switch($type)
+			$chunkend = strpos($buffer,"\r\n",$chunkstart)+2;
+			if($chunkend == false)
 			{
-				case 'array':
-				case 'object':
-					$arr = array();
-					while (list($k,$v) = each($php_val))
-					{
-						$arr[$k] = xmlrpc_encode($v);
-					}
-					$xmlrpc_val->addStruct($arr);
-					break;
-				case 'integer':
-					$xmlrpc_val->addScalar($php_val, $xmlrpcInt);
-					break;
-				case 'double':
-					$xmlrpc_val->addScalar($php_val, $xmlrpcDouble);
-					break;
-				case 'string':
-					$xmlrpc_val->addScalar($php_val, $xmlrpcString);
-					break;
-					// <G_Giunta_2001-02-29>
-					// Add support for encoding/decoding of booleans, since they are supported in PHP
-				case 'boolean':
-					$xmlrpc_val->addScalar($php_val, $xmlrpcBoolean);
-					break;
-					// </G_Giunta_2001-02-29>
-				//case 'unknown type':
-				default:
-					// giancarlo pinerolo <ping@alt.it>
-					// it has to return 
-					// an empty object in case (which is already
-					// at this point), not a boolean. 
-					break;
+				break; //just in case we got a broken connection
 			}
-			return $xmlrpc_val;
+			$temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
+			$chunk_size = hexdec( trim($temp) );
+			$chunkstart = $chunkend;
+		}
+		return $new;
+	}
+
+	/**
+	* xml charset encoding guessing helper function.
+	* Tries to determine the charset encoding of an XML chunk
+	* received over HTTP.
+	* NB: according to the spec (RFC 3023, if text/xml content-type is received over HTTP without a content-type,
+	* we SHOULD assume it is strictly US-ASCII. But we try to be more tolerant of unconforming (legacy?) clients/servers,
+	* which will be most probably using UTF-8 anyway...
+	*
+	* @param string $httpheaders the http Content-type header
+	* @param string $xmlchunk xml content buffer
+	* @param string $encoding_prefs comma separated list of character encodings to be used as default (when mb extension is enabled)
+	*
+	* @todo explore usage of mb_http_input(): does it detect http headers + post data? if so, use it instead of hand-detection!!!
+	*/
+	function guess_encoding($httpheader='', $xmlchunk='', $encoding_prefs=null)
+	{
+		// discussion: see http://www.yale.edu/pclt/encoding/
+		// 1 - test if encoding is specified in HTTP HEADERS
+
+		//Details:
+		// LWS:           (\13\10)?( |\t)+
+		// token:         (any char but excluded stuff)+
+		// header:        Content-type = ...; charset=value(; ...)*
+		//   where value is of type token, no LWS allowed between 'charset' and value
+		// Note: we do not check for invalid chars in VALUE:
+		//   this had better be done using pure ereg as below
+
+		/// @todo this test will pass if ANY header has charset specification, not only Content-Type. Fix it?
+		$matches = array();
+		if(preg_match('/;\s*charset=([^;]+)/i', $httpheader, $matches))
+		{
+			return strtoupper(trim($matches[1]));
+		}
+
+		// 2 - scan the first bytes of the data for a UTF-16 (or other) BOM pattern
+		//     (source: http://www.w3.org/TR/2000/REC-xml-20001006)
+		//     NOTE: actually, according to the spec, even if we find the BOM and determine
+		//     an encoding, we should check if there is an encoding specified
+		//     in the xml declaration, and verify if they match.
+		/// @todo implement check as described above?
+		/// @todo implement check for first bytes of string even without a BOM? (It sure looks harder than for cases WITH a BOM)
+		if(preg_match('/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\x00\x00\xFF\xFE|\xFE\xFF\x00\x00)/', $xmlchunk))
+		{
+			return 'UCS-4';
+		}
+		elseif(preg_match('/^(\xFE\xFF|\xFF\xFE)/', $xmlchunk))
+		{
+			return 'UTF-16';
+		}
+		elseif(preg_match('/^(\xEF\xBB\xBF)/', $xmlchunk))
+		{
+			return 'UTF-8';
+		}
+
+		// 3 - test if encoding is specified in the xml declaration
+		// Details:
+		// SPACE:         (#x20 | #x9 | #xD | #xA)+ === [ \x9\xD\xA]+
+		// EQ:            SPACE?=SPACE? === [ \x9\xD\xA]*=[ \x9\xD\xA]*
+		if (preg_match('/^<\?xml\s+version\s*=\s*'. "((?:\"[a-zA-Z0-9_.:-]+\")|(?:'[a-zA-Z0-9_.:-]+'))".
+			'\s+encoding\s*=\s*' . "((?:\"[A-Za-z][A-Za-z0-9._-]*\")|(?:'[A-Za-z][A-Za-z0-9._-]*'))/",
+			$xmlchunk, $matches))
+		{
+			return strtoupper(substr($matches[2], 1, -1));
+		}
+
+		// 4 - if mbstring is available, let it do the guesswork
+		// NB: we favour finding an encoding that is compatible with what we can process
+		if(extension_loaded('mbstring'))
+		{
+			if($encoding_prefs)
+			{
+				$enc = mb_detect_encoding($xmlchunk, $encoding_prefs);
+			}
+			else
+			{
+				$enc = mb_detect_encoding($xmlchunk);
+			}
+			// NB: mb_detect likes to call it ascii, xml parser likes to call it US_ASCII...
+			// IANA also likes better US-ASCII, so go with it
+			if($enc == 'ASCII')
+			{
+				$enc = 'US-'.$enc;
+			}
+			return $enc;
+		}
+		else
+		{
+			// no encoding specified: as per HTTP1.1 assume it is iso-8859-1?
+			// Both RFC 2616 (HTTP 1.1) and 1945(http 1.0) clearly state that for text/xxx content types
+			// this should be the standard. And we should be getting text/xml as request and response.
+			// BUT we have to be backward compatible with the lib, which always used UTF-8 as default...
+			return $GLOBALS['xmlrpc_defencoding'];
+		}
+	}
+
+	/**
+	* Checks if a given charset encoding is present in a list of encodings or
+	* if it is a valid subset of any encoding in the list
+	* @param string $encoding charset to be tested
+	* @param mixed $validlist comma separated list of valid charsets (or array of charsets)
+	*/
+	function is_valid_charset($encoding, $validlist)
+	{
+		$charset_supersets = array(
+			'US-ASCII' => array ('ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4',
+				'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8',
+				'ISO-8859-9', 'ISO-8859-10', 'ISO-8859-11', 'ISO-8859-12',
+				'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'UTF-8',
+				'EUC-JP', 'EUC-', 'EUC-KR', 'EUC-CN')
+		);
+		if (is_string($validlist))
+			$validlist = explode(',', $validlist);
+		if (@in_array(strtoupper($encoding), $validlist))
+			return true;
+		else
+		{
+			if (array_key_exists($encoding, $charset_supersets))
+				foreach ($validlist as $allowed)
+					if (in_array($allowed, $charset_supersets[$encoding]))
+						return true;
+				return false;
 		}
 	}
+
 ?>
diff -ruN 3.24.src/nucleus/libs/xmlrpcs.inc.php 3.31.src/nucleus/libs/xmlrpcs.inc.php
--- 3.24.src/nucleus/libs/xmlrpcs.inc.php	2005-08-21 09:53:40.000000000 -0500
+++ 3.31.src/nucleus/libs/xmlrpcs.inc.php	2007-10-22 19:36:00.000000000 -0500
@@ -1,7 +1,8 @@
 <?php
 // by Edd Dumbill (C) 1999-2002
 // <edd@usefulinc.com>
-// $Id: xmlrpcs.inc.php,v 1.4.2.3 2005/08/21 07:53:39 dekarma Exp $
+// $Original: xmlrpcs.inc,v 1.66 2006/09/17 21:25:06 ggiunta Exp $
+// $Id: xmlrpcs.inc.php 1199 2007-09-07 07:03:41Z kimitake $
 
 // Copyright (c) 1999,2000,2002 Edd Dumbill.
 // All rights reserved.
@@ -38,173 +39,272 @@
 	// XML RPC Server class
 	// requires: xmlrpc.inc
 
-	// listMethods: either a string, or nothing
-	$_xmlrpcs_listMethods_sig=array(array($xmlrpcArray, $xmlrpcString), array($xmlrpcArray));
+	$GLOBALS['xmlrpcs_capabilities'] = array(
+		// xmlrpc spec: always supported
+		'xmlrpc' => new xmlrpcval(array(
+			'specUrl' => new xmlrpcval('http://www.xmlrpc.com/spec', 'string'),
+			'specVersion' => new xmlrpcval(1, 'int')
+		), 'struct'),
+		// if we support system.xxx functions, we always support multicall, too...
+		// Note that, as of 2006/09/17, the following URL does not respond anymore
+		'system.multicall' => new xmlrpcval(array(
+			'specUrl' => new xmlrpcval('http://www.xmlrpc.com/discuss/msgReader$1208', 'string'),
+			'specVersion' => new xmlrpcval(1, 'int')
+		), 'struct'),
+		// introspection: version 2! we support 'mixed', too
+		'introspection' => new xmlrpcval(array(
+			'specUrl' => new xmlrpcval('http://phpxmlrpc.sourceforge.net/doc-2/ch10.html', 'string'),
+			'specVersion' => new xmlrpcval(2, 'int')
+		), 'struct')
+	);
+
+	/* Functions that implement system.XXX methods of xmlrpc servers */
+	$_xmlrpcs_getCapabilities_sig=array(array($GLOBALS['xmlrpcStruct']));
+	$_xmlrpcs_getCapabilities_doc='This method lists all the capabilites that the XML-RPC server has: the (more or less standard) extensions to the xmlrpc spec that it adheres to';
+	$_xmlrpcs_getCapabilities_sdoc=array(array('list of capabilities, described as structs with a version number and url for the spec'));
+	function _xmlrpcs_getCapabilities($server, $m=null)
+	{
+		$outAr = $GLOBALS['xmlrpcs_capabilities'];
+		// NIL extension
+		if ($GLOBALS['xmlrpc_null_extension']) {
+			$outAr['nil'] = new xmlrpcval(array(
+				'specUrl' => new xmlrpcval('http://www.ontosys.com/xml-rpc/extensions.php', 'string'),
+				'specVersion' => new xmlrpcval(1, 'int')
+			), 'struct');
+		}
+		return new xmlrpcresp(new xmlrpcval($outAr, 'struct'));
+	}
+
+	// listMethods: signature was either a string, or nothing.
+	// The useless string variant has been removed
+	$_xmlrpcs_listMethods_sig=array(array($GLOBALS['xmlrpcArray']));
 	$_xmlrpcs_listMethods_doc='This method lists all the methods that the XML-RPC server knows how to dispatch';
-	function _xmlrpcs_listMethods($server, $m)
+	$_xmlrpcs_listMethods_sdoc=array(array('list of method names'));
+	function _xmlrpcs_listMethods($server, $m=null) // if called in plain php values mode, second param is missing
 	{
-		global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap;
-		$v=new xmlrpcval();
-		$dmap=$server->dmap;
+
 		$outAr=array();
-		for(reset($dmap); list($key, $val)=each($dmap); )
+		foreach($server->dmap as $key => $val)
 		{
-			$outAr[]=new xmlrpcval($key, 'string');
+			$outAr[]=&new xmlrpcval($key, 'string');
 		}
-		$dmap=$_xmlrpcs_dmap;
-		for(reset($dmap); list($key, $val)=each($dmap); )
+		if($server->allow_system_funcs)
 		{
-			$outAr[]=new xmlrpcval($key, 'string');
+			foreach($GLOBALS['_xmlrpcs_dmap'] as $key => $val)
+			{
+				$outAr[]=&new xmlrpcval($key, 'string');
+			}
 		}
-		$v->addArray($outAr);
-		return new xmlrpcresp($v);
+		return new xmlrpcresp(new xmlrpcval($outAr, 'array'));
 	}
 
-	$_xmlrpcs_methodSignature_sig=array(array($xmlrpcArray, $xmlrpcString));
+	$_xmlrpcs_methodSignature_sig=array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcString']));
 	$_xmlrpcs_methodSignature_doc='Returns an array of known signatures (an array of arrays) for the method name passed. If no signatures are known, returns a none-array (test for type != array to detect missing signature)';
+	$_xmlrpcs_methodSignature_sdoc=array(array('list of known signatures, each sig being an array of xmlrpc type names', 'name of method to be described'));
 	function _xmlrpcs_methodSignature($server, $m)
 	{
-		global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap;
-
-		$methName=$m->getParam(0);
-		$methName=$methName->scalarval();
-		if (ereg("^system\.", $methName))
+		// let accept as parameter both an xmlrpcval or string
+		if (is_object($m))
 		{
-			$dmap=$_xmlrpcs_dmap; $sysCall=1;
+			$methName=$m->getParam(0);
+			$methName=$methName->scalarval();
+		}
+		else
+		{
+			$methName=$m;
+		}
+		if(strpos($methName, "system.") === 0)
+		{
+			$dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
 		}
 		else
 		{
 			$dmap=$server->dmap; $sysCall=0;
 		}
-		//	print "<!-- ${methName} -->\n";
-		if (isset($dmap[$methName]))
+		if(isset($dmap[$methName]))
 		{
-			if ($dmap[$methName]['signature'])
+			if(isset($dmap[$methName]['signature']))
 			{
 				$sigs=array();
-				$thesigs=$dmap[$methName]['signature'];
-				for($i=0; $i<sizeof($thesigs); $i++)
+				foreach($dmap[$methName]['signature'] as $inSig)
 				{
 					$cursig=array();
-					$inSig=$thesigs[$i];
-					for($j=0; $j<sizeof($inSig); $j++)
+					foreach($inSig as $sig)
 					{
-						$cursig[]=new xmlrpcval($inSig[$j], 'string');
+						$cursig[]=&new xmlrpcval($sig, 'string');
 					}
-					$sigs[]=new xmlrpcval($cursig, 'array');
+					$sigs[]=&new xmlrpcval($cursig, 'array');
 				}
-				$r=new xmlrpcresp(new xmlrpcval($sigs, 'array'));
+				$r=&new xmlrpcresp(new xmlrpcval($sigs, 'array'));
 			}
 			else
 			{
-				$r=new xmlrpcresp(new xmlrpcval('undef', 'string'));
+				// NB: according to the official docs, we should be returning a
+				// "none-array" here, which means not-an-array
+				$r=&new xmlrpcresp(new xmlrpcval('undef', 'string'));
 			}
 		}
 		else
 		{
-			$r=new xmlrpcresp(0,$xmlrpcerr['introspect_unknown'], $xmlrpcstr['introspect_unknown']);
+			$r=&new xmlrpcresp(0,$GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
 		}
 		return $r;
 	}
 
-	$_xmlrpcs_methodHelp_sig=array(array($xmlrpcString, $xmlrpcString));
+	$_xmlrpcs_methodHelp_sig=array(array($GLOBALS['xmlrpcString'], $GLOBALS['xmlrpcString']));
 	$_xmlrpcs_methodHelp_doc='Returns help text if defined for the method passed, otherwise returns an empty string';
+	$_xmlrpcs_methodHelp_sdoc=array(array('method description', 'name of the method to be described'));
 	function _xmlrpcs_methodHelp($server, $m)
 	{
-		global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap;
-
-		$methName=$m->getParam(0);
-		$methName=$methName->scalarval();
-		if (ereg("^system\.", $methName))
+		// let accept as parameter both an xmlrpcval or string
+		if (is_object($m))
+		{
+			$methName=$m->getParam(0);
+			$methName=$methName->scalarval();
+		}
+		else
+		{
+			$methName=$m;
+		}
+		if(strpos($methName, "system.") === 0)
 		{
-			$dmap=$_xmlrpcs_dmap; $sysCall=1;
+			$dmap=$GLOBALS['_xmlrpcs_dmap']; $sysCall=1;
 		}
 		else
 		{
 			$dmap=$server->dmap; $sysCall=0;
 		}
-		// print "<!-- ${methName} -->\n";
-		if (isset($dmap[$methName]))
+		if(isset($dmap[$methName]))
 		{
-			if ($dmap[$methName]['docstring'])
+			if(isset($dmap[$methName]['docstring']))
 			{
-				$r=new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string');
+				$r=&new xmlrpcresp(new xmlrpcval($dmap[$methName]['docstring']), 'string');
 			}
 			else
 			{
-				$r=new xmlrpcresp(new xmlrpcval('', 'string'));
+				$r=&new xmlrpcresp(new xmlrpcval('', 'string'));
 			}
 		}
 		else
 		{
-			$r=new xmlrpcresp(0, $xmlrpcerr['introspect_unknown'], $xmlrpcstr['introspect_unknown']);
+			$r=&new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['introspect_unknown'], $GLOBALS['xmlrpcstr']['introspect_unknown']);
 		}
 		return $r;
 	}
 
-	$_xmlrpcs_multicall_sig = array(array($xmlrpcArray, $xmlrpcArray));
+	$_xmlrpcs_multicall_sig = array(array($GLOBALS['xmlrpcArray'], $GLOBALS['xmlrpcArray']));
 	$_xmlrpcs_multicall_doc = 'Boxcar multiple RPC calls in one request. See http://www.xmlrpc.com/discuss/msgReader$1208 for details';
-
+	$_xmlrpcs_multicall_sdoc = array(array('list of response structs, where each struct has the usual members', 'list of calls, with each call being represented as a struct, with members "methodname" and "params"'));
 	function _xmlrpcs_multicall_error($err)
 	{
-		if (is_string($err))
+		if(is_string($err))
 		{
-			global $xmlrpcerr, $xmlrpcstr;
-			$str  = $xmlrpcstr["multicall_${err}"];
-			$code = $xmlrpcerr["multicall_${err}"];
+			$str = $GLOBALS['xmlrpcstr']["multicall_${err}"];
+			$code = $GLOBALS['xmlrpcerr']["multicall_${err}"];
 		}
 		else
 		{
 			$code = $err->faultCode();
 			$str = $err->faultString();
 		}
-		$struct['faultCode'] = new xmlrpcval($code, 'int');
-		$struct['faultString'] = new xmlrpcval($str, 'string');
+		$struct = array();
+		$struct['faultCode'] =& new xmlrpcval($code, 'int');
+		$struct['faultString'] =& new xmlrpcval($str, 'string');
 		return new xmlrpcval($struct, 'struct');
 	}
 
 	function _xmlrpcs_multicall_do_call($server, $call)
 	{
-		if ($call->kindOf() != 'struct')
+		if($call->kindOf() != 'struct')
 		{
 			return _xmlrpcs_multicall_error('notstruct');
 		}
-		$methName = $call->structmem('methodName');
-		if (!$methName)
+		$methName = @$call->structmem('methodName');
+		if(!$methName)
 		{
 			return _xmlrpcs_multicall_error('nomethod');
 		}
-		if ($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string')
+		if($methName->kindOf() != 'scalar' || $methName->scalartyp() != 'string')
 		{
 			return _xmlrpcs_multicall_error('notstring');
 		}
-		if ($methName->scalarval() == 'system.multicall')
+		if($methName->scalarval() == 'system.multicall')
 		{
 			return _xmlrpcs_multicall_error('recursion');
 		}
 
-		$params = $call->structmem('params');
-		if (!$params)
+		$params = @$call->structmem('params');
+		if(!$params)
 		{
 			return _xmlrpcs_multicall_error('noparams');
 		}
-		if ($params->kindOf() != 'array')
+		if($params->kindOf() != 'array')
 		{
 			return _xmlrpcs_multicall_error('notarray');
 		}
 		$numParams = $params->arraysize();
 
-		$msg = new xmlrpcmsg($methName->scalarval());
-		for ($i = 0; $i < $numParams; $i++)
+		$msg =& new xmlrpcmsg($methName->scalarval());
+		for($i = 0; $i < $numParams; $i++)
 		{
-			$msg->addParam($params->arraymem($i));
+			if(!$msg->addParam($params->arraymem($i)))
+			{
+				$i++;
+				return _xmlrpcs_multicall_error(new xmlrpcresp(0,
+					$GLOBALS['xmlrpcerr']['incorrect_params'],
+					$GLOBALS['xmlrpcstr']['incorrect_params'] . ": probable xml error in param " . $i));
+			}
 		}
 
 		$result = $server->execute($msg);
 
-		if ($result->faultCode() != 0)
+		if($result->faultCode() != 0)
 		{
-			return _xmlrpcs_multicall_error($result);    // Method returned fault.
+			return _xmlrpcs_multicall_error($result);		// Method returned fault.
+		}
+
+		return new xmlrpcval(array($result->value()), 'array');
+	}
+
+	function _xmlrpcs_multicall_do_call_phpvals($server, $call)
+	{
+		if(!is_array($call))
+		{
+			return _xmlrpcs_multicall_error('notstruct');
+		}
+		if(!array_key_exists('methodName', $call))
+		{
+			return _xmlrpcs_multicall_error('nomethod');
+		}
+		if (!is_string($call['methodName']))
+		{
+			return _xmlrpcs_multicall_error('notstring');
+		}
+		if($call['methodName'] == 'system.multicall')
+		{
+			return _xmlrpcs_multicall_error('recursion');
+		}
+		if(!array_key_exists('params', $call))
+		{
+			return _xmlrpcs_multicall_error('noparams');
+		}
+		if(!is_array($call['params']))
+		{
+			return _xmlrpcs_multicall_error('notarray');
+		}
+
+		// this is a real dirty and simplistic hack, since we might have received a
+		// base64 or datetime values, but they will be listed as strings here...
+		$numParams = count($call['params']);
+		$pt = array();
+		foreach($call['params'] as $val)
+			$pt[] = php_2_xmlrpc_type(gettype($val));
+
+		$result = $server->execute($call['methodName'], $call['params'], $pt);
+
+		if($result->faultCode() != 0)
+		{
+			return _xmlrpcs_multicall_error($result);		// Method returned fault.
 		}
 
 		return new xmlrpcval(array($result->value()), 'array');
@@ -212,53 +312,182 @@
 
 	function _xmlrpcs_multicall($server, $m)
 	{
-		$calls = $m->getParam(0);
-		$numCalls = $calls->arraysize();
 		$result = array();
-
-		for ($i = 0; $i < $numCalls; $i++)
+		// let accept a plain list of php parameters, beside a single xmlrpc msg object
+		if (is_object($m))
 		{
-			$call = $calls->arraymem($i);
-			$result[$i] = _xmlrpcs_multicall_do_call($server, $call);
+			$calls = $m->getParam(0);
+			$numCalls = $calls->arraysize();
+			for($i = 0; $i < $numCalls; $i++)
+			{
+				$call = $calls->arraymem($i);
+				$result[$i] = _xmlrpcs_multicall_do_call($server, $call);
+			}
+		}
+		else
+		{
+			$numCalls=count($m);
+			for($i = 0; $i < $numCalls; $i++)
+			{
+				$result[$i] = _xmlrpcs_multicall_do_call_phpvals($server, $m[$i]);
+			}
 		}
 
 		return new xmlrpcresp(new xmlrpcval($result, 'array'));
 	}
 
-	$_xmlrpcs_dmap=array(
+	$GLOBALS['_xmlrpcs_dmap']=array(
 		'system.listMethods' => array(
 			'function' => '_xmlrpcs_listMethods',
 			'signature' => $_xmlrpcs_listMethods_sig,
-			'docstring' => $_xmlrpcs_listMethods_doc),
+			'docstring' => $_xmlrpcs_listMethods_doc,
+			'signature_docs' => $_xmlrpcs_listMethods_sdoc),
 		'system.methodHelp' => array(
 			'function' => '_xmlrpcs_methodHelp',
 			'signature' => $_xmlrpcs_methodHelp_sig,
-			'docstring' => $_xmlrpcs_methodHelp_doc),
+			'docstring' => $_xmlrpcs_methodHelp_doc,
+			'signature_docs' => $_xmlrpcs_methodHelp_sdoc),
 		'system.methodSignature' => array(
 			'function' => '_xmlrpcs_methodSignature',
 			'signature' => $_xmlrpcs_methodSignature_sig,
-			'docstring' => $_xmlrpcs_methodSignature_doc),
+			'docstring' => $_xmlrpcs_methodSignature_doc,
+			'signature_docs' => $_xmlrpcs_methodSignature_sdoc),
 		'system.multicall' => array(
 			'function' => '_xmlrpcs_multicall',
 			'signature' => $_xmlrpcs_multicall_sig,
-			'docstring' => $_xmlrpcs_multicall_doc
-		)
+			'docstring' => $_xmlrpcs_multicall_doc,
+			'signature_docs' => $_xmlrpcs_multicall_sdoc),
+		'system.getCapabilities' => array(
+			'function' => '_xmlrpcs_getCapabilities',
+			'signature' => $_xmlrpcs_getCapabilities_sig,
+			'docstring' => $_xmlrpcs_getCapabilities_doc,
+			'signature_docs' => $_xmlrpcs_getCapabilities_sdoc)
 	);
 
-	$_xmlrpc_debuginfo='';
+	$GLOBALS['_xmlrpcs_occurred_errors'] = '';
+	$GLOBALS['_xmlrpcs_prev_ehandler'] = '';
+	/**
+	* Error handler used to track errors that occur during server-side execution of PHP code.
+	* This allows to report back to the client whether an internal error has occurred or not
+	* using an xmlrpc response object, instead of letting the client deal with the html junk
+	* that a PHP execution error on the server generally entails.
+	*
+	* NB: in fact a user defined error handler can only handle WARNING, NOTICE and USER_* errors.
+	*
+	*/
+	function _xmlrpcs_errorHandler($errcode, $errstring, $filename=null, $lineno=null, $context=null)
+	{
+		// obey the @ protocol
+		if (error_reporting() == 0)
+			return;
+
+		//if($errcode != E_NOTICE && $errcode != E_WARNING && $errcode != E_USER_NOTICE && $errcode != E_USER_WARNING)
+		if($errcode != 2048) // do not use E_STRICT by name, since on PHP 4 it will not be defined
+		{
+			$GLOBALS['_xmlrpcs_occurred_errors'] = $GLOBALS['_xmlrpcs_occurred_errors'] . $errstring . "\n";
+		}
+		// Try to avoid as much as possible disruption to the previous error handling
+		// mechanism in place
+		if($GLOBALS['_xmlrpcs_prev_ehandler'] == '')
+		{
+			// The previous error handler was the default: all we should do is log error
+			// to the default error log (if level high enough)
+			if(ini_get('log_errors') && (intval(ini_get('error_reporting')) & $errcode))
+			{
+				error_log($errstring);
+			}
+		}
+		else
+		{
+			// Pass control on to previous error handler, trying to avoid loops...
+			if($GLOBALS['_xmlrpcs_prev_ehandler'] != '_xmlrpcs_errorHandler')
+			{
+				// NB: this code will NOT work on php < 4.0.2: only 2 params were used for error handlers
+				if(is_array($GLOBALS['_xmlrpcs_prev_ehandler']))
+				{
+					$GLOBALS['_xmlrpcs_prev_ehandler'][0]->$GLOBALS['_xmlrpcs_prev_ehandler'][1]($errcode, $errstring, $filename, $lineno, $context);
+				}
+				else
+				{
+					$GLOBALS['_xmlrpcs_prev_ehandler']($errcode, $errstring, $filename, $lineno, $context);
+				}
+			}
+		}
+	}
+
+	$GLOBALS['_xmlrpc_debuginfo']='';
+
+	/**
+	* Add a string to the debug info that can be later seralized by the server
+	* as part of the response message.
+	* Note that for best compatbility, the debug string should be encoded using
+	* the $GLOBALS['xmlrpc_internalencoding'] character set.
+	* @param string $m
+	* @access public
+	*/
 	function xmlrpc_debugmsg($m)
 	{
-		global $_xmlrpc_debuginfo;
-		$_xmlrpc_debuginfo=$_xmlrpc_debuginfo . $m . "\n";
+		$GLOBALS['_xmlrpc_debuginfo'] .= $m . "\n";
 	}
 
 	class xmlrpc_server
 	{
+		/// array defining php functions exposed as xmlrpc methods by this server
 		var $dmap=array();
-
-		function xmlrpc_server($dispMap='', $serviceNow=1)
+		/**
+		* Defines how functions in dmap will be invokde: either using an xmlrpc msg object
+		* or plain php values.
+		* valid strings are 'xmlrpcvals', 'phpvals' or 'epivals'
+		*/
+		var $functions_parameters_type='xmlrpcvals';
+		/// controls wether the server is going to echo debugging messages back to the client as comments in response body. valid values: 0,1,2,3
+		var $debug = 1;
+		/**
+		* When set to true, it will enable HTTP compression of the response, in case
+		* the client has declared its support for compression in the request.
+		*/
+		var $compress_response = false;
+		/**
+		* List of http compression methods accepted by the server for requests.
+		* NB: PHP supports deflate, gzip compressions out of the box if compiled w. zlib
+		*/
+		var $accepted_compression = array();
+		/// shall we serve calls to system.* methods?
+		var $allow_system_funcs = true;
+		/// list of charset encodings natively accepted for requests
+		var $accepted_charset_encodings = array();
+		/**
+		* charset encoding to be used for response.
+		* NB: if we can, we will convert the generated response from internal_encoding to the intended one.
+		* can be: a supported xml encoding (only UTF-8 and ISO-8859-1 at present, unless mbstring is enabled),
+		* null (leave unspecified in response, convert output stream to US_ASCII),
+		* 'default' (use xmlrpc library default as specified in xmlrpc.inc, convert output stream if needed),
+		* or 'auto' (use client-specified charset encoding or same as request if request headers do not specify it (unless request is US-ASCII: then use library default anyway).
+		* NB: pretty dangerous if you accept every charset and do not have mbstring enabled)
+		*/
+		var $response_charset_encoding = '';
+		/// storage for internal debug info
+		var $debug_info = '';
+		/// extra data passed at runtime to method handling functions. Used only by EPI layer
+		var $user_data = null;
+
+		/**
+		* @param array $dispmap the dispatch map withd efinition of exposed services
+		* @param boolean $servicenow set to false to prevent the server from runnung upon construction
+		*/
+		function xmlrpc_server($dispMap=null, $serviceNow=true)
 		{
-			global $HTTP_RAW_POST_DATA;
+			// if ZLIB is enabled, let the server by default accept compressed requests,
+			// and compress responses sent to clients that support them
+			if(function_exists('gzinflate'))
+			{
+				$this->accepted_compression = array('gzip', 'deflate');
+				$this->compress_response = true;
+			}
+
+			// by default the xml parser can support these 3 charset encodings
+			$this->accepted_charset_encodings = array('UTF-8', 'ISO-8859-1', 'US-ASCII');
+
 			// dispMap is a dispatch array of methods
 			// mapped to function names and signatures
 			// if a method
@@ -278,228 +507,666 @@
 			}
 		}
 
-		function serializeDebug()
+		/**
+		* Set debug level of server.
+		* @param integer $in debug lvl: determines info added to xmlrpc responses (as xml comments)
+		* 0 = no debug info,
+		* 1 = msgs set from user with debugmsg(),
+		* 2 = add complete xmlrpc request (headers and body),
+		* 3 = add also all processing warnings happened during method processing
+		* (NB: this involves setting a custom error handler, and might interfere
+		* with the standard processing of the php function exposed as method. In
+		* particular, triggering an USER_ERROR level error will not halt script
+		* execution anymore, but just end up logged in the xmlrpc response)
+		* Note that info added at elevel 2 and 3 will be base64 encoded
+		* @access public
+		*/
+		function setDebug($in)
 		{
-			global $_xmlrpc_debuginfo;
-			if ($_xmlrpc_debuginfo!='')
+			$this->debug=$in;
+		}
+
+		/**
+		* Return a string with the serialized representation of all debug info
+		* @param string $charset_encoding the target charset encoding for the serialization
+		* @return string an XML comment (or two)
+		*/
+		function serializeDebug($charset_encoding='')
+		{
+			// Tough encoding problem: which internal charset should we assume for debug info?
+			// It might contain a copy of raw data received from client, ie with unknown encoding,
+			// intermixed with php generated data and user generated data...
+			// so we split it: system debug is base 64 encoded,
+			// user debug info should be encoded by the end user using the INTERNAL_ENCODING
+			$out = '';
+			if ($this->debug_info != '')
 			{
-				return "<!-- DEBUG INFO:\n\n" . xmlrpc_encode_entitites($_xmlrpc_debuginfo) . "\n-->\n";
+				$out .= "<!-- SERVER DEBUG INFO (BASE64 ENCODED):\n".base64_encode($this->debug_info)."\n-->\n";
 			}
-			else
+			if($GLOBALS['_xmlrpc_debuginfo']!='')
 			{
-				return '';
+
+				$out .= "<!-- DEBUG INFO:\n" . xmlrpc_encode_entitites(str_replace('--', '_-', $GLOBALS['_xmlrpc_debuginfo']), $GLOBALS['xmlrpc_internalencoding'], $charset_encoding) . "\n-->\n";
+				// NB: a better solution MIGHT be to use CDATA, but we need to insert it
+				// into return payload AFTER the beginning tag
+				//$out .= "<![CDATA[ DEBUG INFO:\n\n" . str_replace(']]>', ']_]_>', $GLOBALS['_xmlrpc_debuginfo']) . "\n]]>\n";
 			}
+			return $out;
 		}
 
-		function service()
+		/**
+		* Execute the xmlrpc request, printing the response
+		* @param string $data the request body. If null, the http POST request will be examined
+		* @return xmlrpcresp the response object (usually not used by caller...)
+		* @access public
+		*/
+		function service($data=null, $return_payload=false)
 		{
-			//global $xmlrpc_defencoding;
+			if ($data === null)
+			{
+				$data = isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : '';
+			}
+			$raw_data = $data;
+
+			// reset internal debug info
+			$this->debug_info = '';
+
+			// Echo back what we received, before parsing it
+			if($this->debug > 1)
+			{
+				$this->debugmsg("+++GOT+++\n" . $data . "\n+++END+++");
+			}
+
+			$r = $this->parseRequestHeaders($data, $req_charset, $resp_charset, $resp_encoding);
+			if (!$r)
+			{
+				$r=$this->parseRequest($data, $req_charset);
+			}
+
+			// save full body of request into response, for more debugging usages
+			$r->raw_data = $raw_data;
+
+			if($this->debug > 2 && $GLOBALS['_xmlrpcs_occurred_errors'])
+			{
+				$this->debugmsg("+++PROCESSING ERRORS AND WARNINGS+++\n" .
+					$GLOBALS['_xmlrpcs_occurred_errors'] . "+++END+++");
+			}
+
+			$payload=$this->xml_header($resp_charset);
+			if($this->debug > 0)
+			{
+				$payload = $payload . $this->serializeDebug($resp_charset);
+			}
+
+			// G. Giunta 2006-01-27: do not create response serialization if it has
+			// already happened. Helps building json magic
+			if (empty($r->payload))
+			{
+				$r->serialize($resp_charset);
+			}
+			$payload = $payload . $r->payload;
+
+			if ($return_payload)
+			{
+				return $payload;
+			}
+
+			// if we get a warning/error that has output some text before here, then we cannot
+			// add a new header. We cannot say we are sending xml, either...
+			if(!headers_sent())
+			{
+				header('Content-Type: '.$r->content_type);
+				// we do not know if client actually told us an accepted charset, but if he did
+				// we have to tell him what we did
+				header("Vary: Accept-Charset");
+
+				// http compression of output: only
+				// if we can do it, and we want to do it, and client asked us to,
+				// and php ini settings do not force it already
+				$php_no_self_compress = ini_get('zlib.output_compression') == '' && (ini_get('output_handler') != 'ob_gzhandler');
+				if($this->compress_response && function_exists('gzencode') && $resp_encoding != ''
+					&& $php_no_self_compress)
+				{
+					if(strpos($resp_encoding, 'gzip') !== false)
+					{
+						$payload = gzencode($payload);
+						header("Content-Encoding: gzip");
+						header("Vary: Accept-Encoding");
+					}
+					elseif (strpos($resp_encoding, 'deflate') !== false)
+					{
+						$payload = gzcompress($payload);
+						header("Content-Encoding: deflate");
+						header("Vary: Accept-Encoding");
+					}
+				}
+
+				// do not ouput content-length header if php is compressing output for us:
+				// it will mess up measurements
+				if($php_no_self_compress)
+				{
+					header('Content-Length: ' . (int)strlen($payload));
+				}
+			}
+			else
+			{
+				error_log('XML-RPC: xmlrpc_server::service: http headers already sent before response is fully generated. Check for php warning or error messages');
+			}
 
-			$r=$this->parseRequest();
-			//$payload='<?xml version="1.0" encoding="' . $xmlrpc_defencoding . '"?' . '>' . "\n"
-			$payload='<?xml version="1.0" ?' . '>' . "\n"
-				. $this->serializeDebug()
-				. $r->serialize();
-			header('Content-Type: text/xml');
-			header('Content-Length: ' . (int)strlen($payload));
 			print $payload;
+
+			// return request, in case subclasses want it
+			return $r;
 		}
 
-		/*
-		add a method to the dispatch map
+		/**
+		* Add a method to the dispatch map
+		* @param string $methodname the name with which the method will be made available
+		* @param string $function the php function that will get invoked
+		* @param array $sig the array of valid method signatures
+		* @param string $doc method documentation
+		* @access public
 		*/
-		function add_to_map($methodname,$function,$sig,$doc)
+		function add_to_map($methodname,$function,$sig=null,$doc='')
 		{
 			$this->dmap[$methodname] = array(
-				'function'  => $function,
-				'signature' => $sig,
+				'function'	=> $function,
 				'docstring' => $doc
 			);
+			if ($sig)
+			{
+				$this->dmap[$methodname]['signature'] = $sig;
+			}
 		}
 
+		/**
+		* Verify type and number of parameters received against a list of known signatures
+		* @param array $in array of either xmlrpcval objects or xmlrpc type definitions
+		* @param array $sig array of known signatures to match against
+		* @access private
+		*/
 		function verifySignature($in, $sig)
 		{
-			for($i=0; $i<sizeof($sig); $i++)
+			// check each possible signature in turn
+			if (is_object($in))
+			{
+				$numParams = $in->getNumParams();
+			}
+			else
+			{
+				$numParams = count($in);
+			}
+			foreach($sig as $cursig)
 			{
-				// check each possible signature in turn
-				$cursig=$sig[$i];
-				if (sizeof($cursig)==$in->getNumParams()+1)
+				if(count($cursig)==$numParams+1)
 				{
 					$itsOK=1;
-					for($n=0; $n<$in->getNumParams(); $n++)
+					for($n=0; $n<$numParams; $n++)
 					{
-						$p=$in->getParam($n);
-						// print "<!-- $p -->\n";
-						if ($p->kindOf() == 'scalar')
+						if (is_object($in))
 						{
-							$pt=$p->scalartyp();
+							$p=$in->getParam($n);
+							if($p->kindOf() == 'scalar')
+							{
+								$pt=$p->scalartyp();
+							}
+							else
+							{
+								$pt=$p->kindOf();
+							}
 						}
 						else
 						{
-							$pt=$p->kindOf();
+							$pt= $in[$n] == 'i4' ? 'int' : $in[$n]; // dispatch maps never use i4...
 						}
-						// $n+1 as first type of sig is return type
-						if ($pt != $cursig[$n+1])
+
+						// param index is $n+1, as first member of sig is return type
+						if($pt != $cursig[$n+1] && $cursig[$n+1] != $GLOBALS['xmlrpcValue'])
 						{
 							$itsOK=0;
-							$pno=$n+1; $wanted=$cursig[$n+1]; $got=$pt;
+							$pno=$n+1;
+							$wanted=$cursig[$n+1];
+							$got=$pt;
 							break;
 						}
 					}
-					if ($itsOK)
+					if($itsOK)
 					{
 						return array(1,'');
 					}
 				}
 			}
-			if (isset($wanted))
-				return array(0, "Wanted ${wanted}, got ${got} at param ${pno})");
+			if(isset($wanted))
+			{
+				return array(0, "Wanted ${wanted}, got ${got} at param ${pno}");
+			}
 			else
+			{
 				return array(0, "No method signature matches number of parameters");
+			}
 		}
 
-		function parseRequest($data='')
+		/**
+		* Parse http headers received along with xmlrpc request. If needed, inflate request
+		* @return null on success or an xmlrpcresp
+		* @access private
+		*/
+		function parseRequestHeaders(&$data, &$req_encoding, &$resp_encoding, &$resp_compression)
 		{
-			global $_xh,$HTTP_RAW_POST_DATA;
-			global $xmlrpcerr, $xmlrpcstr, $xmlrpcerrxml, $xmlrpc_defencoding,
-			$_xmlrpcs_dmap, $xmlrpc_internalencoding;
+			// Play nice to PHP 4.0.x: superglobals were not yet invented...
+			if(!isset($_SERVER))
+			{
+				$_SERVER = $GLOBALS['HTTP_SERVER_VARS'];
+			}
+
+			if($this->debug > 1)
+			{
+				if(function_exists('getallheaders'))
+				{
+					$this->debugmsg(''); // empty line
+					foreach(getallheaders() as $name => $val)
+					{
+						$this->debugmsg("HEADER: $name: $val");
+					}
+				}
+
+			}
+
+			if(isset($_SERVER['HTTP_CONTENT_ENCODING']))
+			{
+				$content_encoding = str_replace('x-', '', $_SERVER['HTTP_CONTENT_ENCODING']);
+			}
+			else
+			{
+				$content_encoding = '';
+			}
+
+			// check if request body has been compressed and decompress it
+			if($content_encoding != '' && strlen($data))
+			{
+				if($content_encoding == 'deflate' || $content_encoding == 'gzip')
+				{
+					// if decoding works, use it. else assume data wasn't gzencoded
+					if(function_exists('gzinflate') && in_array($content_encoding, $this->accepted_compression))
+					{
+						if($content_encoding == 'deflate' && $degzdata = @gzuncompress($data))
+						{
+							$data = $degzdata;
+							if($this->debug > 1)
+							{
+								$this->debugmsg("\n+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
+							}
+						}
+						elseif($content_encoding == 'gzip' && $degzdata = @gzinflate(substr($data, 10)))
+						{
+							$data = $degzdata;
+							if($this->debug > 1)
+								$this->debugmsg("+++INFLATED REQUEST+++[".strlen($data)." chars]+++\n" . $data . "\n+++END+++");
+						}
+						else
+						{
+							$r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_decompress_fail'], $GLOBALS['xmlrpcstr']['server_decompress_fail']);
+							return $r;
+						}
+					}
+					else
+					{
+						//error_log('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
+						$r =& new xmlrpcresp(0, $GLOBALS['xmlrpcerr']['server_cannot_decompress'], $GLOBALS['xmlrpcstr']['server_cannot_decompress']);
+						return $r;
+					}
+				}
+			}
+
+			// check if client specified accepted charsets, and if we know how to fulfill
+			// the request
+			if ($this->response_charset_encoding == 'auto')
+			{
+				$resp_encoding = '';
+				if (isset($_SERVER['HTTP_ACCEPT_CHARSET']))
+				{
+					// here we should check if we can match the client-requested encoding
+					// with the encodings we know we can generate.
+					/// @todo we should parse q=0.x preferences instead of getting first charset specified...
+					$client_accepted_charsets = explode(',', strtoupper($_SERVER['HTTP_ACCEPT_CHARSET']));
+					// Give preference to internal encoding
+					$known_charsets = array($this->internal_encoding, 'UTF-8', 'ISO-8859-1', 'US-ASCII');
+					foreach ($known_charsets as $charset)
+					{
+						foreach ($client_accepted_charsets as $accepted)
+							if (strpos($accepted, $charset) === 0)
+							{
+								$resp_encoding = $charset;
+								break;
+							}
+						if ($resp_encoding)
+							break;
+					}
+				}
+			}
+			else
+			{
+				$resp_encoding = $this->response_charset_encoding;
+			}
 
-			if ($data=='')
+			if (isset($_SERVER['HTTP_ACCEPT_ENCODING']))
 			{
-				$data=$HTTP_RAW_POST_DATA;
+				$resp_compression = $_SERVER['HTTP_ACCEPT_ENCODING'];
 			}
-            // G. Giunta 2005/02/13: we do NOT expect to receive html entities
-            // so we do not try to convert them into xml character entities
+			else
+			{
+				$resp_compression = '';
+			}
+
+			// 'guestimate' request encoding
+			/// @todo check if mbstring is enabled and automagic input conversion is on: it might mingle with this check???
+			$req_encoding = guess_encoding(isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : '',
+				$data);
+
+			return null;
+		}
+
+		/**
+		* Parse an xml chunk containing an xmlrpc request and execute the corresponding
+		* php function registered with the server
+		* @param string $data the xml request
+		* @param string $req_encoding (optional) the charset encoding of the xml request
+		* @return xmlrpcresp
+		* @access private
+		*/
+		function parseRequest($data, $req_encoding='')
+		{
+			// 2005/05/07 commented and moved into caller function code
+			//if($data=='')
+			//{
+			//	$data=$GLOBALS['HTTP_RAW_POST_DATA'];
+			//}
+
+			// G. Giunta 2005/02/13: we do NOT expect to receive html entities
+			// so we do not try to convert them into xml character entities
 			//$data = xmlrpc_html_entity_xlate($data);
-			$parser = xml_parser_create($xmlrpc_defencoding);
 
-			$_xh[$parser]=array();
-			//$_xh[$parser]['st']='';
-			//$_xh[$parser]['cm']=0;
-			$_xh[$parser]['isf']=0;
-			$_xh[$parser]['isf_reason']='';
-			$_xh[$parser]['params']=array();
-			$_xh[$parser]['stack']=array();
-			$_xh[$parser]['valuestack'] = array();
-			$_xh[$parser]['method']='';
+			$GLOBALS['_xh']=array();
+			$GLOBALS['_xh']['ac']='';
+			$GLOBALS['_xh']['stack']=array();
+			$GLOBALS['_xh']['valuestack'] = array();
+			$GLOBALS['_xh']['params']=array();
+			$GLOBALS['_xh']['pt']=array();
+			$GLOBALS['_xh']['isf']=0;
+			$GLOBALS['_xh']['isf_reason']='';
+			$GLOBALS['_xh']['method']=false; // so we can check later if we got a methodname or not
+			$GLOBALS['_xh']['rt']='';
 
 			// decompose incoming XML into request structure
+			if ($req_encoding != '')
+			{
+				if (!in_array($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+				// the following code might be better for mb_string enabled installs, but
+				// makes the lib about 200% slower...
+				//if (!is_valid_charset($req_encoding, array('UTF-8', 'ISO-8859-1', 'US-ASCII')))
+				{
+					error_log('XML-RPC: xmlrpc_server::parseRequest: invalid charset encoding of received request: '.$req_encoding);
+					$req_encoding = $GLOBALS['xmlrpc_defencoding'];
+				}
+				/// @BUG this will fail on PHP 5 if charset is not specified in the xml prologue,
+				// the encoding is not UTF8 and there are non-ascii chars in the text...
+				$parser = xml_parser_create($req_encoding);
+			}
+			else
+			{
+				$parser = xml_parser_create();
+			}
 
 			xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
-            // G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
-            // the xml parser to give us back data in the expected charset
-            @xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $xmlrpc_internalencoding);
+			// G. Giunta 2005/02/13: PHP internally uses ISO-8859-1, so we have to tell
+			// the xml parser to give us back data in the expected charset
+			xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['xmlrpc_internalencoding']);
 
-			xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
+			if ($this->functions_parameters_type != 'xmlrpcvals')
+				xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee_fast');
+			else
+				xml_set_element_handler($parser, 'xmlrpc_se', 'xmlrpc_ee');
 			xml_set_character_data_handler($parser, 'xmlrpc_cd');
 			xml_set_default_handler($parser, 'xmlrpc_dh');
-			if (!xml_parse($parser, $data, 1))
+			if(!xml_parse($parser, $data, 1))
 			{
 				// return XML error as a faultCode
-				$r=new xmlrpcresp(0,
-				$xmlrpcerrxml+xml_get_error_code($parser),
-				sprintf('XML error: %s at line %d',
+				$r=&new xmlrpcresp(0,
+				$GLOBALS['xmlrpcerrxml']+xml_get_error_code($parser),
+				sprintf('XML error: %s at line %d, column %d',
 					xml_error_string(xml_get_error_code($parser)),
-					xml_get_current_line_number($parser)));
+					xml_get_current_line_number($parser), xml_get_current_column_number($parser)));
 				xml_parser_free($parser);
 			}
-			else
-			if ($_xh[$parser]['isf'])
+			elseif ($GLOBALS['_xh']['isf'])
 			{
 				xml_parser_free($parser);
-				$r=new xmlrpcresp(0,
-					$xmlrpcerr['invalid_request'],
-					$xmlrpcstr['invalid_request'] . ' ' . $_xh[$parser]['isf_reason']);
+				$r=&new xmlrpcresp(0,
+					$GLOBALS['xmlrpcerr']['invalid_request'],
+					$GLOBALS['xmlrpcstr']['invalid_request'] . ' ' . $GLOBALS['_xh']['isf_reason']);
 			}
 			else
 			{
 				xml_parser_free($parser);
+				if ($this->functions_parameters_type != 'xmlrpcvals')
+				{
+					if($this->debug > 1)
+					{
+						$this->debugmsg("\n+++PARSED+++\n".var_export($GLOBALS['_xh']['params'], true)."\n+++END+++");
+					}
+					$r = $this->execute($GLOBALS['_xh']['method'], $GLOBALS['_xh']['params'], $GLOBALS['_xh']['pt']);
+				}
+				else
+				{
+					// build an xmlrpcmsg object with data parsed from xml
+					$m=&new xmlrpcmsg($GLOBALS['_xh']['method']);
+					// now add parameters in
+					for($i=0; $i<count($GLOBALS['_xh']['params']); $i++)
+					{
+						$m->addParam($GLOBALS['_xh']['params'][$i]);
+					}
+
+					if($this->debug > 1)
+					{
+						$this->debugmsg("\n+++PARSED+++\n".var_export($m, true)."\n+++END+++");
+					}
 
-				$m=new xmlrpcmsg($_xh[$parser]['method']);
-				// now add parameters in
-				$plist='';
-				//$allOK = 1;
-				for($i=0; $i<sizeof($_xh[$parser]['params']); $i++)
-				{
-					//print "<!-- " . $_xh[$parser]['params'][$i]. "-->\n";
-					$plist.="$i - " .  $_xh[$parser]['params'][$i]. ";\n";
-					//$allOK = 0;
-					//@eval('$m->addParam(' . $_xh[$parser]['params'][$i]. '); $allOK=1;');
-					@$m->addParam($_xh[$parser]['params'][$i]);
-					//if (!$allOK)
-					//{
-					//	break;
-					//}
-				}
-				// uncomment this to really see what the server's getting!
-				// xmlrpc_debugmsg($plist);
-				//if (!$allOK)
-				//{
-				//	$r = new xmlrpcresp(0,
-  				//		$xmlrpcerr['incorrect_params'],
-				//		$xmlrpcstr['incorrect_params'] . ": xml error in param " . $i);
-				//}
-				//else
-				//{
 					$r = $this->execute($m);
-				//}
+				}
 			}
 			return $r;
 		}
 
-		function execute ($m)
+		/**
+		* Execute a method invoked by the client, checking parameters used
+		* @param mixed $m either an xmlrpcmsg obj or a method name
+		* @param array $params array with method parameters as php types (if m is method name only)
+		* @param array $paramtypes array with xmlrpc types of method parameters (if m is method name only)
+		* @return xmlrpcresp
+		* @access private
+		*/
+		function execute($m, $params=null, $paramtypes=null)
 		{
-			global $xmlrpcerr, $xmlrpcstr, $_xmlrpcs_dmap;
-			// now to deal with the method
-			$methName = $m->method();
-			$sysCall = ereg("^system\.", $methName);
-			$dmap = $sysCall ? $_xmlrpcs_dmap : $this->dmap;
+			if (is_object($m))
+			{
+				$methName = $m->method();
+			}
+			else
+			{
+				$methName = $m;
+			}
+			$sysCall = $this->allow_system_funcs && (strpos($methName, "system.") === 0);
+			$dmap = $sysCall ? $GLOBALS['_xmlrpcs_dmap'] : $this->dmap;
 
-			if (!isset($dmap[$methName]['function']))
+			if(!isset($dmap[$methName]['function']))
 			{
 				// No such method
 				return new xmlrpcresp(0,
-					$xmlrpcerr['unknown_method'],
-					$xmlrpcstr['unknown_method']);
+					$GLOBALS['xmlrpcerr']['unknown_method'],
+					$GLOBALS['xmlrpcstr']['unknown_method']);
 			}
 
-			// Check signature.
-			if (isset($dmap[$methName]['signature']))
+			// Check signature
+			if(isset($dmap[$methName]['signature']))
 			{
 				$sig = $dmap[$methName]['signature'];
-				list($ok, $errstr) = $this->verifySignature($m, $sig);
+				if (is_object($m))
+				{
+					list($ok, $errstr) = $this->verifySignature($m, $sig);
+				}
+				else
+				{
+					list($ok, $errstr) = $this->verifySignature($paramtypes, $sig);
+				}
 				if(!$ok)
 				{
 					// Didn't match.
 					return new xmlrpcresp(
 						0,
-						$xmlrpcerr['incorrect_params'],
-						$xmlrpcstr['incorrect_params'] . ": ${errstr}"
+						$GLOBALS['xmlrpcerr']['incorrect_params'],
+						$GLOBALS['xmlrpcstr']['incorrect_params'] . ": ${errstr}"
 					);
 				}
 			}
 
 			$func = $dmap[$methName]['function'];
+			// let the 'class::function' syntax be accepted in dispatch maps
+			if(is_string($func) && strpos($func, '::'))
+			{
+				$func = explode('::', $func);
+			}
+			// verify that function to be invoked is in fact callable
+			if(!is_callable($func))
+			{
+				error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler is not callable");
+				return new xmlrpcresp(
+					0,
+					$GLOBALS['xmlrpcerr']['server_error'],
+					$GLOBALS['xmlrpcstr']['server_error'] . ": no function matches method"
+				);
+			}
 
-			if ($sysCall)
+			// If debug level is 3, we should catch all errors generated during
+			// processing of user function, and log them as part of response
+			if($this->debug > 2)
 			{
-				return call_user_func($func, $this, $m);
+				$GLOBALS['_xmlrpcs_prev_ehandler'] = set_error_handler('_xmlrpcs_errorHandler');
+			}
+			if (is_object($m))
+			{
+				if($sysCall)
+				{
+					$r = call_user_func($func, $this, $m);
+				}
+				else
+				{
+					$r = call_user_func($func, $m);
+				}
+				if (!is_a($r, 'xmlrpcresp'))
+				{
+					error_log("XML-RPC: xmlrpc_server::execute: function $func registered as method handler does not return an xmlrpcresp object");
+					if (is_a($r, 'xmlrpcval'))
+					{
+						$r =& new xmlrpcresp($r);
+					}
+					else
+					{
+						$r =& new xmlrpcresp(
+							0,
+							$GLOBALS['xmlrpcerr']['server_error'],
+							$GLOBALS['xmlrpcstr']['server_error'] . ": function does not return xmlrpcresp object"
+						);
+					}
+				}
 			}
 			else
 			{
-				return call_user_func($func, $m);
+				// call a 'plain php' function
+				if($sysCall)
+				{
+					array_unshift($params, $this);
+					$r = call_user_func_array($func, $params);
+				}
+				else
+				{
+					// 3rd API convention for method-handling functions: EPI-style
+					if ($this->functions_parameters_type == 'epivals')
+					{
+						$r = call_user_func_array($func, array($methName, $params, $this->user_data));
+						// mimic EPI behaviour: if we get an array that looks like an error, make it
+						// an eror response
+						if (is_array($r) && array_key_exists('faultCode', $r) && array_key_exists('faultString', $r))
+						{
+							$r =& new xmlrpcresp(0, (integer)$r['faultCode'], (string)$r['faultString']);
+						}
+						else
+						{
+							// functions using EPI api should NOT return resp objects,
+							// so make sure we encode the return type correctly
+							$r =& new xmlrpcresp(php_xmlrpc_encode($r, array('extension_api')));
+						}
+					}
+					else
+					{
+						$r = call_user_func_array($func, $params);
+					}
+				}
+				// the return type can be either an xmlrpcresp object or a plain php value...
+				if (!is_a($r, 'xmlrpcresp'))
+				{
+					// what should we assume here about automatic encoding of datetimes
+					// and php classes instances???
+					$r =& new xmlrpcresp(php_xmlrpc_encode($r, array('auto_dates')));
+				}
+			}
+			if($this->debug > 2)
+			{
+				// note: restore the error handler we found before calling the
+				// user func, even if it has been changed inside the func itself
+				if($GLOBALS['_xmlrpcs_prev_ehandler'])
+				{
+					set_error_handler($GLOBALS['_xmlrpcs_prev_ehandler']);
+				}
+				else
+				{
+					restore_error_handler();
+				}
 			}
+			return $r;
 		}
 
-		function echoInput()
+		/**
+		* add a string to the 'internal debug message' (separate from 'user debug message')
+		* @param string $strings
+		* @access private
+		*/
+		function debugmsg($string)
 		{
-			global $HTTP_RAW_POST_DATA;
+			$this->debug_info .= $string."\n";
+		}
 
-			// a debugging routine: just echos back the input
-			// packet as a string value
+		/**
+		* @access private
+		*/
+		function xml_header($charset_encoding='')
+		{
+			if ($charset_encoding != '')
+			{
+				return "<?xml version=\"1.0\" encoding=\"$charset_encoding\"?" . ">\n";
+			}
+			else
+			{
+				return "<?xml version=\"1.0\"?" . ">\n";
+			}
+		}
 
-			$r=new xmlrpcresp;
-			$r->xv=new xmlrpcval( "'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string');
+		/**
+		* A debugging routine: just echoes back the input packet as a string value
+		* DEPRECATED!
+		*/
+		function echoInput()
+		{
+			$r=&new xmlrpcresp(new xmlrpcval( "'Aha said I: '" . $GLOBALS['HTTP_RAW_POST_DATA'], 'string'));
 			print $r->serialize();
 		}
 	}
diff -ruN 3.24.src/nucleus/media.php 3.31.src/nucleus/media.php
--- 3.24.src/nucleus/media.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/media.php	2007-10-22 19:36:04.000000000 -0500
@@ -1,30 +1,30 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 /**
-  * Media popup window for Nucleus
-  *
-  * Purpose:
-  *   - can be openen from an add-item form or bookmarklet popup
-  *   - shows a list of recent files, allowing browsing, search and 
-  *     upload of new files
-  *   - close the popup by selecting a file in the list. The file gets
-  *     passed through to the add-item form (linkto, popupimg or inline img)
-  *
+ * Media popup window for Nucleus
+ *
+ * Purpose:
+ *   - can be openen from an add-item form or bookmarklet popup
+ *   - shows a list of recent files, allowing browsing, search and
+ *     upload of new files
+ *   - close the popup by selecting a file in the list. The file gets
+ *     passed through to the add-item form (linkto, popupimg or inline img)
+ *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: media.php,v 1.18.2.1 2005/08/15 10:51:08 dekarma Exp $
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: media.php 1144 2007-05-11 08:12:43Z kimitake $
  *
-  */
-  
+ */
+
 $CONF = array();
 
 // defines how much media items will be shown per page. You can override this
@@ -33,7 +33,7 @@
 $CONF['MediaPerPage'] = 10;
 
 // include all classes and config data
-include('../config.php');
+require('../config.php');
 include($DIR_LIBS . 'MEDIA.php');	// media classes
 
 sendContentType('application/xhtml+xml', 'media');
@@ -49,19 +49,19 @@
 $teams = mysql_query($query);
 if (mysql_num_rows($teams) == 0)
 	media_doError(_ERROR_DISALLOWEDUPLOAD);
-	
+
 // get action
 $action = requestVar('action');
 if ($action == '')
 	$action = 'selectmedia';
-	
+
 // check ticket
 $aActionsNotToCheck = array('selectmedia', _MEDIA_FILTER_APPLY, _MEDIA_COLLECTION_SELECT);
 if (!in_array($action, $aActionsNotToCheck))
 {
 	if (!$manager->checkTicket())
 		media_doError(_ERROR_BADTICKET);
-} 
+}
 
 
 switch($action) {
@@ -84,10 +84,10 @@
 // select a file
 function media_select() {
 	global $member, $CONF, $DIR_MEDIA, $manager;
-	
+
 	media_head();
-	
-	// show 10 files + navigation buttons 
+
+	// show 10 files + navigation buttons
 	// show msg when no files
 	// show upload form
 	// files sorted according to last modification date
@@ -96,8 +96,8 @@
 	$currentCollection = requestVar('collection');
 	if (!$currentCollection || !@is_dir($DIR_MEDIA . $currentCollection))
 		$currentCollection = $member->getID();
-		
-	
+
+
 	// get collection list
 	$collections = MEDIA::getCollectionList();
 
@@ -125,11 +125,11 @@
 			<input type="hidden" name="collection" value="<?php echo htmlspecialchars($currentCollection)?>" />
 			<input type="submit" name="action" value="<?php echo htmlspecialchars(_MEDIA_UPLOAD_NEW) ?>" title="<?php echo htmlspecialchars(_MEDIA_UPLOADLINK) ?>" />
 			<?php $manager->addTicketHidden() ?>
-		</div></form>	
+		</div></form>
 	<?php	} // if sizeof
-	
-	$filter = requestVar('filter');	
-	$offset = intRequestVar('offset');	
+
+	$filter = requestVar('filter');
+	$offset = intRequestVar('offset');
 	$arr = MEDIA::getMediaListByCollection($currentCollection, $filter);
 
 	?>
@@ -137,28 +137,28 @@
 			<label for="media_filter"><?php echo htmlspecialchars(_MEDIA_FILTER_LABEL)?></label>
 			<input id="media_filter" type="text" name="filter" value="<?php echo htmlspecialchars($filter)?>" />
 			<input type="submit" name="action" value="<?php echo htmlspecialchars(_MEDIA_FILTER_APPLY) ?>" />
-			<input type="hidden" name="collection" value="<?php echo htmlspecialchars($currentCollection)?>" />			
-			<input type="hidden" name="offset" value="<?php echo intval($offset)?>" />						
-		</div></form>	
-	
+			<input type="hidden" name="collection" value="<?php echo htmlspecialchars($currentCollection)?>" />
+			<input type="hidden" name="offset" value="<?php echo intval($offset)?>" />
+		</div></form>
+
 	<?php
-	
-	?>	
+
+	?>
 		<table width="100%">
 		<caption><?php echo _MEDIA_COLLECTION_LABEL . htmlspecialchars($collections[$currentCollection])?></caption>
 		<tr>
 		 <th><?php echo _MEDIA_MODIFIED?></th><th><?php echo _MEDIA_FILENAME?></th><th><?php echo _MEDIA_DIMENSIONS?></th>
 		</tr>
-	
-	<?php	
-	
+
+	<?php
+
 	if (sizeof($arr)>0) {
-	
+
 		if (($offset + $CONF['MediaPerPage']) >= sizeof($arr))
 			$offset = sizeof($arr) - $CONF['MediaPerPage'];
 
 		if ($offset < 0) $offset = 0;
-		
+
 		$idxStart = $offset;
 		$idxEnd = $offset + $CONF['MediaPerPage'];
 		$idxNext = $idxEnd;
@@ -174,15 +174,15 @@
 			$filename = $DIR_MEDIA . $currentCollection . '/' . $obj->filename;
 
 			$old_level = error_reporting(0);
-			$size = @GetImageSize($filename); 
+			$size = @GetImageSize($filename);
 			error_reporting($old_level);
 			$width = $size[0];
 			$height = $size[1];
 			$filetype = $size[2];
-			
+
 			echo "<tr>";
 			echo "<td>". date("Y-m-d",$obj->timestamp) ."</td>";
-			
+
 			// strings for javascript
 			$jsCurrentCollection = str_replace("'","\\'",$currentCollection);
 			$jsFileName = str_replace("'","\\'",$obj->filename);
@@ -209,21 +209,21 @@
 		}
 	} // if (sizeof($arr)>0)
 	?>
-	
+
 		</table>
-	<?php	
+	<?php
 	if ($idxStart > 0)
 		echo "<a href='media.php?offset=$idxPrev&amp;collection=".urlencode($currentCollection)."'>". _LISTS_PREV."</a> ";
 	if ($idxEnd < sizeof($arr))
 		echo "<a href='media.php?offset=$idxNext&amp;collection=".urlencode($currentCollection)."'>". _LISTS_NEXT."</a> ";
-	
+
 	?>
 		<input id="typeradio0" type="radio" name="typeradio" onclick="setType(0);" checked="checked" /><label for="typeradio0"><?php echo _MEDIA_INLINE?></label>
 		<input id="typeradio1" type="radio" name="typeradio" onclick="setType(1);" /><label for="typeradio1"><?php echo _MEDIA_POPUP?></label>
-	<?php	
+	<?php
 	media_foot();
-     
-		
+
+
 }
 
 /**
@@ -233,19 +233,19 @@
 	global $CONF, $member, $manager;
 
 	$currentCollection = requestVar('collection');
-	
+
 	$collections = MEDIA::getCollectionList();
 
 	media_head();
 	?>
 	<h1><?php echo _UPLOAD_TITLE?></h1>
-	
+
 	<p><?php echo _UPLOAD_MSG?></p>
-	
+
 	<form method="post" enctype="multipart/form-data" action="media.php">
 	<div>
- 	  <input type="hidden" name="action" value="uploadfile" />
- 	  <?php $manager->addTicketHidden() ?>
+	  <input type="hidden" name="action" value="uploadfile" />
+	  <?php $manager->addTicketHidden() ?>
 	  <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $CONF['MaxUploadSize']?>" />
 	  File:
 	  <br />
@@ -265,15 +265,15 @@
 		</select>
 	<?php		} else {
 	?>
-	  	<input name="collection" type="hidden" value="<?php echo htmlspecialchars(requestVar('collection'))?>" />			
+		<input name="collection" type="hidden" value="<?php echo htmlspecialchars(requestVar('collection'))?>" />
 	<?php		} // if sizeof
-	?>  
+	?>
 	  <br /><br />
 	  <input type="submit" value="<?php echo _UPLOAD_BUTTON?>" />
 	</div>
 	</form>
-	
-	<?php	
+
+	<?php
 	media_foot();
 }
 
@@ -285,23 +285,41 @@
 	global $DIR_MEDIA, $member, $CONF;
 
 	$uploadInfo = postFileInfo('uploadfile');
-	
+
 	$filename = $uploadInfo['name'];
 	$filetype = $uploadInfo['type'];
 	$filesize = $uploadInfo['size'];
 	$filetempname = $uploadInfo['tmp_name'];
+	$fileerror = intval($uploadInfo['error']);
 	
+	switch ($fileerror)
+	{
+		case 0: // = UPLOAD_ERR_OK
+			break;
+		case 1: // = UPLOAD_ERR_INI_SIZE
+		case 2:	// = UPLOAD_ERR_FORM_SIZE
+			media_doError(_ERROR_FILE_TOO_BIG);
+		case 3: // = UPLOAD_ERR_PARTIAL
+		case 4: // = UPLOAD_ERR_NO_FILE
+		case 6: // = UPLOAD_ERR_NO_TMP_DIR
+		case 7: // = UPLOAD_ERR_CANT_WRITE
+		default:
+			// include error code for debugging
+			// (see http://www.php.net/manual/en/features.file-upload.errors.php)
+			media_doError(_ERROR_BADREQUEST . ' (' . $fileerror . ')');
+	}
+
 	if ($filesize > $CONF['MaxUploadSize'])
 		media_doError(_ERROR_FILE_TOO_BIG);
-	
+
 	// check file type against allowed types
 	$ok = 0;
 	$allowedtypes = explode (',', $CONF['AllowedTypes']);
-	foreach ( $allowedtypes as $type ) 
-		if (eregi("\." .$type. "$",$filename)) $ok = 1;    
+	foreach ( $allowedtypes as $type )
+		if (eregi("\." .$type. "$",$filename)) $ok = 1;
 	if (!$ok) media_doError(_ERROR_BADFILETYPE);
-		
-	if (!is_uploaded_file($filetempname)) 
+
+	if (!is_uploaded_file($filetempname))
 		media_doError(_ERROR_BADREQUEST);
 
 	// prefix filename with current date (YYYY-MM-DD-)
@@ -312,9 +330,9 @@
 	$collection = requestVar('collection');
 	$res = MEDIA::addMediaObject($collection, $filetempname, $filename);
 
-	if ($res != '') 
+	if ($res != '')
 		media_doError($res);
-	
+
 	// shows updated list afterwards
 	media_select();
 }
@@ -323,11 +341,11 @@
 	media_head();
 	?>
 		<h1><?php echo _LOGIN_PLEASE?></h1>
-	
+
 		<form method="post" action="media.php">
 		<div>
 			<input name="action" value="login" type="hidden" />
-			<input name="collection" value="<?php echo htmlspecialchars(requestVar('collection'))?>" type="hidden" />			
+			<input name="collection" value="<?php echo htmlspecialchars(requestVar('collection'))?>" type="hidden" />
 			<?php echo _LOGINFORM_NAME?>: <input name="login" />
 			<br /><?php echo _LOGINFORM_PWD?>: <input name="password" type="password" />
 			<br /><input type="submit" value="<?php echo _LOGIN?>" />
@@ -359,33 +377,33 @@
 		<script type="text/javascript">
 			var type = 0;
 			function setType(val) { type = val; }
-			
+
 			function chooseImage(collection, filename, width, height) {
-				window.opener.focus(); 
+				window.opener.focus();
 				window.opener.includeImage(collection,
-										   filename, 
-				                           type == 0 ? 'inline' : 'popup',
-				                           width,
-				                           height
-				                           );
+										   filename,
+										   type == 0 ? 'inline' : 'popup',
+										   width,
+										   height
+										   );
 				window.close();
 			}
-			
+
 			function chooseOther(collection, filename) {
-				window.opener.focus(); 
+				window.opener.focus();
 				window.opener.includeOtherMedia(collection, filename);
 				window.close();
-			
+
 			}
 		</script>
 	</head>
-	<body>		
+	<body>
 <?php }
 
 function media_foot() {
 ?>
 	</body>
-	</html>	
-<?php }	
+	</html>
+<?php }
 
 ?>
diff -ruN 3.24.src/nucleus/plugins/NP_Ping.php 3.31.src/nucleus/plugins/NP_Ping.php
--- 3.24.src/nucleus/plugins/NP_Ping.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/plugins/NP_Ping.php	2007-10-22 19:35:56.000000000 -0500
@@ -0,0 +1,275 @@
+<?
+/*
+  Note: based on NP_PingPong, adapt for the new ping mechanism
+
+  History
+    v1.0 - Initial version
+    v1.1 - Add JustPosted event support
+    v1.2 - JustPosted event handling in background
+    v1.3 - pinged variable support
+    v1.4 - language file support
+    v1.5 - remove arg1 in exec() call
+ */
+
+class NP_Ping extends NucleusPlugin {
+
+	function getName() { return 'Ping'; }
+
+	function getAuthor() { return 'admun (Edmond Hui)'; }
+	function getURL()    { return 'http://edmondhui.homeip.net/nudn'; }
+	function getVersion() { return '1.5'; }
+
+	function getMinNucleusVersion() { return '330'; }
+
+	function getDescription() {
+		return _PING_DESC;
+	}
+
+	function supportsFeature($what) {
+		switch($what) {
+			case 'SqlTablePrefix':
+				return 1;
+			default:
+				return 0;
+		}
+	}
+
+	function init()
+	{
+		$language = ereg_replace( '[\\|/]', '', getLanguageName());
+		if (file_exists($this->getDirectory()  . $language . '.php')) {
+			include_once($this->getDirectory() . $language . '.php');
+		}else {
+			include_once($this->getDirectory() . 'english.php');
+		}
+	}
+
+	function install() {
+		$this->createOption('pingpong_pingomatic',_PING_PINGOM,'yesno','yes');  // Default, http://pingomatic.com
+		$this->createOption('pingpong_weblogs',_PING_WEBLOGS,'yesno','no'); // http://weblogs.com
+		$this->createOption('pingpong_technorati',_PING_TECHNOR,'yesno','no'); // http://www.technorati.com
+		$this->createOption('pingpong_blogrolling',_PING_BLOGR,'yesno','no'); // http://www.blogrolling.com
+		$this->createOption('pingpong_blogs',_PING_BLOGS,'yesno','no'); // http://blo.gs
+		$this->createOption('pingpong_weblogues',_PING_WEBLOGUES,'yesno','no'); // http://weblogues.com/
+		$this->createOption('pingpong_bloggde',_PING_BLOGGDE,'yesno','no'); // http://blogg.de
+		$this->createOption('ping_background',_PING_BG,'yesno','yes');
+	}
+
+	function getEventList() {
+		return array('SendPing', 'JustPosted');
+	}
+
+	function event_JustPosted($data) {
+		global $DIR_PLUGINS, $DIR_NUCLEUS;
+
+		// exit is another plugin already send ping
+		if ($data['pinged'] == true) {
+			return;
+		}
+
+		if ($this->getOption('ping_background') == "yes") {
+			exec("php $DIR_PLUGINS/ping/ping.php " . $data['blogid'] . " &");
+		} else {
+			$this->sendPings($data['blogid']);
+
+        		ACTIONLOG::add(INFO, 'NP_Ping: Sending ping (from foreground)');
+		}
+
+		// mark the ping has been sent
+		$data['pinged'] = true;
+        }
+
+	function event_SendPing($data) {
+                $this->sendPings($data);
+	}
+
+        function sendPings($data) {
+		if (!class_exists('xmlrpcmsg')) {
+			global $DIR_LIBS;
+			include($DIR_LIBS . 'xmlrpc.inc.php');
+		}
+
+                $this->myBlogId = $data['blogid'];
+
+		if ($this->getOption('pingpong_pingomatic')=='yes') {
+			echo _PINGING . "Ping-o-matic:<br/>";
+			echo $this->pingPingomatic();
+			echo "<br/>";
+		}
+
+		if ($this->getOption('pingpong_weblogs')=='yes') { 
+			echo _PINGING . "Weblogs.com:<br/>";
+			echo $this->pingWeblogs();
+			echo "<br/>";
+		}
+
+		if ($this->getOption('pingpong_technorati')=='yes') {
+			echo _PINGING . "Technorati:<br/>";
+			echo $this->pingTechnorati();
+			echo "<br/>";
+		}
+
+		if ($this->getOption('pingpong_blogrolling')=='yes') {
+			echo _PINGING . "Blogrolling.com:<br/>";
+			echo $this->pingBlogRollingDotCom();
+			echo "<br/>";
+		}
+
+		if ($this->getOption('pingpong_blogs')=='yes') {
+			echo _PINGING . "Blog.gs:<br/>";
+			echo $this->pingBloGs();
+			echo "<br/>";
+		}
+
+		if ($this->getOption('pingpong_weblogues')=='yes') {
+			echo _PINGING . "Weblogues.com:<br/>";
+			echo $this->pingWebloguesDotCom();
+			echo "<br/>";
+		}
+
+		if ($this->getOption('pingpong_bloggde')=='yes') {
+			echo _PINGING . "Blog.de:<br/>";
+			echo $this->pingBloggDe();
+			echo "<br/>";
+		}
+        }
+
+	function pingPingomatic() {
+		$b = new BLOG($this->myBlogId);
+		$message = new xmlrpcmsg(
+					'weblogUpdates.ping', array(
+					new xmlrpcval($b->getName(),'string'),
+					new xmlrpcval($b->getURL(),'string')
+					));
+
+		$c = new xmlrpc_client('/', 'rpc.pingomatic.com', 80);
+		//$c->setDebug(1);
+
+		$r = $c->send($message,30); // 30 seconds timeout...
+		return $this->processPingResult($r);
+	}
+
+	function pingWeblogs() {
+		$b = new BLOG($this->myBlogId);
+		$message = new xmlrpcmsg(
+					'weblogupdates.ping',array(
+					new xmlrpcval($b->getName(),'string'),
+					new xmlrpcval($b->getUrl(),'string')
+					));
+
+		$c = new xmlrpc_client('/rpc2', 'rpc.weblogs.com', 80);
+		//$c->setdebug(1);
+
+		$r = $c->send($message,30); // 30 seconds timeout...
+		return $this->processPingResult($r);
+	} 
+
+	function pingTechnorati() {
+		$b = new BLOG($this->myBlogId);
+		$message = new xmlrpcmsg(
+					'weblogUpdates.ping', array(
+					new xmlrpcval($b->getName(),'string'),
+					new xmlrpcval($b->getURL(),'string')
+					));
+
+		$c = new xmlrpc_client('/rpc/ping/', 'rpc.technorati.com', 80);
+		//$c->setDebug(1);
+
+		$r = $c->send($message,30); // 30 seconds timeout...
+		return $this->processPingResult($r);
+	}
+
+	function pingBlogRollingDotCom() {
+		$b = new BLOG($this->myBlogId);         
+		$message = new xmlrpcmsg(
+					'weblogUpdates.ping',
+					array(
+					new xmlrpcval($b->getName(),'string'), // your blog title
+					new xmlrpcval($b->getURL(),'string')  // your blog url
+					));
+
+		$c = new xmlrpc_client('/pinger/', 'rpc.blogrolling.com', 80);
+		//$c->setDebug(1);
+
+		$r = $c->send($message,30); // 30 seconds timeout...     
+		return $this->processPingResult($r);
+	} 
+
+	function pingBloGs() {
+		$b = new BLOG($this->myBlogId);
+		$message = new xmlrpcmsg(
+					'weblogUpdates.extendedPing', array(
+					new xmlrpcval($b->getName(),'string'),
+					new xmlrpcval($b->getURL(),'string')
+					));
+
+		$c = new xmlrpc_client('/', 'ping.blo.gs', 80);
+		//$c->setDebug(1);
+
+		$r = $c->send($message,30); // 30 seconds timeout...    
+		return $this->processPingResult($r);
+	} 
+
+	function pingWebloguesDotCom() {
+		$b = new BLOG($this->myBlogId);
+		$message = new xmlrpcmsg(
+					'weblogUpdates.extendedPing',
+					array(
+					new xmlrpcval($b->getName(),'string'), // your blog title
+					new xmlrpcval($b->getURL(),'string')  // your blog url
+					));
+
+		$c = new xmlrpc_client('/RPC/', 'www.weblogues.com', 80);
+		//$c->setDebug(1);
+
+		$r = $c->send($message,30); // 30 seconds timeout...     
+		return $this->processPingResult($r);
+	}
+
+	function pingBloggDe() {
+		$b = new BLOG($this->myBlogId);
+		$message = new xmlrpcmsg(
+					'bloggUpdates.ping', array(
+					new xmlrpcval($b->getName(),'string'),
+					new xmlrpcval($b->getURL(),'string')
+					));
+
+		$c = new xmlrpc_client('/', 'xmlrpc.blogg.de', 80);
+		//$c->setDebug(1);
+
+		$r = $c->send($message,30); // 30 seconds timeout...   
+		return $this->processPingResult($r);
+	} 
+
+	function processPingResult($r) {
+		global $php_errormsg;
+
+		if (($r == 0) && ($r->errno || $r->errstring)) {
+			return _PING_ERROR . " " . $r->errno . ' : ' . $r->errstring;
+		} elseif (($r == 0) && ($php_errormsg)) {
+			return _PING_PHP_ERROR . $php_errormsg;
+		} elseif ($r == 0) {
+			return _PING_PHP_PING_ERROR;
+		} elseif ($r->faultCode() != 0) {
+			return _PING_ERROR . ': ' . $r->faultString();
+		} else {
+			$r = $r->value();	// get response struct
+
+			// get values
+			$flerror = $r->structmem('flerror');
+			$flerror = $flerror->scalarval();
+
+			$message = $r->structmem('message');
+			$message = $message->scalarval();
+
+			if ($flerror != 0) {
+      				return _PING_ERROR . ' (flerror=1): ' . $message;
+			}
+			else {
+				return _PING_SUCCESS . ': ' . $message;
+			}
+		}
+	}
+}
+
+?>
diff -ruN 3.24.src/nucleus/plugins/NP_SkinFiles.php 3.31.src/nucleus/plugins/NP_SkinFiles.php
--- 3.24.src/nucleus/plugins/NP_SkinFiles.php	2005-08-15 12:55:10.000000000 -0500
+++ 3.31.src/nucleus/plugins/NP_SkinFiles.php	2007-10-22 19:35:56.000000000 -0500
@@ -5,7 +5,11 @@
    /* ==========================================================================================
 	* Nucleus SkinFiles Plugin
 	*
-	* Copyright 2005 by Jeff MacMichael and Niels Leenheer
+	* Copyright 2005-2007 by Jeff MacMichael and Niels Leenheer
+	*
+	* @version $Id: NP_SkinFiles.php 1116 2007-02-03 08:24:29Z kimitake $
+	* @version $NucleusJP: NP_SkinFiles.php,v 1.3 2006/07/17 20:03:45 kimitake Exp $
+	*
 	* ==========================================================================================
 	* This program is free software and open source software; you can redistribute
 	* it and/or modify it under the terms of the GNU General Public License as
@@ -36,13 +40,15 @@
 	* v1.01 ged   - fixed event_QuickMenu to properly skip for non-admins
 	*               lined up columns for directories & added <tr> highlights
 	* v2.00 rakaz - Almost complete rewrite
+	* v2.01 yama  - modified form button for IE
+	* v2.02 kimitake - multilingual support, modified form button for IE
 	*/
 
 
 	function getName() 		  { return 'SkinFiles'; }
 	function getAuthor()  	  { return 'Misc authors'; }
 	function getURL()  		  { return 'http://www.nucleuscms.org/'; }
-	function getVersion() 	  { return '2.0'; }
+	function getVersion() 	  { return '2.02'; }
 	function getDescription() { return 'A simple file manager for skins.';	}
 
 	function supportsFeature($what) {
@@ -66,6 +72,16 @@
 	function hasAdminArea() {
 		return 1;
 	}
+
+	function init()
+	{
+		// include language file for this plugin
+		$language = ereg_replace( '[\\|/]', '', getLanguageName());
+		if (file_exists($this->getDirectory().$language.'.php'))
+			include_once($this->getDirectory().$language.'.php');
+		else
+			include_once($this->getDirectory().'english.php');
+	}
 	
 	function event_QuickMenu(&$data) {
 		global $member;
@@ -76,12 +92,12 @@
 		array_push(
 			$data['options'], 
 			array(
-				'title' => 'Skin Files',
+				'title' => _SKINFILES_TITLE,
 				'url' => $this->getAdminURL(),
-				'tooltip' => 'Manage skin files'
+				'tooltip' => _SKINFILES_TOOLTIP
 			)
 		);
 	}
 }
 
-?>
\ No newline at end of file
+?>
diff -ruN 3.24.src/nucleus/plugins/ping/english.php 3.31.src/nucleus/plugins/ping/english.php
--- 3.24.src/nucleus/plugins/ping/english.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/plugins/ping/english.php	2007-10-22 19:35:56.000000000 -0500
@@ -0,0 +1,16 @@
+<?php
+	define('_PING_DESC', 'This plugin can be used to ping many blog tracking services. - Don\'t forget to enable the option \'Ping weblog listing service on update\' in your blog settings!');
+	define('_PING_PINGOM', 'Ping-o-matic');
+	define('_PING_WEBLOGS', 'weblogs.com');
+	define('_PING_TECHNOR', 'Technorati');
+	define('_PING_BLOGR', 'Blogrolling');
+	define('_PING_BLOGS', 'Blo.gs (no longer works?)');
+	define('_PING_WEBLOGUES', 'Weblogues (no longer works?)');
+	define('_PING_BLOGGDE', 'Blogg.de (not working??)');
+	define('_PING_BG', 'Ping from background when a future post first appears');
+	define('_PINGING', 'Pinging ');
+	define('_PING_ERROR', 'Error');
+	define('_PING_PHP_ERROR', 'PHP Error: ');
+	define('_PING_PHP_PING_ERROR', 'Error while trying to send ping. Sorry about that.');
+	define('_PING_SUCCESS', 'Success');
+?>
diff -ruN 3.24.src/nucleus/plugins/ping/ping.php 3.31.src/nucleus/plugins/ping/ping.php
--- 3.24.src/nucleus/plugins/ping/ping.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/plugins/ping/ping.php	2007-10-22 19:35:56.000000000 -0500
@@ -0,0 +1,16 @@
+<?php
+require(dirname(__FILE__).'/../../../config.php');
+
+include($DIR_LIBS . 'PLUGINADMIN.php');
+
+// create a object of the plugin via Plugin Admin
+$oPluginAdmin = new PluginAdmin('Ping');
+ACTIONLOG::add(INFO, 'NP_Ping: Sending ping (from background)');
+
+$blogid = intval($argv[1]);
+if ($blogid > 0) {
+	$oPluginAdmin->plugin->sendPings($blogid);
+} else {
+	ACTIONLOG::add(WARNING, 'NP_Ping: invalid blogid, background ping abort');
+}
+?>
Binary files 3.24.src/nucleus/plugins/skinfiles/css.gif and 3.31.src/nucleus/plugins/skinfiles/css.gif differ
diff -ruN 3.24.src/nucleus/plugins/skinfiles/english.php 3.31.src/nucleus/plugins/skinfiles/english.php
--- 3.24.src/nucleus/plugins/skinfiles/english.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/plugins/skinfiles/english.php	2007-10-22 19:35:56.000000000 -0500
@@ -0,0 +1,178 @@
+<?php
+
+   /*
+	* @version $Id: english.php 1116 2007-02-03 08:24:29Z kimitake $
+	*/
+
+define('_SKINFILES_TITLE',				'Skin Files');
+define('_SKINFILES_TOOLTIP',			'Manage skin files');
+
+define('_SKINFILES_MANAGEMENT',			'Skin File Management');
+define('_SKINFILES_CURRENT_LOCATION',	'Current location: ');
+define('_SKINFILES_NAME',				'Name');
+define('_SKINFILES_SIZE',				'Size');
+define('_SKINFILES_LAST_MODIFIED',		'Last Modified');
+define('_SKINFILES_ACTIONS',			'Actions');
+
+define('_SKINFILES_RENAME',				'Rename');
+define('_SKINFILES_RENAME_DIR_MSG',		'Rename directory');
+define('_SKINFILES_RENAME_DIR_MSG2',	'to:');
+define('_SKINFILES_EDIT_FILE_MSG',		'Edit file');
+define('_SKINFILES_RENAME_FILE_MSG',	'Rename file ');
+define('_SKINFILES_RENAME_FILE_MSG2',	'to:');
+define('_SKINFILES_DELETE',				'Delete');
+define('_SKINFILES_EDIT',				'Edit');
+define('_SKINFILES_CANCEL',				'Cancel');
+define('_SKINFILES_DOWNLOAD',			'Download');
+define('_SKINFILES_SAVE_CHANGES',		'Save Changes');
+
+define('_SKINFILES_DATE_FORMAT',		'M d Y, H:i');
+
+define('_SKINFILES_CREATE_NEW_FILE',	'Create a new file');
+define('_SKINFILES_CREATE_NEW_DIR',		'Create a new directory');
+define('_SKINFILES_CREATE_FILE',		'Create file');
+define('_SKINFILES_CREATE',				'Create');
+define('_SKINFILES_UPLOAD',				'Upload');
+define('_SKINFILES_DELETE_FILE',		'Delete file');
+define('_SKINFILES_DELETE_FILE2',		'?');
+define('_SKINFILES_DELETE_DIR',			'Delete directory');
+define('_SKINFILES_DELETE_DIR2',		'?');
+define('_SKINFILES_DELETE_ALL',			'Delete All');
+define('_SKINFILES_DELETE_FILE_MSG',	'Delete the following files from directory');
+define('_SKINFILES_DELETE_FILE_MSG2',	'?');
+define('_SKINFILES_UPLOAD_NEW_FILE',	'Upload new file');
+define('_SKINFILES_DEL_ALL_FILES',		'Delete all files in this directory');
+define('_SKINFILES_DEL_ALL_FILES_MSG',	'Delete all files? (will ask for confirmation)');
+
+define('_SKINFILES_VIEW_FILE',				'View file ');
+define('_SKINFILES_VIEW_FILE_IMG_INFO',		'Image information');
+define('_SKINFILES_VIEW_FILE_TYPE',			'Type:');
+define('_SKINFILES_VIEW_FILE_WIDTH',		'Width:');
+define('_SKINFILES_VIEW_FILE_HEIGHT',		'Height:');
+define('_SKINFILES_VIEW_FILE_PX',			' px');
+define('_SKINFILES_VIEW_FILE_CHANNELS',		'Channels:');
+define('_SKINFILES_VIEW_FILE_COLOR_DEPTH',	'Color depth:');
+define('_SKINFILES_VIEW_FILE_BITS',			' bits');
+define('_SKINFILES_VIEW_FILE_COLORS',		'Colors:');
+define('_SKINFILES_VIEW_FILE_COLORS2',		' colors');
+
+
+
+define('_SKINFILES_ERR_DIR_DOES_NOT_CONTAIN',	'This directory does not contain any files or directories.');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST1',	'Error: The directory ');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST2',	'does not exist ');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST3',	'or you do not have permission to rename the directory.');
+
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR1',	'Error: Could not rename the directory ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR2',	'because no new name was supplied.');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR3',	'Error: Could not rename the directory ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR4',	'because the supplied name contains one or more illegal characters.');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR5',	'Error: Could not rename the directory ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR6',	'because the supplied name is the same as the original name.');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR7',	' Please use a different name.');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR8',	'Error: Could not rename the directory ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR9',	'because the supplied name is already used by another file or directory.');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR10',	'Consider using a different name, or delete the existing file or directory first.');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR11',	'Error: Could not rename the directory ');
+
+define('_SKINFILES_RENAMED_DIR1',				'Message: The directory ');
+define('_SKINFILES_RENAMED_DIR2',				'has been renamed ');
+define('_SKINFILES_RENAMED_DIR3',				'to ');
+define('_SKINFILES_RENAMED_DIR4',				'.');
+
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR1',	'Error: Could not create a new directory because there was no name supplied. ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR2',	'Error: Could not create the directory ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR3',	'because the supplied name contains one or more illegal characters.');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR4',	'Error: Could not create the directory ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR5',	'because the supplied name is already used by another file or directory.');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR6',	' Consider using a different name, or delete the existing file or directory first.');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR7',	'Message: The directory ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR8',	'has been created.');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR9',	'Error: The directory ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR10',	'does not exist ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR11',	'or you do not have permission to access that directory.');
+
+define('_SKINFILES_ERR_DELETE_DIR1',			'Error: The directory ');
+define('_SKINFILES_ERR_DELETE_DIR2',			'does not exist ');
+define('_SKINFILES_ERR_DELETE_DIR3',			'or you do not have permission to delete the directory.');
+define('_SKINFILES_ERR_DELETE_DIR4',			'Error: Could not delete the directory.');
+define('_SKINFILES_ERR_DELETE_DIR5',			'Message: The directory ');
+define('_SKINFILES_ERR_DELETE_DIR6',			'has been deleted.');
+define('_SKINFILES_ERR_DELETE_DIR7',			'There are currently no files in this directory that can be deleted.');
+
+define('_SKINFILES_ERR_EMPTY_DIR1',				'Message: The file ');
+define('_SKINFILES_ERR_EMPTY_DIR2',				'has been deleted.');
+define('_SKINFILES_ERR_EMPTY_DIR3',				'Error: The file ');
+define('_SKINFILES_ERR_EMPTY_DIR4',				'could not be deleted.');
+define('_SKINFILES_ERR_EMPTY_DIR5',				'Error: The directory ');
+define('_SKINFILES_ERR_EMPTY_DIR6',				'does not exist ');
+define('_SKINFILES_ERR_EMPTY_DIR7',				'or you do not have permission to access that directory.');
+
+define('_SKINFILES_ERR_DOWNLOAD_FILE1',			'Error: Could not access the file.');
+define('_SKINFILES_ERR_DOWNLOAD_FILE2',			'Error: No permission to access the file.');
+
+define('_SKINFILES_ERR_VIEW_FILE1',				'Error: The file ');
+define('_SKINFILES_ERR_VIEW_FILE2',				'does not exist ');
+define('_SKINFILES_ERR_VIEW_FILE3',				'or you do not have permission to view the file.');
+
+define('_SKINFILES_ERR_EDIT_FILE1',				'Error: The file ');
+define('_SKINFILES_ERR_EDIT_FILE2',				'does not exist ');
+define('_SKINFILES_ERR_EDIT_FILE3',				'or you do not have permission to edit the file.');
+define('_SKINFILES_ERR_EDIT_FILE4',				'Message: The file ');
+define('_SKINFILES_ERR_EDIT_FILE5',				'has been saved.');
+define('_SKINFILES_ERR_EDIT_FILE6',				'Error: The file ');
+define('_SKINFILES_ERR_EDIT_FILE7',				'could not be saved.');
+
+define('_SKINFILES_ERR_RENAME_FILE1',			'Error: The file ');
+define('_SKINFILES_ERR_RENAME_FILE2',			'does not exist ');
+define('_SKINFILES_ERR_RENAME_FILE3',			'or you do not have permission to rename the file.');
+define('_SKINFILES_ERR_RENAME_FILE4',			'Error: Could not rename the file ');
+define('_SKINFILES_ERR_RENAME_FILE5',			'because no new name was supplied.');
+define('_SKINFILES_ERR_RENAME_FILE6',			'Error: Could not rename the file ');
+define('_SKINFILES_ERR_RENAME_FILE7',			'because the supplied file name contains one or more illegal characters.');
+define('_SKINFILES_ERR_RENAME_FILE8',			'Error: Could not rename the file ');
+define('_SKINFILES_ERR_RENAME_FILE9',			'because the supplied name is the same as the original name. Please use a different name.');
+define('_SKINFILES_ERR_RENAME_FILE10',			'Error: Could not rename the file ');
+define('_SKINFILES_ERR_RENAME_FILE11',			'because the supplied name is already used by another file or directory. Consider using a different name, or ');
+define('_SKINFILES_ERR_RENAME_FILE12',			'delete the existing file or directory first.');
+define('_SKINFILES_ERR_RENAME_FILE13',			'Error: Could not rename the file ');
+define('_SKINFILES_ERR_RENAME_FILE14',			'.');
+define('_SKINFILES_ERR_RENAME_FILE15',			'Message: The file ');
+define('_SKINFILES_ERR_RENAME_FILE16',			'has been renamed ');
+define('_SKINFILES_ERR_RENAME_FILE17',			'to ');
+define('_SKINFILES_ERR_RENAME_FILE18',			'.');
+
+define('_SKINFILES_ERR_CREATE_FILE1',			'Error: Could not create a new file because there was no name supplied.');
+define('_SKINFILES_ERR_CREATE_FILE2',			'Error: Could not create the file ');
+define('_SKINFILES_ERR_CREATE_FILE3',			'because the supplied file name contains one or more illegal characters.');
+define('_SKINFILES_ERR_CREATE_FILE4',			'Error: Could not create the file ');
+define('_SKINFILES_ERR_CREATE_FILE5',			'because the supplied name is already used by another file or directory. Consider using a different name, or ');
+define('_SKINFILES_ERR_CREATE_FILE6',			'delete the existing file or directory first.');
+define('_SKINFILES_ERR_CREATE_FILE7',			'Error: Could not create the file ');
+define('_SKINFILES_ERR_CREATE_FILE8',			'.');
+define('_SKINFILES_ERR_CREATE_FILE9',			'Message: The file ');
+define('_SKINFILES_ERR_CREATE_FILE10',			'has been created.');
+define('_SKINFILES_ERR_CREATE_FILE11',			'Error: The directory ');
+define('_SKINFILES_ERR_CREATE_FILE12',			'does not exist ');
+define('_SKINFILES_ERR_CREATE_FILE13',			'or you do not have permission to access that directory.');
+
+define('_SKINFILES_ERR_DELETE_FILE1',			'Error: The file ');
+define('_SKINFILES_ERR_DELETE_FILE2',			'does not exist ');
+define('_SKINFILES_ERR_DELETE_FILE3',			'or you do not have permission to delete the file.');
+define('_SKINFILES_ERR_DELETE_FILE4',			'Error: Could not delete the file.');
+define('_SKINFILES_ERR_DELETE_FILE5',			'Message: The file ');
+define('_SKINFILES_ERR_DELETE_FILE6',			'has been delete.');
+
+define('_SKINFILES_ERR_UPLOAD_FILE1',			'Error: Could not upload the file ');
+define('_SKINFILES_ERR_UPLOAD_FILE2',			'. ');
+define('_SKINFILES_ERR_UPLOAD_FILE3',			'Max / Current size: ');
+define('_SKINFILES_ERR_UPLOAD_FILE4',			'.');
+define('_SKINFILES_ERR_UPLOAD_FILE5',			'Error: Could not upload the file ');
+define('_SKINFILES_ERR_UPLOAD_FILE6',			',because the supplied file name contains one or more illegal characters.');
+define('_SKINFILES_ERR_UPLOAD_FILE7',			'Message: The file ');
+define('_SKINFILES_ERR_UPLOAD_FILE8',			'has been uploaded.');
+define('_SKINFILES_ERR_UPLOAD_FILE9',			'Error: The directory ');
+define('_SKINFILES_ERR_UPLOAD_FILE10',			'does not exist ');
+define('_SKINFILES_ERR_UPLOAD_FILE11',			'or you do not have permission to access that directory.');
+
+?>
Binary files 3.24.src/nucleus/plugins/skinfiles/generic.png and 3.31.src/nucleus/plugins/skinfiles/generic.png differ
diff -ruN 3.24.src/nucleus/plugins/skinfiles/index.php 3.31.src/nucleus/plugins/skinfiles/index.php
--- 3.24.src/nucleus/plugins/skinfiles/index.php	2005-08-15 12:55:10.000000000 -0500
+++ 3.31.src/nucleus/plugins/skinfiles/index.php	2007-10-22 19:35:56.000000000 -0500
@@ -3,7 +3,11 @@
    /* ==========================================================================================
 	* Nucleus SkinFiles Plugin
 	*
-	* Copyright 2005 by Jeff MacMichael and Niels Leenheer
+	* Copyright 2005-2007 by Jeff MacMichael and Niels Leenheer
+	*
+	* @version $Id: index.php 1200 2007-09-07 07:06:37Z kimitake $
+	* @version $NucleusJP: index.php,v 1.5.2.1 2005/08/25 07:04:13 kimitake Exp $
+	*
 	* ==========================================================================================
 	* This program is free software and open source software; you can redistribute
 	* it and/or modify it under the terms of the GNU General Public License as
@@ -23,10 +27,15 @@
 	*/
 
  	$strRel = '../../../'; 
-	include($strRel . 'config.php');
+	require($strRel . 'config.php');
 	include($DIR_LIBS . 'PLUGINADMIN.php');
 
-	
+	$language = ereg_replace( '[\\|/]', '', getLanguageName());
+	$langfile = $language.'.php';
+	if (file_exists($langfile))
+		include_once($langfile);
+	else
+		include_once('english.php');
 
 	/**
 	  * Create admin area
@@ -139,7 +148,7 @@
 	-->
 	</style>");
 	
-	echo "<h2>Skin File Management</h2>";
+	echo "<h2>" . _SKINFILES_MANAGEMENT . "</h2>";
 	
 	$actions = array (
 		'renfile', 'renfile_process', 'delfile', 'delfile_process', 
@@ -353,7 +362,7 @@
 
 		$relative  = sfRelativePath ($directory);
 		
-		echo '<p class="location">Current location: ' . sfDisplayPath($relative) . '</p>';			
+		echo '<p class="location">' . _SKINFILES_CURRENT_LOCATION . sfDisplayPath($relative) . '</p>';			
 
 			
 		$dirs = array();
@@ -377,7 +386,7 @@
 		ksort($files);
 		
 		echo '<table><thead><tr>';
-		echo '<th>Name</th><th>Size</th><th>Last modified</th><th colspan="4">Actions</th>';
+		echo '<th>' . _SKINFILES_NAME . '</th><th>' . _SKINFILES_SIZE . '</th><th>' . _SKINFILES_LAST_MODIFIED . '</th><th colspan="4">' . _SKINFILES_ACTIONS . '</th>';
 		echo '</tr></thead>';
 
 		while (list($name, $stat) = each($dirs)) {
@@ -404,17 +413,17 @@
 			$delUrl = $manager->addTicketToUrl($pluginUrl . '?action=deldir&dir=' . rawurlencode($dir));
 				
 			echo '<td>&ndash;</td>';
-			echo '<td>' . date('M d Y, H:i', $stat['mtime']);
+			echo '<td>' . date(_SKINFILES_DATE_FORMAT, $stat['mtime']);
 			
 			
 			if (is_writable($directory . $name)) {
-				echo '<td><a href="' . htmlspecialchars($renUrl) . '" title="Rename &laquo;' . htmlspecialchars($name) . '&raquo;">Rename</a></td>';
+				echo '<td><a href="' . htmlspecialchars($renUrl) . '" title="' . _SKINFILES_RENAME . ' &laquo;' . htmlspecialchars($name) . '&raquo;">' . _SKINFILES_RENAME . '</a></td>';
 			} else {
 				echo '<td>&nbsp;</td>';
 			}
 			
 			if (is_writable($directory . $name) && sfDirectoryIsEmpty($directory . $name)) {
-				echo '<td><a href="' . htmlspecialchars($delUrl) . '" title="Delete &laquo;' . htmlspecialchars($name) . '&raquo;">Delete</a></td>';
+				echo '<td><a href="' . htmlspecialchars($delUrl) . '" title="' . _SKINFILES_DELETE . ' &laquo;' . htmlspecialchars($name) . '&raquo;">' . _SKINFILES_DELETE . '</a></td>';
 			} else {
 				echo '<td>&nbsp;</td>';
 			}
@@ -451,11 +460,11 @@
 			echo '</td><td>';
 			echo ceil($stat['size'] / 1024) . ' kB';
 			echo '</td><td>';
-			echo date('M d Y, H:i', $stat['mtime']);
+			echo date(_SKINFILES_DATE_FORMAT, $stat['mtime']);
 			echo '</td><td>';
 				
 			if (is_writable($directory . $name)) {
-				echo '<a href="' . htmlspecialchars($renUrl) . '" title="Rename &laquo;' . htmlspecialchars($name) . '&raquo;">Rename</a>';
+				echo '<a href="' . htmlspecialchars($renUrl) . '" title="' . _SKINFILES_RENAME . ' &laquo;' . htmlspecialchars($name) . '&raquo;">' . _SKINFILES_RENAME . '</a>';
 			} else {
 				echo '&nbsp;';
 			}
@@ -463,7 +472,7 @@
 			echo '</td><td>';
 
 			if (is_writable($directory . $name)) {
-				echo '<a href="' . htmlspecialchars($delUrl) . '" title="Delete &laquo;' . htmlspecialchars($name) . '&raquo;">Delete</a>';
+				echo '<a href="' . htmlspecialchars($delUrl) . '" title="' . _SKINFILES_DELETE . ' &laquo;' . htmlspecialchars($name) . '&raquo;">' . _SKINFILES_DELETE . '</a>';
 			} else {
 				echo '&nbsp;';
 			}
@@ -471,14 +480,14 @@
 			echo '</td><td>';
 			
 			if (is_writable($directory . $name) && sfAllowEditing($name))
-				echo '<a href="'. htmlspecialchars($editUrl) . '" title="Edit &laquo;' . htmlspecialchars($name) . '&raquo;">Edit</a>';
+				echo '<a href="'. htmlspecialchars($editUrl) . '" title="' . _SKINFILES_EDIT . ' &laquo;' . htmlspecialchars($name) . '&raquo;">' . _SKINFILES_EDIT . '</a>';
 			else
 				echo '&nbsp;';
 
 			echo '</td><td>';
 			
 			if (is_readable ($directory . $name))
-				echo '<a href="' . htmlspecialchars($dlUrl) . '" title="Download &laquo;' . htmlspecialchars($name) . '&raquo;">Download</a>';
+				echo '<a href="' . htmlspecialchars($dlUrl) . '" title="' . _SKINFILES_DOWNLOAD . ' &laquo;' . htmlspecialchars($name) . '&raquo;">' . _SKINFILES_DOWNLOAD . '</a>';
 			else
 				echo '&nbsp;';
 				
@@ -486,7 +495,7 @@
 		}
 
 		if (!count($dirs) && !count($files)) {
-			echo '<tr><td colspan="7">This directory does not contain any files or directories</td></tr>';
+			echo '<tr><td colspan="7">' . _SKINFILES_ERR_DIR_DOES_NOT_CONTAIN . '</td></tr>';
 		}
 
 		echo '</table>';
@@ -495,36 +504,36 @@
 		
 			if (is_writable($directory)) {
 				echo '<div class="dialogbox">';
-				echo '<h4 class="light">Create a new file</h4><div>';
+				echo '<h4 class="light">' . _SKINFILES_CREATE_NEW_FILE . '</h4><div>';
 				echo '<form method="post" action="' . htmlspecialchars($pluginUrl) . '">';
 				$manager->addTicketHidden();
 				echo '<input type="hidden" name="action" value="createfile" />';
 				echo '<input type="hidden" name="dir" value="' . htmlspecialchars($relative) . '" />';
 				echo '<input type="text" name="name" size="40" value="untitled.txt" />';
-				echo '<p class="buttons"><input type="submit" value="Create file" /></p></form>';
+				echo '<p class="buttons"><input type="submit" value="' . _SKINFILES_CREATE_FILE . '" /></p></form>';
 				echo '</div></div>';
 	
 				echo '<div class="dialogbox">';
-				echo '<h4 class="light">Upload new file</h4><div>';
+				echo '<h4 class="light">' . _SKINFILES_UPLOAD_NEW_FILE . '</h4><div>';
 				echo '<form method="post" enctype="multipart/form-data" action="' . htmlspecialchars($pluginUrl) . '">';
 				$manager->addTicketHidden();
 				echo '<input type="hidden" name="action" value="uploadfile" />';
 				echo '<input type="hidden" name="dir" value="' . htmlspecialchars($relative) . '" />';
 				echo '<input type="hidden" name="MAX_FILE_SIZE" value="' . $CONF['MaxUploadSize'] . '" />';
 				echo '<input type="file" name="name" size="40" />';
-				echo '<p class="buttons"><input type="submit" value="Upload" /></p></form>';
+				echo '<p class="buttons"><input type="submit" value="' . _SKINFILES_UPLOAD . '" /></p></form>';
 				echo '</div></div>';
 			}
 	
 			if (count($files)) {
 				echo '<div class="dialogbox">';
-				echo '<h4 class="light">Delete all files in this directory</h4><div>';
+				echo '<h4 class="light">' . _SKINFILES_DEL_ALL_FILES . '</h4><div>';
 				echo '<form method="post" action="' . htmlspecialchars($pluginUrl) . '">';
 				$manager->addTicketHidden();
 				echo '<input type="hidden" name="action" value="emptydir" />';
 				echo '<input type="hidden" name="dir" value="' . htmlspecialchars($relative) . '" />';
-				echo 'Delete all files? (will ask for confirmation)';
-				echo '<p class="buttons"><input type="submit" value="Delete All" tabindex="140" onclick="return checkSubmit();" /></p>';
+				echo _SKINFILES_DEL_ALL_FILES_MSG;
+				echo '<p class="buttons"><input type="submit" value="' . _SKINFILES_DELETE_ALL . '" tabindex="140" onclick="return checkSubmit();" /></p>';
 				echo '</form>';
 				echo '</div></div>';
 			}
@@ -532,13 +541,13 @@
 	
 		if (is_writable($directory)) {
 			echo '<div class="dialogbox">';
-			echo '<h4 class="light">Create a new directory</h4><div>';
+			echo '<h4 class="light">' . _SKINFILES_CREATE_NEW_DIR . '</h4><div>';
 			echo '<form method="post" action="' . htmlspecialchars($pluginUrl) . '">';
 			$manager->addTicketHidden();
 			echo '<input type="hidden" name="action" value="createdir" />';
 			echo '<input type="hidden" name="dir" value="' . htmlspecialchars($relative) . '" />';
 			echo '<input type="text" name="name" value="untitled" tabindex="90" size="40" />';
-			echo '<p class="buttons"><input type="submit" value="Create" tabindex="140" onclick="return checkSubmit();" /></p>';
+			echo '<p class="buttons"><input type="submit" value="' . _SKINFILES_CREATE . '" tabindex="140" onclick="return checkSubmit();" /></p>';
 			echo '</form>';
 			echo '</div></div>';
 		}
@@ -563,8 +572,8 @@
 			$relative = sfRelativePath ($directory);
 			$editUrl  = $manager->addTicketToUrl($pluginUrl . '?action=rendir&dir=' . rawurlencode($relative . $file));
 
-			echo '<p class="location">Current location: ' . sfDisplayPath($relative);
-			echo '<a href="' . htmlspecialchars($editUrl) . '" title="Rename &laquo;' . $file . '&raquo;">';
+			echo '<p class="location">' . _SKINFILES_CURRENT_LOCATION . sfDisplayPath($relative);
+			echo '<a href="' . htmlspecialchars($editUrl) . '" title="' . _SKINFILES_RENAME . ' &laquo;' . $file . '&raquo;">';
 			echo '<img src="' . $pluginUrl . 'dir.gif' . '" alt="" /> ' . $file . '</a></p>';
 
 			echo '<div class="dialogbox">';
@@ -573,17 +582,19 @@
 			echo '<input type="hidden" name="action" value="rendir_process" />';
 			echo '<input type="hidden" name="dir" value="' . htmlspecialchars($relative . $file) . '" />';
 
-			echo '<h4>Rename directory &laquo;' . htmlspecialchars($file) . '&raquo; to:</h4><div>';
+			echo '<h4>' . _SKINFILES_RENAME_DIR_MSG . ' &laquo;' . htmlspecialchars($file) . '&raquo; ' . _SKINFILES_RENAME_DIR_MSG2 . '</h4><div>';
 			echo '<p><input type="text" name="name" size="40" value="' . htmlspecialchars($preset != '' ? $preset : $file) . '" /></p>';
-			echo '<p class="buttons"><button name="sure" value="yes" onclick="return checkSubmit();">Rename</button>';
-			echo '<button name="sure" value="no">Cancel</button></p></div>';
-			echo '</form>';
-			echo '</div>';
+			echo '<p class="buttons">';
+			echo '<input type="hidden" name="sure" value="yes" />';
+			echo '<input type="submit" value="' . _SKINFILES_RENAME . '" />';
+			echo '<input type="button" name="sure" value="' . _SKINFILES_CANCEL . '" onclick="history.back();" />';
+			echo '</p>';
+			echo '</div></form></div>';
 		}
 		else
 		{
-			echo "<p class='error'>Error: The directory &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-			echo "or you do not have permission to rename the directory</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_DIR_DOES_NOT_EXIST1 . " &laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DIR_DOES_NOT_EXIST2;
+			echo _SKINFILES_ERR_DIR_DOES_NOT_EXIST3 . "</p>";
 		}
 	}
 	
@@ -603,49 +614,48 @@
 				$name = requestVar('name');
 				
 				if ($name == '') {
-					echo "<p class='error'>Error: Could not rename the directory &laquo;" . htmlspecialchars($file) . "&raquo; ";
-					echo "because no new name was supplied.</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_RENAME_DIR1 . "&laquo;" . htmlspecialchars($file) . "&raquo; ";
+					echo _SKINFILES_ERR_COULD_NOT_RENAME_DIR2 . "</p>";
 					_skinfiles_rendir($name);
 					return;
 				}
 				
 				if (sfIllegalFilename($name)) {
-					echo "<p class='error'>Error: Could not rename the directory &laquo;" . htmlspecialchars($file) . "&raquo; ";
-					echo "because the supplied name contains one or more illegal characters</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_RENAME_DIR3 . "&laquo;" . htmlspecialchars($file) . "&raquo; ";
+					echo _SKINFILES_ERR_COULD_NOT_RENAME_DIR4 . "</p>";
 					_skinfiles_rendir($name);
 					return;
 				} 
 				
 				if ($name == $file) {
-					echo "<p class='error'>Error: Could not rename the directory &laquo;" . htmlspecialchars($file) . "&raquo; ";
-					echo "because the supplied name is the same as the original name. Please use a different name.</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_RENAME_DIR5 . "&laquo;" . htmlspecialchars($file) . "&raquo; ";
+					echo _SKINFILES_ERR_COULD_NOT_RENAME_DIR6 . _SKINFILES_ERR_COULD_NOT_RENAME_DIR7 . "</p>";
 					_skinfiles_rendir($name);
 					return;
 				}
 				
 				if (file_exists($directory . $name)) {
-					echo "<p class='error'>Error: Could not rename the directory &laquo;" . htmlspecialchars($file) . "&raquo; ";
-					echo "because the supplied name is already used by another file or directory. Consider using a different name, or ";
-					echo "delete the existing file or directory first</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_RENAME_DIR8 . "&laquo;" . htmlspecialchars($file) . "&raquo; ";
+					echo _SKINFILES_ERR_COULD_NOT_RENAME_DIR9 . _SKINFILES_ERR_COULD_NOT_RENAME_DIR10 . "</p>";
 					_skinfiles_rendir($name);
 					return;
 				}
 				
 				if (!@rename($directory . $file, $directory . $name)) 
 				{
-					echo "<p class='error'>Error: Could not rename the directory &laquo;" . htmlspecialchars($file) . "&raquo;</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_RENAME_DIR11 . "&laquo;" . htmlspecialchars($file) . "&raquo;</p>";
 					_skinfiles_rendir($name);
 					return;
 				}
 	
-				echo "<p class='message'>Message: The directory &laquo;" . htmlspecialchars($file) . "&raquo; has been renamed ";
-				echo "to &laquo;" . htmlspecialchars($name) . "&raquo;</p>";
+				echo "<p class='message'>" . _SKINFILES_RENAMED_DIR1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_RENAMED_DIR2;
+				echo _SKINFILES_RENAMED_DIR3 . "&laquo;" . htmlspecialchars($name) . "&raquo;" . _SKINFILES_RENAMED_DIR4 . "</p>";
 				sfShowDirectory($directory);
 			} 		
 			else
 			{
-				echo "<p class='error'>Error: The directory &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-				echo "or you do not have permission to rename the directory</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_DIR_DOES_NOT_EXIST1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DIR_DOES_NOT_EXIST2;
+				echo _SKINFILES_ERR_DIR_DOES_NOT_EXIST3 . "</p>";
 			}
 		}
 		else
@@ -670,22 +680,21 @@
 			$name = requestVar('name');
 			
 			if ($name == '') {
-				echo "<p class='error'>Error: Could not create a new directory because there was no name supplied</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_CREATE_DIR1 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			}
 			
 			if (sfIllegalFilename($name)) {
-				echo "<p class='error'>Error: Could not create the directory &laquo;" . htmlspecialchars($name) . "&raquo; ";
-				echo "because the supplied name contains one or more illegal characters</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_CREATE_DIR2 . "&laquo;" . htmlspecialchars($name) . "&raquo; ";
+				echo _SKINFILES_ERR_COULD_NOT_CREATE_DIR3 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			} 
 			
 			if (file_exists($directory . $name)) {
-				echo "<p class='error'>Error: Could not create the directory &laquo;" . htmlspecialchars($name) . "&raquo; ";
-				echo "because the supplied name is already used by another file or directory. Consider using a different name, or ";
-				echo "delete the existing file or directory first</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_CREATE_DIR4 . "&laquo;" . htmlspecialchars($name) . "&raquo; ";
+				echo _SKINFILES_ERR_COULD_NOT_CREATE_DIR5 . _SKINFILES_ERR_COULD_NOT_CREATE_DIR6 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			}
@@ -694,20 +703,20 @@
 
 			if (!@mkdir($directory . $name, 0755)) 
 			{
-				echo "<p class='error'>Error: Could not create the directory &laquo;" . htmlspecialchars($name) . "&raquo;</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_CREATE_DIR2 . "&laquo;" . htmlspecialchars($name) . "&raquo;</p>";
 				sfShowDirectory($directory);
 				return;
 			}
 
 			@umask($mask);
 			
-			echo "<p class='message'>Message: The directory &laquo;" . htmlspecialchars($name) . "&raquo; has been created</p>";
+			echo "<p class='message'>" . _SKINFILES_ERR_COULD_NOT_CREATE_DIR7 . "&laquo;" . htmlspecialchars($name) . "&raquo; " . _SKINFILES_ERR_COULD_NOT_CREATE_DIR8 . "</p>";
 			sfShowDirectory($directory);
 		} 		
 		else
 		{
-			echo "<p class='error'>Error: The directory &laquo;" . htmlspecialchars(basename($directory)) . "&raquo;  does not exist ";
-			echo "or you do not have permission to access that directory</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_COULD_NOT_CREATE_DIR9 . "&laquo;" . htmlspecialchars(basename($directory)) . "&raquo; " .  _SKINFILES_ERR_COULD_NOT_CREATE_DIR10;
+			echo _SKINFILES_ERR_COULD_NOT_CREATE_DIR11 . "</p>";
 		}
 	}
 	
@@ -731,8 +740,8 @@
 			$relative = sfRelativePath ($directory);
 			$delUrl  = $manager->addTicketToUrl($pluginUrl . '?action=deldir&dir=' . rawurlencode($relative . $file));
 
-			echo '<p class="location">Current location: ' . sfDisplayPath($relative);
-			echo '<a href="' . htmlspecialchars($delUrl) . '" title="Delete &laquo;' . $file . '&raquo;">';
+			echo '<p class="location">' . _SKINFILES_CURRENT_LOCATION . sfDisplayPath($relative);
+			echo '<a href="' . htmlspecialchars($delUrl) . '" title="' . _SKINFILES_DELETE . ' &laquo;' . $file . '&raquo;">';
 			echo '<img src="' . $pluginUrl . 'dir.gif' . '" alt="" /> ' . $file . '</a></p>';
 
 			echo '<div class="dialogbox">';
@@ -741,16 +750,18 @@
 			echo '<input type="hidden" name="action" value="deldir_process" />';
 			echo '<input type="hidden" name="dir" value="' . htmlspecialchars($relative . $file) . '" />';
 
-			echo '<h4>Delete directory &laquo;' . htmlspecialchars($file) . '&raquo;?</h4><div>';
-			echo '<p class="buttons"><button name="sure" value="yes">Delete</button>';
-			echo '<button name="sure" value="no">Cancel</button></p>';
-
+			echo '<h4>' . _SKINFILES_DELETE_DIR . ' &laquo;' . htmlspecialchars($file) . '&raquo; ' . _SKINFILES_DELETE_DIR2 . '</h4><div>';
+			echo '<p class="buttons">';
+			echo '<input type="hidden" name="sure" value="yes" />';
+			echo '<input type="submit" value="' . _SKINFILES_DELETE . '" />';
+			echo '<input type="button" name="sure" value="' . _SKINFILES_CANCEL . '" onclick="history.back();" />';
+			echo '</p>';
 			echo '</div></form></div>';
 		}
 		else
 		{
-			echo "<p class='error'>Error: The directory  &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-			echo "or you do not have permission to delete the directory</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_DELETE_DIR1 . " &laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DELETE_DIR2;
+			echo _SKINFILES_ERR_DELETE_DIR3 . "</p>";
 		}
 	}
 	
@@ -770,18 +781,18 @@
 			{
 				if (!@rmdir($directory . $file)) 
 				{
-					echo "<p class='error'>Error: Could not delete the directory &laquo;" . htmlspecialchars($file) . "&raquo;</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_DELETE_DIR4 . "&laquo;" . htmlspecialchars($file) . "&raquo;</p>";
 					sfShowDirectory($directory);
 					return;
 				}
 	
-				echo "<p class='message'>Message: The directory &laquo;" . htmlspecialchars($file) . "&raquo; has been deleted</p>";
+				echo "<p class='message'>" . _SKINFILES_ERR_DELETE_DIR5 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DELETE_DIR6 . "</p>";
 				sfShowDirectory($directory);
 			} 		
 			else
 			{
-				echo "<p class='error'>Error: The directory &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-				echo "or you do not have permission to delete the directory</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_DELETE_DIR1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DELETE_DIR2;
+				echo _SKINFILES_ERR_DELETE_DIR3 . "</p>";
 			}
 		}
 		else
@@ -824,7 +835,7 @@
 			$relative = sfRelativePath ($directory);
 			$emptyUrl  = $manager->addTicketToUrl($pluginUrl . '?action=emptydir&dir=' . rawurlencode($relative . $file));
 
-			echo '<p class="location">Current location: ' . sfDisplayPath($relative);
+			echo '<p class="location">' . _SKINFILES_CURRENT_LOCATION . sfDisplayPath($relative);
 			echo '<a href="' . htmlspecialchars($emptyUrl) . '" title="Empty &laquo;' . $file . '&raquo;">';
 			echo '<img src="' . $pluginUrl . 'dir.gif' . '" alt="" /> ' . $file . '</a></p>';
 
@@ -834,7 +845,7 @@
 			echo '<input type="hidden" name="action" value="emptydir_process" />';
 			echo '<input type="hidden" name="dir" value="' . htmlspecialchars($relative . $file) . '" />';
 
-			echo '<h4>Delete the following files from directory &laquo;' . htmlspecialchars($file) . '&raquo;?</h4><div>';
+			echo '<h4>' . _SKINFILES_DELETE_FILE_MSG . ' &laquo;' . htmlspecialchars($file) . '&raquo;' . _SKINFILES_DELETE_FILE_MSG2 . '</h4><div>';
 			
 			if (count($files)) 
 			{
@@ -842,13 +853,18 @@
 				foreach ($files as $name) {	echo '<li>' . htmlspecialchars($name) . '</li>'; }
 				echo '</ul>';
 	
-				echo '<p class="buttons"><button name="sure" value="yes">Delete</button>';
-				echo '<button name="sure" value="no">Cancel</button></p>';
+				echo '<p class="buttons">';
+				echo '<input type="hidden" name="sure" value="yes" />';
+				echo '<input type="submit" value="' . _SKINFILES_DELETE . '" />';
+				echo '<input type="button" name="sure" value="' . _SKINFILES_CANCEL . '" onclick="history.back();" />';
+				echo '</p>';
 			}
 			else
 			{
-				echo '<p>There are currently no files in this directory that can be deleted</p>';
-				echo '<p class="buttons"><button name="sure" value="no">Cancel</button></p>';
+				echo '<p>' . _SKINFILES_ERR_DELETE_DIR7 . '</p>';
+				echo '<p class="buttons">';
+				echo '<input type="button" name="sure" value="' . _SKINFILES_CANCEL . '" onclick="history.back();" />';
+				echo '</p>';
 			}
 			
 			echo '</div></form></div>';
@@ -856,8 +872,8 @@
 		}
 		else
 		{
-			echo "<p class='error'>Error: The directory &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-			echo "or you do not have permission to access that directory</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_DELETE_DIR1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DELETE_DIR2;
+			echo _SKINFILES_ERR_DELETE_DIR3 . "</p>";
 		}
 	}
 
@@ -881,9 +897,9 @@
 						   is_writable($directory . $file . '/' . $name)) 
 						{
 							if (unlink ($directory .$file . '/' . $name)) 
-								echo "<p class='message'>Message: The file &laquo;" . htmlspecialchars($name) . "&raquo; has been deleted</p>";
+								echo "<p class='message'>" . _SKINFILES_ERR_EMPTY_DIR1 . "&laquo;" . htmlspecialchars($name) . "&raquo; " . _SKINFILES_ERR_EMPTY_DIR2 . "</p>";
 							else
-								echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($name) . "&raquo; could not be deleted</p>";
+								echo "<p class='error'>" . _SKINFILES_ERR_EMPTY_DIR3 . "&laquo;" . htmlspecialchars($name) . "&raquo; " . _SKINFILES_ERR_EMPTY_DIR4 . "</p>";
 						}
 					}
 					
@@ -894,8 +910,8 @@
 			}
 			else
 			{
-				echo "<p class='error'>Error: The directory &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-				echo "or you do not have permission to access that directory</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_EMPTY_DIR5 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_EMPTY_DIR6;
+				echo _SKINFILES_ERR_EMPTY_DIR7 . "</p>";
 			}
 		}
 		else
@@ -940,12 +956,12 @@
 			}
 			else
 			{
-				echo "Error: Could not access the file";
+				echo _SKINFILES_ERR_DOWNLOAD_FILE1;
 			}
 		}
 		else
 		{
-			echo "Error: No permission to access the file";
+			echo _SKINFILES_ERR_DOWNLOAD_FILE2;
 		}
 
 		exit;
@@ -970,11 +986,11 @@
 			$relative = sfRelativePath ($directory);
 			$viewUrl  = $manager->addTicketToUrl($pluginUrl . '?action=viewfile&file=' . rawurlencode(sfRelativePath($directory . $file)));
 
-			echo '<p class="location">Current location: ' . sfDisplayPath($relative);
+			echo '<p class="location">' . _SKINFILES_CURRENT_LOCATION . sfDisplayPath($relative);
 			echo '<a href="' . htmlspecialchars($viewUrl) . '" title="View &laquo;' . $file . '&raquo;">';
 			echo '<img src="' . htmlspecialchars(sfIcon($file)) . '" alt="" /> ' . $file . '</a></p>';
 
-			echo '<h4>View file &laquo;' . htmlspecialchars($file) . '&raquo;</h4>';
+			echo '<h4>' . _SKINFILES_VIEW_FILE . '&laquo;' . htmlspecialchars($file) . '&raquo;</h4>';
 
 			if (sfIsFileType('html', $file))
 			{
@@ -1021,18 +1037,18 @@
 				}
 				
 				echo '<table>';
-				echo '<tr><th colspan="2">Image information</th></tr>';
-				echo '<tr><td>Type:</td><td>' . htmlspecialchars($type) . '</td></tr>';
-				echo '<tr><td>Width:</td><td>' . htmlspecialchars($size[0]) . ' px</td></tr>';
-				echo '<tr><td>Height:</td><td>' . htmlspecialchars($size[1]) . ' px</td></tr>';	
+				echo '<tr><th colspan="2">' . _SKINFILES_VIEW_FILE_IMG_INFO . '</th></tr>';
+				echo '<tr><td>' . _SKINFILES_VIEW_FILE_TYPE . '</td><td>' . htmlspecialchars($type) . '</td></tr>';
+				echo '<tr><td>' . _SKINFILES_VIEW_FILE_WIDTH . '</td><td>' . htmlspecialchars($size[0]) . _SKINFILES_VIEW_FILE_PX . '</td></tr>';
+				echo '<tr><td>' . _SKINFILES_VIEW_FILE_HEIGHT . '</td><td>' . htmlspecialchars($size[1]) . _SKINFILES_VIEW_FILE_PX . '</td></tr>';	
 				
 				if (isset($size['channels']) || isset($size['bits'])) 
 				{
 					$channels = isset($size['channels']) ? $size['channels'] : 3;
 					$depth    = $size[2] == IMAGETYPE_GIF ? $size['bits'] : $size['bits'] * $channels;
-					echo '<tr><td>Channels:</td><td>' . htmlspecialchars($channels) . '</td></tr>';
-					echo '<tr><td>Color depth:</td><td>' . htmlspecialchars($depth) . ' bits</td></tr>';
-					echo '<tr><td>Colors:</td><td>' . htmlspecialchars(pow(2, $depth)) . ' colors</td></tr>';
+					echo '<tr><td>' . _SKINFILES_VIEW_FILE_CHANNELS . '</td><td>' . htmlspecialchars($channels) . '</td></tr>';
+					echo '<tr><td>' . _SKINFILES_VIEW_FILE_COLOR_DEPTH . '</td><td>' . htmlspecialchars($depth) . _SKINFILES_VIEW_FILE_BITS . '</td></tr>';
+					echo '<tr><td>' . _SKINFILES_VIEW_FILE_COLORS . '</td><td>' . htmlspecialchars(pow(2, $depth)) . _SKINFILES_VIEW_FILE_COLORS2 . '</td></tr>';
 				}
 
 				
@@ -1076,8 +1092,8 @@
 		}
 		else
 		{
-			echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-			echo "or you do not have permission to view the file</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_VIEW_FILE1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_VIEW_FILE2;
+			echo _SKINFILES_ERR_VIEW_FILE3 . "</p>";
 		}
 	}
 
@@ -1110,7 +1126,7 @@
 			$relative = sfRelativePath ($directory);
 			$editUrl  = $manager->addTicketToUrl($pluginUrl . '?action=editfile&file=' . rawurlencode(sfRelativePath($directory . $file)));
 
-			echo '<p class="location">Current location: ' . sfDisplayPath($relative);
+			echo '<p class="location">' . _SKINFILES_CURRENT_LOCATION . sfDisplayPath($relative);
 			echo '<a href="' . htmlspecialchars($editUrl) . '" title="Edit &laquo;' . $file . '&raquo;">';
 			echo '<img src="' . htmlspecialchars(sfIcon($file)) . '" alt="" /> ' . $file . '</a></p>';
 
@@ -1122,20 +1138,22 @@
 			echo '<input type="hidden" name="action" value="editfile_process" />';
 			echo '<input type="hidden" name="file" value="' . htmlspecialchars(sfRelativePath($directory . $file)) . '" />';
 
-			echo '<h4>Edit file &laquo;' . htmlspecialchars($file) . '&raquo;</h4><div>';
+			echo '<h4>' . _SKINFILES_EDIT_FILE_MSG . ' &laquo;' . htmlspecialchars($file) . '&raquo;</h4><div>';
 			echo '<p><textarea class="skinedit" tabindex="8" rows="20" cols="80" name="content">';
 			echo htmlspecialchars($content);
 			echo '</textarea></p>';
 			
-			echo '<p class="buttons"><button name="sure" value="yes" onclick="return checkSubmit();">Save Changes</button>';
-			echo '<button name="sure" value="no">Cancel</button></p></div>';
-			echo '</form>';
-			echo '</div>';
+			echo '<p class="buttons">';
+			echo '<input type="hidden" name="sure" value="yes" /">';
+			echo '<input type="submit" value="' .  _SKINFILES_SAVE_CHANGES . '" />';
+			echo '<input type="button" name="sure" value="' . _SKINFILES_CANCEL . '" onclick="history.back();" />';
+			echo '</p>';
+			echo '</div></form></div>';
 		}
 		else
 		{
-			echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-			echo "or you do not have permission to edit the file</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_EDIT_FILE1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_EDIT_FILE2;
+			echo _SKINFILES_ERR_EDIT_FILE3 . "</p>";
 		}
 	}
 
@@ -1162,16 +1180,16 @@
 				}
 				
 				if ($success)
-					echo "<p class='message'>Message: The file &laquo;" . htmlspecialchars($file) . "&raquo; has been saved</p>";
+					echo "<p class='message'>" . _SKINFILES_ERR_EDIT_FILE4 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_EDIT_FILE5 . "</p>";
 				else
-					echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($file) . "&raquo; could not be saved</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_EDIT_FILE6 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_EDIT_FILE7 . "</p>";
 			
 				_skinfiles_editfile();
 			}
 			else
 			{
-				echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-				echo "or you do not have permission to edit the file</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_EDIT_FILE1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_EDIT_FILE2;
+				echo _SKINFILES_ERR_EDIT_FILE3 . "</p>";
 			}
 		}
 		else
@@ -1199,8 +1217,8 @@
 			$relative = sfRelativePath ($directory);
 			$editUrl  = $manager->addTicketToUrl($pluginUrl . '?action=renfile&file=' . rawurlencode(sfRelativePath($directory . $file)));
 
-			echo '<p class="location">Current location: ' . sfDisplayPath($relative);
-			echo '<a href="' . htmlspecialchars($editUrl) . '" title="Rename &laquo;' . $file . '&raquo;">';
+			echo '<p class="location">' . _SKINFILES_CURRENT_LOCATION . sfDisplayPath($relative);
+			echo '<a href="' . htmlspecialchars($editUrl) . '" title="' . _SKINFILES_RENAME . ' &laquo;' . $file . '&raquo;">';
 			echo '<img src="' . htmlspecialchars(sfIcon($file)) . '" alt="" /> ' . $file . '</a></p>';
 
 			echo '<div class="dialogbox">';
@@ -1209,17 +1227,19 @@
 			echo '<input type="hidden" name="action" value="renfile_process" />';
 			echo '<input type="hidden" name="file" value="' . htmlspecialchars(sfRelativePath($directory . $file)) . '" />';
 
-			echo '<h4>Rename file &laquo;' . htmlspecialchars($file) . '&raquo; to:</h4><div>';
+			echo '<h4>' . _SKINFILES_RENAME_FILE_MSG . '&laquo;' . htmlspecialchars($file) . '&raquo; ' . _SKINFILES_RENAME_FILE_MSG2 . '</h4><div>';
 			echo '<p><input type="text" name="name" size="40" value="' . htmlspecialchars($preset != '' ? $preset : $file) . '" /></p>';
-			echo '<p class="buttons"><button name="sure" value="yes" onclick="return checkSubmit();">Rename</button>';
-			echo '<button name="sure" value="no">Cancel</button></p></div>';
-			echo '</form>';
-			echo '</div>';
+			echo '<p class="buttons">';
+			echo '<input type="hidden" name="sure" value="yes" /">';
+			echo '<input type="submit" value="' . _SKINFILES_RENAME . '" />';
+			echo '<input type="button" name="sure" value="' . _SKINFILES_CANCEL . '" onclick="history.back();" />';
+			echo '</p>';
+			echo '</div></form></div>';
 		}
 		else
 		{
-			echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-			echo "or you do not have permission to rename the file</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_RENAME_FILE1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_RENAME_FILE2;
+			echo _SKINFILES_ERR_RENAME_FILE3 . "</p>";
 		}
 	}
 	
@@ -1237,51 +1257,51 @@
 				is_file($directory . $file) && is_writable($directory . $file)) 
 			{
 				$name = requestVar('name');
-				
+
 				if ($name == '') {
-					echo "<p class='error'>Error: Could not rename the file &laquo;" . htmlspecialchars($file) . "&raquo; ";
-					echo "because no new name was supplied.</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_RENAME_FILE4 . "&laquo;" . htmlspecialchars($file) . "&raquo; ";
+					echo _SKINFILES_ERR_RENAME_FILE5 . "</p>";
 					_skinfiles_renfile($name);
 					return;
 				}
 				
 				if (sfIllegalFilename($name)) {
-					echo "<p class='error'>Error: Could not rename the file &laquo;" . htmlspecialchars($file) . "&raquo; ";
-					echo "because the supplied file name contains one or more illegal characters</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_RENAME_FILE6 . "&laquo;" . htmlspecialchars($file) . "&raquo; ";
+					echo _SKINFILES_ERR_RENAME_FILE7 . "</p>";
 					_skinfiles_renfile($name);
 					return;
 				} 
 				
 				if ($name == $file) {
-					echo "<p class='error'>Error: Could not rename the file &laquo;" . htmlspecialchars($file) . "&raquo; ";
-					echo "because the supplied name is the same as the original name. Please use a different name.</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_RENAME_FILE8 . "&laquo;" . htmlspecialchars($file) . "&raquo; ";
+					echo _SKINFILES_ERR_RENAME_FILE9 . "</p>";
 					_skinfiles_renfile($name);
 					return;
 				}
 				
 				if (file_exists($directory . $name)) {
-					echo "<p class='error'>Error: Could not rename the file &laquo;" . htmlspecialchars($file) . "&raquo; ";
-					echo "because the supplied name is already used by another file or directory. Consider using a different name, or ";
-					echo "delete the existing file or directory first</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_RENAME_FILE10 . "&laquo;" . htmlspecialchars($file) . "&raquo; ";
+					echo _SKINFILES_ERR_RENAME_FILE11;
+					echo _SKINFILES_ERR_RENAME_FILE12 . "</p>";
 					_skinfiles_renfile($name);
 					return;
 				}
-				
+
 				if (!@rename($directory . $file, $directory . $name)) 
 				{
-					echo "<p class='error'>Error: Could not rename the file &laquo;" . htmlspecialchars($file) . "&raquo;</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_RENAME_FILE13 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_RENAME_FILE14 . "</p>";
 					_skinfiles_renfile($name);
 					return;
 				}
 	
-				echo "<p class='message'>Message: The file &laquo;" . htmlspecialchars($file) . "&raquo; has been renamed ";
-				echo "to &laquo;" . htmlspecialchars($name) . "&raquo;</p>";
+				echo "<p class='message'>" . _SKINFILES_ERR_RENAME_FILE15 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_RENAME_FILE16;
+				echo _SKINFILES_ERR_RENAME_FILE17 . "&laquo;" . htmlspecialchars($name) . "&raquo;" . _SKINFILES_ERR_RENAME_FILE18 . "</p>";
 				sfShowDirectory($directory);
 			} 		
 			else
 			{
-				echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-				echo "or you do not have permission to rename the file</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_RENAME_FILE1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_RENAME_FILE2;
+				echo _SKINFILES_ERR_RENAME_FILE3 . "</p>";
 			}
 		}
 		else
@@ -1306,29 +1326,29 @@
 			$name = requestVar('name');
 			
 			if ($name == '') {
-				echo "<p class='error'>Error: Could not create a new file because there was no name supplied</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_CREATE_FILE1 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			}
 			
 			if (sfIllegalFilename($name)) {
-				echo "<p class='error'>Error: Could not create the file &laquo;" . htmlspecialchars($name) . "&raquo; ";
-				echo "because the supplied file name contains one or more illegal characters</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_CREATE_FILE2 . "&laquo;" . htmlspecialchars($name) . "&raquo; ";
+				echo _SKINFILES_ERR_CREATE_FILE3 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			} 
 			
 			if (file_exists($directory . $name)) {
-				echo "<p class='error'>Error: Could not create the file &laquo;" . htmlspecialchars($name) . "&raquo; ";
-				echo "because the supplied name is already used by another file or directory. Consider using a different name, or ";
-				echo "delete the existing file or directory first</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_CREATE_FILE4 . "&laquo;" . htmlspecialchars($name) . "&raquo; ";
+				echo _SKINFILES_ERR_CREATE_FILE5;
+				echo _SKINFILES_ERR_CREATE_FILE6 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			}
 			
 			if (!@touch($directory . $name)) 
 			{
-				echo "<p class='error'>Error: Could not create the file &laquo;" . htmlspecialchars($name) . "&raquo;</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_CREATE_FILE7 . "&laquo;" . htmlspecialchars($name) . "&raquo; " . _SKINFILES_ERR_CREATE_FILE8 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			}
@@ -1337,13 +1357,13 @@
 			@chmod($directory . $name, 0755);
 			@umask($mask);
 			
-			echo "<p class='message'>Message: The file &laquo;" . htmlspecialchars($name) . "&raquo; has been created</p>";
+			echo "<p class='message'>" . _SKINFILES_ERR_CREATE_FILE9 . "&laquo;" . htmlspecialchars($name) . "&raquo; " . _SKINFILES_ERR_CREATE_FILE10 . "</p>";
 			sfShowDirectory($directory);
 		} 		
 		else
 		{
-			echo "<p class='error'>Error: The directory &laquo;" . htmlspecialchars(basename($directory)) . "&raquo;  does not exist ";
-			echo "or you do not have permission to access that directory</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_CREATE_FILE11 . "&laquo;" . htmlspecialchars(basename($directory)) . "&raquo; " . _SKINFILES_ERR_CREATE_FILE12;
+			echo _SKINFILES_ERR_CREATE_FILE13 . "</p>";
 		}
 	}
 
@@ -1366,8 +1386,8 @@
 			$relative = sfRelativePath ($directory);
 			$delUrl  = $manager->addTicketToUrl($pluginUrl . '?action=delfile&file=' . rawurlencode(sfRelativePath($directory . $file)));
 
-			echo '<p class="location">Current location: ' . sfDisplayPath($relative);
-			echo '<a href="' . htmlspecialchars($delUrl) . '" title="Delete &laquo;' . $file . '&raquo;">';
+			echo '<p class="location">' . _SKINFILES_CURRENT_LOCATION . sfDisplayPath($relative);
+			echo '<a href="' . htmlspecialchars($delUrl) . '" title="' . _SKINFILES_DELETE . ' &laquo;' . $file . '&raquo;">';
 			echo '<img src="' . htmlspecialchars(sfIcon($file)) . '" alt="" /> ' . $file . '</a></p>';
 
 			echo '<div class="dialogbox">';
@@ -1376,16 +1396,18 @@
 			echo '<input type="hidden" name="action" value="delfile_process" />';
 			echo '<input type="hidden" name="file" value="' . htmlspecialchars(sfRelativePath($directory . $file)) . '" />';
 
-			echo '<h4>Delete file &laquo;' . htmlspecialchars($file) . '&raquo;?</h4><div>';
-			echo '<p class="buttons"><button name="sure" value="yes">Delete</button>';
-			echo '<button name="sure" value="no">Cancel</button></p>';
-
+			echo '<h4>' . _SKINFILES_DELETE_FILE . ' &laquo;' . htmlspecialchars($file) . '&raquo; ' . _SKINFILES_DELETE_FILE2 . '</h4><div>';
+			echo '<p class="buttons">';
+			echo '<input type="hidden" name="sure" value="yes" />';
+			echo '<input type="submit" value="' . _SKINFILES_DELETE . '" />';
+			echo '<input type="button" name="sure" value="' . _SKINFILES_CANCEL . '" onclick="history.back();" />';
+			echo '</p>';
 			echo '</div></form></div>';
 		}
 		else
 		{
-			echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-			echo "or you do not have permission to delete the file</p>";
+			echo "<p class='error'>"  . _SKINFILES_ERR_DELETE_FILE1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DELETE_FILE2;
+			echo _SKINFILES_ERR_DELETE_FILE3 . "</p>";
 		}
 	}
 
@@ -1404,18 +1426,18 @@
 			{
 				if (!@unlink($directory . $file)) 
 				{
-					echo "<p class='error'>Error: Could not delete the file &laquo;" . htmlspecialchars($file) . "&raquo;</p>";
+					echo "<p class='error'>" . _SKINFILES_ERR_DELETE_FILE4 . "&laquo;" . htmlspecialchars($file) . "&raquo;</p>";
 					sfShowDirectory($directory);
 					return;
 				}
 	
-				echo "<p class='message'>Message: The file &laquo;" . htmlspecialchars($file) . "&raquo; has been deleted</p>";
+				echo "<p class='message'>" . _SKINFILES_ERR_DELETE_FILE5 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DELETE_FILE6 . "</p>";
 				sfShowDirectory($directory);
 			} 		
 			else
 			{
-				echo "<p class='error'>Error: The file &laquo;" . htmlspecialchars($file) . "&raquo;  does not exist ";
-				echo "or you do not have permission to delete the file</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_DELETE_FILE1 . "&laquo;" . htmlspecialchars($file) . "&raquo; " . _SKINFILES_ERR_DELETE_FILE2;
+				echo _SKINFILES_ERR_DELETE_FILE3 . "</p>";
 			}
 		}
 		else
@@ -1441,32 +1463,34 @@
 			$file = postFileInfo('name');
 
 			if ($file['size'] > $CONF['MaxUploadSize']) {
-				echo "<p class='error'>Error: Could not upload the file &laquo;" . htmlspecialchars($file['name']) . "&raquo;. " . $CONF['MaxUploadSize'] . '/' . $file['size'] . _ERROR_FILE_TOO_BIG . "</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_UPLOAD_FILE1 . "&laquo;" . htmlspecialchars($file['name']) . "&raquo; " . _SKINFILES_ERR_UPLOAD_FILE2 . _ERROR_FILE_TOO_BIG . "<br />";
+				echo _SKINFILES_ERR_UPLOAD_FILE3 . $CONF['MaxUploadSize'] . " / ";
+				echo $file['size'] . " bytes</p>";
 				sfShowDirectory($directory);
 				return;
 			}
 
 			if (!is_uploaded_file($file['tmp_name'])) {
-				echo "<p class='error'>Error: Could not upload the file &laquo;" . htmlspecialchars($file['name']) . "&raquo;. " . _ERROR_BADREQUEST . "</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_UPLOAD_FILE1 . "&laquo;" . htmlspecialchars($file['name']) . "&raquo; " . _SKINFILES_ERR_UPLOAD_FILE2 . _ERROR_BADREQUEST .  _SKINFILES_ERR_UPLOAD_FILE4 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			}
 			
 			if (sfIllegalFilename($file['name'])) {
-				echo "<p class='error'>Error: Could not upload the file &laquo;" . htmlspecialchars($file['name']) . "&raquo; ";
-				echo "because the supplied file name contains one or more illegal characters</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_UPLOAD_FILE5 . "&laquo;" . htmlspecialchars($file['name']) . "&raquo; ";
+				echo _SKINFILES_ERR_UPLOAD_FILE6 . "</p>";
 				sfShowDirectory($directory);
 				return;
 			}
 			
 			if (file_exists($directory . $file['name'])) {
-				echo "<p class='error'>Error: Could not upload the file &laquo;" . htmlspecialchars($file['name']) . "&raquo;. " . _ERROR_UPLOADDUPLICATE . "</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_UPLOAD_FILE1 . "&laquo;" . htmlspecialchars($file['name']) . "&raquo; " . _SKINFILES_ERR_UPLOAD_FILE2 . _ERROR_UPLOADDUPLICATE . "</p>";
 				sfShowDirectory($directory);
 				return;
 			}
 
 			if (!@move_uploaded_file($file['tmp_name'], $directory . $file['name'])) {
-				echo "<p class='error'>Error: Could not upload the file &laquo;" . htmlspecialchars($file['name']) . "&raquo;. " . _ERROR_UPLOADMOVE . "</p>";
+				echo "<p class='error'>" . _SKINFILES_ERR_UPLOAD_FILE1 . "&laquo;" . htmlspecialchars($file['name']) . "&raquo; " . _SKINFILES_ERR_UPLOAD_FILE2 . _ERROR_UPLOADMOVEP . _SKINFILES_ERR_UPLOAD_FILE4 . "</p>";
 				sfShowDirectory($directory);
 			}
 
@@ -1474,13 +1498,13 @@
 			@chmod($directory . $file['name'], 0755);
 			@umask($mask);
 
-			echo "<p class='message'>Message: The file &laquo;" . htmlspecialchars($file['name']) . "&raquo; has been uploaded</p>";
+			echo "<p class='message'>" . _SKINFILES_ERR_UPLOAD_FILE7 . "&laquo;" . htmlspecialchars($file['name']) . "&raquo; " . _SKINFILES_ERR_UPLOAD_FILE8 . "</p>";
 			sfShowDirectory($directory);
 		}
 		else
 		{
-			echo "<p class='error'>Error: The directory &laquo;" . htmlspecialchars(basename($directory)) . "&raquo;  does not exist ";
-			echo "or you do not have permission to access that directory</p>";
+			echo "<p class='error'>" . _SKINFILES_ERR_UPLOAD_FILE9 . "&laquo;" . htmlspecialchars(basename($directory)) . "&raquo; " . _SKINFILES_ERR_UPLOAD_FILE10;
+			echo _SKINFILES_ERR_UPLOAD_FILE11 . "</p>";
 		}	
 	}
 
@@ -1488,4 +1512,4 @@
 
 
 	
-?>
\ No newline at end of file
+?>
diff -ruN 3.24.src/nucleus/plugins/skinfiles/japanese-euc.php 3.31.src/nucleus/plugins/skinfiles/japanese-euc.php
--- 3.24.src/nucleus/plugins/skinfiles/japanese-euc.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/plugins/skinfiles/japanese-euc.php	2007-10-22 19:35:56.000000000 -0500
@@ -0,0 +1,178 @@
+<?php
+
+   /*
+	* @version $Id: japanese-euc.php 1116 2007-02-03 08:24:29Z kimitake $
+	* @version $NucleusJP: japanese-euc.php,v 1.2 2007/01/29 22:07:42 kimitake Exp $
+	*/
+
+define('_SKINFILES_TITLE',				'ե');
+define('_SKINFILES_TOOLTIP',			'եδ');
+
+define('_SKINFILES_MANAGEMENT',			'ե');
+define('_SKINFILES_CURRENT_LOCATION',	'ߤΥǥ쥯ȥ: ');
+define('_SKINFILES_NAME',				'̾');
+define('_SKINFILES_SIZE',				'');
+define('_SKINFILES_LAST_MODIFIED',		'ǽ');
+define('_SKINFILES_ACTIONS',			'');
+
+define('_SKINFILES_RENAME',				'̾ѹ');
+define('_SKINFILES_RENAME_DIR_MSG',		'Υǥ쥯ȥ̾');
+define('_SKINFILES_RENAME_DIR_MSG2',	'򲼵̾ѹ');
+define('_SKINFILES_EDIT_FILE_MSG',		'եԽ');
+define('_SKINFILES_RENAME_FILE_MSG',	'ե');
+define('_SKINFILES_RENAME_FILE_MSG2',	'̾򲼵ѹ:');
+define('_SKINFILES_DELETE',				'');
+define('_SKINFILES_EDIT',				'Խ');
+define('_SKINFILES_CANCEL',				'󥻥');
+define('_SKINFILES_DOWNLOAD',			'');
+define('_SKINFILES_SAVE_CHANGES',		'¸');
+
+define('_SKINFILES_DATE_FORMAT',		'Y/m/d H:i');
+
+define('_SKINFILES_CREATE_NEW_FILE',	'եκ');
+define('_SKINFILES_CREATE_NEW_DIR',		'ǥ쥯ȥκ');
+define('_SKINFILES_CREATE_FILE',		'ե');
+define('_SKINFILES_CREATE',				'');
+define('_SKINFILES_UPLOAD',				'åץ');
+define('_SKINFILES_DELETE_FILE',		'ե');
+define('_SKINFILES_DELETE_FILE2',		' ޤ');
+define('_SKINFILES_DELETE_DIR',			'ǥ쥯ȥ');
+define('_SKINFILES_DELETE_DIR2',		' ޤ');
+define('_SKINFILES_DELETE_ALL',			'');
+define('_SKINFILES_DELETE_FILE_MSG',	'ǥ쥯ȥ');
+define('_SKINFILES_DELETE_FILE_MSG2',	' 鲼Υեޤ');
+define('_SKINFILES_UPLOAD_NEW_FILE',	'եΥåץ');
+define('_SKINFILES_DEL_ALL_FILES',		'ǥ쥯ȥե');
+define('_SKINFILES_DEL_ALL_FILES_MSG',	'եޤ ʺǽǧ');
+
+define('_SKINFILES_VIEW_FILE',				'եɽ ');
+define('_SKINFILES_VIEW_FILE_IMG_INFO',		'᡼');
+define('_SKINFILES_VIEW_FILE_TYPE',			'');
+define('_SKINFILES_VIEW_FILE_WIDTH',		'');
+define('_SKINFILES_VIEW_FILE_HEIGHT',		'ĥ');
+define('_SKINFILES_VIEW_FILE_PX',			' ԥ');
+define('_SKINFILES_VIEW_FILE_CHANNELS',		'ͥ');
+define('_SKINFILES_VIEW_FILE_COLOR_DEPTH',	'');
+define('_SKINFILES_VIEW_FILE_BITS',			' ӥå');
+define('_SKINFILES_VIEW_FILE_COLORS',		'');
+define('_SKINFILES_VIEW_FILE_COLORS2',		' ');
+
+
+define('_SKINFILES_ERR_DIR_DOES_NOT_CONTAIN',	'Υǥ쥯ȥˤϥե롦ǥ쥯ȥ꤬¸ߤޤ');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST1',	'顼: ǥ쥯ȥ ');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST2',	'¸ߤʤ');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST3',	'Υǥ쥯ȥ̾ѹ븢¤ޤ');
+
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR1',	'顼: ̾ꤵޤǤΤ ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR2',	'ѹǤޤǤ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR3',	'顼: ꤷ̾ˣİʾ̵ʸޤޤƤޤΤ ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR4',	'ѹǤޤǤ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR5',	'顼: ꤷ̾ϸ̾ƱǤΤ ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR6',	'ѹǤޤǤ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR7',	'̤̾ꤷƲ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR8',	'顼: ꤷ̾ϴ¾Υեǥ쥯ȥ˻ѤƤޤΤ ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR9',	'ѹǤޤǤ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR10',	'̤̾Ѥ뤫ޤ¸Υեޤϥǥ쥯ȥƲ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR11',	'顼: Υǥ쥯ȥ̾ѹǤޤǤ ');
+
+define('_SKINFILES_RENAMED_DIR1',				'å: ǥ쥯ȥ ');
+define('_SKINFILES_RENAMED_DIR2',				'̾ ');
+define('_SKINFILES_RENAMED_DIR3',				'');
+define('_SKINFILES_RENAMED_DIR4',				' ѹޤ');
+
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR1',	'顼: ̾ꤵޤǤΤǡ˥ǥ쥯ȥǤޤǤ ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR2',	'顼: ꤷ̾ˣİʾ̵ʸޤޤƤޤΤ ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR3',	'˥ǥ쥯ȥǤޤǤ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR4',	'顼: ꤷ̾ϴ¾Υեޤϥǥ쥯ȥ˻ѤƤޤΤ ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR5',	' Υǥ쥯ȥ򿷵ǺǤޤǤ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR6',	'̤̾Ѥ뤫ޤ¸Υեޤϥǥ쥯ȥƲ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR7',	'å: ǥ쥯ȥ ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR8',	'ޤ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR9',	'顼: ǥ쥯ȥ ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR10',	'¸ߤʤ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR11',	'Υǥ쥯ȥ˥븢¤ޤ');
+
+define('_SKINFILES_ERR_DELETE_DIR1',			'顼: ǥ쥯ȥ ');
+define('_SKINFILES_ERR_DELETE_DIR2',			'¸ߤʤ');
+define('_SKINFILES_ERR_DELETE_DIR3',			'Υǥ쥯ȥ븢¤ޤ');
+define('_SKINFILES_ERR_DELETE_DIR4',			'顼: ǥ쥯ȥǤޤǤ');
+define('_SKINFILES_ERR_DELETE_DIR5',			'å: ǥ쥯ȥ ');
+define('_SKINFILES_ERR_DELETE_DIR6',			'ޤ');
+define('_SKINFILES_ERR_DELETE_DIR7',			'ߤΥǥ쥯ȥˤϺǤեϤޤ');
+
+define('_SKINFILES_ERR_EMPTY_DIR1',				'å: ե ');
+define('_SKINFILES_ERR_EMPTY_DIR2',				'ޤ');
+define('_SKINFILES_ERR_EMPTY_DIR3',				'顼: ե ');
+define('_SKINFILES_ERR_EMPTY_DIR4',				'ϺǤޤǤ');
+define('_SKINFILES_ERR_EMPTY_DIR5',				'顼: ǥ쥯ȥ ');
+define('_SKINFILES_ERR_EMPTY_DIR6',				'¸ߤʤ');
+define('_SKINFILES_ERR_EMPTY_DIR7',				'Υǥ쥯ȥ˥븢¤ޤ');
+
+define('_SKINFILES_ERR_DOWNLOAD_FILE1',			'顼: ե˥ǤޤǤ');
+define('_SKINFILES_ERR_DOWNLOAD_FILE2',			'顼: Υե˥븢¤ޤǤ');
+
+define('_SKINFILES_ERR_VIEW_FILE1',				'顼: ե ');
+define('_SKINFILES_ERR_VIEW_FILE2',				'¸ߤʤ');
+define('_SKINFILES_ERR_VIEW_FILE3',				'Υե򻲾Ȥ븢¤ޤ');
+
+define('_SKINFILES_ERR_EDIT_FILE1',				'顼: ե ');
+define('_SKINFILES_ERR_EDIT_FILE2',				'¸ߤʤ');
+define('_SKINFILES_ERR_EDIT_FILE3',				'ΥեԽ븢¤ޤ');
+define('_SKINFILES_ERR_EDIT_FILE4',				'å: ե ');
+define('_SKINFILES_ERR_EDIT_FILE5',				'¸ޤ');
+define('_SKINFILES_ERR_EDIT_FILE6',				'顼: ե ');
+define('_SKINFILES_ERR_EDIT_FILE7',				'¸ǤޤǤ');
+
+define('_SKINFILES_ERR_RENAME_FILE1',			'顼: ե ');
+define('_SKINFILES_ERR_RENAME_FILE2',			'¸ߤʤ');
+define('_SKINFILES_ERR_RENAME_FILE3',			'Υե̾ѹ븢¤ޤ');
+define('_SKINFILES_ERR_RENAME_FILE4',			'顼: ̾ꤵޤǤΤǡ');
+define('_SKINFILES_ERR_RENAME_FILE5',			'̾ѹǤޤǤ ');
+define('_SKINFILES_ERR_RENAME_FILE6',			'顼: ꤷ̾ˣİʾ̵ʸޤޤƤޤΤ ');
+define('_SKINFILES_ERR_RENAME_FILE7',			'̾ѹǤޤǤ ');
+define('_SKINFILES_ERR_RENAME_FILE8',			'顼: ꤷ̾ϸ̾ƱǤΤ ');
+define('_SKINFILES_ERR_RENAME_FILE9',			'̾ѹǤޤǤ̤̾ѤƲ ');
+define('_SKINFILES_ERR_RENAME_FILE10',			'顼: ꤷ̾ϴ¾Υեޤϥǥ쥯ȥ˻ѤƤޤΤ ');
+define('_SKINFILES_ERR_RENAME_FILE11',			'̾ѹǤޤǤ');
+define('_SKINFILES_ERR_RENAME_FILE12',			'̤̾Ѥ뤫ޤ¸Υեޤϥǥ쥯ȥƲ');
+define('_SKINFILES_ERR_RENAME_FILE13',			'顼: ե ');
+define('_SKINFILES_ERR_RENAME_FILE14',			'̾ѹǤޤǤ');
+define('_SKINFILES_ERR_RENAME_FILE15',			'å: ե ');
+define('_SKINFILES_ERR_RENAME_FILE16',			' ');
+define('_SKINFILES_ERR_RENAME_FILE17',			' ');
+define('_SKINFILES_ERR_RENAME_FILE18',			' ̾ѹޤ');
+
+define('_SKINFILES_ERR_CREATE_FILE1',			'顼: ե̾ꤵޤǤΤǡե뤬ǤޤǤ');
+define('_SKINFILES_ERR_CREATE_FILE2',			'顼: ꤷ̾ˣİʾ̵ʸޤޤƤޤΤǡ');
+define('_SKINFILES_ERR_CREATE_FILE3',			'Ͽ˺ǤޤǤ');
+define('_SKINFILES_ERR_CREATE_FILE4',			'顼: ꤷ̾ϤǤ¾Υեޤϥǥ쥯ȥǻѤƤޤΤǡ');
+define('_SKINFILES_ERR_CREATE_FILE5',			'Ͽ˺ǤޤǤ');
+define('_SKINFILES_ERR_CREATE_FILE6',			'̤̾Ѥ뤫¸Υեޤϥǥ쥯ȥޤƲ');
+define('_SKINFILES_ERR_CREATE_FILE7',			'顼: ե ');
+define('_SKINFILES_ERR_CREATE_FILE8',			'Ͽ˺ǤޤǤ');
+define('_SKINFILES_ERR_CREATE_FILE9',			'å: ե ');
+define('_SKINFILES_ERR_CREATE_FILE10',			' 򿷵˺ޤ');
+define('_SKINFILES_ERR_CREATE_FILE11',			'顼: ǥ쥯ȥ ');
+define('_SKINFILES_ERR_CREATE_FILE12',			' ¸ߤʤ');
+define('_SKINFILES_ERR_CREATE_FILE13',			'Υǥ쥯ȥ˥븢¤ޤ');
+
+define('_SKINFILES_ERR_DELETE_FILE1',			'顼: ե ');
+define('_SKINFILES_ERR_DELETE_FILE2',			'¸ߤʤ');
+define('_SKINFILES_ERR_DELETE_FILE3',			'Υե븢¤ޤ');
+define('_SKINFILES_ERR_DELETE_FILE4',			'顼: եǤޤǤ ');
+define('_SKINFILES_ERR_DELETE_FILE5',			'å: ե ');
+define('_SKINFILES_ERR_DELETE_FILE6',			'ޤ');
+
+define('_SKINFILES_ERR_UPLOAD_FILE1',			'顼: ե ');
+define('_SKINFILES_ERR_UPLOAD_FILE2',			'ΥåץɤǤޤǤ');
+define('_SKINFILES_ERR_UPLOAD_FILE3',			' / ߤΥ: ');
+define('_SKINFILES_ERR_UPLOAD_FILE4',			'');
+define('_SKINFILES_ERR_UPLOAD_FILE5',			'顼: ꤷ̾ˣİʾ̵ʸޤޤƤޤΤǡե ');
+define('_SKINFILES_ERR_UPLOAD_FILE6',			'ΥåץɤǤޤǤ');
+define('_SKINFILES_ERR_UPLOAD_FILE7',			'å: ե ');
+define('_SKINFILES_ERR_UPLOAD_FILE8',			'򥢥åץɤޤ');
+define('_SKINFILES_ERR_UPLOAD_FILE9',			'顼: ǥ쥯ȥ ');
+define('_SKINFILES_ERR_UPLOAD_FILE10',			'¸ߤʤ');
+define('_SKINFILES_ERR_UPLOAD_FILE11',			'Υǥ쥯ȥ˥븢¤ޤ');
+
+?>
diff -ruN 3.24.src/nucleus/plugins/skinfiles/japanese-utf8.php 3.31.src/nucleus/plugins/skinfiles/japanese-utf8.php
--- 3.24.src/nucleus/plugins/skinfiles/japanese-utf8.php	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/nucleus/plugins/skinfiles/japanese-utf8.php	2007-10-22 19:35:56.000000000 -0500
@@ -0,0 +1,178 @@
+<?php
+
+   /*
+	* @version $Id: japanese-utf8.php 1116 2007-02-03 08:24:29Z kimitake $
+	* @version $NucleusJP: japanese-utf8.php,v 1.2 2007/01/29 22:07:42 kimitake Exp $
+	*/
+
+define('_SKINFILES_TITLE',				'スキンファイル');
+define('_SKINFILES_TOOLTIP',			'スキンファイルの管理');
+
+define('_SKINFILES_MANAGEMENT',			'スキンファイル管理');
+define('_SKINFILES_CURRENT_LOCATION',	'現在のディレクトリ: ');
+define('_SKINFILES_NAME',				'名前');
+define('_SKINFILES_SIZE',				'サイズ');
+define('_SKINFILES_LAST_MODIFIED',		'最終更新日');
+define('_SKINFILES_ACTIONS',			'アクション');
+
+define('_SKINFILES_RENAME',				'名前変更');
+define('_SKINFILES_RENAME_DIR_MSG',		'このディレクトリ名');
+define('_SKINFILES_RENAME_DIR_MSG2',	'を下記の名前に変更');
+define('_SKINFILES_EDIT_FILE_MSG',		'ファイルの編集');
+define('_SKINFILES_RENAME_FILE_MSG',	'ファイル');
+define('_SKINFILES_RENAME_FILE_MSG2',	'の名前を下記に変更:');
+define('_SKINFILES_DELETE',				'削除');
+define('_SKINFILES_EDIT',				'編集');
+define('_SKINFILES_CANCEL',				'キャンセル');
+define('_SKINFILES_DOWNLOAD',			'ダウンロード');
+define('_SKINFILES_SAVE_CHANGES',		'保存');
+
+define('_SKINFILES_DATE_FORMAT',		'Y/m/d H:i');
+
+define('_SKINFILES_CREATE_NEW_FILE',	'新規ファイルの作成');
+define('_SKINFILES_CREATE_NEW_DIR',		'新規ディレクトリの作成');
+define('_SKINFILES_CREATE_FILE',		'ファイル作成');
+define('_SKINFILES_CREATE',				'作成');
+define('_SKINFILES_UPLOAD',				'アップロード');
+define('_SKINFILES_DELETE_FILE',		'ファイル');
+define('_SKINFILES_DELETE_FILE2',		' を削除しますか？');
+define('_SKINFILES_DELETE_DIR',			'ディレクトリ');
+define('_SKINFILES_DELETE_DIR2',		' を削除しますか？');
+define('_SKINFILES_DELETE_ALL',			'全削除');
+define('_SKINFILES_DELETE_FILE_MSG',	'ディレクトリ');
+define('_SKINFILES_DELETE_FILE_MSG2',	' から下記のファイルを削除しますか？');
+define('_SKINFILES_UPLOAD_NEW_FILE',	'新規ファイルのアップロード');
+define('_SKINFILES_DEL_ALL_FILES',		'現ディレクトリの全ファイル削除');
+define('_SKINFILES_DEL_ALL_FILES_MSG',	'全ファイルを削除しますか？ （最終確認あり）');
+
+define('_SKINFILES_VIEW_FILE',				'ファイル表示 ');
+define('_SKINFILES_VIEW_FILE_IMG_INFO',		'イメージ情報');
+define('_SKINFILES_VIEW_FILE_TYPE',			'種別');
+define('_SKINFILES_VIEW_FILE_WIDTH',		'横サイズ');
+define('_SKINFILES_VIEW_FILE_HEIGHT',		'縦サイズ');
+define('_SKINFILES_VIEW_FILE_PX',			' ピクセル');
+define('_SKINFILES_VIEW_FILE_CHANNELS',		'チャンネル数');
+define('_SKINFILES_VIEW_FILE_COLOR_DEPTH',	'色深度');
+define('_SKINFILES_VIEW_FILE_BITS',			' ビット');
+define('_SKINFILES_VIEW_FILE_COLORS',		'色数');
+define('_SKINFILES_VIEW_FILE_COLORS2',		' 色');
+
+
+define('_SKINFILES_ERR_DIR_DOES_NOT_CONTAIN',	'このディレクトリにはファイル・ディレクトリが存在しません。');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST1',	'エラー: ディレクトリ ');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST2',	'は存在しないか、');
+define('_SKINFILES_ERR_DIR_DOES_NOT_EXIST3',	'そのディレクトリ名を変更する権限がありません。');
+
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR1',	'エラー: 新しい名前が設定されませんでしたので ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR2',	'は変更できませんでした。');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR3',	'エラー: 設定した名前に１つ以上の無効な文字が含まれていましたので ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR4',	'は変更できませんでした。');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR5',	'エラー: 設定した名前は元の名前と同じでしたので ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR6',	'は変更できませんでした。');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR7',	'別の名前を設定して下さい。');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR8',	'エラー: 設定した名前は既に他のファイルやディレクトリに使用されていましたので ');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR9',	'は変更できませんでした。');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR10',	'別の名前を使用するか、まず既存のファイルまたはディレクトリを削除して下さい。');
+define('_SKINFILES_ERR_COULD_NOT_RENAME_DIR11',	'エラー: 次のディレクトリ名を変更できませんでした。 ');
+
+define('_SKINFILES_RENAMED_DIR1',				'メッセージ: ディレクトリ ');
+define('_SKINFILES_RENAMED_DIR2',				'の名前を ');
+define('_SKINFILES_RENAMED_DIR3',				'');
+define('_SKINFILES_RENAMED_DIR4',				' に変更しました。');
+
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR1',	'エラー: 名前が設定されませんでしたので、新規にディレクトリを作成できませんでした。 ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR2',	'エラー: 設定した名前に１つ以上の無効な文字が含まれていましたので ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR3',	'新規にディレクトリを作成できませんでした。');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR4',	'エラー: 設定した名前は既に他のファイルまたはディレクトリに使用されていましたので ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR5',	' のディレクトリを新規で作成できませんでした。');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR6',	'別の名前を使用するか、まず既存のファイルまたはディレクトリを削除して下さい。');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR7',	'メッセージ: ディレクトリ ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR8',	'を作成しました。');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR9',	'エラー: ディレクトリ ');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR10',	'は存在しないか');
+define('_SKINFILES_ERR_COULD_NOT_CREATE_DIR11',	'そのディレクトリにアクセスする権限がありません。');
+
+define('_SKINFILES_ERR_DELETE_DIR1',			'エラー: ディレクトリ ');
+define('_SKINFILES_ERR_DELETE_DIR2',			'は存在しないか');
+define('_SKINFILES_ERR_DELETE_DIR3',			'そのディレクトリを削除する権限がありません。');
+define('_SKINFILES_ERR_DELETE_DIR4',			'エラー: ディレクトリを削除できませんでした。');
+define('_SKINFILES_ERR_DELETE_DIR5',			'メッセージ: ディレクトリ ');
+define('_SKINFILES_ERR_DELETE_DIR6',			'を削除しました。');
+define('_SKINFILES_ERR_DELETE_DIR7',			'現在このディレクトリには削除できるファイルはありません。');
+
+define('_SKINFILES_ERR_EMPTY_DIR1',				'メッセージ: ファイル ');
+define('_SKINFILES_ERR_EMPTY_DIR2',				'を削除しました。');
+define('_SKINFILES_ERR_EMPTY_DIR3',				'エラー: ファイル ');
+define('_SKINFILES_ERR_EMPTY_DIR4',				'は削除できませんでした。');
+define('_SKINFILES_ERR_EMPTY_DIR5',				'エラー: ディレクトリ ');
+define('_SKINFILES_ERR_EMPTY_DIR6',				'は存在しないか');
+define('_SKINFILES_ERR_EMPTY_DIR7',				'そのディレクトリにアクセスする権限がありません。');
+
+define('_SKINFILES_ERR_DOWNLOAD_FILE1',			'エラー: ファイルにアクセスできませんでした。');
+define('_SKINFILES_ERR_DOWNLOAD_FILE2',			'エラー: そのファイルにアクセスする権限がありませんでした。');
+
+define('_SKINFILES_ERR_VIEW_FILE1',				'エラー: ファイル ');
+define('_SKINFILES_ERR_VIEW_FILE2',				'は存在しないか');
+define('_SKINFILES_ERR_VIEW_FILE3',				'そのファイルを参照する権限がありません。');
+
+define('_SKINFILES_ERR_EDIT_FILE1',				'エラー: ファイル ');
+define('_SKINFILES_ERR_EDIT_FILE2',				'は存在しないか');
+define('_SKINFILES_ERR_EDIT_FILE3',				'そのファイルを編集する権限がありません。');
+define('_SKINFILES_ERR_EDIT_FILE4',				'メッセージ: ファイル ');
+define('_SKINFILES_ERR_EDIT_FILE5',				'を保存しました。');
+define('_SKINFILES_ERR_EDIT_FILE6',				'エラー: ファイル ');
+define('_SKINFILES_ERR_EDIT_FILE7',				'は保存できませんでした。');
+
+define('_SKINFILES_ERR_RENAME_FILE1',			'エラー: ファイル ');
+define('_SKINFILES_ERR_RENAME_FILE2',			'は存在しないか');
+define('_SKINFILES_ERR_RENAME_FILE3',			'そのファイル名を変更する権限がありません。');
+define('_SKINFILES_ERR_RENAME_FILE4',			'エラー: 新しい名前が設定されませんでしたので、');
+define('_SKINFILES_ERR_RENAME_FILE5',			'の名前は変更できませんでした。 ');
+define('_SKINFILES_ERR_RENAME_FILE6',			'エラー: 設定した名前に１つ以上の無効な文字が含まれていましたので ');
+define('_SKINFILES_ERR_RENAME_FILE7',			'の名前は変更できませんでした。 ');
+define('_SKINFILES_ERR_RENAME_FILE8',			'エラー: 設定した名前は元の名前と同じでしたので ');
+define('_SKINFILES_ERR_RENAME_FILE9',			'の名前は変更できませんでした。別の名前を使用して下さい。 ');
+define('_SKINFILES_ERR_RENAME_FILE10',			'エラー: 設定した名前は既に他のファイルまたはディレクトリに使用されていましたので ');
+define('_SKINFILES_ERR_RENAME_FILE11',			'の名前は変更できませんでした。');
+define('_SKINFILES_ERR_RENAME_FILE12',			'別の名前を使用するか、まず既存のファイルまたはディレクトリを削除して下さい。');
+define('_SKINFILES_ERR_RENAME_FILE13',			'エラー: ファイル ');
+define('_SKINFILES_ERR_RENAME_FILE14',			'の名前は変更できませんでした。');
+define('_SKINFILES_ERR_RENAME_FILE15',			'メッセージ: ファイル ');
+define('_SKINFILES_ERR_RENAME_FILE16',			'を ');
+define('_SKINFILES_ERR_RENAME_FILE17',			' ');
+define('_SKINFILES_ERR_RENAME_FILE18',			' へ名前を変更しました。');
+
+define('_SKINFILES_ERR_CREATE_FILE1',			'エラー: ファイル名が設定されませんでしたので、新しいファイルが作成できませんでした。');
+define('_SKINFILES_ERR_CREATE_FILE2',			'エラー: 設定した名前に１つ以上の無効な文字が含まれていましたので、');
+define('_SKINFILES_ERR_CREATE_FILE3',			'は新規に作成できませんでした。');
+define('_SKINFILES_ERR_CREATE_FILE4',			'エラー: 設定した名前はすでに他のファイルまたはディレクトリで使用されていましたので、');
+define('_SKINFILES_ERR_CREATE_FILE5',			'は新規に作成できませんでした。');
+define('_SKINFILES_ERR_CREATE_FILE6',			'別の名前を使用するか、既存のファイルまたはディレクトリをまず削除して下さい。');
+define('_SKINFILES_ERR_CREATE_FILE7',			'エラー: ファイル ');
+define('_SKINFILES_ERR_CREATE_FILE8',			'は新規に作成できませんでした。');
+define('_SKINFILES_ERR_CREATE_FILE9',			'メッセージ: ファイル ');
+define('_SKINFILES_ERR_CREATE_FILE10',			' を新規に作成しました。');
+define('_SKINFILES_ERR_CREATE_FILE11',			'エラー: ディレクトリ ');
+define('_SKINFILES_ERR_CREATE_FILE12',			' は存在しないか');
+define('_SKINFILES_ERR_CREATE_FILE13',			'そのディレクトリにアクセスする権限がありません。');
+
+define('_SKINFILES_ERR_DELETE_FILE1',			'エラー: ファイル ');
+define('_SKINFILES_ERR_DELETE_FILE2',			'は存在しないか');
+define('_SKINFILES_ERR_DELETE_FILE3',			'そのファイルを削除する権限がありません。');
+define('_SKINFILES_ERR_DELETE_FILE4',			'エラー: ファイルを削除できませんでした。 ');
+define('_SKINFILES_ERR_DELETE_FILE5',			'メッセージ: ファイル ');
+define('_SKINFILES_ERR_DELETE_FILE6',			'を削除しました。');
+
+define('_SKINFILES_ERR_UPLOAD_FILE1',			'エラー: ファイル ');
+define('_SKINFILES_ERR_UPLOAD_FILE2',			'のアップロードができませんでした。');
+define('_SKINFILES_ERR_UPLOAD_FILE3',			'最大 / 現在のサイズ: ');
+define('_SKINFILES_ERR_UPLOAD_FILE4',			'。');
+define('_SKINFILES_ERR_UPLOAD_FILE5',			'エラー: 設定した名前に１つ以上の無効な文字が含まれていましたので、ファイル ');
+define('_SKINFILES_ERR_UPLOAD_FILE6',			'のアップロードができませんでした。');
+define('_SKINFILES_ERR_UPLOAD_FILE7',			'メッセージ: ファイル ');
+define('_SKINFILES_ERR_UPLOAD_FILE8',			'をアップロードしました。');
+define('_SKINFILES_ERR_UPLOAD_FILE9',			'エラー: ディレクトリ ');
+define('_SKINFILES_ERR_UPLOAD_FILE10',			'は存在しないか');
+define('_SKINFILES_ERR_UPLOAD_FILE11',			'そのディレクトリにアクセスする権限がありません。');
+
+?>
diff -ruN 3.24.src/nucleus/styles/addedit.css 3.31.src/nucleus/styles/addedit.css
--- 3.24.src/nucleus/styles/addedit.css	2004-08-05 09:50:50.000000000 -0500
+++ 3.31.src/nucleus/styles/addedit.css	2007-10-22 19:35:56.000000000 -0500
@@ -2,7 +2,7 @@
 	This stylesheet serves to make item previews look nicer, and to markup the 
 	buttonbar
 	
-	$Id: addedit.css,v 1.2 2004/08/05 07:50:50 dekarma Exp $
+	$Id: addedit.css 757 2005-08-12 07:29:40Z dekarma $
 */
 
 .leftbox, .rightbox {
diff -ruN 3.24.src/nucleus/styles/admin.css 3.31.src/nucleus/styles/admin.css
--- 3.24.src/nucleus/styles/admin.css	2004-10-10 13:37:06.000000000 -0500
+++ 3.31.src/nucleus/styles/admin.css	2007-10-22 19:35:56.000000000 -0500
@@ -1,7 +1,7 @@
 /*
 	admin area style
 	
-	$Id: admin.css,v 1.15 2004/10/10 11:37:05 dekarma Exp $
+	$Id: admin.css 845 2005-12-26 17:23:01Z dekarma $
 */
 
 body {
@@ -173,7 +173,6 @@
 
 	color: gray;
 	padding-left: 20px;
-	letter-spacing: 2;
 }
 
 #content .note, pre {
diff -ruN 3.24.src/nucleus/styles/bookmarklet.css 3.31.src/nucleus/styles/bookmarklet.css
--- 3.24.src/nucleus/styles/bookmarklet.css	2004-08-05 09:50:50.000000000 -0500
+++ 3.31.src/nucleus/styles/bookmarklet.css	2007-10-22 19:35:56.000000000 -0500
@@ -1,7 +1,7 @@
 /* 
 	style definitions for the bookmarklet 
 	
-	$Id: bookmarklet.css,v 1.3 2004/08/05 07:50:50 dekarma Exp $
+	$Id: bookmarklet.css 757 2005-08-12 07:29:40Z dekarma $
 */
 
 body {
diff -ruN 3.24.src/nucleus/styles/manual.css 3.31.src/nucleus/styles/manual.css
--- 3.24.src/nucleus/styles/manual.css	2004-08-05 09:50:50.000000000 -0500
+++ 3.31.src/nucleus/styles/manual.css	2007-10-22 19:35:56.000000000 -0500
@@ -1,7 +1,7 @@
 /*
 	documentation style
 	
-	$Id: manual.css,v 1.3 2004/08/05 07:50:50 dekarma Exp $
+	$Id: manual.css 757 2005-08-12 07:29:40Z dekarma $
 */
 
 body {
diff -ruN 3.24.src/nucleus/styles/popups.css 3.31.src/nucleus/styles/popups.css
--- 3.24.src/nucleus/styles/popups.css	2004-08-05 09:50:50.000000000 -0500
+++ 3.31.src/nucleus/styles/popups.css	2007-10-22 19:35:56.000000000 -0500
@@ -1,7 +1,7 @@
 /*
 	media library popup
 	
-	$Id: popups.css,v 1.2 2004/08/05 07:50:50 dekarma Exp $
+	$Id: popups.css 757 2005-08-12 07:29:40Z dekarma $
 */
 
 body {
diff -ruN 3.24.src/nucleus/xmlrpc/api_blogger.inc.php 3.31.src/nucleus/xmlrpc/api_blogger.inc.php
--- 3.24.src/nucleus/xmlrpc/api_blogger.inc.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/xmlrpc/api_blogger.inc.php	2007-10-22 19:36:02.000000000 -0500
@@ -1,21 +1,21 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
-  */
-  
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
+
 /**
  * This file contains definitions for the methods in the Blogger API
  *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: api_blogger.inc.php,v 1.8.2.1 2005/08/15 10:51:08 dekarma Exp $
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: api_blogger.inc.php 1119 2007-02-04 06:24:28Z kimitake $
  */
 
 
@@ -40,10 +40,10 @@
 		$password = _getScalar($m,3);
 		$content = _getScalar($m,4);
 		$publish = _getScalar($m,5);
-		
+
 		$title = blogger_extractTitle($content);
 		$category = blogger_extractCategory($content);
-		$content = blogger_removeSpecialTags($content);	
+		$content = blogger_removeSpecialTags($content);
 
 		return _addItem($blogid, $username, $password, $title, $content, '', $publish, 0, $category);
 	}
@@ -65,7 +65,7 @@
 	$f_blogger_editPost_doc = "Edits an item of a blog";
 	function f_blogger_editPost($m) {
 		global $manager;
-		
+
 		$itemid = intval(_getScalar($m,1));
 		$username = _getScalar($m,2);
 		$password = _getScalar($m,3);
@@ -74,9 +74,9 @@
 
 		$title = blogger_extractTitle($content);
 		$category = blogger_extractCategory($content);
-		$content = blogger_removeSpecialTags($content);	
+		$content = blogger_removeSpecialTags($content);
 
-		// get old title and extended part 
+		// get old title and extended part
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
 		$old =& $manager->getItem($itemid,1,1);
@@ -85,7 +85,7 @@
 
 		$blog = new BLOG($blogid);
 		$catid = $blog->getCategoryIdFromName($category);
-		
+
 		if ($old['draft'] && $publish) {
 			$wasdraft = 1;
 			$publish = 1;
@@ -264,19 +264,19 @@
 
 
 	/**
-	  * Returns a list of recent items 
+	  * Returns a list of recent items
 	  */
 	function _getRecentItemsBlogger($blogid, $username, $password, $amount) {
-		
+
 		$blogid = intval($blogid);
 		$amount = intval($amount);
-			
+
 		// 1. login
 		$mem = new MEMBER();
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// 2. check if allowed 
+		// 2. check if allowed
 		if (!BLOG::existsID($blogid))
 			return _error(2,"No such blog ($blogid)");
 		if (!$mem->teamRights($blogid))
@@ -287,7 +287,7 @@
 
 		// 3. create and return list of recent items
 		// Struct returned has dateCreated, userid, blogid and content
-		
+
 		$blog = new BLOG($blogid);
 
 		$structarray = array();		// the array in which the structs will be stored
@@ -298,15 +298,15 @@
 			   ." ORDER BY itime DESC"
 			   ." LIMIT $amount";
 		$r = sql_query($query);
-		
+
 		while ($row = mysql_fetch_assoc($r)) {
-		
+
 			// remove linebreaks if needed
 			if ($blog->convertBreaks())
 				$row['ibody'] = removeBreaks($row['ibody']);
 
 			$content = blogger_specialTags($row) . $row['ibody'];
-		
+
 			$newstruct = new xmlrpcval(array(
 				"userid" => new xmlrpcval($row['iauthor'],"string"),
 				"dateCreated" => new xmlrpcval(iso8601_encode(strtotime($row['itime'])),"dateTime.iso8601"),
@@ -316,25 +316,25 @@
 				"authorName" => new xmlrpcval($row['mname'],'string'),
 				"title" => new xmlrpcval($row['title'],'string'),
 			),'struct');
-			array_push($structarray, $newstruct);		
+			array_push($structarray, $newstruct);
 		}
 
 		return new xmlrpcresp(new xmlrpcval( $structarray , "array"));
 
 	}
-	
+
 	/**
 	  * Returns one item (Blogger version)
 	  */
 	function _getItemBlogger($itemid, $username, $password) {
 		global $manager;
-	
+
 		// 1. login
 		$mem = new MEMBER();
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// 2. check if allowed 
+		// 2. check if allowed
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
 		$blogid = getBlogIDFromItemID($itemid);
@@ -346,10 +346,10 @@
 
 		$item =& $manager->getItem($itemid,1,1); // (also allow drafts and future items)
 		$blog = new BLOG($blogid);
-		
+
 		// get category
 		$item['category'] = $blog->getCategoryName($item['catid']);
-		
+
 		// remove linebreaks if needed
 		if ($blog->convertBreaks())
 			$item['body'] = removeBreaks($item['body']);
@@ -375,10 +375,10 @@
 
 	function blogger_extractCategory($body) {
 		return blogger_matchTag('category',$body);
-	}	
-	
+	}
+
 	function blogger_matchTag($tag, $body) {
-		if (preg_match("/<" . $tag .">(.+?)<\/".$tag.">/is",$body,$match)) 
+		if (preg_match("/<" . $tag .">(.+?)<\/".$tag.">/is",$body,$match))
 			return $match[1];
 		else
 			return "";
@@ -389,13 +389,13 @@
 		$body = preg_replace("/<category>(.+?)<\/category>/","",$body);
 		return trim($body);
 	}
-	
+
 	function blogger_specialTags($item) {
 		$result = "<title>". $item['title']."</title>";
 		$result .= "<category>".$item['category']."</category>";
 		return $result;
 	}
-	
+
 
 
 	$functionDefs = array_merge($functionDefs,
@@ -444,9 +444,9 @@
 			 array( "function" => "f_blogger_setTemplate",
 				"signature" => $f_blogger_setTemplate_sig,
 				"docstring" => $f_blogger_setTemplate_doc)
-		
+
 		)
 	);
 
 
-?>
\ No newline at end of file
+?>
diff -ruN 3.24.src/nucleus/xmlrpc/api_metaweblog.inc.php 3.31.src/nucleus/xmlrpc/api_metaweblog.inc.php
--- 3.24.src/nucleus/xmlrpc/api_metaweblog.inc.php	2005-08-21 11:46:00.000000000 -0500
+++ 3.31.src/nucleus/xmlrpc/api_metaweblog.inc.php	2007-10-22 19:36:02.000000000 -0500
@@ -1,25 +1,25 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
-  */
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
 
 /**
  *	This file contains definitions for the methods of the metaWeblog API
  *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: api_metaweblog.inc.php,v 1.15.2.2 2005/08/21 09:46:00 dekarma Exp $
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: api_metaweblog.inc.php 1116 2007-02-03 08:24:29Z kimitake $
  */
-	 
-	
+
+
 	// metaWeblog.newPost
 	$f_metaWeblog_newPost_sig = array(array(
 			// return type
@@ -42,15 +42,15 @@
 		$password = 		_getScalar($m,2);
 		$struct = 			$m->getParam(3);
 		
-			$content = 		_getStructVal($struct, 'description');
-			$more = 		_getStructVal($struct, 'mt_text_more');
-			$title = 		_getStructVal($struct, 'title');
-
-			// category is optional (thus: be careful)!
-			$catlist = $struct->structmem('categories');
-			if ($catlist && ($catlist->kindOf() == "array") && ($catlist->arraysize() > 0)) 
-				$category = _getArrayVal($catlist, 0);
-
+		$content = 		_getStructVal($struct, 'description');
+		$more = 		_getStructVal($struct, 'mt_text_more');
+		$title = 		_getStructVal($struct, 'title');
+
+		// category is optional (thus: be careful)!
+		$catlist = $struct->structmem('categories');
+		if ($catlist && ($catlist->kindOf() == "array") && ($catlist->arraysize() > 0))
+			$category = _getArrayVal($catlist, 0);
+		
 		
 		$comments = (int) _getStructVal($struct, 'mt_allow_comments') ? 0 : 1;
 		$publish = _getScalar($m,4);
@@ -73,49 +73,49 @@
 
 		return $res;
 	}
-	
-	
+
+
 	// metaWeblog.getCategories
 	$f_metaWeblog_getCategories_sig = array(array(
 		// return
 		$xmlrpcStruct,	// categories for blog
-		
+
 		// params
 		$xmlrpcString,	// blogid
 		$xmlrpcString,	// username
 		$xmlrpcString,	// password
-		
+
 	));
 	$f_metaWeblog_getCategories_doc = "Returns the categories for a given blog";
 	function f_metaWeblog_getCategories($m) {
 		$blogid =	_getScalar($m,0);
 		$username =	_getScalar($m,1);
 		$password =	_getScalar($m,2);
-	
+
 		return _categoryList($blogid, $username, $password);
 	}
-	
+
 
 	// metaWeblog.getPost
 	$f_metaWeblog_getPost_sig = array(array(
 		// return
-		$xmlrpcStruct,	// the juice 
-		
+		$xmlrpcStruct,	// the juice
+
 		// params
 		$xmlrpcString,	// itemid
 		$xmlrpcString,	// username
 		$xmlrpcString,	// password
-		
+
 	));
 	$f_metaWeblog_getPost_doc = "Retrieves a post";
 	function f_metaWeblog_getPost($m) {
 		$itemid =	_getScalar($m,0);
 		$username =	_getScalar($m,1);
 		$password =	_getScalar($m,2);
-	
+
 		return _mw_getPost($itemid, $username, $password);
 	}
-	
+
 
 	// metaWeblog.editPost
 	$f_metaWeblog_editPost_sig = array(array(
@@ -147,18 +147,18 @@
 			$catlist = $struct->structmem('categories');
 			if ($catlist && ($catlist->kindOf() == "array") && ($catlist->arraysize() > 0)) {
 				$category = _getArrayVal($catlist, 0);
-			} 
-			
+			}
+
 		$publish = _getScalar($m,4);
 
 		
-		// get old title and extended part 
+		// get old title and extended part
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
 		$blogid = getBlogIDFromItemID($itemid);
 
 		$old =& $manager->getItem($itemid,1,1);
-		
+
 		if ($category == '')
 		{
 			// leave category unchanged when not present
@@ -169,7 +169,7 @@
 			$blog = new BLOG($blogid);
 			$catid = $blog->getCategoryIdFromName($category);
 		}
-		
+
 		if ($old['draft'] && $publish) {
 			$wasdraft = 1;
 			$publish = 1;
@@ -207,12 +207,12 @@
 
 		return $res;
 	}
-	
+
 	// metaWeblog.newMediaObject
 	$f_metaWeblog_newMediaObject_sig = array(array(
 		//  return type
 		$xmlrpcStruct,		// "url" element
-		
+
 		// params
 		$xmlrpcString,		// blogid
 		$xmlrpcString,		// username
@@ -224,15 +224,15 @@
 		$blogid		= _getScalar($m, 0);
 		$username	= _getScalar($m, 1);
 		$password 	= _getScalar($m, 2);
-		
+
 		$struct		= $m->getParam(3);
 			$name	= _getStructVal($struct, 'name');
 			$type	= _getStructVal($struct, 'type');
 			$bits	= _getStructVal($struct, 'bits');
-			
+
 		return _newMediaObject($blogid, $username, $password, array('name' => $name, 'type' => $type, 'bits' => $bits));
 	}
-	
+
 	// metaWeblog.getRecentPosts
 	$f_metaWeblog_getRecentPosts_sig = array(array(
 		// return type
@@ -250,21 +250,21 @@
 		$username	= _getScalar($m, 1);
 		$password 	= _getScalar($m, 2);
 		$amount		= intval(_getScalar($m, 3));
-		
-		return _getRecentItemsMetaWeblog($blogid, $username, $password, $amount); 
+
+		return _getRecentItemsMetaWeblog($blogid, $username, $password, $amount);
 	}
-	
+
 	function _getRecentItemsMetaWeblog($blogid, $username, $password, $amount) {
-	
+
 		$blogid = intval($blogid);
 		$amount = intval($amount);
-	
+
 		// 1. login
 		$mem = new MEMBER();
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// 2. check if allowed 
+		// 2. check if allowed
 		if (!BLOG::existsID($blogid))
 			return _error(2,"No such blog ($blogid)");
 		if (!$mem->teamRights($blogid))
@@ -275,7 +275,7 @@
 
 		// 3. create and return list of recent items
 		// Struct returned has dateCreated, userid, blogid and content
-		
+
 		$blog = new BLOG($blogid);
 
 		$structarray = array();		// the array in which the structs will be stored
@@ -286,9 +286,9 @@
 			   ." ORDER BY itime DESC"
 			   ." LIMIT $amount";
 		$r = sql_query($query);
-		
+
 		while ($row = mysql_fetch_assoc($r)) {
-		
+
 			// remove linebreaks if needed
 			if ($blog->convertBreaks()) {
 				$row['ibody'] = removeBreaks($row['ibody']);
@@ -313,73 +313,73 @@
 				"mt_allow_comments" => new xmlrpcval($row['iclosed'] ? 0 : 1, "int"),
 				"mt_allow_pings" 	=> new xmlrpcval(1, "int")
 			),'struct');
-			
+
 		//TODO: String link?
 		//TODO: String permaLink?
-		
-		
-			array_push($structarray, $newstruct);		
+
+
+			array_push($structarray, $newstruct);
 		}
 
 		return new xmlrpcresp(new xmlrpcval( $structarray , "array"));
 	}
-	
+
 	function _newMediaObject($blogid, $username, $password, $info) {
 		global $CONF, $DIR_MEDIA, $DIR_LIBS;
-		
+
 		// - login
 		$mem = new MEMBER();
 		if (!$mem->login($username, $password))
 			return _error(1,'Could not log in');
-		
-		// - check if team member 
+
+		// - check if team member
 		if (!BLOG::existsID($blogid))
 			return _error(2,"No such blog ($blogid)");
 		if (!$mem->teamRights($blogid))
 			return _error(3,'Not a team member');
-			
+
 		$b = new BLOG($blogid);
-		
+
 		// - decode data
 		$data = $info['bits']; // decoding was done transparantly by xmlrpclib
-		
+
 		// - check filesize
 		if (strlen($data) > $CONF['MaxUploadSize'])
 			return _error(9, 'filesize is too big');
 
-		
+
 		// - check if filetype is allowed (check filename)
 		$filename = $info['name'];
 		$ok = 0;
 		$allowedtypes = explode (',', $CONF['AllowedTypes']);
-		foreach ( $allowedtypes as $type ) 
-			if (eregi("\." .$type. "$",$filename)) $ok = 1;    
-		if (!$ok) 
+		foreach ( $allowedtypes as $type )
+			if (eregi("\." .$type. "$",$filename)) $ok = 1;
+		if (!$ok)
 			_error(8, 'Filetype is not allowed');
-				
+
 		// - add file to media library
 		include_once($DIR_LIBS . 'MEDIA.php');	// media classes
-		
+
 		// always use private media library of member
 		$collection = $mem->getID();
 
 		// prefix filename with current date (YYYY-MM-DD-)
 		// this to avoid nameclashes
 		if ($CONF['MediaPrefix'])
-			$filename = strftime("%Y%m%d-", time()) . $filename;	
-			
+			$filename = strftime("%Y%m%d-", time()) . $filename;
+
 		$res = MEDIA::addMediaObjectRaw($collection, $filename, $data);
 		if ($res)
 			return _error(10, $res);
-		
+
 		// - return URL
 		$urlstruct = new xmlrpcval(array(
 			"url" => new xmlrpcval($CONF['MediaURL'] . $collection. '/' . $filename,'string')
-		),'struct');		
-		
+		),'struct');
+
 		return new xmlrpcresp($urlstruct);
 	}
-	
+
 	function _categoryList($blogid, $username, $password) {
 		// 1. login
 		$mem = new MEMBER();
@@ -391,9 +391,9 @@
 			return _error(2,"No such blog ($blogid)");
 		if (!$mem->teamRights($blogid))
 			return _error(3,"Not a team member");
-			
+
 		$b = new BLOG($blogid);
-		
+
 		$categorystruct = array();
 
 		$query =  "SELECT cname, cdesc, catid"
@@ -412,22 +412,22 @@
 				)
 			,'struct');
 		}
-		
-		
+
+
 		return new xmlrpcresp(new xmlrpcval( $categorystruct , "struct"));
-	
+
 	}
-	
-	
+
+
 	function _mw_getPost($itemid, $username, $password) {
 		global $manager;
-		
+
 		// 1. login
 		$mem = new MEMBER();
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// 2. check if allowed 
+		// 2. check if allowed
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
 		$blogid = getBlogIDFromItemID($itemid);
@@ -436,13 +436,13 @@
 
 		// 3. return the item
 		$item =& $manager->getItem($itemid,1,1); // (also allow drafts and future items)
-		
+
 		$b = new BLOG($blogid);
 		if ($b->convertBreaks()) {
 			$item['body'] = removeBreaks($item['body']);
 			$item['more'] = removeBreaks($item['more']);
 		}
-			
+
 		$categoryname = $b->getCategoryName($item['catid']);
 
 		$newstruct = new xmlrpcval(array(
@@ -462,14 +462,14 @@
 			"mt_allow_comments" => new xmlrpcval($item['closed'] ? 0 : 1, "int"),
 			"mt_allow_pings" 	=> new xmlrpcval(1, "int")
 		),'struct');
-		
+
 		//TODO: add "String link" to struct?
-		//TODO: add "String permaLink" to struct? 
+		//TODO: add "String permaLink" to struct?
 
 		return new xmlrpcresp($newstruct);
-	
+
 	}
-	
+
 	$functionDefs = array_merge($functionDefs,
 		array(
 			 "metaWeblog.newPost" =>
@@ -484,14 +484,14 @@
 				"function" => "f_metaWeblog_getCategories",
 				"signature" => $f_metaWeblog_getCategories_sig,
 				"docstring" => $f_metaWeblog_getCategories_doc
-			 ),	
+			 ),
 
 			 "metaWeblog.getPost" =>
 			 array(
 				"function" => "f_metaWeblog_getPost",
 				"signature" => $f_metaWeblog_getPost_sig,
 				"docstring" => $f_metaWeblog_getPost_doc
-			 ),	
+			 ),
 
 			 "metaWeblog.editPost" =>
 			 array(
@@ -499,21 +499,21 @@
 				"signature" => $f_metaWeblog_editPost_sig,
 				"docstring" => $f_metaWeblog_editPost_doc
 			 ),
-			 
+
 			 'metaWeblog.newMediaObject' =>
 			 array(
-			 	'function' => 'f_metaWeblog_newMediaObject',
-			 	'signature' => $f_metaWeblog_newMediaObject_sig,
-			 	'docstring' => $f_metaWeblog_newMediaObject_doc
+				'function' => 'f_metaWeblog_newMediaObject',
+				'signature' => $f_metaWeblog_newMediaObject_sig,
+				'docstring' => $f_metaWeblog_newMediaObject_doc
 			 ),
-			 
+
 			 'metaWeblog.getRecentPosts' =>
 			 array(
-			 	'function' => 'f_metaWeblog_getRecentPosts',
-			 	'signature' => $f_metaWeblog_getRecentPosts_sig,
-			 	'docstring' => $f_metaWeblog_getRecentPosts_doc
-			 )			 
-		
+				'function' => 'f_metaWeblog_getRecentPosts',
+				'signature' => $f_metaWeblog_getRecentPosts_sig,
+				'docstring' => $f_metaWeblog_getRecentPosts_doc
+			 )
+
 		)
 	);
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/xmlrpc/api_mt.inc.php 3.31.src/nucleus/xmlrpc/api_mt.inc.php
--- 3.24.src/nucleus/xmlrpc/api_mt.inc.php	2005-08-21 11:46:00.000000000 -0500
+++ 3.31.src/nucleus/xmlrpc/api_mt.inc.php	2007-10-22 19:36:02.000000000 -0500
@@ -1,26 +1,24 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
-  */
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
 /**
  * This file contains definitions for the methods in the Movable Type API
  *
  * Wouter Demuynck 2003-08-31
  *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: api_mt.inc.php,v 1.11.2.2 2005/08/21 09:46:00 dekarma Exp $
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
  */
 
-
 	// mt.supportedMethods
 	$f_mt_supportedMethods_sig = array(array(
 			// return type
@@ -28,7 +26,7 @@
 		));
 	$f_mt_supportedMethods_doc = 'returns an array of supported methods';
 	function f_mt_supportedMethods($m) {
-		$res = new xmlrpcresp(new xmlrpcval( 
+		$res = new xmlrpcresp(new xmlrpcval(
 			array(
 				new xmlrpcval('mt.supportedMethods', 'string'),
 				new xmlrpcval('mt.supportedTextFilters', 'string'),
@@ -42,7 +40,7 @@
 		);
 		return $res;
 	}
-	
+
 	// mt.supportedTextFilters
 	$f_mt_supportedTextFilters_sig = array(array(
 			// return type
@@ -50,24 +48,24 @@
 		));
 	$f_mt_supportedTextFilters_doc = 'returns the supported text filters';
 	function f_mt_supportedTextFilters($m) {
-		$res = new xmlrpcresp(new xmlrpcval( 
+		$res = new xmlrpcresp(new xmlrpcval(
 			array(
 				// no text filters in nucleus
 			), 'array')
 		);
 		return $res;
 	}
-	
+
 	// mt.getCategoryList
 	$f_mt_getCategoryList_sig = array(array(
 			// return type
 			$xmlrpcArray,		// array of structs
-			
+
 			// params
 			$xmlrpcString,		// blogid
 			$xmlrpcString,		// username
 			$xmlrpcString		// password
-			
+
 		));
 	$f_mt_getCategoryList_doc = 'Returns a list of all categories defined in the weblog';
 	function f_mt_getCategoryList($m) {
@@ -77,12 +75,12 @@
 
 		return _mt_categoryList($blogid, $username, $password);
 	}
-	
+
 	// mt.publishPost
 	$f_mt_publishPost_sig = array(array(
 			// return type
 			$xmlrpcBoolean,		// true
-			
+
 			// params
 			$xmlrpcString,		// itemid
 			$xmlrpcString,		// username
@@ -92,11 +90,11 @@
 	function f_mt_publishPost($m) {
 		$itemid		= intval(_getScalar($m, 0));
 		$username	= _getScalar($m, 1);
-		$password	= _getScalar($m, 2);		
-		
+		$password	= _getScalar($m, 2);
+
 		return _mt_publishPost($itemid, $username, $password);
 	}
-	
+
 	// mt.getPostCategories
 	$f_mt_getPostCategories_sig = array(array(
 		// return
@@ -111,7 +109,7 @@
 		$itemid		= intval(_getScalar($m, 0));
 		$username	= _getScalar($m, 1);
 		$password	= _getScalar($m, 2);
-		
+
 		return _mt_getPostCategories($itemid, $username, $password);
 	}
 
@@ -132,7 +130,7 @@
 		$password	= _getScalar($m, 2);
 
 		$categories = $m->getParam(3);
-		$iSize = $categories->arraysize();		
+		$iSize = $categories->arraysize();
 
 		$category = '';
 		for ($i=0;$i<$iSize;$i++) {
@@ -142,18 +140,18 @@
 				$bPrimary = $bPrimary->scalarval();
 			else if (!$category)
 				$bPrimary = 1;	// "Using isPrimary to set the primary category is optional--
-								// in the absence of this flag, the first struct in the array 
+								// in the absence of this flag, the first struct in the array
 								// will be assigned the primary category for the post." (MT doc)
 			if ($bPrimary) {
 				$category = $struct->structmem('categoryId');
 				$category = $category->scalarval();
 			}
-			
+
 		}
-		
+
 		return _mt_setPostCategories($itemid, $username, $password, $category);
 	}
-	
+
 	// mt.getRecentPostTitles
 	$f_mt_getRecentPostTitles_sig = array(array(
 		// return
@@ -167,10 +165,10 @@
 	$f_mt_getRecentPostTitles_doc = 'Returns a bandwidth-friendly list of the most recent posts in the system.';
 	function f_mt_getRecentPostTitles($m) {
 		$blogid		= intval(_getScalar($m, 0));
-		$username	= _getScalar($m, 1);		
+		$username	= _getScalar($m, 1);
 		$password	= _getScalar($m, 2);
 		$iAmount	= intval(_getScalar($m, 3));
-		
+
 		return _mt_getRecentPostTitles($blogid, $username, $password, $iAmount);
 	}
 
@@ -186,7 +184,7 @@
 		global $manager;
 		
 		$itemid = intval(_getScalar($m, 0));
-				
+
 		$trackbacks = array ();
 		$tbstruct   = array ();
 			
@@ -204,39 +202,39 @@
 				
 		return new xmlrpcresp(new xmlrpcval( $tbstruct , "array"));
 	}
-	
+
 	$functionDefs = array_merge($functionDefs,
 		array(
 			 "mt.supportedMethods" =>
 			 array( "function" => "f_mt_supportedMethods",
 				"signature" => $f_mt_supportedMethods_sig,
 				"docstring" => $f_mt_supportedMethods_doc),
-		
+
 			 "mt.supportedTextFilters" =>
 			 array( "function" => "f_mt_supportedTextFilters",
 				"signature" => $f_mt_supportedTextFilters_sig,
 				"docstring" => $f_mt_supportedTextFilters_doc),
-				
+
 			 "mt.getCategoryList" =>
 			 array( "function" => "f_mt_getCategoryList",
 				"signature" => $f_mt_getCategoryList_sig,
 				"docstring" => $f_mt_getCategoryList_doc),
-				
+
 			 "mt.publishPost" =>
 			 array( "function" => "f_mt_publishPost",
 				"signature" => $f_mt_publishPost_sig,
 				"docstring" => $f_mt_publishPost_doc),
-				
+
 			 "mt.getPostCategories" =>
 			 array( "function" => "f_mt_getPostCategories",
 				"signature" => $f_mt_getPostCategories_sig,
 				"docstring" => $f_mt_getPostCategories_doc),
-				
+
 			 "mt.setPostCategories" =>
 			 array( "function" => "f_mt_setPostCategories",
 				"signature" => $f_mt_setPostCategories_sig,
 				"docstring" => $f_mt_setPostCategories_doc),
-				
+
 			 "mt.getRecentPostTitles" =>
 			 array( "function" => "f_mt_getRecentPostTitles",
 				"signature" => $f_mt_getRecentPostTitles_sig,
@@ -258,19 +256,19 @@
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// check if item exists			
+		// check if item exists
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
-			
+
 		$blogid = getBlogIDFromItemID($itemid);
 		$blog = new BLOG($blogid);
 
 		if (!$mem->canAlterItem($itemid))
 			return _error(7,"Not allowed to alter item");
-		
-		$old =& $manager->getItem($itemid,1,1);		
 
-		$catid = $blog->getCategoryIdFromName($category);		
+		$old =& $manager->getItem($itemid,1,1);
+
+		$catid = $blog->getCategoryIdFromName($category);
 
 		$publish = 0;
 		if ($old['draft'] && $publish) {
@@ -279,11 +277,11 @@
 		} else {
 			$wasdraft = 0;
 		}
-		
+
 		return _edititem($itemid, $username, $password, $catid, $old['title'], $old['body'], $old['more'], $wasdraft, $publish, $old['closed']);
 	}
-	
-	
+
+
 	function _mt_getPostCategories($itemid, $username, $password) {
 		global $manager;
 
@@ -292,7 +290,7 @@
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// check if item exists			
+		// check if item exists
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
 
@@ -301,25 +299,25 @@
 
 		if (!$mem->canAlterItem($itemid))
 			return _error(7, 'You are not allowed to request this information');
-		
-		$info =& $manager->getItem($itemid,1,1);		
+
+		$info =& $manager->getItem($itemid,1,1);
 		$catName = $blog->getCategoryName($info['catid']);
-		
+
 		$struct = new xmlrpcval(
 			array(
 				'categoryId' => new xmlrpcval($catName, 'string'),
 				'categoryName' => new xmlrpcval($catName, 'string'),
 				'isPrimary'	=> new xmlrpcval(1, 'boolean')
 			), 'struct'
-		);		
-		
+		);
+
 		return new xmlrpcresp(new xmlrpcval(array($struct), 'array'));
 
 	}
-	
+
 	function _mt_publishPost($itemid, $username, $password) {
 		global $manager;
-		
+
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
 
@@ -330,8 +328,8 @@
 
 		return _edititem($itemid, $username, $password, $old['catid'], $old['title'], $old['body'], $old['more'], $old['draft'], 1, $old['closed']);
 	}
-	
-	
+
+
 	function _mt_categoryList($blogid, $username, $password) {
 		// 1. login
 		$mem = new MEMBER();
@@ -343,9 +341,9 @@
 			return _error(2,"No such blog ($blogid)");
 		if (!$mem->teamRights($blogid))
 			return _error(3,"Not a team member");
-			
+
 		$b = new BLOG($blogid);
-		
+
 		$categorystruct = array();
 
 		$query =  "SELECT cname, cdesc, catid"
@@ -362,25 +360,25 @@
 					"categoryId" => new xmlrpcval($obj->cname,"string")
 				)
 			,'struct');
-			
+
 		}
-		
-		
+
+
 		return new xmlrpcresp(new xmlrpcval( $categorystruct , "array"));
-	
+
 	}
-	
-	function _mt_getRecentPostTitles($blogid, $username, $password, $iAmount) 
+
+	function _mt_getRecentPostTitles($blogid, $username, $password, $iAmount)
 	{
 		$blogid = intval($blogid);
 		$iAmount = intval($iAmount);
-	
+
 		// 1. login
 		$mem = new MEMBER();
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// 2. check if allowed 
+		// 2. check if allowed
 		if (!BLOG::existsID($blogid))
 			return _error(2,"No such blog ($blogid)");
 		if (!$mem->teamRights($blogid))
@@ -391,7 +389,7 @@
 
 		// 3. create and return list of recent items
 		// Struct returned has dateCreated, userid, postid and title
-		
+
 		$blog = new BLOG($blogid);
 
 		$structarray = array();		// the array in which the structs will be stored
@@ -402,23 +400,23 @@
 			   ." ORDER BY itime DESC"
 			   ." LIMIT $iAmount";
 		$r = sql_query($query);
-		
+
 		while ($row = mysql_fetch_assoc($r)) {
-		
+
 			$newstruct = new xmlrpcval(array(
 				"dateCreated" => new xmlrpcval(iso8601_encode(strtotime($row['itime'])),"dateTime.iso8601"),
 				"postid" => new xmlrpcval($row['inumber'],"string"),
 				"title" => new xmlrpcval($row['title'],"string"),
 				"userid" => new xmlrpcval($row['iauthor'],"string")
 			),'struct');
-		
-			array_push($structarray, $newstruct);		
+
+			array_push($structarray, $newstruct);
 		}
 
 		return new xmlrpcresp(new xmlrpcval( $structarray , "array"));
-	
+
 	}
-	
+
 
 
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/xmlrpc/api_nucleus.inc.php 3.31.src/nucleus/xmlrpc/api_nucleus.inc.php
--- 3.24.src/nucleus/xmlrpc/api_nucleus.inc.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/nucleus/xmlrpc/api_nucleus.inc.php	2007-10-22 19:36:02.000000000 -0500
@@ -1,14 +1,14 @@
 <?php
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
-  */
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
+ */
 
 /**
  * This file contains definitions for the functions in the Nucleus API
@@ -16,8 +16,8 @@
  * NOTE: These functions are deprecated and will most likely be removed!
  *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: api_nucleus.inc.php,v 1.8.2.1 2005/08/15 10:51:08 dekarma Exp $
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: api_nucleus.inc.php 1116 2007-02-03 08:24:29Z kimitake $
  */
 
 	// nucleus.addItem
@@ -101,7 +101,7 @@
 	$f_nucleus_editItem_doc = "Edits an item of a blog";
 	function f_nucleus_editItem($m) {
 		global $manager;
-	
+
 		$itemid = intval(_getScalar($m,0));
 		$username = _getScalar($m,1);
 		$password = _getScalar($m,2);
@@ -111,7 +111,7 @@
 		$publish = _getScalar($m,6);
 		$closed = _getScalar($m,7);
 
-		// get old title and extended part 
+		// get old title and extended part
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
 
@@ -206,13 +206,13 @@
 	function _getRecentItems($blogid, $username, $password, $amount) {
 		$blogid = intval($blogid);
 		$amount = intval($amount);
-	
+
 		// 1. login
 		$mem = new MEMBER();
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// 2. check if allowed 
+		// 2. check if allowed
 		if (!BLOG::existsID($blogid))
 			return _error(2,"No such blog ($blogid)");
 		if (!$mem->teamRights($blogid))
@@ -243,31 +243,31 @@
 				"draft" => new xmlrpcval($obj->idraft,"boolean"),
 				"closed" => new xmlrpcval($obj->iclosed,"boolean"),
 			),'struct');
-			array_push($structarray, $newstruct);		
+			array_push($structarray, $newstruct);
 		}
 
 		return new xmlrpcresp(new xmlrpcval( $structarray , "array"));
 
 	}
-	
-	
+
+
 
 	/**
 	  * Returns one item (Nucleus version)
 	  */
 	function _getItem($itemid, $username, $password) {
 		global $manager;
-	
+
 		// 1. login
 		$mem = new MEMBER();
 		if (!$mem->login($username, $password))
 			return _error(1,"Could not log in");
 
-		// 2. check if allowed 
+		// 2. check if allowed
 		if (!$manager->existsItem($itemid,1,1))
 			return _error(6,"No such item ($itemid)");
 		$blogid = getBlogIDFromItemID($itemid);
-		
+
 		if (!$mem->teamRights($blogid))
 			return _error(3,"Not a team member");
 
@@ -275,7 +275,7 @@
 		// Structure returned has dateCreated, userid, blogid and content
 
 		$item =& $manager->getItem($itemid,1,1); // (also allow drafts and future items)
-		
+
 		$blog = new BLOG($blogid);
 		if ($blog->convertBreaks())
 			$item['body'] = removeBreaks($item['body']);
@@ -294,7 +294,7 @@
 		return new xmlrpcresp($newstruct);
 
 
-	}	
+	}
 
 
 	$functionDefs = array_merge($functionDefs,
@@ -322,19 +322,19 @@
 			"nucleus.getUsersBlogs" =>
 			array( "function" => "f_nucleus_getUsersBlogs",
 				"signature" => $f_nucleus_getUsersBlogs_sig,
-				"docstring" => $f_nucleus_getUsersBlogs_doc),		
+				"docstring" => $f_nucleus_getUsersBlogs_doc),
 
 			"nucleus.getRecentItems" =>
 			array( "function" => "f_nucleus_getRecentItems",
 				"signature" => $f_nucleus_getRecentItems_sig,
-				"docstring" => $f_nucleus_getRecentItems_doc),		
+				"docstring" => $f_nucleus_getRecentItems_doc),
 
 			"nucleus.getItem" =>
 			array( "function" => "f_nucleus_getItem",
 				"signature" => $f_nucleus_getItem_sig,
 				"docstring" => $f_nucleus_getItem_doc)
-		)		
-		
+		)
+
 	);
 
 ?>
\ No newline at end of file
diff -ruN 3.24.src/nucleus/xmlrpc/server.php 3.31.src/nucleus/xmlrpc/server.php
--- 3.24.src/nucleus/xmlrpc/server.php	2005-08-21 09:43:02.000000000 -0500
+++ 3.31.src/nucleus/xmlrpc/server.php	2007-10-22 19:36:02.000000000 -0500
@@ -1,7 +1,7 @@
 <?php
 /*
  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
- * Copyright (C) 2002-2005 The Nucleus Group
+ * Copyright (C) 2002-2007 The Nucleus Group
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -61,11 +61,11 @@
  * mt.supportedMethods
  *
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: server.php,v 1.8.2.2 2005/08/21 07:43:01 dekarma Exp $
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: server.php 1201 2007-09-07 07:12:21Z kimitake $
  */
 $CONF = array();
-include("../../config.php");	// include Nucleus libs and code
+require("../../config.php");	// include Nucleus libs and code
 include($DIR_LIBS . "xmlrpc.inc.php");
 include($DIR_LIBS . "xmlrpcs.inc.php");
 
diff -ruN 3.24.src/rsd.php 3.31.src/rsd.php
--- 3.24.src/rsd.php	2005-02-21 19:04:54.000000000 -0600
+++ 3.31.src/rsd.php	2008-01-17 10:01:12.000000000 -0600
@@ -5,4 +5,4 @@
 selectSkin('xml/rsd');
 selector();
 
-?>
+?>
\ No newline at end of file
diff -ruN 3.24.src/skins/atom/skinbackup.xml 3.31.src/skins/atom/skinbackup.xml
--- 3.24.src/skins/atom/skinbackup.xml	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/skins/atom/skinbackup.xml	2007-10-22 19:35:52.000000000 -0500
@@ -1,11 +1,31 @@
-<nucleusskin><meta><skin name="feeds/atom" /><template name="feeds/atom/modified" /><template name="feeds/atom/entries" /><info><![CDATA[Atom 0.3 weblog syndication]]></info></meta><skin name="feeds/atom" type="application/atom+xml" includeMode="normal" includePrefix=""><description>Atom 0.3 weblog syndication</description><part name="index"><![CDATA[<?xml version="1.0" encoding="<%charset%>"?>
+<nucleusskin>
+	<meta>
+		<skin name="feeds/atom" />
+		<template name="feeds/atom/modified" />
+		<template name="feeds/atom/entries" />
+		<info><![CDATA[Atom 0.3 weblog syndication]]></info>
+	</meta>
+	
+	<skin name="feeds/atom" type="application/atom+xml" includeMode="normal" includePrefix="">
+		<description>Atom 0.3 weblog syndication</description>
+		<part name="index"><![CDATA[<?xml version="1.0" encoding="<%charset%>"?>
 <feed version="0.3" xmlns="http://purl.org/atom/ns#">
     <title><%blogsetting(name)%></title>
     <link rel="alternate" type="text/html" href="<%blogsetting(url)%>" />
     <generator url="http://nucleuscms.org/"><%version%></generator>
     <modified><%blog(feeds/atom/modified,1)%></modified>
     <%blog(feeds/atom/entries,10)%>
-</feed>]]></part></skin><template name="feeds/atom/modified"><description>Atom feeds: Inserts last modification date</description><part name="ITEM"><![CDATA[<%date(utc)%>]]></part></template><template name="feeds/atom/entries"><description>Atom feeds: Feed items</description><part name="ITEM"><![CDATA[<entry>
+</feed>]]></part>
+	</skin>
+
+	<template name="feeds/atom/modified">
+		<description>Atom feeds: Inserts last modification date</description>
+		<part name="ITEM"><![CDATA[<%date(utc)%>]]></part>
+	</template>
+
+	<template name="feeds/atom/entries">
+		<description>Atom feeds: Feed items</description>
+		<part name="ITEM"><![CDATA[<entry>
  <title type="text/html" mode="escaped"><![CDATA[<%title%>]]></title>
  <link rel="alternate" type="text/html" href="<%blogurl%>index.php?itemid=<%itemid%>" />
  <author>
@@ -16,9 +36,8 @@
  <content type="text/html" mode="escaped"><![CDATA[<%body%><%more%>]]></content>
  <id><%blogurl%>:<%blogid%>:<%itemid%></id>
 </entry>]]></part>
-
-<part name="IMAGE_CODE"><![CDATA[<%image%>]]></part>
-<part name="MEDIA_CODE"><![CDATA[<%media%>]]></part>
-<part name="POPUP_CODE"><![CDATA[<%media%>]]></part>
-
-</template></nucleusskin>
\ No newline at end of file
+		<part name="IMAGE_CODE"><![CDATA[<%image%>]]></part>
+		<part name="MEDIA_CODE"><![CDATA[<%media%>]]></part>
+		<part name="POPUP_CODE"><![CDATA[<%media%>]]></part>
+	</template>
+</nucleusskin>
\ No newline at end of file
diff -ruN 3.24.src/skins/default/default_left.css 3.31.src/skins/default/default_left.css
--- 3.24.src/skins/default/default_left.css	2005-03-05 10:35:52.000000000 -0600
+++ 3.31.src/skins/default/default_left.css	2007-10-22 19:35:52.000000000 -0500
@@ -28,7 +28,7 @@
 /* Headings */
 h1,h2,h3,h4,h5,h6
 {
-    font-family: "Georgia", "Lucida Grande", "Lucida Sans Unicode", "Trebuchet MS", Trebuchet, Arial, sans-serif;
+	font-family: "Georgia", "Lucida Grande", "Lucida Sans Unicode", "Trebuchet MS", Trebuchet, Arial, sans-serif;
 	font-weight: normal;
 	margin: 0;
 }
@@ -294,7 +294,7 @@
 	color: #3A3523;
 	font-size: 12px;
 	font-weight: bold;
-    font-family: "Georgia", "Lucida Grande", "Lucida Sans Unicode", Arial, "Trebuchet MS", sans-serif;
+	font-family: "Georgia", "Lucida Grande", "Lucida Sans Unicode", Arial, "Trebuchet MS", sans-serif;
 	padding: 4px 10px;
 }
 .sidebardl dd
@@ -345,16 +345,16 @@
 .commentform, .mailform
 {
 	margin-top: 10px;
-    padding: 10px;
-    background: #EEEEEE;
-    /* Rounded borders, for Mozilla browsers */
-    /* -moz-border-radius: 10px; */
+	padding: 10px;
+	background: #EEEEEE;
+	/* Rounded borders, for Mozilla browsers */
+	/* -moz-border-radius: 10px; */
 }
 .commentform img{
-    margin: 5px 0 0 0;
+	margin: 5px 0 0 0;
 }
-.formfield
-{
+.formfield {
+	display:block;
 	font-size: 11px;
 	background: white;
 	color: #494949;
@@ -375,60 +375,63 @@
 	border-right: 1px solid #868686;
 	margin: 1px 0 0 0;
 }
+.commentform .formfield, .commentform .formbutton, .loginform .formbutton {
+	display: block;
+}
 .searchform .formfield
 {
 	width: 130px;
-    font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
+	font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 0;
 	margin: 0 2px 2px 0;
 }
 .searchform .formbutton
 {
 	width: 60px;
-    font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
+	font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 2px;
 }
 .loginform .formfield
 {
 	width: 130px;
-    font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
+	font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 0;
 	margin: 0 2px 2px 0;
 }
 .loginform .formbutton
 {
 	width: 60px;
-    font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
+	font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 2px;
 }
 .mainform .formfield
 {
 	width: 280px;
-    font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
+	font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 0;
 	margin: 0 2px 2px 0;
 }
 .mailform .formbutton
 {
 	width: 100px;
-    font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
+	font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 2px;
 }
-#nucleus_cf_name, #nucleus_cf_mail
+#nucleus_cf_name, #nucleus_cf_mail, #nucleus_cf_email
 {
-    width: 300px;
-    margin-right: 105px;
-    font-family: Arial, Trebuchet MS, Verdana, sans-serif;
+	width: 300px;
+	margin-right: 105px;
+	font-family: Arial, Trebuchet MS, Verdana, sans-serif;
 }
 .commentform textarea, .commentform .formfield, .mailform textarea, .mailform .formfield
 {
-    width: 300px;
+	width: 300px;
 }
 .commentform .formbutton
 {
 	width: 100px;
 	height: 22px;
-    font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
+	font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
 }
 .error
 {
@@ -436,7 +439,6 @@
 	font-weight: bold;
 }
 
-
 /*-------------------------------------------------
   Miscelaneous
 -------------------------------------------------*/
diff -ruN 3.24.src/skins/default/default_right.css 3.31.src/skins/default/default_right.css
--- 3.24.src/skins/default/default_right.css	2005-03-05 10:35:52.000000000 -0600
+++ 3.31.src/skins/default/default_right.css	2007-10-22 19:35:52.000000000 -0500
@@ -28,7 +28,7 @@
 /* Headings */
 h1,h2,h3,h4,h5,h6
 {
-    font-family: "Georgia", "Lucida Grande", "Lucida Sans Unicode", "Trebuchet MS", Trebuchet, Arial, sans-serif;
+	font-family: "Georgia", "Lucida Grande", "Lucida Sans Unicode", "Trebuchet MS", Trebuchet, Arial, sans-serif;
 	font-weight: normal;
 	margin: 0;
 }
@@ -294,7 +294,7 @@
 	color: #3A3523;
 	font-size: 12px;
 	font-weight: bold;
-    font-family: "Georgia", "Lucida Grande", "Lucida Sans Unicode", Arial, "Trebuchet MS", sans-serif;
+	font-family: "Georgia", "Lucida Grande", "Lucida Sans Unicode", Arial, "Trebuchet MS", sans-serif;
 	padding: 4px 10px;
 }
 .sidebardl dd
@@ -345,16 +345,16 @@
 .commentform, .mailform
 {
 	margin-top: 10px;
-    padding: 10px;
-    background: #EEEEEE;
-    /* Rounded borders, for Mozilla browsers */
-    /* -moz-border-radius: 10px; */
+	padding: 10px;
+	background: #EEEEEE;
+	/* Rounded borders, for Mozilla browsers */
+	/* -moz-border-radius: 10px; */
 }
 .commentform img{
-    margin: 5px 0 0 0;
+	margin: 5px 0 0 0;
 }
-.formfield
-{
+.formfield {
+	display:block;
 	font-size: 11px;
 	background: white;
 	color: #494949;
@@ -375,60 +375,63 @@
 	border-right: 1px solid #868686;
 	margin: 1px 0 0 0;
 }
+.commentform .formfield, .commentform .formbutton, .loginform .formbutton {
+	display: block;
+}
 .searchform .formfield
 {
 	width: 130px;
-    font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
+	font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 0;
 	margin: 0 2px 2px 0;
 }
 .searchform .formbutton
 {
 	width: 60px;
-    font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
+	font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 2px;
 }
 .loginform .formfield
 {
 	width: 130px;
-    font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
+	font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 0;
 	margin: 0 2px 2px 0;
 }
 .loginform .formbutton
 {
 	width: 60px;
-    font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
+	font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 2px;
 }
 .mainform .formfield
 {
 	width: 280px;
-    font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
+	font-family: Arial, Tahoma, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 0;
 	margin: 0 2px 2px 0;
 }
 .mailform .formbutton
 {
 	width: 100px;
-    font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
+	font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
 	padding: 2px 2px;
 }
-#nucleus_cf_name, #nucleus_cf_mail
+#nucleus_cf_name, #nucleus_cf_mail, #nucleus_cf_email
 {
-    width: 300px;
-    margin-right: 105px;
-    font-family: Arial, Trebuchet MS, Verdana, sans-serif;
+	width: 300px;
+	margin-right: 105px;
+	font-family: Arial, Trebuchet MS, Verdana, sans-serif;
 }
 .commentform textarea, .commentform .formfield, .mailform textarea, .mailform .formfield
 {
-    width: 300px;
+	width: 300px;
 }
 .commentform .formbutton
 {
 	width: 100px;
 	height: 22px;
-    font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
+	font-family: Tahoma, Arial, Trebuchet MS, Verdana, sans-serif;
 }
 .error
 {
@@ -436,7 +439,6 @@
 	font-weight: bold;
 }
 
-
 /*-------------------------------------------------
   Miscelaneous
 -------------------------------------------------*/
diff -ruN 3.24.src/skins/default/footer.inc 3.31.src/skins/default/footer.inc
--- 3.24.src/skins/default/footer.inc	2005-02-27 11:01:36.000000000 -0600
+++ 3.31.src/skins/default/footer.inc	2007-10-22 19:35:52.000000000 -0500
@@ -14,4 +14,4 @@
 </div>
 
 </body>
-</html>
\ No newline at end of file
+</html>
diff -ruN 3.24.src/skins/default/head.inc 3.31.src/skins/default/head.inc
--- 3.24.src/skins/default/head.inc	2005-03-05 10:33:26.000000000 -0600
+++ 3.31.src/skins/default/head.inc	2007-10-22 19:35:52.000000000 -0500
@@ -6,8 +6,8 @@
 
 <!-- meta information for search engines -->
 <meta name="generator" content="<%version%>" />
-<meta name="name" content="<%blogsetting(name)%>" />
-<meta name="description" content="<%blogsetting(desc)%>" />
+<meta name="name" content="<%if(skintype,error)%><%sitevar(name)%><%else%><%blogsetting(name)%><%endif%>" />
+<meta name="description" content="<%if(skintype,error)%><%sitevar(name)%><%else%><%blogsetting(desc)%><%endif%>" />
 
 <!-- prevent caching (can be removed) -->
 <meta http-equiv="Pragma" content="no-cache" />
diff -ruN 3.24.src/skins/default/show_benchmark.inc 3.31.src/skins/default/show_benchmark.inc
--- 3.24.src/skins/default/show_benchmark.inc	1969-12-31 18:00:00.000000000 -0600
+++ 3.31.src/skins/default/show_benchmark.inc	2007-10-22 19:35:52.000000000 -0500
@@ -0,0 +1,14 @@
+<?
+if (!function_exists('getmtime'))
+{
+  function getmtime()
+  {
+    $a = explode (' ',microtime());
+    return(double) $a[0] + $a[1];
+  }
+}
+
+  global $StartTime, $SQLCount;
+  $loadtime = getmtime() - $StartTime;
+  printf("%.3f sec/%d queries", $loadtime, $SQLCount);
+?>
diff -ruN 3.24.src/skins/default/sidebar.inc 3.31.src/skins/default/sidebar.inc
--- 3.24.src/skins/default/sidebar.inc	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/skins/default/sidebar.inc	2007-10-22 19:35:52.000000000 -0500
@@ -5,26 +5,34 @@
 
 <!-- archive: navigation -->
 <%if(skintype,archive)%>
+<%if(archiveprevexists)%>
 <dd><a href="<%prevlink%>" title="Previous month">Previous <%archivetype%></a></dd>
+<%else%>
+<dd>&nbsp;</dd>
+<%endif%>
+<%if(archivenextexists)%>
 <dd><a href="<%nextlink%>" title="Next month">Next <%archivetype%></a></dd>
-<dd><a href="<%todaylink%>" title="Today&#39;s entry">Today</a></dd>
+<%else%>
+<dd>&nbsp;</dd>
+<%endif%>
+<dd><a href="<%todaylink%>" title="Today's entry">Today</a></dd>
 <dd><a href="<%archivelink%>" title="Archives">Archives</a></dd>
 <%endif%>
 
 <!-- archivelist: navigation -->
 <%if(skintype,archivelist)%>
-<dd><a href="<%todaylink%>" title="Today&#39;s entry">Today</a></dd>
+<dd><a href="<%todaylink%>" title="Today's entry">Today</a></dd>
 <dd><a href="<%archivelink%>" title="Archives">Archives</a></dd>
 <%endif%>
 
 <!-- error: navigation -->
 <%if(skintype,error)%>
-<dd><a href="<%todaylink%>" title="Today&#39;s entry">Today</a></dd>
+<dd><a href="<%todaylink%>" title="Today's entry">Today</a></dd>
 <%endif%>
 
 <!-- index: navigation -->
 <%if(skintype,index)%>
-<dd><a href="<%todaylink%>" title="Today&#39;s entry">Today</a></dd>
+<dd><a href="<%todaylink%>" title="Today's entry">Today</a></dd>
 <dd><a href="<%archivelink%>" title="Archives">Archives</a></dd>
 <%endif%>
 
@@ -32,18 +40,18 @@
 <%if(skintype,item)%>
 <dd><a href="<%nextlink%>" title="Previous item">Previous Item</a></dd>
 <dd><a href="<%prevlink%>" title="Next item">Next Item</a></dd>
-<dd><a href="<%todaylink%>" title="Today&#39;s entry">Today</a></dd>
+<dd><a href="<%todaylink%>" title="Today's entry">Today</a></dd>
 <dd><a href="<%archivelink%>" title="Archives">Archives</a></dd>
 <%endif%>
 
 <!-- member: navigation -->
 <%if(skintype,member)%>
-<dd><a href="<%todaylink%>" title="Today&#39;s entry">Today</a></dd>
+<dd><a href="<%todaylink%>" title="Today's entry">Today</a></dd>
 <%endif%>
 
 <!-- search: navigation -->
 <%if(skintype,search)%>
-<dd><a href="<%todaylink%>" title="Today&#39;s entry">Today</a></dd>
+<dd><a href="<%todaylink%>" title="Today's entry">Today</a></dd>
 <dd><a href="<%archivelink%>" title="Archives">Archives</a></dd>
 <%endif%>
 
@@ -65,6 +73,14 @@
 </div>
 <%endif%><%endif%>
 
+<!-- bloglist-->
+<div class="sidebar">
+<dl class="sidebardl">
+<dt>Blogs</dt>
+<%bloglist(default/index)%>
+</dl>
+</div>
+
 <!-- search form -->
 <div class="sidebar">
 <dl class="sidebardl">
diff -ruN 3.24.src/skins/default/skinbackup.xml 3.31.src/skins/default/skinbackup.xml
--- 3.24.src/skins/default/skinbackup.xml	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/skins/default/skinbackup.xml	2007-10-22 19:35:52.000000000 -0500
@@ -240,6 +240,10 @@
 <a href="<%archivelink%>" title="Archive for %B, %Y">%B, %Y</a>
 </dd>]]></part>
 
+	<part name="BLOGLIST_LISTITEM"><![CDATA[<dd>
+<a href="<%bloglink%>" title="<%blogdesc%>"><%blogname%></a>
+</dd>]]></part>
+
 	<part name="CATLIST_HEADER"><![CDATA[<dd>
 <a href="<%blogurl%>" title="All categories">All</a>
 </dd>]]></part>
@@ -252,7 +256,7 @@
 
 	<part name="COMMENTS_NONE"><![CDATA[<div class="contentitem3">
 <small class="contentitemcomments">
-<a href="<%itemlink%>#c" rel="bookmark" title="Add comment on &#39;<%itemtitle(attribute)%>&#39;">Add comment</a>
+<a href="<%itemlink%>#c" rel="bookmark" title="Add comment on '<%itemtitle(attribute)%>'">Add comment</a>
 </small>
 </div>]]></part>
 
@@ -260,7 +264,7 @@
 
 	<part name="COMMENTS_TOOMUCH"><![CDATA[<div class="contentitem3">
 <small class="contentitemcomments">
-<a href="<%itemlink%>#c" rel="bookmark" title="Add comment on &#39;<%itemtitle(attribute)%>&#39;"><%commentcount%> <%commentword%></a>
+<a href="<%itemlink%>#c" rel="bookmark" title="Add comment on '<%itemtitle(attribute)%>'"><%commentcount%> <%commentword%></a>
 </small>
 </div>]]></part>
 
@@ -303,7 +307,7 @@
 	<part name="MEDIA_CODE"><![CDATA[<%media%>]]></part>
 
 	<part name="MORELINK"><![CDATA[<p>&raquo;
-<a href="<%itemlink%>#more" title="Read more on &#39;<%title(attribute)%>&#39;">Read More</a>
+<a href="<%itemlink%>#more" title="Read more on '<%title(attribute)%>'">Read More</a>
 </p>]]></part>
 
 	<part name="POPUP_CODE"><![CDATA[<%popuplink%>]]></part>
@@ -380,4 +384,4 @@
 
 </template>
 
-</nucleusskin>
\ No newline at end of file
+</nucleusskin>
diff -ruN 3.24.src/skins/rsd/skinbackup.xml 3.31.src/skins/rsd/skinbackup.xml
--- 3.24.src/skins/rsd/skinbackup.xml	2005-08-15 12:51:10.000000000 -0500
+++ 3.31.src/skins/rsd/skinbackup.xml	2007-10-22 19:35:54.000000000 -0500
@@ -6,10 +6,10 @@
   <homepageLink><%sitevar(url)%></homepageLink>
   <apis>
    <api name="MetaWeblog" preferred="true" apiLink="<%adminurl%>xmlrpc/server.php" blogID="<%blogsetting(id)%>">
-    <docs>http://nucleuscms.org/documentation/devdocs/xmlrpc.html</docs>
+	<docs>http://nucleuscms.org/documentation/devdocs/xmlrpc.html</docs>
    </api>
    <api name="Blogger" preferred="false" apiLink="<%adminurl%>xmlrpc/server.php" blogID="<%blogsetting(id)%>">
-    <docs>http://nucleuscms.org/documentation/devdocs/xmlrpc.html</docs>
+	<docs>http://nucleuscms.org/documentation/devdocs/xmlrpc.html</docs>
    </api>
   </apis>
  </service>
diff -ruN 3.24.src/xml-rss2.php 3.31.src/xml-rss2.php
--- 3.24.src/xml-rss2.php	2005-08-15 12:51:08.000000000 -0500
+++ 3.31.src/xml-rss2.php	2008-01-17 10:01:12.000000000 -0600
@@ -1,68 +1,69 @@
 <?php
 
 /*
-  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
-  * Copyright (C) 2002-2005 The Nucleus Group
-  *
-  * 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.
-  * (see nucleus/documentation/index.html#license for more info)
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2007 The Nucleus Group
+ *
+ * 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.
+ * (see nucleus/documentation/index.html#license for more info)
  */
 
 /**
-  * Nucleus RSS syndication channel skin
+ * Nucleus RSS syndication channel skin
  * @license http://nucleuscms.org/license.txt GNU General Public License
- * @copyright Copyright (C) 2002-2005 The Nucleus Group
- * @version $Id: xml-rss2.php,v 1.9.2.1 2005/08/15 10:51:08 dekarma Exp $
-  */
+ * @copyright Copyright (C) 2002-2007 The Nucleus Group
+ * @version $Id: xml-rss2.php 1116 2007-02-03 08:24:29Z kimitake $
+ */
 
-header("Pragma: no-cache");
+header('Pragma: no-cache');
 
 $CONF = array();
-$CONF['Self'] = "xml-rss2.php";
+$CONF['Self'] = 'xml-rss2.php';
 
 include('./config.php');
 
 if (!$CONF['DisableSite']) {
+
 	// get feed into $feed
 	ob_start();
-		selectSkin('feeds/rss20');
-		selector();
+	selectSkin('feeds/rss20');
+	selector();
 	$feed = ob_get_contents();
 	ob_end_clean();
-	
+
 	// create ETAG (hash of feed)
 	// (HTTP_IF_NONE_MATCH has quotes around it)
-	$eTag = '"'.md5($feed).'"';
-	header('Etag: '.$eTag);
-	
+	$eTag = '"' . md5($feed) . '"';
+	header('Etag: ' . $eTag);
+
 	// compare Etag to what we got
-	if ($eTag == serverVar('HTTP_IF_NONE_MATCH')) {	
-		header("HTTP/1.0 304 Not Modified");
+	if ($eTag == serverVar('HTTP_IF_NONE_MATCH') ) {
+		header('HTTP/1.0 304 Not Modified');
 		header('Content-Length: 0');
 	} else {
 		// dump feed
 		echo $feed;
 	}
-		
+
 } else {
 	// output empty RSS file...
 	// (because site is disabled)
-	
+
 	echo '<' . '?xml version="1.0" encoding="' . _CHARSET . '"?' . '>';
-	
+
 	?>
 	<rss version="2.0">
-	  <channel>
-	    <title><?php echo htmlspecialchars($CONF['SiteName'])?></title>
-	    <link><?php echo htmlspecialchars($CONF['IndexURL'])?></link>
-	    <description></description>
-	    <docs>http://backend.userland.com/rss</docs>
- 	  </channel>
-	</rss>	
+		<channel>
+			<title><?php echo htmlspecialchars($CONF['SiteName']); ?></title>
+			<link><?php echo htmlspecialchars($CONF['IndexURL']); ?></link>
+			<description></description>
+			<docs>http://backend.userland.com/rss</docs>
+		</channel>
+	</rss>
 	<?php
 }
 
-?>
+?>
\ No newline at end of file
