diffstat for php-letodms-core-3.3.4 php-letodms-core-3.3.9

 LetoDMS_Core-3.3.4/Core.php                           |   79 
 LetoDMS_Core-3.3.4/Core/inc.AccessUtils.php           |   48 
 LetoDMS_Core-3.3.4/Core/inc.ClassAccess.php           |   76 
 LetoDMS_Core-3.3.4/Core/inc.ClassDMS.php              | 1252 --------
 LetoDMS_Core-3.3.4/Core/inc.ClassDocument.php         | 2735 -----------------
 LetoDMS_Core-3.3.4/Core/inc.ClassDocumentCategory.php |  118 
 LetoDMS_Core-3.3.4/Core/inc.ClassFolder.php           | 1186 -------
 LetoDMS_Core-3.3.4/Core/inc.ClassGroup.php            |  296 -
 LetoDMS_Core-3.3.4/Core/inc.ClassKeywords.php         |  137 
 LetoDMS_Core-3.3.4/Core/inc.ClassNotification.php     |   78 
 LetoDMS_Core-3.3.4/Core/inc.ClassUser.php             |  848 -----
 LetoDMS_Core-3.3.4/Core/inc.DBAccess.php              |  284 -
 LetoDMS_Core-3.3.4/Core/inc.FileUtils.php             |  174 -
 LetoDMS_Core-3.3.4/tests/getfoldertree.php            |   25 
 LetoDMS_Core-3.3.4/tests/getusers.php                 |   14 
 LetoDMS_Core-3.3.9/Core.php                           |   79 
 LetoDMS_Core-3.3.9/Core/inc.AccessUtils.php           |   48 
 LetoDMS_Core-3.3.9/Core/inc.ClassAccess.php           |   76 
 LetoDMS_Core-3.3.9/Core/inc.ClassDMS.php              | 1256 ++++++++
 LetoDMS_Core-3.3.9/Core/inc.ClassDocument.php         | 2752 ++++++++++++++++++
 LetoDMS_Core-3.3.9/Core/inc.ClassDocumentCategory.php |  118 
 LetoDMS_Core-3.3.9/Core/inc.ClassFolder.php           | 1204 +++++++
 LetoDMS_Core-3.3.9/Core/inc.ClassGroup.php            |  296 +
 LetoDMS_Core-3.3.9/Core/inc.ClassKeywords.php         |  137 
 LetoDMS_Core-3.3.9/Core/inc.ClassNotification.php     |   78 
 LetoDMS_Core-3.3.9/Core/inc.ClassUser.php             |  848 +++++
 LetoDMS_Core-3.3.9/Core/inc.DBAccess.php              |  291 +
 LetoDMS_Core-3.3.9/Core/inc.FileUtils.php             |  174 +
 LetoDMS_Core-3.3.9/tests/getfoldertree.php            |   25 
 LetoDMS_Core-3.3.9/tests/getusers.php                 |   14 
 debian/changelog                                      |   20 
 debian/control                                        |    1 
 package.xml                                           |  128 
 33 files changed, 7519 insertions(+), 7376 deletions(-)

diff -Nru php-letodms-core-3.3.4/debian/changelog php-letodms-core-3.3.9/debian/changelog
--- php-letodms-core-3.3.4/debian/changelog	2012-04-23 20:50:17.000000000 +0200
+++ php-letodms-core-3.3.9/debian/changelog	2012-09-20 11:58:11.000000000 +0200
@@ -1,3 +1,23 @@
+php-letodms-core (3.3.9-1) unstable; urgency=low
+
+  * New upstream release (More security fixes for preventing CSRF, XSS and sql
+    injection attacks).
+
+ -- Francisco Manuel Garcia Claramonte <francisco@debian.org>  Mon, 17 Sep 2012 12:26:28 +0200
+
+php-letodms-core (3.3.7-1) unstable; urgency=low
+
+  * New upstream release. Fixed some security issues.
+
+ -- Francisco Manuel Garcia Claramonte <francisco@debian.org>  Mon, 27 Aug 2012 13:12:21 +0200
+
+php-letodms-core (3.3.6-1) unstable; urgency=low
+
+  * New upstream release.
+  * Added Homepage control field.
+
+ -- Francisco Manuel Garcia Claramonte <francisco@debian.org>  Wed, 18 Jul 2012 18:09:21 +0200
+
 php-letodms-core (3.3.4-1) unstable; urgency=low
 
   * New upstream release
diff -Nru php-letodms-core-3.3.4/debian/control php-letodms-core-3.3.9/debian/control
--- php-letodms-core-3.3.4/debian/control	2012-04-23 16:55:30.000000000 +0200
+++ php-letodms-core-3.3.9/debian/control	2012-08-09 13:25:31.000000000 +0200
@@ -4,6 +4,7 @@
 Maintainer: Francisco Manuel Garcia Claramonte <francisco@debian.org>
 Build-Depends: debhelper (>= 7), dh-make-php (>= 0.2.3), cdbs
 Standards-Version: 3.9.3
+Homepage: http://www.letodms.com/
 
 Package: php-letodms-core
 Architecture: all
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.AccessUtils.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.AccessUtils.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.AccessUtils.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.AccessUtils.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,48 +0,0 @@
-<?php
-/**
- * Some definitions for access control
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal,
- *             2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Used to indicate that a search should return all
- * results in the ACL table. See {@link LetoDMS_Core_Folder::getAccessList()}
- */
-define("M_ANY", -1);
-
-/**
- * No rights at all
- */
-define("M_NONE", 1);
-
-/**
- * Read access only
- */
-define("M_READ", 2);
-
-/**
- * Read and write access only
- */
-define("M_READWRITE", 3);
-
-/**
- * Unrestricted access
- */
-define("M_ALL", 4);
-
-define ("O_GTEQ", ">=");
-define ("O_LTEQ", "<=");
-define ("O_EQ", "=");
-
-define("T_FOLDER", 1);		//TargetType = Folder
-define("T_DOCUMENT", 2);	//    "      = Document
-
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassAccess.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassAccess.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassAccess.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassAccess.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,76 +0,0 @@
-<?php
-/**
- * Implementation of user and group access object
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Class to represent a user access right.
- * This class cannot be used to modify access rights.
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_UserAccess { /* {{{ */
-	var $_user;
-	var $_mode;
-
-	function LetoDMS_Core_UserAccess($user, $mode) {
-		$this->_user = $user;
-		$this->_mode = $mode;
-	}
-
-	function getUserID() { return $this->_user->getID(); }
-
-	function getMode() { return $this->_mode; }
-
-	function isAdmin() {
-		return ($this->_mode == LetoDMS_Core_User::role_admin);
-	}
-
-	function getUser() {
-		return $this->_user;
-	}
-} /* }}} */
-
-
-/**
- * Class to represent a group access right.
- * This class cannot be used to modify access rights.
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_GroupAccess { /* {{{ */
-	var $_group;
-	var $_mode;
-
-	function LetoDMS_Core_GroupAccess($group, $mode) {
-		$this->_group = $group;
-		$this->_mode = $mode;
-	}
-
-	function getGroupID() { return $this->_group->getID(); }
-
-	function getMode() { return $this->_mode; }
-
-	function getGroup() {
-		return $this->_group;
-	}
-} /* }}} */
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassDMS.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassDMS.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassDMS.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassDMS.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,1252 +0,0 @@
-<?php
-/**
- * Implementation of the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2010, Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Include some files
- */
-require_once("inc.DBAccess.php");
-require_once("inc.AccessUtils.php");
-require_once("inc.FileUtils.php");
-require_once("inc.ClassAccess.php");
-require_once("inc.ClassFolder.php");
-require_once("inc.ClassDocument.php");
-require_once("inc.ClassGroup.php");
-require_once("inc.ClassUser.php");
-require_once("inc.ClassKeywords.php");
-require_once("inc.ClassNotification.php");
-
-/**
- * Class to represent the complete document management system.
- * This class is needed to do most of the dms operations. It needs
- * an instance of {@link LetoDMS_Core_DatabaseAccess} to access the
- * underlying database. Many methods are factory functions which create
- * objects representing the entities in the dms, like folders, documents,
- * users, or groups.
- *
- * Each dms has its own database for meta data and a data store for document
- * content. Both must be specified when creating a new instance of this class.
- * All folders and documents are organized in a hierachy like
- * a regular file system starting with a {@link $rootFolderID}
- *
- * This class does not enforce any access rights on documents and folders
- * by design. It is up to the calling application to use the methods
- * {@link LetoDMS_Core_Folder::getAccessMode} and
- * {@link LetoDMS_Core_Document::getAccessMode} and interpret them as desired.
- * Though, there are two convinient functions to filter a list of
- * documents/folders for which users have access rights for. See
- * {@link LetoDMS_Core_DMS::filterAccess}
- * and {@link LetoDMS_Core_DMS::filterUsersByAccess}
- *
- * Though, this class has two methods to set the currently logged in user
- * ({@link setUser} and {@link login}), none of them need to be called, because
- * there is currently no class within the LetoDMS core which needs the logged
- * in user.
- *
- * <code>
- * <?php
- * include("inc/inc.ClassDMS.php");
- * $db = new LetoDMS_Core_DatabaseAccess($type, $hostname, $user, $passwd, $name);
- * $db->connect() or die ("Could not connect to db-server");
- * $dms = new LetoDMS_Core_DMS($db, $contentDir);
- * $dms->setRootFolderID(1);
- * ...
- * ?>
- * </code>
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2010, Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_DMS {
-	/**
-	 * @var object $db reference to database object. This must be an instance
-	 *      of {@link LetoDMS_Core_DatabaseAccess}.
-	 * @access protected
-	 */
-	protected $db;
-
-	/**
-	 * @var object $user reference to currently logged in user. This must be
-	 *      an instance of {@link LetoDMS_Core_User}. This variable is currently not
-	 *      used. It is set by {@link setUser}.
-	 * @access private
-	 */
-	private $user;
-
-	/**
-	 * @var string $contentDir location in the file system where all the
-	 *      document data is located. This should be an absolute path.
-	 * @access public
-	 */
-	public $contentDir;
-
-	/**
-	 * @var integer $rootFolderID ID of root folder
-	 * @access public
-	 */
-	public $rootFolderID;
-
-	/**
-	 * @var boolean $enableConverting set to true if conversion of content
-	 *      is desired
-	 * @access public
-	 */
-	public $enableConverting;
-
-	/**
-	 * @var array $convertFileTypes list of files types that shall be converted
-	 * @access public
-	 */
-	public $convertFileTypes;
-
-	/**
-	 * @var array $viewOnlineFileTypes list of files types that can be viewed
-	 *      online
-	 * @access public
-	 */
-	public $viewOnlineFileTypes;
-
-	/**
-	 * @var string $version version of pear package
-	 * @access public
-	 */
-	public $version;
-
-	/**
-	 * Filter objects out which are not accessible in a given mode by a user.
-	 *
-	 * @param array $objArr list of objects (either documents or folders)
-	 * @param object $user user for which access is checked
-	 * @param integer $minMode minimum access mode required
-	 * @return array filtered list of objects
-	 */
-	static function filterAccess($objArr, $user, $minMode) { /* {{{ */
-		if (!is_array($objArr)) {
-			return array();
-		}
-		$newArr = array();
-		foreach ($objArr as $obj) {
-			if ($obj->getAccessMode($user) >= $minMode)
-				array_push($newArr, $obj);
-		}
-		return $newArr;
-	} /* }}} */
-
-	/**
-	 * Filter users out which cannot access an object in a given mode.
-	 *
-	 * @param object $obj object that shall be accessed
-	 * @param array $users list of users which are to check for sufficient
-	 *        access rights
-	 * @param integer $minMode minimum access right on the object for each user
-	 * @return array filtered list of users
-	 */
-	static function filterUsersByAccess($obj, $users, $minMode) { /* {{{ */
-		$newArr = array();
-		foreach ($users as $currUser) {
-			if ($obj->getAccessMode($currUser) >= $minMode)
-				array_push($newArr, $currUser);
-		}
-		return $newArr;
-	} /* }}} */
-
-	/**
-	 * Create a new instance of the dms
-	 *
-	 * @param object $db object to access the underlying database
-	 * @param string $contentDir path in filesystem containing the data store
-	 *        all document contents is stored
-	 * @return object instance of LetoDMS_Core_DMS
-	 */
-	function __construct($db, $contentDir) { /* {{{ */
-		$this->db = $db;
-		if(substr($contentDir, -1) == '/')
-			$this->contentDir = $contentDir;
-		else
-			$this->contentDir = $contentDir.'/';
-		$this->rootFolderID = 1;
-		$this->maxDirID = 0; //31998;
-		$this->enableAdminRevApp = false;
-		$this->enableConverting = false;
-		$this->convertFileTypes = array();
-		$this->version = '3.3.4';
-		if($this->version[0] == '@')
-			$this->version = '3.3.4';
-	} /* }}} */
-
-	function getDB() { /* {{{ */
-		return $this->db;
-	} /* }}} */
-
-	/**
-	 * Return the database version
-	 *
-	 * @return array array with elements major, minor, subminor, date
-	 */
-	function getDBVersion() { /* {{{ */
-		$tbllist = $this->db->TableList();
-		$tbllist = explode(',',strtolower(join(',',$tbllist)));
-		if(!array_search('tblversion', $tbllist))
-			return false;
-		$queryStr = "SELECT * FROM tblVersion order by major,minor,subminor limit 1";
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr) != 1)
-			return false;
-		$resArr = $resArr[0];
-		return $resArr;
-	} /* }}} */
-
-	/**
-	 * Check if the version in the database is the same as of this package
-	 * Only the major and minor version number will be checked.
-	 *
-	 * @return boolean returns false if versions do not match, but returns
-	 *         true if version matches or table tblVersion does not exists.
-	 */
-	function checkVersion() { /* {{{ */
-		$tbllist = $this->db->TableList();
-		$tbllist = explode(',',strtolower(join(',',$tbllist)));
-		if(!array_search('tblversion', $tbllist))
-			return true;
-		$queryStr = "SELECT * FROM tblVersion order by major,minor,subminor limit 1";
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr) != 1)
-			return false;
-		$resArr = $resArr[0];
-		$ver = explode('.', $this->version);
-		if(($resArr['major'] != $ver[0]) || ($resArr['minor'] != $ver[1]))
-			return false;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Set id of root folder
-	 * This function must be called right after creating an instance of
-	 * LetoDMS_Core_DMS
-	 *
-	 * @param interger $id id of root folder
-	 */
-	function setRootFolderID($id) { /* {{{ */
-		$this->rootFolderID = $id;
-	} /* }}} */
-
-	/**
-	 * Set maximum number of subdirectories per directory
-	 *
-	 * The value of maxDirID is quite crucial because, all documents are
-	 * associated with a directory in the filesystem. Consequently, there is
-	 * maximum number of documents, because depending on the file system
-	 * the maximum number of subdirectories is limited. Since version 3.3.0 of
-	 * letodms an additional directory level has been introduced. All documents
-	 * from 1 to maxDirID-1 will be saved in 1/<docid>, documents from maxDirID
-	 * to 2*maxDirID-1 are stored in 2/<docid> and so on.
-	 *
-	 * This function must be called right after creating an instance of
-	 * LetoDMS_Core_DMS
-	 *
-	 * @param interger $id id of root folder
-	 */
-	function setMaxDirID($id) { /* {{{ */
-		$this->maxDirID = $id;
-	} /* }}} */
-
-	/**
-	 * Get root folder
-	 *
-	 * @return object/boolean return the object of the root folder or false if
-	 *        the root folder id was not set before with {@link setRootFolderID}.
-	 */
-	function getRootFolder() { /* {{{ */
-		if(!$this->rootFolderID) return false;
-		return $this->getFolder($this->rootFolderID);
-	} /* }}} */
-
-	function setEnableAdminRevApp($enable) { /* {{{ */
-		$this->enableAdminRevApp = $enable;
-	} /* }}} */
-
-	function setEnableConverting($enable) { /* {{{ */
-		$this->enableConverting = $enable;
-	} /* }}} */
-
-	function setConvertFileTypes($types) { /* {{{ */
-		$this->convertFileTypes = $types;
-	} /* }}} */
-
-	function setViewOnlineFileTypes($types) { /* {{{ */
-		$this->viewOnlineFileTypes = $types;
-	} /* }}} */
-
-	/**
-	 * Login as a user
-	 *
-	 * Checks if the given credentials are valid and returns a user object.
-	 * It also sets the property $user for later access on the currently
-	 * logged in user
-	 *
-	 * @param string $username login name of user
-	 * @param string $password password of user
-	 *
-	 * @return object instance of class LetoDMS_Core_User or false
-	 */
-	function login($username, $password) { /* {{{ */
-	} /* }}} */
-
-	/**
-	 * Set the logged in user
-	 *
-	 * If user authentication was done externally, this function can
-	 * be used to tell the dms who is currently logged in.
-	 *
-	 * @param object $user
-	 *
-	 */
-	function setUser($user) { /* {{{ */
-		$this->user = $user;
-	} /* }}} */
-
-	/**
-	 * Return a document by its id
-	 *
-	 * This function retrieves a document from the database by its id.
-	 *
-	 * @param integer $id internal id of document
-	 * @return object instance of LetoDMS_Core_Document or false
-	 */
-	function getDocument($id) { /* {{{ */
-		if (!is_numeric($id)) return false;
-
-		$queryStr = "SELECT * FROM tblDocuments WHERE id = " . (int) $id;
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr) != 1)
-			return false;
-		$resArr = $resArr[0];
-
-		// New Locking mechanism uses a separate table to track the lock.
-		$queryStr = "SELECT * FROM tblDocumentLocks WHERE document = " . (int) $id;
-		$lockArr = $this->db->getResultArray($queryStr);
-		if ((is_bool($lockArr) && $lockArr==false) || (count($lockArr)==0)) {
-			// Could not find a lock on the selected document.
-			$lock = -1;
-		}
-		else {
-			// A lock has been identified for this document.
-			$lock = $lockArr[0]["userID"];
-		}
-
-		$document = new LetoDMS_Core_Document($resArr["id"], $resArr["name"], $resArr["comment"], $resArr["date"], $resArr["expires"], $resArr["owner"], $resArr["folder"], $resArr["inheritAccess"], $resArr["defaultAccess"], $lock, $resArr["keywords"], $resArr["sequence"]);
-		$document->setDMS($this);
-		return $document;
-	} /* }}} */
-
-	/**
-	 * Returns all documents of a given user
-	 *
-	 * @param object $user
-	 * @return array list of documents
-	 */
-	function getDocumentsByUser($user) { /* {{{ */
-		$queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser` ".
-			"FROM `tblDocuments` ".
-			"LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ".
-			"WHERE `tblDocuments`.`owner` = " . $user->getID() . " ORDER BY `sequence`";
-
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		$documents = array();
-		foreach ($resArr as $row) {
-			$document = new LetoDMS_Core_Document($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], $row["lockUser"], $row["keywords"], $row["sequence"]);
-			$document->setDMS($this);
-			$documents[] = $document;
-		}
-		return $documents;
-	} /* }}} */
-
-	/**
-	 * Returns a document by its name
-	 *
-	 * This function searches a document by its name and restricts the search
-	 * to given folder if passed as the second parameter.
-	 *
-	 * @param string $name
-	 * @param object $folder
-	 * @return object/boolean found document or false
-	 */
-	function getDocumentByName($name, $folder=null) { /* {{{ */
-		if (!$name) return false;
-
-		$queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser` ".
-			"FROM `tblDocuments` ".
-			"LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ".
-			"WHERE `tblDocuments`.`name` = " . $this->db->qstr($name);
-		if($folder)
-			$queryStr .= " AND `tblDocuments`.`folder` = ". $folder->getID();
-		$queryStr .= " LIMIT 1";
-
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		if(!$resArr)
-			return false;
-
-		$row = $resArr[0];
-		$document = new LetoDMS_Core_Document($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], $row["lockUser"], $row["keywords"], $row["sequence"]);
-		$document->setDMS($this);
-		return $document;
-	} /* }}} */
-
-	/*
-	 * Search the database for documents
-	 *
-	 * @param query string seach query with space separated words
-	 * @param limit integer number of items in result set
-	 * @param offset integer index of first item in result set
-	 * @param logicalmode string either AND or OR
-	 * @param searchin array() list of fields to search in
-	 *        1 = keywords, 2=name, 3=comment
-	 * @param startFolder object search in the folder only (null for root folder)
-	 * @param owner object search for documents owned by this user
-	 * @param status array list of status
-	 * @param creationstartdate array search for documents created after this date
-	 * @param creationenddate array search for documents created before this date
-	 * @param categories array list of categories the documents must have assigned
-	 * @param mode int decide whether to search for documents/folders
-	 *        0x1 = documents only
-	 *        0x2 = folders only
-	 *        0x3 = both
-	 * @return array containing the elements total and docs
-	 */
-	function search($query, $limit=0, $offset=0, $logicalmode='AND', $searchin=array(), $startFolder=null, $owner=null, $status = array(), $creationstartdate=array(), $creationenddate=array(), $categories=array(), $mode=0x3) { /* {{{ */
-		// Split the search string into constituent keywords.
-		$tkeys=array();
-		if (strlen($query)>0) {
-			$tkeys = preg_split("/[\t\r\n ,]+/", $query);
-		}
-
-		// if none is checkd search all
-		if (count($searchin)==0)
-			$searchin=array( 0, 1, 2, 3);
-
-		/*--------- Do it all over again for folders -------------*/
-		if($mode & 0x2) {
-			$searchKey = "";
-			// Assemble the arguments for the concatenation function. This allows the
-			// search to be carried across all the relevant fields.
-			$concatFunction = "";
-			if (in_array(2, $searchin)) {
-				$concatFunction = (strlen($concatFunction) == 0 ? "" : $concatFunction.", ")."`tblFolders`.`name`";
-			}
-			if (in_array(3, $searchin)) {
-				$concatFunction = (strlen($concatFunction) == 0 ? "" : $concatFunction.", ")."`tblFolders`.`comment`";
-			}
-
-			if (strlen($concatFunction)>0 && count($tkeys)>0) {
-				$concatFunction = "CONCAT_WS(' ', ".$concatFunction.")";
-				foreach ($tkeys as $key) {
-					$key = trim($key);
-					if (strlen($key)>0) {
-						$searchKey = (strlen($searchKey)==0 ? "" : $searchKey." ".$logicalmode." ").$concatFunction." LIKE ".$this->db->qstr('%'.$key.'%');
-					}
-				}
-			}
-
-			// Check to see if the search has been restricted to a particular sub-tree in
-			// the folder hierarchy.
-			$searchFolder = "";
-			if ($startFolder) {
-				$searchFolder = "`tblFolders`.`folderList` LIKE '%:".$startFolder->getID().":%'";
-			}
-
-			// Check to see if the search has been restricted to a particular
-			// document owner.
-			$searchOwner = "";
-			if ($owner) {
-				$searchOwner = "`tblFolders`.`owner` = '".$owner->getId()."'";
-			}
-
-			// Is the search restricted to documents created between two specific dates?
-			$searchCreateDate = "";
-			if ($creationstartdate) {
-				$startdate = makeTimeStamp(0, 0, 0, $creationstartdate['year'], $creationstartdate["month"], $creationstartdate["day"]);
-				if ($startdate) {
-					$searchCreateDate .= "`tblFolders`.`date` >= ".$startdate;
-				}
-			}
-			if ($creationenddate) {
-				$stopdate = makeTimeStamp(23, 59, 59, $creationenddate["year"], $creationenddate["month"], $creationenddate["day"]);
-				if ($stopdate) {
-					if($startdate)
-						$searchCreateDate .= " AND ";
-					$searchCreateDate .= "`tblFolders`.`date` <= ".$stopdate;
-				}
-			}
-
-			$searchQuery = "FROM `tblFolders` WHERE 1=1";
-
-			if (strlen($searchKey)>0) {
-				$searchQuery .= " AND (".$searchKey.")";
-			}
-			if (strlen($searchFolder)>0) {
-				$searchQuery .= " AND ".$searchFolder;
-			}
-			if (strlen($searchOwner)>0) {
-				$searchQuery .= " AND (".$searchOwner.")";
-			}
-			if (strlen($searchCreateDate)>0) {
-				$searchQuery .= " AND (".$searchCreateDate.")";
-			}
-
-			// Count the number of rows that the search will produce.
-			$resArr = $this->db->getResultArray("SELECT COUNT(*) AS num ".$searchQuery);
-			$totalFolders = 0;
-			if (is_numeric($resArr[0]["num"]) && $resArr[0]["num"]>0) {
-				$totalFolders = (integer)$resArr[0]["num"];
-			}
-
-			// If there are no results from the count query, then there is no real need
-			// to run the full query. TODO: re-structure code to by-pass additional
-			// queries when no initial results are found.
-
-			// Only search if the offset is not beyond the number of folders
-			if($totalFolders > $offset) {
-				// Prepare the complete search query, including the LIMIT clause.
-				$searchQuery = "SELECT `tblFolders`.* ".$searchQuery;
-
-				if($limit) {
-					$searchQuery .= " LIMIT ".$offset.",".$limit;
-				}
-
-				// Send the complete search query to the database.
-				$resArr = $this->db->getResultArray($searchQuery);
-			} else {
-				$resArr = array();
-			}
-
-			// ------------------- Ausgabe der Ergebnisse ----------------------------
-			$numResults = count($resArr);
-			if ($numResults == 0) {
-				$folderresult = array('totalFolders'=>$totalFolders, 'folders'=>array());
-			} else {
-				foreach ($resArr as $folderArr) {
-					$folders[] = $this->getFolder($folderArr['id']);
-				}
-				$folderresult = array('totalFolders'=>$totalFolders, 'folders'=>$folders);
-			}
-		} else {
-			$folderresult = array('totalFolders'=>0, 'folders'=>array());
-		}
-
-		/*--------- Do it all over again for documents -------------*/
-
-		if($mode & 0x1) {
-			$searchKey = "";
-			// Assemble the arguments for the concatenation function. This allows the
-			// search to be carried across all the relevant fields.
-			$concatFunction = "";
-			if (in_array(1, $searchin)) {
-				$concatFunction = "`tblDocuments`.`keywords`";
-			}
-			if (in_array(2, $searchin)) {
-				$concatFunction = (strlen($concatFunction) == 0 ? "" : $concatFunction.", ")."`tblDocuments`.`name`";
-			}
-			if (in_array(3, $searchin)) {
-				$concatFunction = (strlen($concatFunction) == 0 ? "" : $concatFunction.", ")."`tblDocuments`.`comment`";
-			}
-
-			if (strlen($concatFunction)>0 && count($tkeys)>0) {
-				$concatFunction = "CONCAT_WS(' ', ".$concatFunction.")";
-				foreach ($tkeys as $key) {
-					$key = trim($key);
-					if (strlen($key)>0) {
-						$searchKey = (strlen($searchKey)==0 ? "" : $searchKey." ".$logicalmode." ").$concatFunction." LIKE ".$this->db->qstr('%'.$key.'%');
-					}
-				}
-			}
-
-			// Check to see if the search has been restricted to a particular sub-tree in
-			// the folder hierarchy.
-			$searchFolder = "";
-			if ($startFolder) {
-				$searchFolder = "`tblDocuments`.`folderList` LIKE '%:".$startFolder->getID().":%'";
-			}
-
-			// Check to see if the search has been restricted to a particular
-			// document owner.
-			$searchOwner = "";
-			if ($owner) {
-				$searchOwner = "`tblDocuments`.`owner` = '".$owner->getId()."'";
-			}
-
-			// Check to see if the search has been restricted to a particular
-			// document category.
-			$searchCategories = "";
-			if ($categories) {
-				$catids = array();
-				foreach($categories as $category)
-					$catids[] = $category->getId();
-				$searchCategories = "`tblDocumentCategory`.`categoryID` in (".implode(',', $catids).")";
-			}
-
-			// Is the search restricted to documents created between two specific dates?
-			$searchCreateDate = "";
-			if ($creationstartdate) {
-				$startdate = makeTimeStamp(0, 0, 0, $creationstartdate['year'], $creationstartdate["month"], $creationstartdate["day"]);
-				if ($startdate) {
-					$searchCreateDate .= "`tblDocuments`.`date` >= ".$startdate;
-				}
-			}
-			if ($creationenddate) {
-				$stopdate = makeTimeStamp(23, 59, 59, $creationenddate["year"], $creationenddate["month"], $creationenddate["day"]);
-				if ($stopdate) {
-					if($startdate)
-						$searchCreateDate .= " AND ";
-					$searchCreateDate .= "`tblDocuments`.`date` <= ".$stopdate;
-				}
-			}
-
-			// ---------------------- Suche starten ----------------------------------
-
-			//
-			// Construct the SQL query that will be used to search the database.
-			//
-
-			if (!$this->db->createTemporaryTable("ttcontentid") || !$this->db->createTemporaryTable("ttstatid")) {
-				return false;
-			}
-
-			$searchQuery = "FROM `tblDocumentContent` ".
-				"LEFT JOIN `tblDocuments` ON `tblDocuments`.`id` = `tblDocumentContent`.`document` ".
-				"LEFT JOIN `tblDocumentStatus` ON `tblDocumentStatus`.`documentID` = `tblDocumentContent`.`document` ".
-				"LEFT JOIN `tblDocumentStatusLog` ON `tblDocumentStatusLog`.`statusID` = `tblDocumentStatus`.`statusID` ".
-				"LEFT JOIN `ttstatid` ON `ttstatid`.`maxLogID` = `tblDocumentStatusLog`.`statusLogID` ".
-				"LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentStatus`.`version` AND `ttcontentid`.`document` = `tblDocumentStatus`.`documentID` ".
-				"LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ".
-				"LEFT JOIN `tblDocumentCategory` ON `tblDocuments`.`id`=`tblDocumentCategory`.`documentID` ".
-				"WHERE `ttstatid`.`maxLogID`=`tblDocumentStatusLog`.`statusLogID` ".
-				"AND `ttcontentid`.`maxVersion` = `tblDocumentContent`.`version`";
-
-			if (strlen($searchKey)>0) {
-				$searchQuery .= " AND (".$searchKey.")";
-			}
-			if (strlen($searchFolder)>0) {
-				$searchQuery .= " AND ".$searchFolder;
-			}
-			if (strlen($searchOwner)>0) {
-				$searchQuery .= " AND (".$searchOwner.")";
-			}
-			if (strlen($searchCategories)>0) {
-				$searchQuery .= " AND (".$searchCategories.")";
-			}
-			if (strlen($searchCreateDate)>0) {
-				$searchQuery .= " AND (".$searchCreateDate.")";
-			}
-
-			// status
-			if ($status) {
-				$searchQuery .= " AND `tblDocumentStatusLog`.`status` IN (".implode(',', $status).")";
-			}
-
-			// Count the number of rows that the search will produce.
-			$resArr = $this->db->getResultArray("SELECT COUNT(*) AS num ".$searchQuery);
-			$totalDocs = 0;
-			if (is_numeric($resArr[0]["num"]) && $resArr[0]["num"]>0) {
-				$totalDocs = (integer)$resArr[0]["num"];
-			}
-
-			// If there are no results from the count query, then there is no real need
-			// to run the full query. TODO: re-structure code to by-pass additional
-			// queries when no initial results are found.
-
-			// Prepare the complete search query, including the LIMIT clause.
-			$searchQuery = "SELECT `tblDocuments`.*, ".
-				"`tblDocumentContent`.`version`, ".
-				"`tblDocumentStatusLog`.`status`, `tblDocumentLocks`.`userID` as `lockUser` ".$searchQuery;
-
-			// calculate the remaining entrŅes of the current page
-			// If page is not full yet, get remaining entries
-			$remain = $limit - count($folderresult['folders']);
-			if($remain) {
-				if($remain == $limit)
-					$offset -= $totalFolders;
-				else
-					$offset = 0;
-				if($limit)
-					$searchQuery .= " LIMIT ".$offset.",".$remain;
-
-				// Send the complete search query to the database.
-				$resArr = $this->db->getResultArray($searchQuery);
-			} else {
-				$resArr = array();
-			}
-
-			// ------------------- Ausgabe der Ergebnisse ----------------------------
-			$numResults = count($resArr);
-			if ($numResults == 0) {
-				$docresult = array('totalDocs'=>$totalDocs, 'docs'=>array());
-			} else {
-				foreach ($resArr as $docArr) {
-					$docs[] = $this->getDocument($docArr['id']);
-				}
-				$docresult = array('totalDocs'=>$totalDocs, 'docs'=>$docs);
-			}
-		} else {
-			$docresult = array('totalDocs'=>0, 'docs'=>array());
-		}
-
-		if($limit) {
-			$totalPages = (integer)(($totalDocs+$totalFolders)/$limit);
-			if ((($totalDocs+$totalFolders)%$limit) > 0) {
-				$totalPages++;
-			}
-		} else {
-			$totalPages = 1;
-		}
-
-		return array_merge($docresult, $folderresult, array('totalPages'=>$totalPages));
-	} /* }}} */
-
-	/**
-	 * Return a folder by its id
-	 *
-	 * This function retrieves a folder from the database by its id.
-	 *
-	 * @param integer $id internal id of folder
-	 * @return object instance of LetoDMS_Core_Folder or false
-	 */
-	function getFolder($id) { /* {{{ */
-		if (!is_numeric($id)) return false;
-
-		$queryStr = "SELECT * FROM tblFolders WHERE id = " . (int) $id;
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		else if (count($resArr) != 1)
-			return false;
-
-		$resArr = $resArr[0];
-		$folder = new LetoDMS_Core_Folder($resArr["id"], $resArr["name"], $resArr["parent"], $resArr["comment"], $resArr["date"], $resArr["owner"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr["sequence"]);
-		$folder->setDMS($this);
-		return $folder;
-	} /* }}} */
-
-	/**
-	 * Return a folder by its name
-	 *
-	 * This function retrieves a folder from the database by its name. The
-	 * search covers the whole database. If
-	 * the parameter $folder is not null, it will search for the name
-	 * only within this parent folder. It will not be done recursively.
-	 *
-	 * @param string $name name of the folder
-	 * @param object $folder parent folder
-	 * @return object/boolean found folder or false
-	 */
-	function getFolderByName($name, $folder=null) { /* {{{ */
-		if (!$name) return false;
-
-		$queryStr = "SELECT * FROM tblFolders WHERE name = " . $this->db->qstr($name);
-		if($folder)
-			$queryStr .= " AND `parent` = ". $folder->getID();
-		$queryStr .= " LIMIT 1";
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-
-		if(!$resArr)
-			return false;
-
-		$resArr = $resArr[0];
-		$folder = new LetoDMS_Core_Folder($resArr["id"], $resArr["name"], $resArr["parent"], $resArr["comment"], $resArr["date"], $resArr["owner"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr["sequence"]);
-		$folder->setDMS($this);
-		return $folder;
-	} /* }}} */
-
-	/**
-	 * Return a user by its id
-	 *
-	 * This function retrieves a user from the database by its id.
-	 *
-	 * @param integer $id internal id of user
-	 * @return object instance of LetoDMS_Core_User or false
-	 */
-	function getUser($id) { /* {{{ */
-		if (!is_numeric($id))
-			return false;
-
-		$queryStr = "SELECT * FROM tblUsers WHERE id = " . (int) $id;
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false) return false;
-		if (count($resArr) != 1) return false;
-
-		$resArr = $resArr[0];
-
-		$user = new LetoDMS_Core_User($resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $resArr["role"], $resArr["hidden"]);
-		$user->setDMS($this);
-		return $user;
-	} /* }}} */
-
-	/**
-	 * Return a user by its login
-	 *
-	 * This function retrieves a user from the database by its login.
-	 * If the second optional parameter $email is not empty, the user must
-	 * also have the given email.
-	 *
-	 * @param string $login internal login of user
-	 * @param string $email email of user
-	 * @return object instance of LetoDMS_Core_User or false
-	 */
-	function getUserByLogin($login, $email='') { /* {{{ */
-		$queryStr = "SELECT * FROM tblUsers WHERE login = ".$this->db->qstr($login);
-		if($email)
-			$queryStr .= " AND email=".$this->db->qstr($email);
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false) return false;
-		if (count($resArr) != 1) return false;
-
-		$resArr = $resArr[0];
-
-		$user = new LetoDMS_Core_User($resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $resArr["role"], $resArr["hidden"]);
-		$user->setDMS($this);
-		return $user;
-	} /* }}} */
-
-	/**
-	 * Return a user by its email
-	 *
-	 * This function retrieves a user from the database by its email.
-	 * It is needed when the user requests a new password.
-	 *
-	 * @param integer $email email address of user
-	 * @return object instance of LetoDMS_Core_User or false
-	 */
-	function getUserByEmail($email) { /* {{{ */
-		$queryStr = "SELECT * FROM tblUsers WHERE email = ".$this->db->qstr($email);
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false) return false;
-		if (count($resArr) != 1) return false;
-
-		$resArr = $resArr[0];
-
-		$user = new LetoDMS_Core_User($resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $resArr["role"], $resArr["hidden"]);
-		$user->setDMS($this);
-		return $user;
-	} /* }}} */
-
-	/**
-	 * Return list of all users
-	 *
-	 * @return array of instances of LetoDMS_Core_User or false
-	 */
-	function getAllUsers() { /* {{{ */
-		$queryStr = "SELECT * FROM tblUsers ORDER BY login";
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-
-		$users = array();
-
-		for ($i = 0; $i < count($resArr); $i++) {
-			$user = new LetoDMS_Core_User($resArr[$i]["id"], $resArr[$i]["login"], $resArr[$i]["pwd"], $resArr[$i]["fullName"], $resArr[$i]["email"], (isset($resArr["language"])?$resArr["language"]:NULL), (isset($resArr["theme"])?$resArr["theme"]:NULL), $resArr[$i]["comment"], $resArr[$i]["role"], $resArr[$i]["hidden"]);
-			$user->setDMS($this);
-			$users[$i] = $user;
-		}
-
-		return $users;
-	} /* }}} */
-
-	/**
-	 * Add a new user
-	 *
-	 * @param string $login login name
-	 * @param string $pwd password of new user
-	 * @param string $email Email of new user
-	 * @param string $language language of new user
-	 * @param string $comment comment of new user
-	 * @param integer $role role of new user (can be 0=normal, 1=admin, 2=guest)
-	 * @param integer $isHidden hide user in all lists, if this is set login
-	 *        is still allowed
-	 * @return object of LetoDMS_Core_User
-	 */
-	function addUser($login, $pwd, $fullName, $email, $language, $theme, $comment, $role='0', $isHidden=0) { /* {{{ */
-		if (is_object($this->getUserByLogin($login))) {
-			return false;
-		}
-		if($role == '')
-			$role = '0';
-		$queryStr = "INSERT INTO tblUsers (login, pwd, fullName, email, language, theme, comment, role, hidden) VALUES ('".$login."', '".$pwd."', '".$fullName."', '".$email."', '".$language."', '".$theme."', '".$comment."', '".$role."', '".$isHidden."')";
-		$res = $this->db->getResult($queryStr);
-		if (!$res)
-			return false;
-
-		return $this->getUser($this->db->getInsertID());
-	} /* }}} */
-
-	/**
-	 * Get a group by its id
-	 *
-	 * @param integer $id id of group
-	 * @return object/boolean group or false if no group was found
-	 */
-	function getGroup($id) { /* {{{ */
-		if (!is_numeric($id))
-			return false;
-
-		$queryStr = "SELECT * FROM tblGroups WHERE id = " . (int) $id;
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		else if (count($resArr) != 1) //wenn, dann wohl eher 0 als > 1 ;-)
-			return false;
-
-		$resArr = $resArr[0];
-
-		$group = new LetoDMS_Core_Group($resArr["id"], $resArr["name"], $resArr["comment"]);
-		$group->setDMS($this);
-		return $group;
-	} /* }}} */
-
-	/**
-	 * Get a group by its name
-	 *
-	 * @param string $name name of group
-	 * @return object/boolean group or false if no group was found
-	 */
-	function getGroupByName($name) { /* {{{ */
-		$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` WHERE `tblGroups`.`name` = ".$this->db->qstr($name);
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		else if (count($resArr) != 1) //wenn, dann wohl eher 0 als > 1 ;-)
-			return false;
-
-		$resArr = $resArr[0];
-
-		$group = new LetoDMS_Core_Group($resArr["id"], $resArr["name"], $resArr["comment"]);
-		$group->setDMS($this);
-		return $group;
-	} /* }}} */
-
-	/**
-	 * Get a list of all groups
-	 *
-	 * @return array array of instances of {@link LetoDMS_Core_Group}
-	 */
-	function getAllGroups() { /* {{{ */
-		$queryStr = "SELECT * FROM tblGroups ORDER BY name";
-		$resArr = $this->db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-
-		$groups = array();
-
-		for ($i = 0; $i < count($resArr); $i++) {
-
-			$group = new LetoDMS_Core_Group($resArr[$i]["id"], $resArr[$i]["name"], $resArr[$i]["comment"]);
-			$group->setDMS($this);
-			$groups[$i] = $group;
-		}
-
-		return $groups;
-	} /* }}} */
-
-	/**
-	 * Create a new user group
-	 *
-	 * @param string $name name of group
-	 * @param string $comment comment of group
-	 * @return object/boolean instance of {@link LetoDMS_Core_Group} or false in
-	 *         case of an error.
-	 */
-	function addGroup($name, $comment) { /* {{{ */
-		if (is_object($this->getGroupByName($name))) {
-			return false;
-		}
-
-		$queryStr = "INSERT INTO tblGroups (name, comment) VALUES ('".$name."', '" . $comment . "')";
-		if (!$this->db->getResult($queryStr))
-			return false;
-
-		return $this->getGroup($this->db->getInsertID());
-	} /* }}} */
-
-	function getKeywordCategory($id) { /* {{{ */
-		if (!is_numeric($id))
-			return false;
-
-		$queryStr = "SELECT * FROM tblKeywordCategories WHERE id = " . (int) $id;
-		$resArr = $this->db->getResultArray($queryStr);
-		if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1))
-			return false;
-
-		$resArr = $resArr[0];
-		$cat = new LetoDMS_Core_Keywordcategory($resArr["id"], $resArr["owner"], $resArr["name"]);
-		$cat->setDMS($this);
-		return $cat;
-	} /* }}} */
-
-	function getKeywordCategoryByName($name, $owner) { /* {{{ */
-		$queryStr = "SELECT * FROM tblKeywordCategories WHERE name = " . $this->db->qstr($name) . " AND owner = " . (int) $owner;
-		$resArr = $this->db->getResultArray($queryStr);
-		if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1))
-			return false;
-
-		$resArr = $resArr[0];
-		$cat = new LetoDMS_Core_Keywordcategory($resArr["id"], $resArr["owner"], $resArr["name"]);
-		$cat->setDMS($this);
-		return $cat;
-	} /* }}} */
-
-	function getAllKeywordCategories($userIDs = array()) { /* {{{ */
-		$queryStr = "SELECT * FROM tblKeywordCategories";
-		if ($userIDs)
-			$queryStr .= " WHERE owner in (".implode(',', $userIDs).")";
-
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		$categories = array();
-		foreach ($resArr as $row) {
-			$cat = new LetoDMS_Core_KeywordCategory($row["id"], $row["owner"], $row["name"]);
-			$cat->setDMS($this);
-			array_push($categories, $cat);
-		}
-
-		return $categories;
-	} /* }}} */
-
-	function getAllUserKeywordCategories($userID) { /* {{{ */
-		$queryStr = "SELECT * FROM tblKeywordCategories";
-		if ($userID != -1)
-			$queryStr .= " WHERE owner = " . (int) $userID;
-
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		$categories = array();
-		foreach ($resArr as $row) {
-			$cat = new LetoDMS_Core_KeywordCategory($row["id"], $row["owner"], $row["name"]);
-			$cat->setDMS($this);
-			array_push($categories, $cat);
-		}
-
-		return $categories;
-	} /* }}} */
-
-	function addKeywordCategory($owner, $name) { /* {{{ */
-		if (is_object($this->getKeywordCategoryByName($name, $owner))) {
-			return false;
-		}
-		$queryStr = "INSERT INTO tblKeywordCategories (owner, name) VALUES ($owner, '$name')";
-		if (!$this->db->getResult($queryStr))
-			return false;
-
-		return $this->getKeywordCategory($this->db->getInsertID());
-	} /* }}} */
-
-	function getDocumentCategory($id) { /* {{{ */
-		if (!is_numeric($id))
-			return false;
-
-		$queryStr = "SELECT * FROM tblCategory WHERE id = " . (int) $id;
-		$resArr = $this->db->getResultArray($queryStr);
-		if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1))
-			return false;
-
-		$resArr = $resArr[0];
-		$cat = new LetoDMS_Core_DocumentCategory($resArr["id"], $resArr["name"]);
-		$cat->setDMS($this);
-		return $cat;
-	} /* }}} */
-
-	function getDocumentCategories() { /* {{{ */
-		$queryStr = "SELECT * FROM tblCategory";
-
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		$categories = array();
-		foreach ($resArr as $row) {
-			$cat = new LetoDMS_Core_DocumentCategory($row["id"], $row["name"]);
-			$cat->setDMS($this);
-			array_push($categories, $cat);
-		}
-
-		return $categories;
-	} /* }}} */
-
-	/**
-	 * Get a category by its name
-	 *
-	 * The name of a category is by default unique.
-	 *
-	 * @param string $name human readable name of category
-	 * @return object instance of LetoDMS_Core_DocumentCategory
-	 */
-	function getDocumentCategoryByName($name) { /* {{{ */
-		$queryStr = "SELECT * FROM tblCategory where name=".$this->db->qstr($name);
-
-		$resArr = $this->db->getResultArray($queryStr);
-		if (!$resArr)
-			return false;
-
-		$row = $resArr[0];
-		$cat = new LetoDMS_Core_DocumentCategory($row["id"], $row["name"]);
-		$cat->setDMS($this);
-
-		return $cat;
-	} /* }}} */
-
-	function addDocumentCategory($name) { /* {{{ */
-		if (is_object($this->getDocumentCategoryByName($name))) {
-			return false;
-		}
-		$queryStr = "INSERT INTO tblCategory (name) VALUES ('$name')";
-		if (!$this->db->getResult($queryStr))
-			return false;
-
-		return $this->getDocumentCategory($this->db->getInsertID());
-	} /* }}} */
-
-	/**
-	 * Get all notifications for a group
-	 *
-	 * @param object $group group for which notifications are to be retrieved
-	 * @param integer $type type of item (T_DOCUMENT or T_FOLDER)
-	 * @return array array of notifications
-	 */
-	function getNotificationsByGroup($group, $type=0) { /* {{{ */
-		$queryStr = "SELECT `tblNotify`.* FROM `tblNotify` ".
-		 "WHERE `tblNotify`.`groupID` = ". $group->getID();
-		if($type) {
-			$queryStr .= " AND `tblNotify`.`targetType` = ". (int) $type;
-		}
-
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		$notifications = array();
-		foreach ($resArr as $row) {
-			$not = new LetoDMS_Core_Notification($row["target"], $row["targetType"], $row["userID"], $row["groupID"]);
-			$not->setDMS($this);
-			array_push($notifications, $cat);
-		}
-
-		return $notifications;
-	} /* }}} */
-
-	/**
-	 * Get all notifications for a user
-	 *
-	 * @param object $user user for which notifications are to be retrieved
-	 * @param integer $type type of item (T_DOCUMENT or T_FOLDER)
-	 * @return array array of notifications
-	 */
-	function getNotificationsByUser($user, $type) { /* {{{ */
-		$queryStr = "SELECT `tblNotify`.* FROM `tblNotify` ".
-		 "WHERE `tblNotify`.`userID` = ". $user->getID();
-		if($type) {
-			$queryStr .= " AND `tblNotify`.`targetType` = ". (int) $type;
-		}
-
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		$notifications = array();
-		foreach ($resArr as $row) {
-			$not = new LetoDMS_Core_Notification($row["target"], $row["targetType"], $row["userID"], $row["groupID"]);
-			$not->setDMS($this);
-			array_push($notifications, $cat);
-		}
-
-		return $notifications;
-	} /* }}} */
-
-	/**
-	 * Create a token to request a new password.
-	 * This function will not delete the password but just creates an entry
-	 * in tblUserRequestPassword indicating a password request.
-	 *
-	 * @return string hash value of false in case of an error
-	 */
-	function createPasswordRequest($user) { /* {{{ */
-		$hash = md5(uniqid(time()));
-		$queryStr = "INSERT INTO tblUserPasswordRequest (userID, hash, `date`) VALUES (" . $user->getId() . ", '" . $hash ."', now())";
-		$resArr = $this->db->getResult($queryStr);
-		if (is_bool($resArr) && !$resArr) return false;
-		return $hash;
-
-	} /* }}} */
-
-	/**
-	 * Check if hash for a password request is valid.
-	 * This function searches a previously create password request and
-	 * returns the user.
-	 *
-	 * @param string $hash
-	 */
-	function checkPasswordRequest($hash) { /* {{{ */
-		/* Get the password request from the database */
-		$queryStr = "SELECT * FROM tblUserPasswordRequest where hash=".$this->db->qstr($hash);
-		$resArr = $this->db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		if (count($resArr) != 1)
-			return false;
-		$resArr = $resArr[0];
-
-		return $this->getUser($resArr['userID']);
-
-	} /* }}} */
-
-	/**
-	 * Delete a password request
-	 *
-	 * @param string $hash
-	 */
-	function deletePasswordRequest($hash) { /* {{{ */
-		/* Delete the request, so nobody can use it a second time */
-		$queryStr = "DELETE FROM tblUserPasswordRequest WHERE hash=".$this->db->qstr($hash);
-		if (!$this->db->getResult($queryStr))
-			return false;
-		return true;
-	}
-}
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassDocumentCategory.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassDocumentCategory.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassDocumentCategory.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassDocumentCategory.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,118 +0,0 @@
-<?php
-/**
- * Implementation of document categories in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Class to represent a document category in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C)2011 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_DocumentCategory {
-	/**
-	 * @var integer $_id id of document category
-	 * @access protected
-	 */
-	var $_id;
-
-	/**
-	 * @var string $_name name of category
-	 * @access protected
-	 */
-	var $_name;
-
-	/**
-	 * @var object $_dms reference to dms this category belongs to
-	 * @access protected
-	 */
-	var $_dms;
-
-	function LetoDMS_Core_DocumentCategory($id, $name) {
-		$this->_id = $id;
-		$this->_name = $name;
-		$this->_dms = null;
-	}
-
-	function setDMS($dms) {
-		$this->_dms = $dms;
-	}
-
-	function getID() { return $this->_id; }
-
-	function getName() { return $this->_name; }
-
-	function setName($newName) {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblCategory SET name = ".$db->qstr($newName)." WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_name = $newName;
-		return true;
-	}
-
-	function isUsed() {
-		$db = $this->_dms->getDB();
-		
-		$queryStr = "SELECT * FROM tblDocumentCategory WHERE categoryID=".$this->_id;
-		$resArr = $db->getResultArray($queryStr);
-		if (is_array($resArr) && count($resArr) == 0)
-			return false;
-		return true;
-	}
-
-	function getCategories() {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT * FROM tblCategory";
-		return $db->getResultArray($queryStr);
-	}
-
-	function addCategory($keywords) {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "INSERT INTO tblCategory (category) VALUES (".$db->qstr($keywords).")";
-		return $db->getResult($queryStr);
-	}
-
-	function remove() {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE FROM tblCategory WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		return true;
-	}
-
-	function getDocumentsByCategory() {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT * FROM tblDocumentCategory where categoryID=".$this->_id;
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		$documents = array();
-		foreach ($resArr as $row) {
-			array_push($documents, $this->_dms->getDocument($row["id"]));
-		}
-		return $documents;
-	}
-
-}
-
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassDocument.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassDocument.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassDocument.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassDocument.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,2735 +0,0 @@
-<?php
-/**
- * Implementation of a document in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL2
- * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
- *             Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * The different states a document can be in
- */
-define("S_DRAFT_REV", 0);
-define("S_DRAFT_APP", 1);
-define("S_RELEASED",  2);
-define("S_REJECTED", -1);
-define("S_OBSOLETE", -2);
-define("S_EXPIRED",  -3);
-
-/**
- * Class to represent a document in the document management system
- *
- * A document in LetoDMS is similar to files in a regular file system.
- * Documents may have any number of content elements
- * ({@link LetoDMS_Core_DocumentContent}). These content elements are often
- * called versions ordered in a timely manner. The most recent content element
- * is the current version.
- *
- * Documents can be linked to other documents and can have attached files.
- * The document content can be anything that can be stored in a regular
- * file.
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
- *             Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_Document { /* {{{ */
-	/**
-	 * @var integer unique id of document
-	 */
-	var $_id;
-
-	/**
-	 * @var string name of document
-	 */
-	var $_name;
-
-	/**
-	 * @var string comment of document
-	 */
-	var $_comment;
-
-	/**
-	 * @var integer unix timestamp of creation date
-	 */
-	var $_date;
-
-	/**
-	 * @var integer id of user who is the owner
-	 */
-	var $_ownerID;
-
-	/**
-	 * @var integer id of folder this document belongs to
-	 */
-	var $_folderID;
-
-	/**
-	 * @var integer timestamp of expiration date
-	 */
-	var $_expires;
-
-	/**
-	 * @var boolean true if access is inherited, otherwise false
-	 */
-	var $_inheritAccess;
-
-	/**
-	 * @var integer default access if access rights are not inherited
-	 */
-	var $_defaultAccess;
-
-	/**
-	 * @var array list of notifications for users and groups
-	 */
-	var $_notifyList;
-
-	/**
-	 * @var boolean true if document is locked, otherwise false
-	 */
-	var $_locked;
-
-	/**
-	 * @var string list of keywords
-	 */
-	var $_keywords;
-
-	/**
-	 * @var array list of categories
-	 */
-	var $_categories;
-
-	/**
-	 * @var integer position of document within the parent folder
-	 */
-	var $_sequence;
-
-	/**
-	 * @var object back reference to document management system
-	 */
-	var $_dms;
-
-	function LetoDMS_Core_Document($id, $name, $comment, $date, $expires, $ownerID, $folderID, $inheritAccess, $defaultAccess, $locked, $keywords, $sequence) { /* {{{ */
-		$this->_id = $id;
-		$this->_name = $name;
-		$this->_comment = $comment;
-		$this->_date = $date;
-		$this->_expires = $expires;
-		$this->_ownerID = $ownerID;
-		$this->_folderID = $folderID;
-		$this->_inheritAccess = $inheritAccess;
-		$this->_defaultAccess = $defaultAccess;
-		$this->_locked = ($locked == null || $locked == '' ? -1 : $locked);
-		$this->_keywords = $keywords;
-		$this->_sequence = $sequence;
-		$this->_categories = array();
-		$this->_notifyList = array();
-		$this->_dms = null;
-	} /* }}} */
-
-	/*
-	 * Set dms this document belongs to.
-	 *
-	 * Each document needs a reference to the dms it belongs to. It will be
-	 * set when the folder is created by LetoDMS::getDocument() or
-	 * LetoDMS::search(). The dms has a
-	 * references to the currently logged in user and the database connection.
-	 *
-	 * @param object $dms reference to dms
-	 */
-	function setDMS($dms) { /* {{{ */
-		$this->_dms = $dms;
-	} /* }}} */
-
-	/*
-	 * Return the directory of the document in the file system relativ
-	 * to the contentDir
-	 *
-	 * @return string directory of document
-	 */
-	function getDir() { /* {{{ */
-		if($this->_dms->maxDirID) {
-			$dirid = (int) (($this->_id-1) / $this->_dms->maxDirID) + 1; 
-			return $dirid."/".$this->_id."/";
-		} else {
-			return $this->_id."/";
-		}
-	} /* }}} */
-
-	/*
-	 * Return the internal id of the document
-	 *
-	 * @return integer id of document
-	 */
-	function getID() { return $this->_id; }
-
-	/*
-	 * Return the name of the document
-	 *
-	 * @return string name of document
-	 */
-	function getName() { return $this->_name; }
-
-	/*
-	 * Set the name of the document
-	 *
-	 * @param $newName string new name of document
-	 */
-	function setName($newName) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocuments SET name = ".$db->qstr($newName)." WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_name = $newName;
-		return true;
-	} /* }}} */
-
-	/*
-	 * Return the comment of the document
-	 *
-	 * @return string comment of document
-	 */
-	function getComment() { return $this->_comment; }
-
-	/*
-	 * Set the comment of the document
-	 *
-	 * @param $newComment string new comment of document
-	 */
-	function setComment($newComment) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocuments SET comment = ".$db->qstr($newComment)." WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_comment = $newComment;
-		return true;
-	} /* }}} */
-
-	function getKeywords() { return $this->_keywords; }
-
-	function setKeywords($newKeywords) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocuments SET keywords = ".$db->qstr($newKeywords)." WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_keywords = $newKeywords;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Retrieve a list of all categories this document belongs to
-	 *
-	 * @return array list of category objects
-	 */
-	function getCategories() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if(!$this->_categories) {
-			$queryStr = "SELECT * FROM tblCategory where id in (select categoryID from tblDocumentCategory where documentID = ".$this->_id.")";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$resArr)
-				return false;
-
-			foreach ($resArr as $row) {
-				$cat = new LetoDMS_Core_DocumentCategory($row['id'], $row['name']);
-				$cat->setDMS($this->_dms);
-				$this->_categories[] = $cat;
-			}
-		}
-		return $this->_categories;
-	} /* }}} */
-
-	/**
-	 * Set a list of categories for the document
-	 * This function will delete currently assigned categories and sets new
-	 * categories.
-	 *
-	 * @param array $newCategories list of category objects
-	 */
-	function setCategories($newCategories) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE from tblDocumentCategory WHERE documentID = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		foreach($newCategories as $cat) {
-			$queryStr = "INSERT INTO tblDocumentCategory (categoryID, documentID) VALUES (". $cat->getId() .", ". $this->_id .")";
-			if (!$db->getResult($queryStr))
-				return false;
-		}
-
-		$this->_categories = $newCategories;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Return creation date of the document
-	 *
-	 * @return integer unix timestamp of creation date
-	 */
-	function getDate() { /* {{{ */
-		return $this->_date;
-	} /* }}} */
-
-	/**
-	 * Return the parent folder of the document
-	 *
-	 * @return object parent folder
-	 */
-	function getFolder() { /* {{{ */
-		if (!isset($this->_folder))
-			$this->_folder = $this->_dms->getFolder($this->_folderID);
-		return $this->_folder;
-	} /* }}} */
-
-	/**
-	 * Set folder of a document
-	 *
-	 * This function basically moves a document from a folder to another
-	 * folder.
-	 *
-	 * @param object $newFolder
-	 * @return boolean false in case of an error, otherwise true
-	 */
-	function setFolder($newFolder) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocuments SET folder = " . $newFolder->getID() . " WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$this->_folderID = $newFolder->getID();
-		$this->_folder = $newFolder;
-
-		// Make sure that the folder search path is also updated.
-		$path = $newFolder->getPath();
-		$flist = "";
-		foreach ($path as $f) {
-			$flist .= ":".$f->getID();
-		}
-		if (strlen($flist)>1) {
-			$flist .= ":";
-		}
-		$queryStr = "UPDATE tblDocuments SET folderList = '" . $flist . "' WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Return owner of document
-	 *
-	 * @return object owner of document as an instance of {@link LetoDMS_Core_User}
-	 */
-	function getOwner() { /* {{{ */
-		if (!isset($this->_owner))
-			$this->_owner = $this->_dms->getUser($this->_ownerID);
-		return $this->_owner;
-	} /* }}} */
-
-	/**
-	 * Set owner of a document
-	 *
-	 * @param object $newOwner new owner
-	 * @return boolean true if successful otherwise false
-	 */
-	function setOwner($newOwner) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocuments set owner = " . $newOwner->getID() . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_ownerID = $newOwner->getID();
-		$this->_owner = $newOwner;
-		return true;
-	} /* }}} */
-
-	function getDefaultAccess() { /* {{{ */
-		if ($this->inheritsAccess()) {
-			$res = $this->getFolder();
-			if (!$res) return false;
-			return $this->_folder->getDefaultAccess();
-		}
-		return $this->_defaultAccess;
-	} /* }}} */
-
-	function setDefaultAccess($mode) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocuments set defaultAccess = " . (int) $mode . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_defaultAccess = $mode;
-
-		// If any of the notification subscribers no longer have read access,
-		// remove their subscription.
-		foreach ($this->_notifyList["users"] as $u) {
-			if ($this->getAccessMode($u) < M_READ) {
-				$this->removeNotify($u->getID(), true);
-			}
-		}
-		foreach ($this->_notifyList["groups"] as $g) {
-			if ($this->getGroupAccessMode($g) < M_READ) {
-				$this->removeNotify($g->getID(), false);
-			}
-		}
-
-		return true;
-	} /* }}} */
-
-	function inheritsAccess() { return $this->_inheritAccess; }
-
-	/**
-	 * Set inherited access mode
-	 * Setting inherited access mode will set or unset the internal flag which
-	 * controls if the access mode is inherited from the parent folder or not.
-	 * It will not modify the
-	 * access control list for the current object. It will remove all
-	 * notifications of users which do not even have read access anymore
-	 * after setting or unsetting inherited access.
-	 *
-	 * @param boolean $inheritAccess set to true for setting and false for
-	 *        unsetting inherited access mode
-	 * @return boolean true if operation was successful otherwise false
-	 */
-	function setInheritAccess($inheritAccess) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocuments SET inheritAccess = " . ($inheritAccess ? "1" : "0") . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_inheritAccess = ($inheritAccess ? "1" : "0");
-
-		// If any of the notification subscribers no longer have read access,
-		// remove their subscription.
-		if(isset($this->_notifyList["users"])) {
-			foreach ($this->_notifyList["users"] as $u) {
-				if ($this->getAccessMode($u) < M_READ) {
-					$this->removeNotify($u->getID(), true);
-				}
-			}
-		}
-		if(isset($this->_notifyList["groups"])) {
-			foreach ($this->_notifyList["groups"] as $g) {
-				if ($this->getGroupAccessMode($g) < M_READ) {
-					$this->removeNotify($g->getID(), false);
-				}
-			}
-		}
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Check if document expires
-	 *
-	 * @return boolean true if document has expiration date set, otherwise false
-	 */
-	function expires() { /* {{{ */
-		if (intval($this->_expires) == 0)
-			return false;
-		else
-			return true;
-	} /* }}} */
-
-	/**
-	 * Get expiration time of document
-	 *
-	 * @return integer/boolean expiration date as unix timestamp or false
-	 */
-	function getExpires() { /* {{{ */
-		if (intval($this->_expires) == 0)
-			return false;
-		else
-			return $this->_expires;
-	} /* }}} */
-
-	/**
-	 * Set expiration date as unix timestamp
-	 *
-	 * @param integer unix timestamp of expiration date
-	 */
-	function setExpires($expires) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$expires = (!$expires) ? 0 : $expires;
-
-		if ($expires == $this->_expires) {
-			// No change is necessary.
-			return true;
-		}
-
-		$queryStr = "UPDATE tblDocuments SET expires = " . (int) $expires . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_expires = $expires;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Check if the document has expired
-	 *
-	 * @return boolean true if document has expired otherwise false
-	 */
-	function hasExpired() { /* {{{ */
-		if (intval($this->_expires) == 0) return false;
-		if (time()>$this->_expires+24*60*60) return true;
-		return false;
-	} /* }}} */
-
-	// return true if status has changed (to reload page)
-	function verifyLastestContentExpriry(){ /* {{{ */
-		$lc=$this->getLatestContent();
-		if($lc) {
-			$st=$lc->getStatus();
-
-			if (($st["status"]==S_DRAFT_REV || $st["status"]==S_DRAFT_APP) && $this->hasExpired()){
-				$lc->setStatus(S_EXPIRED,"", $this->getOwner());
-				return true;
-			}
-			else if ($st["status"]==S_EXPIRED && !$this->hasExpired() ){
-				$lc->verifyStatus(true, $this->getOwner());
-				return true;
-			}
-		}
-		return false;
-	} /* }}} */
-
-	/**
-	 * Check if document is locked
-	 *
-	 * @return boolean true if locked otherwise false
-	 */
-	function isLocked() { return $this->_locked != -1; }
-
-	/**
-	 * Lock or unlock document
-	 *
-	 * @param $falseOrUser user object for locking or false for unlocking
-	 * @return boolean true if operation was successful otherwise false
-	 */
-	function setLocked($falseOrUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$lockUserID = -1;
-		if (is_bool($falseOrUser) && !$falseOrUser) {
-			$queryStr = "DELETE FROM tblDocumentLocks WHERE document = ".$this->_id;
-		}
-		else if (is_object($falseOrUser)) {
-			$queryStr = "INSERT INTO tblDocumentLocks (document, userID) VALUES (".$this->_id.", ".$falseOrUser->getID().")";
-			$lockUserID = $falseOrUser->getID();
-		}
-		else {
-			return false;
-		}
-		if (!$db->getResult($queryStr)) {
-			return false;
-		}
-		unset($this->_lockingUser);
-		$this->_locked = $lockUserID;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Get the user currently locking the document
-	 *
-	 * @return object user have a lock
-	 */
-	function getLockingUser() { /* {{{ */
-		if (!$this->isLocked())
-			return false;
-
-		if (!isset($this->_lockingUser))
-			$this->_lockingUser = $this->_dms->getUser($this->_locked);
-		return $this->_lockingUser;
-	} /* }}} */
-
-	function getSequence() { return $this->_sequence; }
-
-	function setSequence($seq) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocuments SET sequence = " . $seq . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_sequence = $seq;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Delete all entries for this document from the access control list
-	 *
-	 * @return boolean true if operation was successful otherwise false
-	 */
-	function clearAccessList() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE FROM tblACLs WHERE targetType = " . T_DOCUMENT . " AND target = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_accessList);
-		return true;
-	} /* }}} */
-
-	/**
-	 * Returns a list of access privileges
-	 *
-	 * If the document inherits the access privileges from the parent folder
-	 * those will be returned.
-	 * $mode and $op can be set to restrict the list of returned access
-	 * privileges. If $mode is set to M_ANY no restriction will apply
-	 * regardless of the value of $op. The returned array contains a list
-	 * of {@link LetoDMS_Core_UserAccess} and
-	 * {@link LetoDMS_Core_GroupAccess} objects.
-	 * 
-	 * @param integer $mode access mode (defaults to M_ANY)
-	 * @param integer $op operation (defaults to O_EQ)
-	 * @return array multi dimensional array
-	 */
-	function getAccessList($mode = M_ANY, $op = O_EQ) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if ($this->inheritsAccess()) {
-			$res = $this->getFolder();
-			if (!$res) return false;
-			return $this->_folder->getAccessList($mode, $op);
-		}
-
-		if (!isset($this->_accessList[$mode])) {
-			if ($op!=O_GTEQ && $op!=O_LTEQ && $op!=O_EQ) {
-				return false;
-			}
-			$modeStr = "";
-			if ($mode!=M_ANY) {
-				$modeStr = " AND mode".$op.(int)$mode;
-			}
-			$queryStr = "SELECT * FROM tblACLs WHERE targetType = ".T_DOCUMENT.
-				" AND target = " . $this->_id .	$modeStr . " ORDER BY targetType";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$resArr)
-				return false;
-
-			$this->_accessList[$mode] = array("groups" => array(), "users" => array());
-			foreach ($resArr as $row) {
-				if ($row["userID"] != -1)
-					array_push($this->_accessList[$mode]["users"], new LetoDMS_Core_UserAccess($this->_dms->getUser($row["userID"]), $row["mode"]));
-				else //if ($row["groupID"] != -1)
-					array_push($this->_accessList[$mode]["groups"], new LetoDMS_Core_GroupAccess($this->_dms->getGroup($row["groupID"]), $row["mode"]));
-			}
-		}
-
-		return $this->_accessList[$mode];
-	} /* }}} */
-
-	/**
-	 * Add access right to folder
-	 * This function may change in the future. Instead of passing the a flag
-	 * and a user/group id a user or group object will be expected.
-	 *
-	 * @param integer $mode access mode
-	 * @param integer $userOrGroupID id of user or group
-	 * @param integer $isUser set to 1 if $userOrGroupID is the id of a
-	 *        user
-	 */
-	function addAccess($mode, $userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		$queryStr = "INSERT INTO tblACLs (target, targetType, ".$userOrGroup.", mode) VALUES
-					(".$this->_id.", ".T_DOCUMENT.", " . (int) $userOrGroupID . ", " .(int) $mode. ")";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_accessList);
-
-		// Update the notify list, if necessary.
-		if ($mode == M_NONE) {
-			$this->removeNotify($userOrGroupID, $isUser);
-		}
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Change access right of document
-	 * This function may change in the future. Instead of passing the a flag
-	 * and a user/group id a user or group object will be expected.
-	 *
-	 * @param integer $newMode access mode
-	 * @param integer $userOrGroupID id of user or group
-	 * @param integer $isUser set to 1 if $userOrGroupID is the id of a
-	 *        user
-	 */
-	function changeAccess($newMode, $userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		$queryStr = "UPDATE tblACLs SET mode = " . (int) $newMode . " WHERE targetType = ".T_DOCUMENT." AND target = " . $this->_id . " AND " . $userOrGroup . " = " . (int) $userOrGroupID;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_accessList);
-
-		// Update the notify list, if necessary.
-		if ($newMode == M_NONE) {
-			$this->removeNotify($userOrGroupID, $isUser);
-		}
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Remove access rights for a user or group
-	 *
-	 * @param integer $userOrGroupID ID of user or group
-	 * @param boolean $isUser true if $userOrGroupID is a user id, false if it
-	 *        is a group id.
-	 * @return boolean true on success, otherwise false
-	 */
-	function removeAccess($userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		$queryStr = "DELETE FROM tblACLs WHERE targetType = ".T_DOCUMENT." AND target = ".$this->_id." AND ".$userOrGroup." = " . (int) $userOrGroupID;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_accessList);
-
-		// Update the notify list, if the user looses access rights.
-		$mode = ($isUser ? $this->getAccessMode($this->_dms->getUser($userOrGroupID)) : $this->getGroupAccessMode($this->_dms->getGroup($userOrGroupID)));
-		if ($mode == M_NONE) {
-			$this->removeNotify($userOrGroupID, $isUser);
-		}
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Returns the greatest access privilege for a given user
-	 *
-	 * This function searches the access control list for entries of
-	 * user $user. If it finds more than one entry it will return the
-	 * one allowing the greatest privileges. If there is no entry in the
-	 * access control list, it will return the default access mode.
-	 * The function takes inherited access rights into account.
-	 * For a list of possible access rights see @file inc.AccessUtils.php
-	 *
-	 * @param $user object instance of class LetoDMS_Core_User
-	 * @return integer access mode
-	 */
-	function getAccessMode($user) { /* {{{ */
-		/* Administrators have unrestricted access */
-		if ($user->isAdmin()) return M_ALL;
-
-		/* The owner of the document has unrestricted access */
-		if ($user->getID() == $this->_ownerID) return M_ALL;
-
-		/* The guest users do not have more than read access */
-		if ($user->isGuest()) {
-			$mode = $this->getDefaultAccess();
-			if ($mode >= M_READ) return M_READ;
-			else return M_NONE;
-		}
-
-		/* Check ACLs */
-		$accessList = $this->getAccessList();
-		if (!$accessList) return false;
-
-		foreach ($accessList["users"] as $userAccess) {
-			if ($userAccess->getUserID() == $user->getID()) {
-				return $userAccess->getMode();
-			}
-		}
-		foreach ($accessList["groups"] as $groupAccess) {
-			if ($user->isMemberOfGroup($groupAccess->getGroup())) {
-//				if ($groupAccess->getMode()>$result)
-					return $groupAccess->getMode();
-			}
-		}
-		$result = $this->getDefaultAccess();
-		return $result;
-	} /* }}} */
-
-	/**
-	 * Returns the greatest access privilege for a given group
-	 *
-	 * This function searches the access control list for entries of
-	 * group $group. If it finds more than one entry it will return the
-	 * one allowing the greatest privileges. If there is no entry in the
-	 * access control list, it will return the default access mode.
-	 * The function takes inherited access rights into account.
-	 * For a list of possible access rights see @file inc.AccessUtils.php
-	 *
-	 * @param $group object instance of class LetoDMS_Core_Group
-	 * @return integer access mode
-	 */
-	function getGroupAccessMode($group) { /* {{{ */
-		$highestPrivileged = M_NONE;
-
-		//ACLs durchforsten
-		$foundInACL = false;
-		$accessList = $this->getAccessList();
-		if (!$accessList)
-			return false;
-
-		foreach ($accessList["groups"] as $groupAccess) {
-			if ($groupAccess->getGroupID() == $group->getID()) {
-				$foundInACL = true;
-				if ($groupAccess->getMode() > $highestPrivileged)
-					$highestPrivileged = $groupAccess->getMode();
-				if ($highestPrivileged == M_ALL) // max access right -> skip the rest
-					return $highestPrivileged;
-			}
-		}
-
-		if ($foundInACL)
-			return $highestPrivileged;
-
-		//Standard-Berechtigung verwenden
-		return $this->getDefaultAccess();
-	} /* }}} */
-
-	/**
-	 * Returns a list of all notifications
-	 *
-	 * The returned list has two elements called 'users' and 'groups'. Each one
-	 * is an array itself countaining objects of class LetoDMS_Core_User and
-	 * LetoDMS_Core_Group.
-	 *
-	 * @return array list of notifications
-	 */
-	function getNotifyList() { /* {{{ */
-		if (empty($this->_notifyList)) {
-			$db = $this->_dms->getDB();
-
-			$queryStr ="SELECT * FROM tblNotify WHERE targetType = " . T_DOCUMENT . " AND target = " . $this->_id;
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && $resArr == false)
-				return false;
-
-			$this->_notifyList = array("groups" => array(), "users" => array());
-			foreach ($resArr as $row)
-			{
-				if ($row["userID"] != -1)
-					array_push($this->_notifyList["users"], $this->_dms->getUser($row["userID"]) );
-				else //if ($row["groupID"] != -1)
-					array_push($this->_notifyList["groups"], $this->_dms->getGroup($row["groupID"]) );
-			}
-		}
-		return $this->_notifyList;
-	} /* }}} */
-
-	/**
-	 * Add a user/group to the notification list
-	 * This function does not check if the currently logged in user
-	 * is allowed to add a notification. This must be checked by the calling
-	 * application.
-	 *
-	 * @param $userOrGroupID integer id of user or group to add
-	 * @param $isUser integer 1 if $userOrGroupID is a user,
-	 *                0 if $userOrGroupID is a group
-	 * @return integer  0: Update successful.
-	 *                 -1: Invalid User/Group ID.
-	 *                 -2: Target User / Group does not have read access.
-	 *                 -3: User is already subscribed.
-	 *                 -4: Database / internal error.
-	 */
-	function addNotify($userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$userOrGroup = ($isUser ? "userID" : "groupID");
-
-		/* Verify that user / group exists. */
-		$obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
-		if (!is_object($obj)) {
-			return -1;
-		}
-
-		/* Verify that the requesting user has permission to add the target to
-		 * the notification system.
-		 */
-		/*
-		 * The calling application should enforce the policy on who is allowed
-		 * to add someone to the notification system. If is shall remain here
-		 * the currently logged in user should be passed to this function
-		 *
-		GLOBAL $user;
-		if ($user->isGuest()) {
-			return -2;
-		}
-		if (!$user->isAdmin()) {
-			if ($isUser) {
-				if ($user->getID() != $obj->getID()) {
-					return -2;
-				}
-			}
-			else {
-				if (!$obj->isMember($user)) {
-					return -2;
-				}
-			}
-		}
-		 */
-
-		/* Verify that target user / group has read access to the document. */
-		if ($isUser) {
-			// Users are straightforward to check.
-			if ($this->getAccessMode($obj) < M_READ) {
-				return -2;
-			}
-		}
-		else {
-			// Groups are a little more complex.
-			if ($this->getDefaultAccess() >= M_READ) {
-				// If the default access is at least READ-ONLY, then just make sure
-				// that the current group has not been explicitly excluded.
-				$acl = $this->getAccessList(M_NONE, O_EQ);
-				$found = false;
-				foreach ($acl["groups"] as $group) {
-					if ($group->getGroupID() == $userOrGroupID) {
-						$found = true;
-						break;
-					}
-				}
-				if ($found) {
-					return -2;
-				}
-			}
-			else {
-				// The default access is restricted. Make sure that the group has
-				// been explicitly allocated access to the document.
-				$acl = $this->getAccessList(M_READ, O_GTEQ);
-				if (is_bool($acl)) {
-					return -4;
-				}
-				$found = false;
-				foreach ($acl["groups"] as $group) {
-					if ($group->getGroupID() == $userOrGroupID) {
-						$found = true;
-						break;
-					}
-				}
-				if (!$found) {
-					return -2;
-				}
-			}
-		}
-		/* Check to see if user/group is already on the list. */
-		$queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
-			"AND `tblNotify`.`targetType` = '".T_DOCUMENT."' ".
-			"AND `tblNotify`.`".$userOrGroup."` = '".(int) $userOrGroupID."'";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr)) {
-			return -4;
-		}
-		if (count($resArr)>0) {
-			return -3;
-		}
-
-		$queryStr = "INSERT INTO tblNotify (target, targetType, " . $userOrGroup . ") VALUES (" . $this->_id . ", " . T_DOCUMENT . ", " . (int) $userOrGroupID . ")";
-		if (!$db->getResult($queryStr))
-			return -4;
-
-		unset($this->_notifyList);
-		return 0;
-	} /* }}} */
-
-	/**
-	 * Remove a user or group from the notification list
-	 * This function does not check if the currently logged in user
-	 * is allowed to remove a notification. This must be checked by the calling
-	 * application.
-	 *
-	 * @param $userOrGroupID id of user or group
-	 * @param $isUser boolean true if a user is passed in $userOrGroupID, false
-	 *        if a group is passed in $userOrGroupID
-	 * @return integer 0 if operation was succesful
-	 *                 -1 if the userid/groupid is invalid
-	 *                 -3 if the user/group is already subscribed
-	 *                 -4 in case of an internal database error
-	 */
-	function removeNotify($userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		/* Verify that user / group exists. */
-		$obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
-		if (!is_object($obj)) {
-			return -1;
-		}
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		/* Verify that the requesting user has permission to add the target to
-		 * the notification system.
-		 */
-		/*
-		 * The calling application should enforce the policy on who is allowed
-		 * to add someone to the notification system. If is shall remain here
-		 * the currently logged in user should be passed to this function
-		 *
-		GLOBAL $user;
-		if ($user->isGuest()) {
-			return -2;
-		}
-		if (!$user->isAdmin()) {
-			if ($isUser) {
-				if ($user->getID() != $obj->getID()) {
-					return -2;
-				}
-			}
-			else {
-				if (!$obj->isMember($user)) {
-					return -2;
-				}
-			}
-		}
-		 */
-
-		/* Check to see if the target is in the database. */
-		$queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
-			"AND `tblNotify`.`targetType` = '".T_DOCUMENT."' ".
-			"AND `tblNotify`.`".$userOrGroup."` = '".(int) $userOrGroupID."'";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr)) {
-			return -4;
-		}
-		if (count($resArr)==0) {
-			return -3;
-		}
-
-		$queryStr = "DELETE FROM tblNotify WHERE target = " . $this->_id . " AND targetType = " . T_DOCUMENT . " AND " . $userOrGroup . " = " . (int) $userOrGroupID;
-		if (!$db->getResult($queryStr))
-			return -4;
-
-		unset($this->_notifyList);
-		return 0;
-	} /* }}} */
-
-	/**
-	 * Add content to a document
-	 *
-	 * Each document may have any number of content elements attached to it.
-	 * Each content element has a version number. Newer versions (greater
-	 * version number) replace older versions.
-	 *
-	 * @param string $comment comment
-	 * @param object $user user who shall be the owner of this content
-	 * @param string $tmpFile file containing the actuall content
-	 * @param string $orgFileName original file name
-	 * @param string $mimeType MimeType of the content
-	 * @param array $reviewers list of reviewers
-	 * @param array $approvers list of approvers
-	 * @param integer $version version number of content or 0 if next higher version shall be used.
-	 * @return bool/array false in case of an error or a result set
-	 */
-	function addContent($comment, $user, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers=array(), $approvers=array(), $version=0) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		// the doc path is id/version.filetype
-		$dir = $this->getDir();
-
-		$date = mktime();
-
-		/* The version field in table tblDocumentContent used to be auto
-		 * increment but that requires the field to be primary as well if
-		 * innodb is used. That's why the version is now determined here.
-		 */
-		if ((int)$version<1) {
-			$queryStr = "SELECT MAX(version) as m from tblDocumentContent where document = ".$this->_id;
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$res)
-				return false;
-
-			$version = $resArr[0]['m']+1;
-		}
-
-		$queryStr = "INSERT INTO tblDocumentContent (document, version, comment, date, createdBy, dir, orgFileName, fileType, mimeType) VALUES ".
-						"(".$this->_id.", ".(int)$version.",".$db->qstr($comment).", ".$date.", ".$user->getID().", ".$db->qstr($dir).", ".$db->qstr($orgFileName).", ".$db->qstr($fileType).", ".$db->qstr($mimeType).")";
-		if (!$db->getResult($queryStr)) return false;
-
-		// copy file
-		if (!LetoDMS_Core_File::makeDir($this->_dms->contentDir . $dir)) return false;
-		if (!LetoDMS_Core_File::copyFile($tmpFile, $this->_dms->contentDir . $dir . $version . $fileType)) return false;
-
-		unset($this->_content);
-		unset($this->_latestContent);
-		$docResultSet = new LetoDMS_Core_AddContentResultSet(new LetoDMS_Core_DocumentContent($this, $version, $comment, $date, $user->getID(), $dir, $orgFileName, $fileType, $mimeType));
-
-		// TODO - verify
-		if ($this->_dms->enableConverting && in_array($docResultSet->_content->getFileType(), array_keys($this->_dms->convertFileTypes)))
-			$docResultSet->_content->convert(); // Even if if fails, do not return false
-
-		$queryStr = "INSERT INTO `tblDocumentStatus` (`documentID`, `version`) ".
-			"VALUES (". $this->_id .", ". (int) $version .")";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$statusID = $db->getInsertID();
-
-		// Add reviewers into the database. Reviewers must review the document
-		// and submit comments, if appropriate. Reviewers can also recommend that
-		// a document be rejected.
-		$pendingReview=false;
-		$reviewRes = array();
-		foreach (array("i", "g") as $i){
-			if (isset($reviewers[$i])) {
-				foreach ($reviewers[$i] as $reviewerID) {
-					$reviewer=($i=="i" ?$this->_dms->getUser($reviewerID) : $this->_dms->getGroup($reviewerID));
-					$res = ($i=="i" ? $docResultSet->_content->addIndReviewer($reviewer, $user, true) : $docResultSet->_content->addGrpReviewer($reviewer, $user, true));
-					$docResultSet->addReviewer($reviewer, $i, $res);
-					// If no error is returned, or if the error is just due to email
-					// failure, mark the state as "pending review".
-					if ($res==0 || $res=-3 || $res=-4) {
-						$pendingReview=true;
-					}
-				}
-			}
-		}
-		// Add approvers to the database. Approvers must also review the document
-		// and make a recommendation on its release as an approved version.
-		$pendingApproval=false;
-		$approveRes = array();
-		foreach (array("i", "g") as $i){
-			if (isset($approvers[$i])) {
-				foreach ($approvers[$i] as $approverID) {
-					$approver=($i=="i" ? $this->_dms->getUser($approverID) : $this->_dms->getGroup($approverID));
-					$res=($i=="i" ? $docResultSet->_content->addIndApprover($approver, $user, !$pendingReview) : $docResultSet->_content->addGrpApprover($approver, $user, !$pendingReview));
-					$docResultSet->addApprover($approver, $i, $res);
-					if ($res==0 || $res=-3 || $res=-4) {
-						$pendingApproval=true;
-					}
-				}
-			}
-		}
-
-		// If there are no reviewers or approvers, the document is automatically
-		// promoted to the released state.
-		if ($pendingReview) {
-			$status = S_DRAFT_REV;
-			$comment = "";
-		}
-		else if ($pendingApproval) {
-			$status = S_DRAFT_APP;
-			$comment = "";
-		}
-		else {
-			$status = S_RELEASED;
-			$comment="";
-		}
-		$queryStr = "INSERT INTO `tblDocumentStatusLog` (`statusID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $statusID ."', '". $status."', 'New document content submitted". $comment ."', NOW(), '". $user->getID() ."')";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$docResultSet->setStatus($status,$comment,$user);
-
-		return $docResultSet;
-	} /* }}} */
-
-	/**
-	 * Return all content elements of a document
-	 *
-	 * This functions returns an array of content elements ordered by version
-	 *
-	 * @return array list of objects of class LetoDMS_Core_DocumentContent
-	 */
-	function getContent() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!isset($this->_content)) {
-			$queryStr = "SELECT * FROM tblDocumentContent WHERE document = ".$this->_id." ORDER BY version";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$res)
-				return false;
-
-			$this->_content = array();
-			foreach ($resArr as $row)
-				array_push($this->_content, new LetoDMS_Core_DocumentContent($this, $row["version"], $row["comment"], $row["date"], $row["createdBy"], $row["dir"], $row["orgFileName"], $row["fileType"], $row["mimeType"]));
-		}
-
-		return $this->_content;
-	} /* }}} */
-
-	/**
-	 * Return the content element of a document with a given version number
-	 *
-	 * @param integer $version version number of content element
-	 * @return object object of class LetoDMS_Core_DocumentContent
-	 */
-	function getContentByVersion($version) { /* {{{ */
-		if (!is_numeric($version)) return false;
-
-		if (isset($this->_content)) {
-			foreach ($this->_content as $revision) {
-				if ($revision->getVersion() == $version)
-					return $revision;
-			}
-			return false;
-		}
-
-		$db = $this->_dms->getDB();
-		$queryStr = "SELECT * FROM tblDocumentContent WHERE document = ".$this->_id." AND version = " . (int) $version;
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$res)
-			return false;
-		if (count($resArr) != 1)
-			return false;
-
-		$resArr = $resArr[0];
-		return new LetoDMS_Core_DocumentContent($this, $resArr["version"], $resArr["comment"], $resArr["date"], $resArr["createdBy"], $resArr["dir"], $resArr["orgFileName"], $resArr["fileType"], $resArr["mimeType"]);
-	} /* }}} */
-
-	function getLatestContent() { /* {{{ */
-		if (!isset($this->_latestContent)) {
-			$db = $this->_dms->getDB();
-			$queryStr = "SELECT * FROM tblDocumentContent WHERE document = ".$this->_id." ORDER BY version DESC LIMIT 0,1";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$resArr)
-				return false;
-			if (count($resArr) != 1)
-				return false;
-
-			$resArr = $resArr[0];
-			$this->_latestContent = new LetoDMS_Core_DocumentContent($this, $resArr["version"], $resArr["comment"], $resArr["date"], $resArr["createdBy"], $resArr["dir"], $resArr["orgFileName"], $resArr["fileType"], $resArr["mimeType"]);
-		}
-		return $this->_latestContent;
-	} /* }}} */
-
-	function removeContent($version) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$emailList = array();
-		$emailList[] = $version->_userID;
-
-		if (file_exists( $this->_dms->contentDir.$version->getPath() ))
-			if (!LetoDMS_Core_File::removeFile( $this->_dms->contentDir.$version->getPath() ))
-				return false;
-
-		$status = $version->getStatus();
-		$stID = $status["statusID"];
-
-		$queryStr = "DELETE FROM tblDocumentContent WHERE `document` = " . $this->getID() .	" AND `version` = " . $version->_version;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$queryStr = "DELETE FROM `tblDocumentStatusLog` WHERE `statusID` = '".$stID."'";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$queryStr = "DELETE FROM `tblDocumentStatus` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$status = $version->getReviewStatus();
-		$stList = "";
-		foreach ($status as $st) {
-			$stList .= (strlen($stList)==0 ? "" : ", "). "'".$st["reviewID"]."'";
-			if ($st["status"]==0 && !in_array($st["required"], $emailList)) {
-				$emailList[] = $st["required"];
-			}
-		}
-		if (strlen($stList)>0) {
-			$queryStr = "DELETE FROM `tblDocumentReviewLog` WHERE `tblDocumentReviewLog`.`reviewID` IN (".$stList.")";
-			if (!$db->getResult($queryStr))
-				return false;
-		}
-		$queryStr = "DELETE FROM `tblDocumentReviewers` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'";
-		if (!$db->getResult($queryStr))
-			return false;
-		$status = $version->getApprovalStatus();
-		$stList = "";
-		foreach ($status as $st) {
-			$stList .= (strlen($stList)==0 ? "" : ", "). "'".$st["approveID"]."'";
-			if ($st["status"]==0 && !in_array($st["required"], $emailList)) {
-				$emailList[] = $st["required"];
-			}
-		}
-		if (strlen($stList)>0) {
-			$queryStr = "DELETE FROM `tblDocumentApproveLog` WHERE `tblDocumentApproveLog`.`approveID` IN (".$stList.")";
-			if (!$db->getResult($queryStr))
-				return false;
-		}
-		$queryStr = "DELETE FROM `tblDocumentApprovers` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		return true;
-	} /* }}} */
-
-	function getDocumentLink($linkID) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!is_numeric($linkID)) return false;
-
-		$queryStr = "SELECT * FROM tblDocumentLinks WHERE document = " . $this->_id ." AND id = " . (int) $linkID;
-		$resArr = $db->getResultArray($queryStr);
-		if ((is_bool($resArr) && !$resArr) || count($resArr)==0)
-			return false;
-
-		$resArr = $resArr[0];
-		$document = $this->_dms->getDocument($resArr["document"]);
-		$target = $this->_dms->getDocument($resArr["target"]);
-		return new LetoDMS_Core_DocumentLink($resArr["id"], $document, $target, $resArr["userID"], $resArr["public"]);
-	} /* }}} */
-
-	function getDocumentLinks() { /* {{{ */
-		if (!isset($this->_documentLinks)) {
-			$db = $this->_dms->getDB();
-
-			$queryStr = "SELECT * FROM tblDocumentLinks WHERE document = " . $this->_id;
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$resArr)
-				return false;
-			$this->_documentLinks = array();
-
-			foreach ($resArr as $row) {
-				$target = $this->_dms->getDocument($row["target"]);
-				array_push($this->_documentLinks, new LetoDMS_Core_DocumentLink($row["id"], $this, $target, $row["userID"], $row["public"]));
-			}
-		}
-		return $this->_documentLinks;
-	} /* }}} */
-
-	function addDocumentLink($targetID, $userID, $public) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$public = ($public) ? "1" : "0";
-
-		$queryStr = "INSERT INTO tblDocumentLinks(document, target, userID, public) VALUES (".$this->_id.", ".(int)$targetID.", ".(int)$userID.", ".(int)$public.")";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_documentLinks);
-		return true;
-	} /* }}} */
-
-	function removeDocumentLink($linkID) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!is_numeric($linkID)) return false;
-
-		$queryStr = "DELETE FROM tblDocumentLinks WHERE document = " . $this->_id ." AND id = " . (int) $linkID;
-		if (!$db->getResult($queryStr)) return false;
-		unset ($this->_documentLinks);
-		return true;
-	} /* }}} */
-
-	function getDocumentFile($ID) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!is_numeric($ID)) return false;
-
-		$queryStr = "SELECT * FROM tblDocumentFiles WHERE document = " . $this->_id ." AND id = " . (int) $ID;
-		$resArr = $db->getResultArray($queryStr);
-		if ((is_bool($resArr) && !$resArr) || count($resArr)==0) return false;
-
-		$resArr = $resArr[0];
-		return new LetoDMS_Core_DocumentFile($resArr["id"], $this, $resArr["userID"], $resArr["comment"], $resArr["date"], $resArr["dir"], $resArr["fileType"], $resArr["mimeType"], $resArr["orgFileName"], $resArr["name"]);
-	} /* }}} */
-
-	function getDocumentFiles() { /* {{{ */
-		if (!isset($this->_documentFiles)) {
-			$db = $this->_dms->getDB();
-
-			$queryStr = "SELECT * FROM tblDocumentFiles WHERE document = " . $this->_id." ORDER BY `date` DESC";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$resArr) return false;
-
-			$this->_documentFiles = array();
-
-			foreach ($resArr as $row) {
-				array_push($this->_documentFiles, new LetoDMS_Core_DocumentFile($row["id"], $this, $row["userID"], $row["comment"], $row["date"], $row["dir"], $row["fileType"], $row["mimeType"], $row["orgFileName"], $row["name"]));
-			}
-		}
-		return $this->_documentFiles;
-	} /* }}} */
-
-	function addDocumentFile($name, $comment, $user, $tmpFile, $orgFileName,$fileType, $mimeType ) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$dir = $this->getDir();
-
-		$queryStr = "INSERT INTO tblDocumentFiles (comment, date, dir, document, fileType, mimeType, orgFileName, userID, name) VALUES ".
-			"(".$db->qstr($comment).", '".mktime()."', ".$db->qstr($dir).", ".$this->_id.", ".$db->qstr($fileType).", ".$db->qstr($mimeType).", ".$db->qstr($orgFileName).",".$user->getID().",".$db->qstr($name).")";
-		if (!$db->getResult($queryStr)) return false;
-
-		$id = $db->getInsertID();
-
-		$file = $this->getDocumentFile($id);
-		if (is_bool($file) && !$file) return false;
-
-		// copy file
-		if (!LetoDMS_Core_File::makeDir($this->_dms->contentDir . $dir)) return false;
-		if (!LetoDMS_Core_File::copyFile($tmpFile, $this->_dms->contentDir . $file->getPath() )) return false;
-
-		return true;
-	} /* }}} */
-
-	function removeDocumentFile($ID) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!is_numeric($ID)) return false;
-
-		$file = $this->getDocumentFile($ID);
-		if (is_bool($file) && !$file) return false;
-
-		if (file_exists( $this->_dms->contentDir . $file->getPath() )){
-			if (!LetoDMS_Core_File::removeFile( $this->_dms->contentDir . $file->getPath() ))
-				return false;
-		}
-
-		$name=$file->getName();
-		$comment=$file->getcomment();
-
-		$queryStr = "DELETE FROM tblDocumentFiles WHERE document = " . $this->getID() . " AND id = " . (int) $ID;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset ($this->_documentFiles);
-
-		return true;
-	} /* }}} */
-
-	function remove() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$res = $this->getContent();
-		if (is_bool($res) && !$res) return false;
-
-		// FIXME: call a new function removeContent instead
-		foreach ($this->_content as $version)
-			if (!$this->removeContent($version))
-				return false;
-
-		// remove document file
-		$res = $this->getDocumentFiles();
-		if (is_bool($res) && !$res) return false;
-
-		foreach ($res as $documentfile)
-			if(!$this->removeDocumentFile($documentfile->getId()))
-				return false;
-
-		// TODO: versioning file?
-
-		if (file_exists( $this->_dms->contentDir . $this->getDir() ))
-			if (!LetoDMS_Core_File::removeDir( $this->_dms->contentDir . $this->getDir() ))
-				return false;
-
-		$queryStr = "DELETE FROM tblDocuments WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblACLs WHERE target = " . $this->_id . " AND targetType = " . T_DOCUMENT;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblDocumentLinks WHERE document = " . $this->_id . " OR target = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblDocumentLocks WHERE document = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblDocumentFiles WHERE document = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblDocumentCategory WHERE documentID = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		// Delete the notification list.
-		$queryStr = "DELETE FROM tblNotify WHERE target = " . $this->_id . " AND targetType = " . T_DOCUMENT;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		return true;
-	} /* }}} */
-
-	function getApproversList() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!isset($this->_approversList)) {
-
-			$this->_approversList = array("groups" => array(), "users" => array());
-			$userIDs = "";
-			$groupIDs = "";
-			$defAccess  = $this->getDefaultAccess();
-
-			if ($defAccess<M_READ) {
-				// Get the list of all users and groups that are listed in the ACL as
-				// having read access to the document.
-				$tmpList = $this->getAccessList(M_READ, O_GTEQ);
-			}
-			else {
-				// Get the list of all users and groups that DO NOT have read access
-				// to the document.
-				$tmpList = $this->getAccessList(M_NONE, O_LTEQ);
-			}
-			foreach ($tmpList["groups"] as $group) {
-				$groupIDs .= (strlen($groupIDs)==0 ? "" : ", ") . $group->getGroupID();
-			}
-			foreach ($tmpList["users"] as $c_user) {
-
-				if (!$this->_dms->enableAdminRevApp && $c_user->isAdmin()) continue;
-				$userIDs .= (strlen($userIDs)==0 ? "" : ", ") . $c_user->getUserID();
-			}
-
-			// Construct a query against the users table to identify those users
-			// that have read access to this document, either directly through an
-			// ACL entry, by virtue of ownership or by having administrative rights
-			// on the database.
-			$queryStr="";
-			if ($defAccess < M_READ) {
-				if (strlen($groupIDs)>0) {
-					$queryStr = "(SELECT `tblUsers`.* FROM `tblUsers` ".
-						"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
-						"WHERE `tblGroupMembers`.`groupID` IN (". $groupIDs .") ".
-						"AND `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest.")";
-				}
-				$queryStr .= (strlen($queryStr)==0 ? "" : " UNION ").
-					"(SELECT `tblUsers`.* FROM `tblUsers` ".
-					"WHERE (`tblUsers`.`role` != ".LetoDMS_Core_User::role_guest.") ".
-					"AND ((`tblUsers`.`id` = ". $this->_ownerID . ") ".
-					"OR (`tblUsers`.`role` = ".LetoDMS_Core_User::role_admin.")".
-					(strlen($userIDs) == 0 ? "" : " OR (`tblUsers`.`id` IN (". $userIDs ."))").
-					")) ORDER BY `login`";
-			}
-			else {
-				if (strlen($groupIDs)>0) {
-					$queryStr = "(SELECT `tblUsers`.* FROM `tblUsers` ".
-						"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
-						"WHERE `tblGroupMembers`.`groupID` NOT IN (". $groupIDs .")".
-						"AND `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest .
-						(strlen($userIDs) == 0 ? ")" : " AND (`tblUsers`.`id` NOT IN (". $userIDs .")))");
-				}
-				$queryStr .= (strlen($queryStr)==0 ? "" : " UNION ").
-					"(SELECT `tblUsers`.* FROM `tblUsers` ".
-					"WHERE (`tblUsers`.`id` = ". $this->_ownerID . ") ".
-					"OR (`tblUsers`.`role` = ".LetoDMS_Core_User::role_admin."))".
-					"UNION ".
-					"(SELECT `tblUsers`.* FROM `tblUsers` ".
-					"WHERE `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest .
-					(strlen($userIDs) == 0 ? ")" : " AND (`tblUsers`.`id` NOT IN (". $userIDs .")))").
-					" ORDER BY `login`";
-			}
-			$resArr = $db->getResultArray($queryStr);
-			if (!is_bool($resArr)) {
-				foreach ($resArr as $row) {
-					$user = $this->_dms->getUser($row['id']);
-					if (!$this->_dms->enableAdminRevApp && $user->isAdmin()) continue;
-					$this->_approversList["users"][] = $user;
-				}
-			}
-
-			// Assemble the list of groups that have read access to the document.
-			$queryStr="";
-			if ($defAccess < M_READ) {
-				if (strlen($groupIDs)>0) {
-					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
-						"WHERE `tblGroups`.`id` IN (". $groupIDs .")";
-				}
-			}
-			else {
-				if (strlen($groupIDs)>0) {
-					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
-						"WHERE `tblGroups`.`id` NOT IN (". $groupIDs .")";
-				}
-				else {
-					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups`";
-				}
-			}
-			if (strlen($queryStr)>0) {
-				$resArr = $db->getResultArray($queryStr);
-				if (!is_bool($resArr)) {
-					foreach ($resArr as $row) {
-						$group = $this->_dms->getGroup($row["id"]);
-						$this->_approversList["groups"][] = $group;
-					}
-				}
-			}
-		}
-		return $this->_approversList;
-	} /* }}} */
-
-	/**
-	 * Get the internally used folderList which stores the ids of folders from
-	 * the root folder to the parent folder.
-	 *
-	 * @return string column separated list of folder ids
-	 */
-	function getFolderList() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT folderList FROM tblDocuments where id = ".$this->_id;
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-
-		return $resArr[0]['folderList'];
-	} /* }}} */
-
-	/**
-	 * Checks the internal data of the document and repairs it.
-	 * Currently, this function only repairs an incorrect folderList
-	 *
-	 * @return boolean true on success, otherwise false
-	 */
-	function repair() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$curfolderlist = $this->getFolderList();
-
-		// calculate the folderList of the folder
-		$parent = $this->getFolder();
-		$pathPrefix="";
-		$path = $parent->getPath();
-		foreach ($path as $f) {
-			$pathPrefix .= ":".$f->getID();
-		}
-		if (strlen($pathPrefix)>1) {
-			$pathPrefix .= ":";
-		}
-		if($curfolderlist != $pathPrefix) {
-			$queryStr = "UPDATE tblDocuments SET folderList='".$pathPrefix."' WHERE id = ". $this->_id;
-			$res = $db->getResult($queryStr);
-			if (!$res)
-				return false;
-		}
-		return true;
-	} /* }}} */
-} /* }}} */
-
-
-/**
- * Class to represent content of a document
- *
- * Each document has content attached to it, often called a 'version' of the
- * document. The document content represents a file on the disk with some
- * meta data stored in the database. A document content has a version number
- * which is incremented with each replacement of the old content. Old versions
- * are kept unless they are explicitly deleted by
- * {@link LetoDMS_Core_Document::removeContent()}.
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
- *             Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal,
- *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_DocumentContent { /* {{{ */
-
-	// if status is released and there are reviewers set status draft_rev
-	// if status is released or draft_rev and there are approves set status draft_app
-	// if status is draft and there are no approver and no reviewers set status to release
-	function verifyStatus($ignorecurrentstatus=false, $user=null) { /* {{{ */
-
-		unset($this->_status);
-		$st=$this->getStatus();
-
-		if (!$ignorecurrentstatus && ($st["status"]==S_OBSOLETE || $st["status"]==S_REJECTED || $st["status"]==S_EXPIRED )) return;
-
-		$pendingReview=false;
-		unset($this->_reviewStatus);  // force to be reloaded from DB
-		$reviewStatus=$this->getReviewStatus(true);
-		if (is_array($reviewStatus) && count($reviewStatus)>0) {
-			foreach ($reviewStatus as $r){
-				if ($r["status"]==0){
-					$pendingReview=true;
-					break;
-				}
-			}
-		}
-		$pendingApproval=false;
-		unset($this->_approvalStatus);  // force to be reloaded from DB
-		$approvalStatus=$this->getApprovalStatus(true);
-		if (is_array($approvalStatus) && count($approvalStatus)>0) {
-			foreach ($approvalStatus as $a){
-				if ($a["status"]==0){
-					$pendingApproval=true;
-					break;
-				}
-			}
-		}
-		if ($pendingReview) $this->setStatus(S_DRAFT_REV,"",$user);
-		else if ($pendingApproval) $this->setStatus(S_DRAFT_APP,"",$user);
-		else $this->setStatus(S_RELEASED,"",$user);
-	} /* }}} */
-
-	function LetoDMS_Core_DocumentContent($document, $version, $comment, $date, $userID, $dir, $orgFileName, $fileType, $mimeType) { /* {{{ */
-		$this->_document = $document;
-		$this->_version = (int) $version;
-		$this->_comment = $comment;
-		$this->_date = $date;
-		$this->_userID = (int) $userID;
-		$this->_dir = $dir;
-		$this->_orgFileName = $orgFileName;
-		$this->_fileType = $fileType;
-		$this->_mimeType = $mimeType;
-	} /* }}} */
-
-	function getVersion() { return $this->_version; }
-	function getComment() { return $this->_comment; }
-	function getDate() { return $this->_date; }
-	function getOriginalFileName() { return $this->_orgFileName; }
-	function getFileType() { return $this->_fileType; }
-	function getFileName(){ return "data" . $this->_fileType; }
-	function getDir() { return $this->_dir; }
-	function getMimeType() { return $this->_mimeType; }
-	function getUser() { /* {{{ */
-		if (!isset($this->_user))
-			$this->_user = $this->_document->_dms->getUser($this->_userID);
-		return $this->_user;
-	} /* }}} */
-	function getPath() { return $this->_document->getDir() . $this->_version . $this->_fileType; }
-
-	function setComment($newComment) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$queryStr = "UPDATE tblDocumentContent SET comment = ".$db->qstr($newComment)." WHERE `document` = " . $this->_document->getID() .	" AND `version` = " . $this->_version;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_comment = $newComment;
-
-		return true;
-	} /* }}} */
-
-	function convert() { /* {{{ */
-		if (file_exists($this->_document->_dms->contentDir . $this->_document->getID() .'/' . "index.html"))
-			return true;
-
-		if (!in_array($this->_fileType, array_keys($this->_document->_dms->convertFileTypes)))
-			return false;
-
-		$source = $this->_document->_dms->contentDir . $this->_document->getID() .'/' . $this->getFileName();
-		$target = $this->_document->_dms->contentDir . $this->_document->getID() .'/' . "index.html";
-	//	$source = str_replace("/", "\\", $source);
-	//	$target = str_replace("/", "\\", $target);
-
-		$command = $this->_document->_dms->convertFileTypes[$this->_fileType];
-		$command = str_replace("{SOURCE}", "\"$source\"", $command);
-		$command = str_replace("{TARGET}", "\"$target\"", $command);
-
-		$output = array();
-		$res = 0;
-		exec($command, $output, $res);
-
-		if ($res != 0) {
-			print (implode("\n", $output));
-			return false;
-		}
-		return true;
-	} /* }}} */
-
-	/* FIXME: this function should not be part of the DMS. It lies in the duty
-	 * of the application whether a file can viewed online or not.
-	 */
-	function viewOnline() { /* {{{ */
-		if (!isset($this->_document->_dms->_viewOnlineFileTypes) || !is_array($this->_document->_dms->_viewOnlineFileTypes)) {
-			return false;
-		}
-
-		if (in_array(strtolower($this->_fileType), $this->_document->_dms->_viewOnlineFileTypes))
-			return true;
-
-		if ($this->_document->_dms->enableConverting && in_array($this->_fileType, array_keys($this->_document->_dms->convertFileTypes)))
-			if ($this->wasConverted()) return true;
-
-		return false;
-	} /* }}} */
-
-	function wasConverted() { /* {{{ */
-		return file_exists($this->_document->_dms->contentDir . $this->_document->getID() .'/' . "index.html");
-	} /* }}} */
-
-	function getURL() { /* {{{ */
-		if (!$this->viewOnline())return false;
-
-		if (in_array(strtolower($this->_fileType), $this->_document->_dms->_viewOnlineFileTypes))
-			return "/" . $this->_document->getID() . "/" . $this->_version . "/" . $this->getOriginalFileName();
-		else
-			return "/" . $this->_document->getID() . "/" . $this->_version . "/index.html";
-	} /* }}} */
-
-	/**
-	 * Get the latest status of the content
-	 *
-	 * The status of the content reflects its current review and approval
-	 * state. A status can be a negative or positive number or 0. A negative
-	 * numbers indicate a missing approval, review or an obsolete content.
-	 * Positive numbers indicate some kind of approval but not necessarily
-	 * a release.
-	 * S_DRAFT_REV, 0
-	 * S_DRAFT_APP, 1
-	 * S_RELEASED, 2
-	 * S_REJECTED, -1
-	 * S_OBSOLETE, -2
-	 * S_EXPIRED, -3
-	 * When a content is inserted and does not need approval nor review,
-	 * then its status is set to S_RELEASED immediately. Any change of
-	 * the status is monitored in the table tblDocumentStatusLog. This
-	 * function will always return the latest entry for the content.
-	 */
-	function getStatus($limit=1) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		if (!is_numeric($limit)) return false;
-
-		// Retrieve the current overall status of the content represented by
-		// this object.
-		if (!isset($this->_status)) {
-		/*
-			if (!$db->createTemporaryTable("ttstatid", $forceTemporaryTable)) {
-				return false;
-			}
-			$queryStr="SELECT `tblDocumentStatus`.*, `tblDocumentStatusLog`.`status`, ".
-				"`tblDocumentStatusLog`.`comment`, `tblDocumentStatusLog`.`date`, ".
-				"`tblDocumentStatusLog`.`userID` ".
-				"FROM `tblDocumentStatus` ".
-				"LEFT JOIN `tblDocumentStatusLog` USING (`statusID`) ".
-				"LEFT JOIN `ttstatid` ON `ttstatid`.`maxLogID` = `tblDocumentStatusLog`.`statusLogID` ".
-				"WHERE `ttstatid`.`maxLogID`=`tblDocumentStatusLog`.`statusLogID` ".
-				"AND `tblDocumentStatus`.`documentID` = '". $this->_document->getID() ."' ".
-				"AND `tblDocumentStatus`.`version` = '". $this->_version ."' ";
-		*/
-			$queryStr=
-				"SELECT `tblDocumentStatus`.*, `tblDocumentStatusLog`.`status`, ".
-				"`tblDocumentStatusLog`.`comment`, `tblDocumentStatusLog`.`date`, ".
-				"`tblDocumentStatusLog`.`userID` ".
-				"FROM `tblDocumentStatus` ".
-				"LEFT JOIN `tblDocumentStatusLog` USING (`statusID`) ".
-				"WHERE `tblDocumentStatus`.`documentID` = '". $this->_document->getID() ."' ".
-				"AND `tblDocumentStatus`.`version` = '". $this->_version ."' ".
-				"ORDER BY `tblDocumentStatusLog`.`statusLogID` DESC LIMIT ".(int) $limit;
-
-			$res = $db->getResultArray($queryStr);
-			if (is_bool($res) && !$res)
-				return false;
-			if (count($res)!=1)
-				return false;
-			$this->_status = $res[0];
-		}
-		return $this->_status;
-	} /* }}} */
-
-	/**
-	 * Set the status of the content
-	 * Setting the status means to add another entry into the table
-	 * tblDocumentStatusLog
-	 *
-	 * @param integer $status new status of content
-	 * @param string $comment comment for this status change
-	 * @param object $updateUser user initiating the status change
-	 * @return boolean true on success, otherwise false
-	 */
-	function setStatus($status, $comment, $updateUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		if (!is_numeric($status)) return false;
-
-		/* return an error if $updateuser is not set */
-		if(!$updateUser)
-			return false;
-
-		// If the supplied value lies outside of the accepted range, return an
-		// error.
-		if ($status < -3 || $status > 2) {
-			return false;
-		}
-
-		// Retrieve the current overall status of the content represented by
-		// this object, if it hasn't been done already.
-		if (!isset($this->_status)) {
-			$this->getStatus();
-		}
-		if ($this->_status["status"]==$status) {
-			return false;
-		}
-		$queryStr = "INSERT INTO `tblDocumentStatusLog` (`statusID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $this->_status["statusID"] ."', '". (int) $status ."', ".$db->qstr($comment).", NOW(), '". $updateUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res)
-			return false;
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Get the current review status of the document content
-	 * The review status is a list of reviewers and its current status
-	 *
-	 * @param integer $limit the number of recent status changes per reviewer
-	 * @return array list of review status
-	 */
-	function getReviewStatus($limit=1) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		if (!is_numeric($limit)) return false;
-
-		// Retrieve the current status of each assigned reviewer for the content
-		// represented by this object.
-		if (!isset($this->_reviewStatus)) {
-			/* First get a list of all reviews for this document content */
-			$queryStr=
-				"SELECT reviewId FROM tblDocumentReviewers WHERE `version`='".$this->_version
-				."' AND `documentID` = '". $this->_document->getID() ."' ";
-			$recs = $db->getResultArray($queryStr);
-			if (is_bool($recs) && !$recs)
-				return false;
-			$this->_reviewStatus = array();
-			if($recs) {
-				foreach($recs as $rec) {
-					$queryStr=
-						"SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
-						"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
-						"`tblDocumentReviewLog`.`userID`, `tblUsers`.`fullName`, `tblGroups`.`name` AS `groupName` ".
-						"FROM `tblDocumentReviewers` ".
-						"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
-						"LEFT JOIN `tblUsers` on `tblUsers`.`id` = `tblDocumentReviewers`.`required`".
-						"LEFT JOIN `tblGroups` on `tblGroups`.`id` = `tblDocumentReviewers`.`required`".
-						"WHERE `tblDocumentReviewers`.`reviewId` = '". $rec['reviewId'] ."' ".
-						"ORDER BY `tblDocumentReviewLog`.`reviewLogID` DESC LIMIT ".(int) $limit;
-
-					$res = $db->getResultArray($queryStr);
-					if (is_bool($res) && !$res) {
-						unset($this->_reviewStatus);
-						return false;
-					}
-					$this->_reviewStatus = array_merge($this->_reviewStatus, $res);
-				}
-			}
-		}
-		return $this->_reviewStatus;
-	} /* }}} */
-
-	function getApprovalStatus($limit=1) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		if (!is_numeric($limit)) return false;
-
-		// Retrieve the current status of each assigned approver for the content
-		// represented by this object.
-		if (!isset($this->_approvalStatus)) {
-			/* First get a list of all approvals for this document content */
-			$queryStr=
-				"SELECT approveId FROM tblDocumentApprovers WHERE `version`='".$this->_version
-				."' AND `documentID` = '". $this->_document->getID() ."' ";
-			$recs = $db->getResultArray($queryStr);
-			if (is_bool($recs) && !$recs)
-				return false;
-			$this->_approvalStatus = array();
-			if($recs) {
-				foreach($recs as $rec) {
-					$queryStr=
-						"SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
-						"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
-						"`tblDocumentApproveLog`.`userID`, `tblUsers`.`fullName`, `tblGroups`.`name` AS `groupName` ".
-						"FROM `tblDocumentApprovers` ".
-						"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
-						"LEFT JOIN `tblUsers` on `tblUsers`.`id` = `tblDocumentApprovers`.`required` ".
-						"LEFT JOIN `tblGroups` on `tblGroups`.`id` = `tblDocumentApprovers`.`required`".
-						"WHERE `tblDocumentApprovers`.`approveId` = '". $rec['approveId'] ."' ".
-						"ORDER BY `tblDocumentApproveLog`.`approveLogId` DESC LIMIT ".(int) $limit;
-
-					$res = $db->getResultArray($queryStr);
-					if (is_bool($res) && !$res) {
-						unset($this->_approvalStatus);
-						return false;
-					}
-					$this->_approvalStatus = array_merge($this->_approvalStatus, $res);
-				}
-			}
-		}
-		return $this->_approvalStatus;
-	} /* }}} */
-
-	function addIndReviewer($user, $requestUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$userID = $user->getID();
-
-		// Get the list of users and groups with write access to this document.
-		if (!isset($this->_approversList)) {
-			$this->_approversList = $this->_document->getApproversList();
-		}
-		$approved = false;
-		foreach ($this->_approversList["users"] as $appUser) {
-			if ($userID == $appUser->getID()) {
-				$approved = true;
-				break;
-			}
-		}
-		if (!$approved) {
-			return -2;
-		}
-
-		// Check to see if the user has already been added to the review list.
-		$reviewStatus = $user->getReviewStatus($this->_document->getID(), $this->_version);
-		if (is_bool($reviewStatus) && !$reviewStatus) {
-			return -1;
-		}
-		if (count($reviewStatus["indstatus"]) > 0 && $reviewStatus["indstatus"][0]["status"]!=-2) {
-			// User is already on the list of reviewers; return an error.
-			return -3;
-		}
-
-		// Add the user into the review database.
-		if (! isset($reviewStatus["indstatus"][0]["status"])|| (isset($reviewStatus["indstatus"][0]["status"]) && $reviewStatus["indstatus"][0]["status"]!=-2)) {
-			$queryStr = "INSERT INTO `tblDocumentReviewers` (`documentID`, `version`, `type`, `required`) ".
-				"VALUES ('". $this->_document->getID() ."', '". $this->_version ."', '0', '". $userID ."')";
-			$res = $db->getResult($queryStr);
-			if (is_bool($res) && !$res) {
-				return -1;
-			}
-			$reviewID = $db->getInsertID();
-		}
-		else {
-			$reviewID = isset($reviewStatus["indstatus"][0]["reviewID"])?$reviewStatus["indstatus"][0]["reviewID"]:NULL;
-		}
-
-		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $reviewID ."', '0', '', NOW(), '". $requestUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res) {
-			return -1;
-		}
-
-		// Add reviewer to event notification table.
-		//$this->_document->addNotify($userID, true);
-
-		return 0;
-	} /* }}} */
-
-	function addGrpReviewer($group, $requestUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$groupID = $group->getID();
-
-		// Get the list of users and groups with write access to this document.
-		if (!isset($this->_approversList)) {
-			// TODO: error checking.
-			$this->_approversList = $this->_document->getApproversList();
-		}
-		$approved = false;
-		foreach ($this->_approversList["groups"] as $appGroup) {
-			if ($groupID == $appGroup->getID()) {
-				$approved = true;
-				break;
-			}
-		}
-		if (!$approved) {
-			return -2;
-		}
-
-		// Check to see if the group has already been added to the review list.
-		$reviewStatus = $group->getReviewStatus($this->_document->getID(), $this->_version);
-		if (is_bool($reviewStatus) && !$reviewStatus) {
-			return -1;
-		}
-		if (count($reviewStatus) > 0 && $reviewStatus[0]["status"]!=-2) {
-			// Group is already on the list of reviewers; return an error.
-			return -3;
-		}
-
-		// Add the group into the review database.
-		if (!isset($reviewStatus[0]["status"]) || (isset($reviewStatus[0]["status"]) && $reviewStatus[0]["status"]!=-2)) {
-			$queryStr = "INSERT INTO `tblDocumentReviewers` (`documentID`, `version`, `type`, `required`) ".
-				"VALUES ('". $this->_document->getID() ."', '". $this->_version ."', '1', '". $groupID ."')";
-			$res = $db->getResult($queryStr);
-			if (is_bool($res) && !$res) {
-				return -1;
-			}
-			$reviewID = $db->getInsertID();
-		}
-		else {
-			$reviewID = isset($reviewStatus[0]["reviewID"])?$reviewStatus[0]["reviewID"]:NULL;
-		}
-
-		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $reviewID ."', '0', '', NOW(), '". $requestUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res) {
-			return -1;
-		}
-
-		// Add reviewer to event notification table.
-		//$this->_document->addNotify($groupID, false);
-
-		return 0;
-	} /* }}} */
-
-	function setReviewByInd($user, $requestUser, $status, $comment) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		// Check to see if the user can be removed from the review list.
-		$reviewStatus = $user->getReviewStatus($this->_document->getID(), $this->_version);
-		if (is_bool($reviewStatus) && !$reviewStatus) {
-			return -1;
-		}
-		if (count($reviewStatus["indstatus"])==0) {
-			// User is not assigned to review this document. No action required.
-			// Return an error.
-			return -3;
-		}
-		if ($reviewStatus["indstatus"][0]["status"]==-2) {
-			// User has been deleted from reviewers
-			return -4;
-		}
-		// Check if the status is really different from the current status
-		if ($reviewStatus["indstatus"][0]["status"] == $status)
-			return 0;
-
-		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`,
-  	  `comment`, `date`, `userID`) ".
-			"VALUES ('". $reviewStatus["indstatus"][0]["reviewID"] ."', '".
-			(int) $status ."', ".$db->qstr($comment).", NOW(), '".
-			$requestUser->getID() ."')";
-		$res=$db->getResult($queryStr);
-		if (is_bool($res) && !$res)
-			return -1;
-		else
-			return 0;
- } /* }}} */
-
-	function setReviewByGrp($group, $requestUser, $status, $comment) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		// Check to see if the user can be removed from the review list.
-		$reviewStatus = $group->getReviewStatus($this->_document->getID(), $this->_version);
-		if (is_bool($reviewStatus) && !$reviewStatus) {
-			return -1;
-		}
-		if (count($reviewStatus)==0) {
-			// User is not assigned to review this document. No action required.
-			// Return an error.
-			return -3;
-		}
-		if ($reviewStatus[0]["status"]==-2) {
-			// Group has been deleted from reviewers
-			return -4;
-		}
-
-		// Check if the status is really different from the current status
-		if ($reviewStatus[0]["status"] == $status)
-			return 0;
-
-		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`,
-  	  `comment`, `date`, `userID`) ".
-			"VALUES ('". $reviewStatus[0]["reviewID"] ."', '".
-			(int) $status ."', ".$db->qstr($comment).", NOW(), '".
-			$requestUser->getID() ."')";
-		$res=$db->getResult($queryStr);
-		if (is_bool($res) && !$res)
-			return -1;
-		else
-			return 0;
- } /* }}} */
-
-	function addIndApprover($user, $requestUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$userID = $user->getID();
-
-		// Get the list of users and groups with write access to this document.
-		if (!isset($this->_approversList)) {
-			// TODO: error checking.
-			$this->_approversList = $this->_document->getApproversList();
-		}
-		$approved = false;
-		foreach ($this->_approversList["users"] as $appUser) {
-			if ($userID == $appUser->getID()) {
-				$approved = true;
-				break;
-			}
-		}
-		if (!$approved) {
-			return -2;
-		}
-
-		// Check to see if the user has already been added to the approvers list.
-		$approvalStatus = $user->getApprovalStatus($this->_document->getID(), $this->_version);
-		if (is_bool($approvalStatus) && !$approvalStatus) {
-			return -1;
-		}
-		if (count($approvalStatus["indstatus"]) > 0 && $approvalStatus["indstatus"][0]["status"]!=-2) {
-			// User is already on the list of approvers; return an error.
-			return -3;
-		}
-
-		if ( !isset($approvalStatus["indstatus"][0]["status"]) || (isset($approvalStatus["indstatus"][0]["status"]) && $approvalStatus["indstatus"][0]["status"]!=-2)) {
-			// Add the user into the approvers database.
-			$queryStr = "INSERT INTO `tblDocumentApprovers` (`documentID`, `version`, `type`, `required`) ".
-				"VALUES ('". $this->_document->getID() ."', '". $this->_version ."', '0', '". $userID ."')";
-			$res = $db->getResult($queryStr);
-			if (is_bool($res) && !$res) {
-				return -1;
-			}
-			$approveID = $db->getInsertID();
-		}
-		else {
-			$approveID = isset($approvalStatus["indstatus"][0]["approveID"]) ? $approvalStatus["indstatus"][0]["approveID"] : NULL;
-		}
-
-		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $approveID ."', '0', '', NOW(), '". $requestUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res) {
-			return -1;
-		}
-
-		return 0;
-	} /* }}} */
-
-	function addGrpApprover($group, $requestUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$groupID = $group->getID();
-
-		// Get the list of users and groups with write access to this document.
-		if (!isset($this->_approversList)) {
-			// TODO: error checking.
-			$this->_approversList = $this->_document->getApproversList();
-		}
-		$approved = false;
-		foreach ($this->_approversList["groups"] as $appGroup) {
-			if ($groupID == $appGroup->getID()) {
-				$approved = true;
-				break;
-			}
-		}
-		if (!$approved) {
-			return -2;
-		}
-
-		// Check to see if the group has already been added to the approver list.
-		$approvalStatus = $group->getApprovalStatus($this->_document->getID(), $this->_version);
-		if (is_bool($approvalStatus) && !$approvalStatus) {
-			return -1;
-		}
-		if (count($approvalStatus) > 0 && $approvalStatus[0]["status"]!=-2) {
-			// Group is already on the list of approvers; return an error.
-			return -3;
-		}
-
-		// Add the group into the approver database.
-		if (!isset($approvalStatus[0]["status"]) || (isset($approvalStatus[0]["status"]) && $approvalStatus[0]["status"]!=-2)) {
-			$queryStr = "INSERT INTO `tblDocumentApprovers` (`documentID`, `version`, `type`, `required`) ".
-				"VALUES ('". $this->_document->getID() ."', '". $this->_version ."', '1', '". $groupID ."')";
-			$res = $db->getResult($queryStr);
-			if (is_bool($res) && !$res) {
-				return -1;
-			}
-			$approveID = $db->getInsertID();
-		}
-		else {
-			$approveID = isset($approvalStatus[0]["approveID"])?$approvalStatus[0]["approveID"]:NULL;
-		}
-
-		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $approveID ."', '0', '', NOW(), '". $requestUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res) {
-			return -1;
-		}
-
-		// Add approver to event notification table.
-		//$this->_document->addNotify($groupID, false);
-
-		return 0;
-	} /* }}} */
-
-	/**
-	 * Sets approval status of a document content for a user
-	 * This function can be used to approve or reject a document content, or
-	 * to reset its approval state. The user initiating the approval may
-	 * not be the user filled in as an approver of the document content.
-	 * In most cases this will be but an admin may set the approval for
-	 * somebody else.
-	 * It is first checked if the user is in the list of approvers at all.
-	 * Then it is check if the approval status is already -2. In both cases
-	 * the function returns with an error.
-	 *
-	 * @param object $user user in charge for doing the approval
-	 * @param object $requestUser user actually calling this function
-	 * @param integer $status the status of the approval, possible values are
-	 *        0=unprocessed (maybe used to reset a status)
-	 *        1=approved,
-	 *       -1=rejected,
-	 *       -2=user is deleted (use {link
-	 *       LetoDMS_Core_DocumentContent::delIndApprover} instead)
-	 * @param string $comment approval comment
-	 * @return integer 0 on success, < 0 in case of an error
-	 */
-	function setApprovalByInd($user, $requestUser, $status, $comment) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		// Check to see if the user can be removed from the approval list.
-		$approvalStatus = $user->getApprovalStatus($this->_document->getID(), $this->_version);
-		if (is_bool($approvalStatus) && !$approvalStatus) {
-			return -1;
-		}
-		if (count($approvalStatus["indstatus"])==0) {
-			// User is not assigned to approve this document. No action required.
-			// Return an error.
-			return -3;
-		}
-		if ($approvalStatus["indstatus"][0]["status"]==-2) {
-			// User has been deleted from approvers
-			return -4;
-		}
-		// Check if the status is really different from the current status
-		if ($approvalStatus["indstatus"][0]["status"] == $status)
-			return 0;
-
-		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`,
-  	  `comment`, `date`, `userID`) ".
-			"VALUES ('". $approvalStatus["indstatus"][0]["approveID"] ."', '".
-			(int) $status ."', ".$db->qstr($comment).", NOW(), '".
-			$requestUser->getID() ."')";
-		$res=$db->getResult($queryStr);
-		if (is_bool($res) && !$res)
-			return -1;
-		else
-			return 0;
- } /* }}} */
-
-	/**
-	 * Sets approval status of a document content for a group
-	 * The functions behaves like
-	 * {link LetoDMS_Core_DocumentContent::setApprovalByInd} but does it for
-	 * group instead of a user
-	 */
-	function setApprovalByGrp($group, $requestUser, $status, $comment) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		// Check to see if the user can be removed from the approval list.
-		$approvalStatus = $group->getApprovalStatus($this->_document->getID(), $this->_version);
-		if (is_bool($approvalStatus) && !$approvalStatus) {
-			return -1;
-		}
-		if (count($approvalStatus)==0) {
-			// User is not assigned to approve this document. No action required.
-			// Return an error.
-			return -3;
-		}
-		if ($approvalStatus[0]["status"]==-2) {
-			// Group has been deleted from approvers
-			return -4;
-		}
-
-		// Check if the status is really different from the current status
-		if ($approvalStatus[0]["status"] == $status)
-			return 0;
-
-		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`,
-  	  `comment`, `date`, `userID`) ".
-			"VALUES ('". $approvalStatus[0]["approveID"] ."', '".
-			(int) $status ."', ".$db->qstr($comment).", NOW(), '".
-			$requestUser->getID() ."')";
-		$res=$db->getResult($queryStr);
-		if (is_bool($res) && !$res)
-			return -1;
-		else
-			return 0;
- } /* }}} */
-
-	function delIndReviewer($user, $requestUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$userID = $user->getID();
-
-		// Check to see if the user can be removed from the review list.
-		$reviewStatus = $user->getReviewStatus($this->_document->getID(), $this->_version);
-		if (is_bool($reviewStatus) && !$reviewStatus) {
-			return -1;
-		}
-		if (count($reviewStatus["indstatus"])==0) {
-			// User is not assigned to review this document. No action required.
-			// Return an error.
-			return -3;
-		}
-		if ($reviewStatus["indstatus"][0]["status"]!=0) {
-			// User has already submitted a review or has already been deleted;
-			// return an error.
-			return -3;
-		}
-
-		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $reviewStatus["indstatus"][0]["reviewID"] ."', '-2', '', NOW(), '". $requestUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res) {
-			return -1;
-		}
-
-		return 0;
-	} /* }}} */
-
-	function delGrpReviewer($group, $requestUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$groupID = $group->getID();
-
-		// Check to see if the user can be removed from the review list.
-		$reviewStatus = $group->getReviewStatus($this->_document->getID(), $this->_version);
-		if (is_bool($reviewStatus) && !$reviewStatus) {
-			return -1;
-		}
-		if (count($reviewStatus)==0) {
-			// User is not assigned to review this document. No action required.
-			// Return an error.
-			return -3;
-		}
-		if ($reviewStatus[0]["status"]!=0) {
-			// User has already submitted a review or has already been deleted;
-			// return an error.
-			return -3;
-		}
-
-		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $reviewStatus[0]["reviewID"] ."', '-2', '', NOW(), '". $requestUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res) {
-			return -1;
-		}
-
-		return 0;
-	} /* }}} */
-
-	function delIndApprover($user, $requestUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$userID = $user->getID();
-
-		// Check to see if the user can be removed from the approval list.
-		$approvalStatus = $user->getApprovalStatus($this->_document->getID(), $this->_version);
-		if (is_bool($approvalStatus) && !$approvalStatus) {
-			return -1;
-		}
-		if (count($approvalStatus["indstatus"])==0) {
-			// User is not assigned to approve this document. No action required.
-			// Return an error.
-			return -3;
-		}
-		if ($approvalStatus["indstatus"][0]["status"]!=0) {
-			// User has already submitted an approval or has already been deleted;
-			// return an error.
-			return -3;
-		}
-
-		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $approvalStatus["indstatus"][0]["approveID"] ."', '-2', '', NOW(), '". $requestUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res) {
-			return -1;
-		}
-
-		return 0;
-	} /* }}} */
-
-	function delGrpApprover($group, $requestUser) { /* {{{ */
-		$db = $this->_document->_dms->getDB();
-
-		$groupID = $group->getID();
-
-		// Check to see if the user can be removed from the approver list.
-		$approvalStatus = $group->getApprovalStatus($this->_document->getID(), $this->_version);
-		if (is_bool($approvalStatus) && !$approvalStatus) {
-			return -1;
-		}
-		if (count($approvalStatus)==0) {
-			// User is not assigned to approve this document. No action required.
-			// Return an error.
-			return -3;
-		}
-		if ($approvalStatus[0]["status"]!=0) {
-			// User has already submitted an approval or has already been deleted;
-			// return an error.
-			return -3;
-		}
-
-		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
-			"VALUES ('". $approvalStatus[0]["approveID"] ."', '-2', '', NOW(), '". $requestUser->getID() ."')";
-		$res = $db->getResult($queryStr);
-		if (is_bool($res) && !$res) {
-			return -1;
-		}
-
-		return 0;
-	} /* }}} */
-} /* }}} */
-
-
-/**
- * Class to represent a link between two document
- *
- * Document links are to establish a reference from one document to
- * another document. The owner of the document link may not be the same
- * as the owner of one of the documents.
- * Use {@link LetoDMS_Core_Document::addDocumentLink()} to add a reference
- * to another document.
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
- *             Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal,
- *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_DocumentLink { /* {{{ */
-	var $_id;
-	var $_document;
-	var $_target;
-	var $_userID;
-	var $_public;
-
-	function LetoDMS_Core_DocumentLink($id, $document, $target, $userID, $public) {
-		$this->_id = $id;
-		$this->_document = $document;
-		$this->_target = $target;
-		$this->_userID = $userID;
-		$this->_public = $public;
-	}
-
-	function getID() { return $this->_id; }
-
-	function getDocument() {
-		return $this->_document;
-	}
-
-	function getTarget() {
-		return $this->_target;
-	}
-
-	function getUser() {
-		if (!isset($this->_user))
-			$this->_user = $this->_document->_dms->getUser($this->_userID);
-		return $this->_user;
-	}
-
-	function isPublic() { return $this->_public; }
-
-} /* }}} */
-
-/**
- * Class to represent a file attached to a document
- *
- * Beside the regular document content arbitrary files can be attached
- * to a document. This is a similar concept as attaching files to emails.
- * The owner of the attached file and the document may not be the same.
- * Use {@link LetoDMS_Core_Document::addDocumentFile()} to attach a file.
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
- *             Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal,
- *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_DocumentFile { /* {{{ */
-	var $_id;
-	var $_document;
-	var $_userID;
-	var $_comment;
-	var $_date;
-	var $_dir;
-	var $_fileType;
-	var $_mimeType;
-	var $_orgFileName;
-	var $_name;
-
-	function LetoDMS_Core_DocumentFile($id, $document, $userID, $comment, $date, $dir, $fileType, $mimeType, $orgFileName,$name) {
-		$this->_id = $id;
-		$this->_document = $document;
-		$this->_userID = $userID;
-		$this->_comment = $comment;
-		$this->_date = $date;
-		$this->_dir = $dir;
-		$this->_fileType = $fileType;
-		$this->_mimeType = $mimeType;
-		$this->_orgFileName = $orgFileName;
-		$this->_name = $name;
-	}
-
-	function getID() { return $this->_id; }
-	function getDocument() { return $this->_document; }
-	function getUserID() { return $this->_userID; }
-	function getComment() { return $this->_comment; }
-	function getDate() { return $this->_date; }
-	function getDir() { return $this->_dir; }
-	function getFileType() { return $this->_fileType; }
-	function getMimeType() { return $this->_mimeType; }
-	function getOriginalFileName() { return $this->_orgFileName; }
-	function getName() { return $this->_name; }
-
-	function getUser() {
-		if (!isset($this->_user))
-			$this->_user = $this->_document->_dms->getUser($this->_userID);
-		return $this->_user;
-	}
-
-	function getPath() {
-		return $this->_document->getDir() . "f" .$this->_id . $this->_fileType;
-	}
-
-} /* }}} */
-
-//
-// Perhaps not the cleanest object ever devised, it exists to encapsulate all
-// of the data generated during the addition of new content to the database.
-// The object stores a copy of the new DocumentContent object, the newly assigned
-// reviewers and approvers and the status.
-//
-/**
- * Class to represent a list of document contents
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
- *             Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal,
- *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_AddContentResultSet { /* {{{ */
-
-	var $_indReviewers;
-	var $_grpReviewers;
-	var $_indApprovers;
-	var $_grpApprovers;
-	var $_content;
-	var $_status;
-
-	function LetoDMS_Core_AddContentResultSet($content) {
-
-		$this->_content = $content;
-		$this->_indReviewers = null;
-		$this->_grpReviewers = null;
-		$this->_indApprovers = null;
-		$this->_grpApprovers = null;
-		$this->_status = null;
-	}
-
-	function addReviewer($reviewer, $type, $status) {
-
-		if (!is_object($reviewer) || (strcasecmp($type, "i") && strcasecmp($type, "g")) && !is_integer($status)){
-			return false;
-		}
-		if (!strcasecmp($type, "i")) {
-			if (strcasecmp(get_class($reviewer), "LetoDMS_Core_User")) {
-				return false;
-			}
-			if ($this->_indReviewers == null) {
-				$this->_indReviewers = array();
-			}
-			$this->_indReviewers[$status][] = $reviewer;
-		}
-		if (!strcasecmp($type, "g")) {
-			if (strcasecmp(get_class($reviewer), "LetoDMS_Core_Group")) {
-				return false;
-			}
-			if ($this->_grpReviewers == null) {
-				$this->_grpReviewers = array();
-			}
-			$this->_grpReviewers[$status][] = $reviewer;
-		}
-		return true;
-	}
-
-	function addApprover($approver, $type, $status) {
-
-		if (!is_object($approver) || (strcasecmp($type, "i") && strcasecmp($type, "g")) && !is_integer($status)){
-			return false;
-		}
-		if (!strcasecmp($type, "i")) {
-			if (strcasecmp(get_class($approver), "LetoDMS_Core_User")) {
-				return false;
-			}
-			if ($this->_indApprovers == null) {
-				$this->_indApprovers = array();
-			}
-			$this->_indApprovers[$status][] = $approver;
-		}
-		if (!strcasecmp($type, "g")) {
-			if (strcasecmp(get_class($approver), "LetoDMS_Core_Group")) {
-				return false;
-			}
-			if ($this->_grpApprovers == null) {
-				$this->_grpApprovers = array();
-			}
-			$this->_grpApprovers[$status][] = $approver;
-		}
-		return true;
-	}
-
-	function setStatus($status) {
-		if (!is_integer($status)) {
-			return false;
-		}
-		if ($status<-3 || $status>2) {
-			return false;
-		}
-		$this->_status = $status;
-		return true;
-	}
-
-	function getStatus() {
-		return $this->_status;
-	}
-
-	function getReviewers($type) {
-		if (strcasecmp($type, "i") && strcasecmp($type, "g")) {
-			return false;
-		}
-		if (!strcasecmp($type, "i")) {
-			return ($this->_indReviewers == null ? array() : $this->_indReviewers);
-		}
-		else {
-			return ($this->_grpReviewers == null ? array() : $this->_grpReviewers);
-		}
-	}
-
-	function getApprovers($type) {
-		if (strcasecmp($type, "i") && strcasecmp($type, "g")) {
-			return false;
-		}
-		if (!strcasecmp($type, "i")) {
-			return ($this->_indApprovers == null ? array() : $this->_indApprovers);
-		}
-		else {
-			return ($this->_grpApprovers == null ? array() : $this->_grpApprovers);
-		}
-	}
-} /* }}} */
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassFolder.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassFolder.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassFolder.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassFolder.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,1186 +0,0 @@
-<?php
-/**
- * Implementation of a folder in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL2
- * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
- *             Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Class to represent a folder in the document management system
- *
- * A folder in LetoDMS is equivalent to a directory in a regular file
- * system. It can contain further subfolders and documents. Each folder
- * has a single parent except for the root folder which has no parent.
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_Folder {
-	/**
-	 * @var integer unique id of folder
-	 */
-	var $_id;
-
-	/**
-	 * @var string name of folder
-	 */
-	var $_name;
-
-	/**
-	 * @var integer id of parent folder
-	 */
-	var $_parentID;
-
-	/**
-	 * @var string comment of document
-	 */
-	var $_comment;
-
-	/**
-	 * @var integer id of user who is the owner
-	 */
-	var $_ownerID;
-
-	/**
-	 * @var boolean true if access is inherited, otherwise false
-	 */
-	var $_inheritAccess;
-
-	/**
-	 * @var integer default access if access rights are not inherited
-	 */
-	var $_defaultAccess;
-
-	/**
-	 * @var array list of notifications for users and groups
-	 */
-	var $_notifyList;
-
-	/**
-	 * @var integer position of folder within the parent folder
-	 */
-	var $_sequence;
-
-	/**
-	 * @var object back reference to document management system
-	 */
-	var $_dms;
-
-	function LetoDMS_Core_Folder($id, $name, $parentID, $comment, $date, $ownerID, $inheritAccess, $defaultAccess, $sequence) { /* {{{ */
-		$this->_id = $id;
-		$this->_name = $name;
-		$this->_parentID = $parentID;
-		$this->_comment = $comment;
-		$this->_date = $date;
-		$this->_ownerID = $ownerID;
-		$this->_inheritAccess = $inheritAccess;
-		$this->_defaultAccess = $defaultAccess;
-		$this->_sequence = $sequence;
-		$this->_notifyList = array();
-		$this->_dms = null;
-	} /* }}} */
-
-	/*
-	 * Set dms this folder belongs to.
-	 *
-	 * Each folder needs a reference to the dms it belongs to. It will be
-	 * set when the folder is created by LetoDMS::getFolder(). The dms has a
-	 * references to the currently logged in user and the database connection.
-	 *
-	 * @param object $dms reference to dms
-	 */
-	function setDMS($dms) { /* {{{ */
-		$this->_dms = $dms;
-	} /* }}} */
-
-	/*
-	 * Get the internal id of the folder.
-	 *
-	 * @return integer id of folder
-	 */
-	function getID() { return $this->_id; }
-
-	/*
-	 * Get the name of the folder.
-	 *
-	 * @return string name of folder
-	 */
-	function getName() { return $this->_name; }
-
-	/*
-	 * Set the name of the folder.
-	 *
-	 * @param string $newName set a new name of the folder
-	 */
-	function setName($newName) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblFolders SET name = " . $db->qstr($newName) . " WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_name = $newName;
-
-		return true;
-	} /* }}} */
-
-	function getComment() { return $this->_comment; }
-
-	function setComment($newComment) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblFolders SET comment = " . $db->qstr($newComment) . " WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_comment = $newComment;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Return creation date of folder
-	 *
-	 * @return integer unix timestamp of creation date
-	 */
-	function getDate() { /* {{{ */
-		return $this->_date;
-	} /* }}} */
-
-	/**
-	 * Returns the parent
-	 *
-	 * @return object parent folder or false if there is no parent folder
-	 */
-	function getParent() { /* {{{ */
-		if ($this->_id == $this->_dms->rootFolderID || empty($this->_parentID)) {
-			return false;
-		}
-
-		if (!isset($this->_parent)) {
-			$this->_parent = $this->_dms->getFolder($this->_parentID);
-		}
-		return $this->_parent;
-	} /* }}} */
-
-	/**
-	 * Set a new folder
-	 *
-	 * This function moves a folder from one parent folder into another parent
-	 * folder. It will fail if the root folder is moved.
-	 *
-	 * @param object new parent folder
-	 * @return boolean true if operation was successful otherwise false
-	 */
-	function setParent($newParent) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if ($this->_id == $this->_dms->rootFolderID || empty($this->_parentID)) {
-			return false;
-		}
-
-		// Update the folderList of the folder
-		$pathPrefix="";
-		$path = $newParent->getPath();
-		foreach ($path as $f) {
-			$pathPrefix .= ":".$f->getID();
-		}
-		if (strlen($pathPrefix)>1) {
-			$pathPrefix .= ":";
-		}
-		$queryStr = "UPDATE tblFolders SET parent = ".$newParent->getID().", folderList='".$pathPrefix."' WHERE id = ". $this->_id;
-		$res = $db->getResult($queryStr);
-		if (!$res)
-			return false;
-		$this->_parentID = $newParent->getID();
-		$this->_parent = $newParent;
-
-		// Must also ensure that any documents in this folder tree have their
-		// folderLists updated.
-		$pathPrefix="";
-		$path = $this->getPath();
-		foreach ($path as $f) {
-			$pathPrefix .= ":".$f->getID();
-		}
-		if (strlen($pathPrefix)>1) {
-			$pathPrefix .= ":";
-		}
-
-		$queryStr = "SELECT `tblDocuments`.`id`, `tblDocuments`.`folderList` FROM `tblDocuments` WHERE `folderList` LIKE '%:".$this->_id.":%'";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-
-		foreach ($resArr as $row) {
-			$newPath = ereg_replace("^.*:".$this->_id.":(.*$)", $pathPrefix."\\1", $row["folderList"]);
-			$queryStr="UPDATE `tblDocuments` SET `folderList` = '".$newPath."' WHERE `tblDocuments`.`id` = '".$row["id"]."'";
-			$res = $db->getResult($queryStr);
-		}
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Returns the owner
-	 *
-	 * @return object owner of the folder
-	 */
-	function getOwner() { /* {{{ */
-		if (!isset($this->_owner))
-			$this->_owner = $this->_dms->getUser($this->_ownerID);
-		return $this->_owner;
-	} /* }}} */
-
-	/**
-	 * Set the owner
-	 *
-	 * @param object new owner of the folder
-	 * @return boolean true if successful otherwise false
-	 */
-	function setOwner($newOwner) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblFolders set owner = " . $newOwner->getID() . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_ownerID = $newOwner->getID();
-		$this->_owner = $newOwner;
-		return true;
-	} /* }}} */
-
-	function getDefaultAccess() { /* {{{ */
-		if ($this->inheritsAccess()) {
-			$res = $this->getParent();
-			if (!$res) return false;
-			return $this->_parent->getDefaultAccess();
-		}
-
-		return $this->_defaultAccess;
-	} /* }}} */
-
-	function setDefaultAccess($mode) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblFolders set defaultAccess = " . (int) $mode . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_defaultAccess = $mode;
-
-		// If any of the notification subscribers no longer have read access,
-		// remove their subscription.
-		if (empty($this->_notifyList))
-			$this->getNotifyList();
-		foreach ($this->_notifyList["users"] as $u) {
-			if ($this->getAccessMode($u) < M_READ) {
-				$this->removeNotify($u->getID(), true);
-			}
-		}
-		foreach ($this->_notifyList["groups"] as $g) {
-			if ($this->getGroupAccessMode($g) < M_READ) {
-				$this->removeNotify($g->getID(), false);
-			}
-		}
-
-		return true;
-	} /* }}} */
-
-	function inheritsAccess() { return $this->_inheritAccess; }
-
-	function setInheritAccess($inheritAccess) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$inheritAccess = ($inheritAccess) ? "1" : "0";
-
-		$queryStr = "UPDATE tblFolders SET inheritAccess = " . (int) $inheritAccess . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_inheritAccess = $inheritAccess;
-
-		// If any of the notification subscribers no longer have read access,
-		// remove their subscription.
-		if (empty($this->_notifyList))
-			$this->getNotifyList();
-		foreach ($this->_notifyList["users"] as $u) {
-			if ($this->getAccessMode($u) < M_READ) {
-				$this->removeNotify($u->getID(), true);
-			}
-		}
-		foreach ($this->_notifyList["groups"] as $g) {
-			if ($this->getGroupAccessMode($g) < M_READ) {
-				$this->removeNotify($g->getID(), false);
-			}
-		}
-
-		return true;
-	} /* }}} */
-
-	function getSequence() { return $this->_sequence; }
-
-	function setSequence($seq) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblFolders SET sequence = " . $seq . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_sequence = $seq;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Returns a list of subfolders
-	 * This function does not check for access rights. Use
-	 * {@link LetoDMS_Core_DMS::filterAccess} for checking each folder against
-	 * the currently logged in user and the access rights.
-	 *
-	 * @param string $orderby if set to 'n' the list is ordered by name, otherwise
-	 *        it will be ordered by sequence
-	 * @return array list of folder objects or false in case of an error
-	 */
-	function getSubFolders($orderby="") { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!isset($this->_subFolders)) {
-			if ($orderby=="n") $queryStr = "SELECT * FROM tblFolders WHERE parent = " . $this->_id . " ORDER BY name";
-			else $queryStr = "SELECT * FROM tblFolders WHERE parent = " . $this->_id . " ORDER BY sequence";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && $resArr == false)
-				return false;
-
-			$this->_subFolders = array();
-			for ($i = 0; $i < count($resArr); $i++)
-//				$this->_subFolders[$i] = new LetoDMS_Core_Folder($resArr[$i]["id"], $resArr[$i]["name"], $resArr[$i]["parent"], $resArr[$i]["comment"], $resArr[$i]["owner"], $resArr[$i]["inheritAccess"], $resArr[$i]["defaultAccess"], $resArr[$i]["sequence"]);
-				$this->_subFolders[$i] = $this->_dms->getFolder($resArr[$i]["id"]);
-		}
-
-		return $this->_subFolders;
-	} /* }}} */
-
-	function addSubFolder($name, $comment, $owner, $sequence) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		// Set the folderList of the folder
-		$pathPrefix="";
-		$path = $this->getPath();
-		foreach ($path as $f) {
-			$pathPrefix .= ":".$f->getID();
-		}
-		if (strlen($pathPrefix)>1) {
-			$pathPrefix .= ":";
-		}
-		//inheritAccess = true, defaultAccess = M_READ
-		$queryStr = "INSERT INTO tblFolders (name, parent, folderList, comment, date, owner, inheritAccess, defaultAccess, sequence) ".
-					"VALUES (".$db->qstr($name).", ".$this->_id.", ".$db->qstr($pathPrefix).", ".$db->qstr($comment).", ".mktime().", ".$owner->getID().", 1, ".M_READ.", ". $sequence.")";
-		if (!$db->getResult($queryStr))
-			return false;
-		$newFolder = $this->_dms->getFolder($db->getInsertID());
-		unset($this->_subFolders);
-
-		return $newFolder;
-	} /* }}} */
-
-	/**
-	 * Returns an array of all parents, grand parent, etc. up to root folder.
-	 * The folder itself is the last element of the array.
-	 *
-	 * @return array Array of parents
-	 */
-	function getPath() { /* {{{ */
-		if (!isset($this->_parentID) || ($this->_parentID == "") || ($this->_parentID == 0)) {
-			return array($this);
-		}
-		else {
-			$res = $this->getParent();
-			if (!$res) return false;
-
-			$path = $this->_parent->getPath();
-			if (!$path) return false;
-
-			array_push($path, $this);
-			return $path;
-		}
-	} /* }}} */
-
-	/**
-	 * Returns a unix file system path
-	 *
-	 * @return string path separated with '/'
-	 */
-	function getFolderPathPlain() { /* {{{ */
-		$path="";
-		$folderPath = $this->getPath();
-		for ($i = 0; $i  < count($folderPath); $i++) {
-			$path .= $folderPath[$i]->getName();
-			if ($i +1 < count($folderPath))
-				$path .= " / ";
-		}
-		return $path;
-	} /* }}} */
-
-	/**
-	 * Check, if this folder is a subfolder of a given folder
-	 *
-	 * @param object $folder parent folder
-	 * @return boolean true if folder is a subfolder
-	 */
-	function isDescendant($folder) { /* {{{ */
-		if ($this->_parentID == $folder->getID())
-			return true;
-		elseif (isset($this->_parentID)) {
-			$res = $this->getParent();
-			if (!$res) return false;
-
-			return $this->_parent->isDescendant($folder);
-		} else
-			return false;
-	} /* }}} */
-
-	/**
-	 * Get all documents of the folder
-	 * This function does not check for access rights. Use
-	 * {@link LetoDMS_Core_DMS::filterAccess} for checking each document against
-	 * the currently logged in user and the access rights.
-	 *
-	 * @param string $orderby if set to 'n' the list is ordered by name, otherwise
-	 *        it will be ordered by sequence
-	 * @return array list of documents or false in case of an error
-	 */
-	function getDocuments($orderby="") { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!isset($this->_documents)) {
-			if ($orderby=="n") $queryStr = "SELECT * FROM tblDocuments WHERE folder = " . $this->_id . " ORDER BY name";
-			else $queryStr = "SELECT * FROM tblDocuments WHERE folder = " . $this->_id . " ORDER BY sequence";
-
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$resArr)
-				return false;
-
-			$this->_documents = array();
-			foreach ($resArr as $row) {
-//				array_push($this->_documents, new LetoDMS_Core_Document($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], isset($row["lockUser"])?$row["lockUser"]:NULL, $row["keywords"], $row["sequence"]));
-				array_push($this->_documents, $this->_dms->getDocument($row["id"]));
-			}
-		}
-		return $this->_documents;
-	} /* }}} */
-
-	// $comment will be used for both document and version leaving empty the version_comment 
-	/**
-	 * Add a new document to the folder
-	 * This function will add a new document and its content from a given file. 
-	 * It does not check for access rights on the folder. The new documents
-	 * default access right is read only and the access right is inherited.
-	 *
-	 * @param string $name name of new document
-	 * @param string $comment comment of new document
-	 * @param integer $expires expiration date as a unix timestamp or 0 for no
-	 *        expiration date
-	 * @param object $owner owner of the new document
-	 * @param string $keywords keywords of new document
-	 * @param string $tmpFile the path of the file containing the content
-	 * @param string $orgFileName the original file name
-	 * @param string $fileType usually the extension of the filename
-	 * @param string $mimeType mime type of the content
-	 * @param float $sequence position of new document within the folder
-	 * @param array $reviewers list of users who must review this document
-	 * @param array $approvers list of users who must approve this document
-	 * @param string $reqversion version number of the content
-	 * @param string $version_comment comment of the content. If left empty
-	 *        the $comment will be used.
-	 * @return array/boolean false in case of error, otherwise an array
-	 *        containing two elements. The first one is the new document, the
-	 *        second one is the result set returned when inserting the content.
-	 */
-	function addDocument($name, $comment, $expires, $owner, $keywords, $categories, $tmpFile, $orgFileName, $fileType, $mimeType, $sequence, $reviewers=array(), $approvers=array(),$reqversion,$version_comment="") { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$expires = (!$expires) ? 0 : $expires;
-
-		// Must also ensure that the document has a valid folderList.
-		$pathPrefix="";
-		$path = $this->getPath();
-		foreach ($path as $f) {
-			$pathPrefix .= ":".$f->getID();
-		}
-		if (strlen($pathPrefix)>1) {
-			$pathPrefix .= ":";
-		}
-
-		$queryStr = "INSERT INTO tblDocuments (name, comment, date, expires, owner, folder, folderList, inheritAccess, defaultAccess, locked, keywords, sequence) VALUES ".
-					"(".$db->qstr($name).", ".$db->qstr($comment).", " . mktime().", ".(int) $expires.", ".$owner->getID().", ".$this->_id.",".$db->qstr($pathPrefix).", 1, ".M_READ.", -1, ".$db->qstr($keywords).", " . $sequence . ")";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$document = $this->_dms->getDocument($db->getInsertID());
-
-		if ($version_comment!="")
-			$res = $document->addContent($version_comment, $owner, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers, $approvers,$reqversion);
-		else $res = $document->addContent($comment, $owner, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers, $approvers,$reqversion);
-
-		if (is_bool($res) && !$res) {
-			$queryStr = "DELETE FROM tblDocuments WHERE id = " . $document->getID();
-			$db->getResult($queryStr);
-			return false;
-		}
-
-		if($categories) {
-			$document->setCategories($categories);
-		}
-		return array($document, $res);
-	} /* }}} */
-
-	function remove() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		// Do not delete the root folder.
-		if ($this->_id == $this->_dms->rootFolderID || !isset($this->_parentID) || ($this->_parentID == null) || ($this->_parentID == "") || ($this->_parentID == 0)) {
-			return false;
-		}
-
-		//Entfernen der Unterordner und Dateien
-		$res = $this->getSubFolders();
-		if (is_bool($res) && !$res) return false;
-		$res = $this->getDocuments();
-		if (is_bool($res) && !$res) return false;
-
-		foreach ($this->_subFolders as $subFolder) {
-			$res = $subFolder->remove(FALSE);
-			if (!$res) return false;
-		}
-
-		foreach ($this->_documents as $document) {
-			$res = $document->remove(FALSE);
-			if (!$res) return false;
-		}
-
-		//Entfernen der Datenbankeinträge
-		$queryStr = "DELETE FROM tblFolders WHERE id =  " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblACLs WHERE target = ". $this->_id. " AND targetType = " . T_FOLDER;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$queryStr = "DELETE FROM tblNotify WHERE target = ". $this->_id. " AND targetType = " . T_FOLDER;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Returns a list of access privileges
-	 *
-	 * If the document inherits the access privileges from the parent folder
-	 * those will be returned.
-	 * $mode and $op can be set to restrict the list of returned access
-	 * privileges. If $mode is set to M_ANY no restriction will apply
-	 * regardless of the value of $op. The returned array contains a list
-	 * of {@link LetoDMS_Core_UserAccess} and
-	 * {@link LetoDMS_Core_GroupAccess} objects.
-	 * 
-	 * @param integer $mode access mode (defaults to M_ANY)
-	 * @param integer $op operation (defaults to O_EQ)
-	 * @return array multi dimensional array
-	 */
-	function getAccessList($mode = M_ANY, $op = O_EQ) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if ($this->inheritsAccess()) {
-			$res = $this->getParent();
-			if (!$res) return false;
-			return $this->_parent->getAccessList($mode, $op);
-		}
-
-		if (!isset($this->_accessList[$mode])) {
-			if ($op!=O_GTEQ && $op!=O_LTEQ && $op!=O_EQ) {
-				return false;
-			}
-			$modeStr = "";
-			if ($mode!=M_ANY) {
-				$modeStr = " AND mode".$op.(int)$mode;
-			}
-			$queryStr = "SELECT * FROM tblACLs WHERE targetType = ".T_FOLDER.
-				" AND target = " . $this->_id .	$modeStr . " ORDER BY targetType";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && !$resArr)
-				return false;
-
-			$this->_accessList[$mode] = array("groups" => array(), "users" => array());
-			foreach ($resArr as $row) {
-				if ($row["userID"] != -1)
-					array_push($this->_accessList[$mode]["users"], new LetoDMS_Core_UserAccess($this->_dms->getUser($row["userID"]), $row["mode"]));
-				else //if ($row["groupID"] != -1)
-					array_push($this->_accessList[$mode]["groups"], new LetoDMS_Core_GroupAccess($this->_dms->getGroup($row["groupID"]), $row["mode"]));
-			}
-		}
-
-		return $this->_accessList[$mode];
-	} /* }}} */
-
-	/**
-	 * Delete all entries for this folder from the access control list
-	 *
-	 * @return boolean true if operation was successful otherwise false
-	 */
-	function clearAccessList() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE FROM tblACLs WHERE targetType = " . T_FOLDER . " AND target = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_accessList);
-		return true;
-	} /* }}} */
-
-	/**
-	 * Add access right to folder
-	 * This function may change in the future. Instead of passing the a flag
-	 * and a user/group id a user or group object will be expected.
-	 *
-	 * @param integer $mode access mode
-	 * @param integer $userOrGroupID id of user or group
-	 * @param integer $isUser set to 1 if $userOrGroupID is the id of a
-	 *        user
-	 */
-	function addAccess($mode, $userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		$queryStr = "INSERT INTO tblACLs (target, targetType, ".$userOrGroup.", mode) VALUES 
-					(".$this->_id.", ".T_FOLDER.", " . (int) $userOrGroupID . ", " .(int) $mode. ")";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_accessList);
-
-		// Update the notify list, if necessary.
-		if ($mode == M_NONE) {
-			$this->removeNotify($userOrGroupID, $isUser);
-		}
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Change access right of folder
-	 * This function may change in the future. Instead of passing the a flag
-	 * and a user/group id a user or group object will be expected.
-	 *
-	 * @param integer $newMode access mode
-	 * @param integer $userOrGroupID id of user or group
-	 * @param integer $isUser set to 1 if $userOrGroupID is the id of a
-	 *        user
-	 */
-	function changeAccess($newMode, $userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		$queryStr = "UPDATE tblACLs SET mode = " . (int) $newMode . " WHERE targetType = ".T_FOLDER." AND target = " . $this->_id . " AND " . $userOrGroup . " = " . (int) $userOrGroupID;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_accessList);
-
-		// Update the notify list, if necessary.
-		if ($newMode == M_NONE) {
-			$this->removeNotify($userOrGroupID, $isUser);
-		}
-
-		return true;
-	} /* }}} */
-
-	function removeAccess($userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		$queryStr = "DELETE FROM tblACLs WHERE targetType = ".T_FOLDER." AND target = ".$this->_id." AND ".$userOrGroup." = " . (int) $userOrGroupID;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		unset($this->_accessList);
-
-		// Update the notify list, if necessary.
-		$mode = ($isUser ? $this->getAccessMode($this->_dms->getUser($userOrGroupID)) : $this->getGroupAccessMode($this->_dms->getGroup($userOrGroupID)));
-		if ($mode == M_NONE) {
-			$this->removeNotify($userOrGroupID, $isUser);
-		}
-
-		return true;
-	} /* }}} */
-
-	/**
-	 * Get the access mode of a user on the folder
-	 * This function returns the access mode for a given user. An administrator
-	 * and the owner of the folder has unrestricted access. A guest user has
-	 * read only access or no access if access rights are further limited
-	 * by access control lists. All other users have access rights according
-	 * to the access control lists or the default access. This function will
-	 * recursive check for access rights of parent folders if access rights
-	 * are inherited.
-	 *
-	 * @param object $user user for which access shall be checked
-	 * @return integer access mode
-	 */
-	function getAccessMode($user) { /* {{{ */
-		/* Admins have full access */
-		if ($user->isAdmin()) return M_ALL;
-
-		/* User has full access if he/she is the owner of the document */
-		if ($user->getID() == $this->_ownerID) return M_ALL;
-
-		/* Guest has read access by default, if guest login is allowed at all */
-		if ($user->isGuest()) {
-			$mode = $this->getDefaultAccess();
-			if ($mode >= M_READ) return M_READ;
-			else return M_NONE;
-		}
-
-		/* check ACLs */
-		$accessList = $this->getAccessList();
-		if (!$accessList) return false;
-
-		foreach ($accessList["users"] as $userAccess) {
-			if ($userAccess->getUserID() == $user->getID()) {
-				return $userAccess->getMode();
-			}
-		}
-		foreach ($accessList["groups"] as $groupAccess) {
-			if ($user->isMemberOfGroup($groupAccess->getGroup())) {
-//				if ($groupAccess->getMode()>$result)
-					return $groupAccess->getMode();
-			}
-		}
-		$result = $this->getDefaultAccess();
-		return $result;
-	} /* }}} */
-
-	/**
-	 * Get the access mode for a group on the folder
-	 * This function returns the access mode for a given group. The algorithmn
-	 * applied to get the access mode is the same as describe at
-	 * {@link getAccessMode}
-	 *
-	 * @param object $group group for which access shall be checked
-	 * @return integer access mode
-	 */
-	function getGroupAccessMode($group) { /* {{{ */
-		$highestPrivileged = M_NONE;
-		$foundInACL = false;
-		$accessList = $this->getAccessList();
-		if (!$accessList)
-			return false;
-
-		foreach ($accessList["groups"] as $groupAccess) {
-			if ($groupAccess->getGroupID() == $group->getID()) {
-				$foundInACL = true;
-				if ($groupAccess->getMode() > $highestPrivileged)
-					$highestPrivileged = $groupAccess->getMode();
-				if ($highestPrivileged == M_ALL) /* no need to check further */
-					return $highestPrivileged;
-			}
-		}
-		if ($foundInACL)
-			return $highestPrivileged;
-
-		/* Take default access */
-		return $this->getDefaultAccess();
-	} /* }}} */
-
-	/**
-	 * Get a list of all notification
-	 * This function returns all users and groups that have registerd a
-	 * notification for the folder
-	 *
-	 * @return array array with a the elements 'users' and 'groups' which
-	 *        contain a list of users and groups.
-	 */
-	function getNotifyList() { /* {{{ */
-		if (empty($this->_notifyList)) {
-			$db = $this->_dms->getDB();
-
-			$queryStr ="SELECT * FROM tblNotify WHERE targetType = " . T_FOLDER . " AND target = " . $this->_id;
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && $resArr == false)
-				return false;
-
-			$this->_notifyList = array("groups" => array(), "users" => array());
-			foreach ($resArr as $row)
-			{
-				if ($row["userID"] != -1)
-					array_push($this->_notifyList["users"], $this->_dms->getUser($row["userID"]) );
-				else //if ($row["groupID"] != -1)
-					array_push($this->_notifyList["groups"], $this->_dms->getGroup($row["groupID"]) );
-			}
-		}
-		return $this->_notifyList;
-	} /* }}} */
-
-	/*
-	 * Add a user/group to the notification list
-	 * This function does not check if the currently logged in user
-	 * is allowed to add a notification. This must be checked by the calling
-	 * application.
-	 *
-	 * @param integer $userOrGroupID
-	 * @param boolean $isUser true if $userOrGroupID is a user id otherwise false
-	 * @return integer error code
-	 *    -1: Invalid User/Group ID.
-	 *    -2: Target User / Group does not have read access.
-	 *    -3: User is already subscribed.
-	 *    -4: Database / internal error.
-	 *     0: Update successful.
-	 */
-	function addNotify($userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		/* Verify that user / group exists */
-		$obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
-		if (!is_object($obj)) {
-			return -1;
-		}
-
-		/* Verify that the requesting user has permission to add the target to
-		 * the notification system.
-		 */
-		/*
-		 * The calling application should enforce the policy on who is allowed
-		 * to add someone to the notification system. If is shall remain here
-		 * the currently logged in user should be passed to this function
-		 *
-		GLOBAL $user;
-		if ($user->isGuest()) {
-			return -2;
-		}
-		if (!$user->isAdmin()) {
-			if ($isUser) {
-				if ($user->getID() != $obj->getID()) {
-					return -2;
-				}
-			}
-			else {
-				if (!$obj->isMember($user)) {
-					return -2;
-				}
-			}
-		}
-		*/
-
-		//
-		// Verify that user / group has read access to the document.
-		//
-		if ($isUser) {
-			// Users are straightforward to check.
-			if ($this->getAccessMode($obj) < M_READ) {
-				return -2;
-			}
-		}
-		else {
-			// FIXME: Why not check the access list first and if this returns
-			// not result, then use the default access?
-			// Groups are a little more complex.
-			if ($this->getDefaultAccess() >= M_READ) {
-				// If the default access is at least READ-ONLY, then just make sure
-				// that the current group has not been explicitly excluded.
-				$acl = $this->getAccessList(M_NONE, O_EQ);
-				$found = false;
-				foreach ($acl["groups"] as $group) {
-					if ($group->getGroupID() == $userOrGroupID) {
-						$found = true;
-						break;
-					}
-				}
-				if ($found) {
-					return -2;
-				}
-			}
-			else {
-				// The default access is restricted. Make sure that the group has
-				// been explicitly allocated access to the document.
-				$acl = $this->getAccessList(M_READ, O_GTEQ);
-				if (is_bool($acl)) {
-					return -4;
-				}
-				$found = false;
-				foreach ($acl["groups"] as $group) {
-					if ($group->getGroupID() == $userOrGroupID) {
-						$found = true;
-						break;
-					}
-				}
-				if (!$found) {
-					return -2;
-				}
-			}
-		}
-		//
-		// Check to see if user/group is already on the list.
-		//
-		$queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
-			"AND `tblNotify`.`targetType` = '".T_FOLDER."' ".
-			"AND `tblNotify`.`".$userOrGroup."` = '". (int) $userOrGroupID."'";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr)) {
-			return -4;
-		}
-		if (count($resArr)>0) {
-			return -3;
-		}
-
-		$queryStr = "INSERT INTO tblNotify (target, targetType, " . $userOrGroup . ") VALUES (" . $this->_id . ", " . T_FOLDER . ", " .  (int) $userOrGroupID . ")";
-		if (!$db->getResult($queryStr))
-			return -4;
-
-		unset($this->_notifyList);
-		return 0;
-	} /* }}} */
-
-	/*
-	 * Removes notify for a user or group to folder
-	 * This function does not check if the currently logged in user
-	 * is allowed to remove a notification. This must be checked by the calling
-	 * application.
-	 *
-	 * @param integer $userOrGroupID
-	 * @param boolean $isUser true if $userOrGroupID is a user id otherwise false
-	 * @return integer error code
-	 *    -1: Invalid User/Group ID.
-	 *    -3: User is not subscribed.
-	 *    -4: Database / internal error.
-	 *     0: Update successful.
-	 */
-	function removeNotify($userOrGroupID, $isUser) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		/* Verify that user / group exists. */
-		$obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
-		if (!is_object($obj)) {
-			return -1;
-		}
-
-		$userOrGroup = ($isUser) ? "userID" : "groupID";
-
-		/* Verify that the requesting user has permission to add the target to
-		 * the notification system.
-		 */
-		/*
-		 * The calling application should enforce the policy on who is allowed
-		 * to add someone to the notification system. If is shall remain here
-		 * the currently logged in user should be passed to this function
-		 *
-		GLOBAL  $user;
-		if ($user->isGuest()) {
-			return -2;
-		}
-		if (!$user->isAdmin()) {
-			if ($isUser) {
-				if ($user->getID() != $obj->getID()) {
-					return -2;
-				}
-			}
-			else {
-				if (!$obj->isMember($user)) {
-					return -2;
-				}
-			}
-		}
-		*/
-
-		//
-		// Check to see if the target is in the database.
-		//
-		$queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
-			"AND `tblNotify`.`targetType` = '".T_FOLDER."' ".
-			"AND `tblNotify`.`".$userOrGroup."` = '". (int) $userOrGroupID."'";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr)) {
-			return -4;
-		}
-		if (count($resArr)==0) {
-			return -3;
-		}
-
-		$queryStr = "DELETE FROM tblNotify WHERE target = " . $this->_id . " AND targetType = " . T_FOLDER . " AND " . $userOrGroup . " = " .  (int) $userOrGroupID;
-		if (!$db->getResult($queryStr))
-			return -4;
-
-		unset($this->_notifyList);
-		return 0;
-	} /* }}} */
-
-	function getApproversList() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!isset($this->_approversList)) {
-			$this->_approversList = array("groups" => array(), "users" => array());
-			$userIDs = "";
-			$groupIDs = "";
-			$defAccess  = $this->getDefaultAccess();
-
-			if ($defAccess<M_READ) {
-				// Get the list of all users and groups that are listed in the ACL as
-				// having write access to the folder.
-				$tmpList = $this->getAccessList(M_READ, O_GTEQ);
-			}
-			else {
-				// Get the list of all users and groups that DO NOT have write access
-				// to the folder.
-				$tmpList = $this->getAccessList(M_NONE, O_LTEQ);
-			}
-			foreach ($tmpList["groups"] as $groupAccess) {
-				$groupIDs .= (strlen($groupIDs)==0 ? "" : ", ") . $groupAccess->getGroupID();
-			}
-			foreach ($tmpList["users"] as $userAccess) {
-				$user = $userAccess->getUser();
-				if (!$user->isGuest()) {
-					$userIDs .= (strlen($userIDs)==0 ? "" : ", ") . $userAccess->getUserID();
-				}
-			}
-
-			// Construct a query against the users table to identify those users
-			// that have write access to this folder, either directly through an
-			// ACL entry, by virtue of ownership or by having administrative rights
-			// on the database.
-			$queryStr="";
-			if ($defAccess < M_READ) {
-				if (strlen($groupIDs)>0) {
-					$queryStr = "(SELECT `tblUsers`.* FROM `tblUsers` ".
-						"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
-						"WHERE `tblGroupMembers`.`groupID` IN (". $groupIDs .") ".
-						"AND `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest.")";
-				}
-				$queryStr .= (strlen($queryStr)==0 ? "" : " UNION ").
-					"(SELECT `tblUsers`.* FROM `tblUsers` ".
-					"WHERE (`tblUsers`.`role` != ".LetoDMS_Core_User::role_guest.") ".
-					"AND ((`tblUsers`.`id` = ". $this->_ownerID . ") ".
-					"OR (`tblUsers`.`role` = ".LetoDMS_Core_User::role_admin.")".
-					(strlen($userIDs) == 0 ? "" : " OR (`tblUsers`.`id` IN (". $userIDs ."))").
-					")) ORDER BY `login`";
-			}
-			else {
-				if (strlen($groupIDs)>0) {
-					$queryStr = "(SELECT `tblUsers`.* FROM `tblUsers` ".
-						"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
-						"WHERE `tblGroupMembers`.`groupID` NOT IN (". $groupIDs .")".
-						"AND `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest." ".
-						(strlen($userIDs) == 0 ? ")" : " AND (`tblUsers`.`id` NOT IN (". $userIDs .")))");
-				}
-				$queryStr .= (strlen($queryStr)==0 ? "" : " UNION ").
-					"(SELECT `tblUsers`.* FROM `tblUsers` ".
-					"WHERE (`tblUsers`.`id` = ". $this->_ownerID . ") ".
-					"OR (`tblUsers`.`role` = ".LetoDMS_Core_User::role_admin."))".
-					"UNION ".
-					"(SELECT `tblUsers`.* FROM `tblUsers` ".
-					"WHERE `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest." ".
-					(strlen($userIDs) == 0 ? ")" : " AND (`tblUsers`.`id` NOT IN (". $userIDs .")))").
-					" ORDER BY `login`";
-			}
-			$resArr = $db->getResultArray($queryStr);
-			if (!is_bool($resArr)) {
-				foreach ($resArr as $row) {
-					$user = $this->_dms->getUser($row['id']);
-					if (!$this->_dms->enableAdminRevApp && $user->isAdmin()) continue;					
-					$this->_approversList["users"][] = $user;
-				}
-			}
-
-			// Assemble the list of groups that have write access to the folder.
-			$queryStr="";
-			if ($defAccess < M_READ) {
-				if (strlen($groupIDs)>0) {
-					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
-						"WHERE `tblGroups`.`id` IN (". $groupIDs .")";
-				}
-			}
-			else {
-				if (strlen($groupIDs)>0) {
-					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
-						"WHERE `tblGroups`.`id` NOT IN (". $groupIDs .")";
-				}
-				else {
-					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups`";
-				}
-			}
-			if (strlen($queryStr)>0) {
-				$resArr = $db->getResultArray($queryStr);
-				if (!is_bool($resArr)) {
-					foreach ($resArr as $row) {
-						$group = $this->_dms->getGroup($row["id"]);
-						$this->_approversList["groups"][] = $group;
-					}
-				}
-			}
-		}
-		return $this->_approversList;
-	} /* }}} */
-
-	/**
-	 * Get the internally used folderList which stores the ids of folders from
-	 * the root folder to the parent folder.
-	 *
-	 * @return string column separated list of folder ids
-	 */
-	function getFolderList() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT folderList FROM tblFolders where id = ".$this->_id;
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && !$resArr)
-			return false;
-		return $resArr[0]['folderList'];
-	} /* }}} */
-
-	/**
-	 * Checks the internal data of the folder and repairs it.
-	 * Currently, this function only repairs an incorrect folderList
-	 *
-	 * @return boolean true on success, otherwise false
-	 */
-	function repair() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$curfolderlist = $this->getFolderList();
-
-		// calculate the folderList of the folder
-		$parent = $this->getParent();
-		$pathPrefix="";
-		$path = $parent->getPath();
-		foreach ($path as $f) {
-			$pathPrefix .= ":".$f->getID();
-		}
-		if (strlen($pathPrefix)>1) {
-			$pathPrefix .= ":";
-		}
-		if($curfolderlist != $pathPrefix) {
-			$queryStr = "UPDATE tblFolders SET folderList='".$pathPrefix."' WHERE id = ". $this->_id;
-			$res = $db->getResult($queryStr);
-			if (!$res)
-				return false;
-		}
-		return true;
-	} /* }}} */
-
-}
-
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassGroup.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassGroup.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassGroup.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassGroup.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,296 +0,0 @@
-<?php
-/**
- * Implementation of the group object in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Class to represent a user group in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_Group {
-	/**
-	 * The id of the user group
-	 *
-	 * @var integer
-	 */
-	var $_id;
-
-	/**
-	 * The name of the user group
-	 *
-	 * @var string
-	 */
-	var $_name;
-
-	/**
-	 * Back reference to DMS this user group belongs to
-	 *
-	 * @var object
-	 */
-	var $_dms;
-
-	function LetoDMS_Core_Group($id, $name, $comment) { /* {{{ */
-		$this->_id = $id;
-		$this->_name = $name;
-		$this->_comment = $comment;
-		$this->_dms = null;
-	} /* }}} */
-
-	function setDMS($dms) { /* {{{ */
-		$this->_dms = $dms;
-	} /* }}} */
-
-	function getID() { return $this->_id; }
-
-	function getName() { return $this->_name; }
-
-	function setName($newName) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblGroups SET name = ".$db->qstr($newName)." WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_name = $newName;
-		return true;
-	} /* }}} */
-
-	function getComment() { return $this->_comment; }
-
-	function setComment($newComment) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblGroups SET comment = ".$db->qstr($newComment)." WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_comment = $newComment;
-		return true;
-	} /* }}} */
-
-	function getUsers() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!isset($this->_users)) {
-			$queryStr = "SELECT `tblUsers`.* FROM `tblUsers` ".
-				"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
-				"WHERE `tblGroupMembers`.`groupID` = '". $this->_id ."'";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && $resArr == false)
-				return false;
-
-			$this->_users = array();
-
-			foreach ($resArr as $row) {
-				$user = new LetoDMS_Core_User($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $row["role"], $row['hidden']);
-				array_push($this->_users, $user);
-			}
-		}
-		return $this->_users;
-	} /* }}} */
-
-	function getManagers() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT `tblUsers`.* FROM `tblUsers` ".
-			"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
-			"WHERE `tblGroupMembers`.`groupID` = '". $this->_id ."' AND tblGroupMembers.manager = 1";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-
-		$managers = array();
-
-		foreach ($resArr as $row) {
-			$user = new LetoDMS_Core_User($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $row["role"], $row['hidden']);
-			array_push($managers, $user);
-		}
-		return $managers;
-	} /* }}} */
-
-	function addUser($user,$asManager=false) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "INSERT INTO tblGroupMembers (groupID, userID, manager) VALUES (".$this->_id.", ".$user->getID(). ", " . ($asManager?"1":"0") ." )";
-		$res = $db->getResult($queryStr);
-
-		if ($res) return false;
-
-		unset($this->_users);
-		return true;
-	} /* }}} */
-
-	function removeUser($user) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE FROM tblGroupMembers WHERE groupID = ".$this->_id." AND userID = ".$user->getID();
-		$res = $db->getResult($queryStr);
-
-		if ($res) return false;
-		unset($this->_users);
-		return true;
-	} /* }}} */
-
-	// $asManager=false: verify if user is in group
-	// $asManager=true : verify if user is in group as manager
-	function isMember($user,$asManager=false) { /* {{{ */
-		if (isset($this->_users)&&!$asManager) {
-			foreach ($this->_users as $usr)
-				if ($usr->getID() == $user->getID())
-					return true;
-			return false;
-		}
-
-		$db = $this->_dms->getDB();
-		if ($asManager) $queryStr = "SELECT * FROM tblGroupMembers WHERE groupID = " . $this->_id . " AND userID = " . $user->getID() . " AND manager = 1";
-		else $queryStr = "SELECT * FROM tblGroupMembers WHERE groupID = " . $this->_id . " AND userID = " . $user->getID();
-
-		$resArr = $db->getResultArray($queryStr);
-
-		if (is_bool($resArr) && $resArr == false) return false;
-		if (count($resArr) != 1) return false;
-
-		return true;
-	} /* }}} */
-
-	function toggleManager($user) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!$this->isMember($user)) return false;
-
-		if ($this->isMember($user,true)) $queryStr = "UPDATE tblGroupMembers SET manager = 0 WHERE groupID = ".$this->_id." AND userID = ".$user->getID();
-		else $queryStr = "UPDATE tblGroupMembers SET manager = 1 WHERE groupID = ".$this->_id." AND userID = ".$user->getID();
-
-		if (!$db->getResult($queryStr)) return false;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Delete user group
-	 * This function deletes the user group and all it references, like access
-	 * control lists, notifications, as a child of other groups, etc.
-	 *
-	 * @param object $user the user doing the removal (needed for entry in
-	 *        review log.
-	 * @return boolean true on success or false in case of an error
-	 */
-	function remove($user) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE FROM tblGroups WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblGroupMembers WHERE groupID = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblACLs WHERE groupID = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblNotify WHERE groupID = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblMandatoryReviewers WHERE reviewerGroupID = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-		$queryStr = "DELETE FROM tblMandatoryApprovers WHERE approverGroupID = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		// TODO : update document status if reviewer/approver has been deleted
-
-
-		$reviewStatus = $this->getReviewStatus();
-		foreach ($reviewStatus as $r) {
-			$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
-				"VALUES ('". $r["reviewID"] ."', '-2', 'Review group removed from process', NOW(), '". $user->getID() ."')";
-			$res=$db->getResult($queryStr);
-		}
-
-		$approvalStatus = $this->getApprovalStatus();
-		foreach ($approvalStatus as $a) {
-			$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
-				"VALUES ('". $a["approveID"] ."', '-2', 'Approval group removed from process', NOW(), '". $user->getID() ."')";
-			$res=$db->getResult($queryStr);
-		}
-
-		return true;
-	} /* }}} */
-
-	function getReviewStatus($documentID=null, $version=null) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!$db->createTemporaryTable("ttreviewid")) {
-			return false;
-		}
-
-		$status = array();
-
-		// See if the group is assigned as a reviewer.
-		$queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
-			"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
-			"`tblDocumentReviewLog`.`userID` ".
-			"FROM `tblDocumentReviewers` ".
-			"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
-			"LEFT JOIN `ttreviewid` on `ttreviewid`.`maxLogID` = `tblDocumentReviewLog`.`reviewLogID` ".
-			"WHERE `ttreviewid`.`maxLogID`=`tblDocumentReviewLog`.`reviewLogID` ".
-			($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
-			($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
-			"AND `tblDocumentReviewers`.`type`='1' ".
-			"AND `tblDocumentReviewers`.`required`='". $this->_id ."' ";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr)>0) {
-			foreach ($resArr as $res)
-				$status[] = $res;
-		}
-		return $status;
-	} /* }}} */
-
-	function getApprovalStatus($documentID=null, $version=null) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!$db->createTemporaryTable("ttapproveid")) {
-			return false;
-		}
-
-		$status = array();
-
-		// See if the group is assigned as an approver.
-		$queryStr = "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
-			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
-			"`tblDocumentApproveLog`.`userID` ".
-			"FROM `tblDocumentApprovers` ".
-			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
-			"LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
-			"WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
-			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
-			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
-			"AND `tblDocumentApprovers`.`type`='1' ".
-			"AND `tblDocumentApprovers`.`required`='". $this->_id ."' ";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr)>0) {
-			foreach ($resArr as $res)
-				$status[] = $res;
-		}
-
-		return $status;
-	} /* }}} */
-}
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassKeywords.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassKeywords.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassKeywords.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassKeywords.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,137 +0,0 @@
-<?php
-/**
- * Implementation of keyword categories in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Class to represent a keyword category in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_KeywordCategory {
-	/**
-	 * @var integer $_id id of keyword category
-	 * @access protected
-	 */
-	var $_id;
-
-	/**
-	 * @var integer $_ownerID id of user who is the owner
-	 * @access protected
-	 */
-	var $_ownerID;
-
-	/**
-	 * @var string $_name name of category
-	 * @access protected
-	 */
-	var $_name;
-
-	/**
-	 * @var object $_dms reference to dms this category belongs to
-	 * @access protected
-	 */
-	var $_dms;
-
-	function LetoDMS_Core_KeywordCategory($id, $ownerID, $name) {
-		$this->_id = $id;
-		$this->_name = $name;
-		$this->_ownerID = $ownerID;
-		$this->_dms = null;
-	}
-
-	function setDMS($dms) {
-		$this->_dms = $dms;
-	}
-
-	function getID() { return $this->_id; }
-
-	function getName() { return $this->_name; }
-
-	function getOwner() {
-		if (!isset($this->_owner))
-			$this->_owner = $this->_dms->getUser($this->_ownerID);
-		return $this->_owner;
-	}
-
-	function setName($newName) {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblKeywordCategories SET name = ".$db->qstr($newName)." WHERE id = ". $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_name = $newName;
-		return true;
-	}
-
-	function setOwner($user) {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblKeywordCategories SET owner = " . $user->getID() . " WHERE id " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_ownerID = $user->getID();
-		$this->_owner = $user;
-		return true;
-	}
-
-	function getKeywordLists() {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT * FROM tblKeywords WHERE category = " . $this->_id;
-		return $db->getResultArray($queryStr);
-	}
-
-	function editKeywordList($listID, $keywords) {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblKeywords SET keywords = ".$db->qstr($keywords)." WHERE id = $listID";
-		return $db->getResult($queryStr);
-	}
-
-	function addKeywordList($keywords) {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "INSERT INTO tblKeywords (category, keywords) VALUES (" . $this->_id . ", ".$db->qstr($keywords).")";
-		return $db->getResult($queryStr);
-	}
-
-	function removeKeywordList($listID) {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE FROM tblKeywords WHERE id = $listID";
-		return $db->getResult($queryStr);
-	}
-
-	function remove() {
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE FROM tblKeywords WHERE category = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$queryStr = "DELETE FROM tblKeywordCategories WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		return true;
-	}
-}
-
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassNotification.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassNotification.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassNotification.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassNotification.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,78 +0,0 @@
-<?php
-/**
- * Implementation of a notification object
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Class to represent a notification
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_Notification { /* {{{ */
-	/**
-	 * @var integer id of target (document or folder)
-	 *
-	 * @access protected
-	 */
-	var $_target;
-
-	/**
-	 * @var integer document or folder
-	 *
-	 * @access protected
-	 */
-	var $_targettype;
-
-	/**
-	 * @var integer id of user to notify
-	 *
-	 * @access protected
-	 */
-	var $_userid;
-
-	/**
-	 * @var integer id of group to notify
-	 *
-	 * @access protected
-	 */
-	var $_groupid;
-
-	/**
-	 * @var object reference to the dms instance this user belongs to
-	 *
-	 * @access protected
-	 */
-	var $_dms;
-
-	function LetoDMS_Core_Notification($target, $targettype, $userid, $groupid) {
-		$this->_target = $target;
-		$this->_targettype = $targettype;
-		$this->_userid = $userid;
-		$this->_groupid = $groupid;
-	}
-
-	function setDMS($dms) {
-		$this->_dms = $dms;
-	}
-
-	function getTarget() { return $this->_target; }
-
-	function getTargetType() { return $this->_targettype; }
-
-	function getUser() { return $this->_dms->getUser($this->_userid); }
-
-	function getGroup() { return $this->_dms->getGroup($this->_groupid); }
-} /* }}} */
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassUser.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassUser.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.ClassUser.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.ClassUser.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,848 +0,0 @@
-<?php
-/**
- * Implementation of the user object in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Class to represent a user in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_User {
-	/**
-	 * @var integer id of user
-	 *
-	 * @access protected
-	 */
-	var $_id;
-
-	/**
-	 * @var string login name of user
-	 *
-	 * @access protected
-	 */
-	var $_login;
-
-	/**
-	 * @var string password of user as saved in database (md5)
-	 *
-	 * @access protected
-	 */
-	var $_pwd;
-
-	/**
-	 * @var string full human readable name of user
-	 *
-	 * @access protected
-	 */
-	var $_fullName;
-
-	/**
-	 * @var string email address of user
-	 *
-	 * @access protected
-	 */
-	var $_email;
-
-	/**
-	 * @var string prefered language of user
-	 *      possible values are 'English', 'German', 'Chinese_ZH_TW', 'Czech'
-	 *      'Francais', 'Hungarian', 'Italian', 'Portuguese_BR', 'Slovak', 
-	 *      'Spanish'
-	 *
-	 * @access protected
-	 */
-	var $_language;
-
-	/**
-	 * @var string preselected theme of user
-	 *
-	 * @access protected
-	 */
-	var $_theme;
-
-	/**
-	 * @var string comment of user
-	 *
-	 * @access protected
-	 */
-	var $_comment;
-
-	/**
-	 * @var string role of user. Can be one of LetoDMS_Core_User::role_user,
-	 *      LetoDMS_Core_User::role_admin, LetoDMS_Core_User::role_guest
-	 *
-	 * @access protected
-	 */
-	var $_role;
-
-	/**
-	 * @var string true if user shall be hidden
-	 *
-	 * @access protected
-	 */
-	var $_isHidden;
-
-	/**
-	 * @var object reference to the dms instance this user belongs to
-	 *
-	 * @access protected
-	 */
-	var $_dms;
-
-	const role_user = '0';
-	const role_admin = '1';
-	const role_guest = '2';
-
-	function LetoDMS_Core_User($id, $login, $pwd, $fullName, $email, $language, $theme, $comment, $role, $isHidden=0) {
-		$this->_id = $id;
-		$this->_login = $login;
-		$this->_pwd = $pwd;
-		$this->_fullName = $fullName;
-		$this->_email = $email;
-		$this->_language = $language;
-		$this->_theme = $theme;
-		$this->_comment = $comment;
-		$this->_role = $role;
-		$this->_isHidden = $isHidden;
-		$this->_dms = null;
-	}
-
-	function setDMS($dms) {
-		$this->_dms = $dms;
-	}
-
-	function getID() { return $this->_id; }
-
-	function getLogin() { return $this->_login; }
-
-	function setLogin($newLogin) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET login =".$db->qstr($newLogin)." WHERE id = " . $this->_id;
-		$res = $db->getResult($queryStr);
-		if (!$res)
-			return false;
-
-		$this->_login = $newLogin;
-		return true;
-	} /* }}} */
-
-	function getFullName() { return $this->_fullName; }
-
-	function setFullName($newFullName) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET fullname = ".$db->qstr($newFullName)." WHERE id = " . $this->_id;
-		$res = $db->getResult($queryStr);
-		if (!$res)
-			return false;
-
-		$this->_fullName = $newFullName;
-		return true;
-	} /* }}} */
-
-	function getPwd() { return $this->_pwd; }
-
-	function setPwd($newPwd) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET pwd =".$db->qstr($newPwd)." WHERE id = " . $this->_id;
-		$res = $db->getResult($queryStr);
-		if (!$res)
-			return false;
-
-		$this->_pwd = $newPwd;
-		return true;
-	} /* }}} */
-
-	function getEmail() { return $this->_email; }
-
-	function setEmail($newEmail) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET email =".$db->qstr($newEmail)." WHERE id = " . $this->_id;
-		$res = $db->getResult($queryStr);
-		if (!$res)
-			return false;
-
-		$this->_email = $newEmail;
-		return true;
-	} /* }}} */
-
-	function getLanguage() { return $this->_language; }
-
-	function setLanguage($newLanguage) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET language =".$db->qstr($newLanguage)." WHERE id = " . $this->_id;
-		$res = $db->getResult($queryStr);
-		if (!$res)
-			return false;
-
-		$this->_language = $newLanguage;
-		return true;
-	} /* }}} */
-
-	function getTheme() { return $this->_theme; }
-
-	function setTheme($newTheme) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET theme =".$db->qstr($newTheme)." WHERE id = " . $this->_id;
-		$res = $db->getResult($queryStr);
-		if (!$res)
-			return false;
-
-		$this->_theme = $newTheme;
-		return true;
-	} /* }}} */
-
-	function getComment() { return $this->_comment; }
-
-	function setComment($newComment) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET comment =".$db->qstr($newComment)." WHERE id = " . $this->_id;
-		$res = $db->getResult($queryStr);
-		if (!$res)
-			return false;
-
-		$this->_comment = $newComment;
-		return true;
-	} /* }}} */
-
-	function getRole() { return $this->_role; }
-
-	function setRole($newrole) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET role = " . $newrole . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_role = $newrole;
-		return true;
-	} /* }}} */
-
-	function isAdmin() { return ($this->_role == LetoDMS_Core_User::role_admin); }
-
-	function setAdmin($isAdmin) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET role = " . LetoDMS_Core_User::role_admin . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_role = LetoDMS_Core_User::role_admin;
-		return true;
-	} /* }}} */
-
-	function isGuest() { return ($this->_role == LetoDMS_Core_User::role_guest); }
-
-	function setGuest($isGuest) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "UPDATE tblUsers SET role = " . LetoDMS_Core_User::role_guest . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_role = LetoDMS_Core_User::role_guest;
-		return true;
-	} /* }}} */
-
-	function isHidden() { return $this->_isHidden; }
-
-	function setHidden($isHidden) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$isHidden = ($isHidden) ? "1" : "0";
-		$queryStr = "UPDATE tblUsers SET hidden = " . $isHidden . " WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_isHidden = $isHidden;
-		return true;
-	}	 /* }}} */
-
-	/**
-	 * Remove the user and also remove all its keywords, notifies, etc.
-	 * Do not remove folders and documents of the user, but assign them
-	 * to a different user.
-	 *
-	 * @param object $user the user doing the removal (needed for entry in
-	 *        review log.
-	 * @param object $assignToUser the user who is new owner of folders and
-	 *        documents which previously were owned by the delete user.
-	 * @return boolean true on success or false in case of an error
-	 */
-	function remove($user, $assignToUser=null) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		/* Records like folders and documents that formely have belonged to
-		 * the user will assign to another user. If no such user is set,
-		 * the function now returns false and will not use the admin user
-		 * anymore.
-		 */
-		if(!$assignToUser)
-			return;
-		$assignTo = $assignToUser->getID();
-
-		// delete private keyword lists
-		$queryStr = "SELECT tblKeywords.id FROM tblKeywords, tblKeywordCategories WHERE tblKeywords.category = tblKeywordCategories.id AND tblKeywordCategories.owner = " . $this->_id;
-		$resultArr = $db->getResultArray($queryStr);
-		if (count($resultArr) > 0) {
-			$queryStr = "DELETE FROM tblKeywords WHERE ";
-			for ($i = 0; $i < count($resultArr); $i++) {
-				$queryStr .= "id = " . $resultArr[$i]["id"];
-				if ($i + 1 < count($resultArr))
-					$queryStr .= " OR ";
-			}
-			if (!$db->getResult($queryStr))	return false;
-		}
-
-		$queryStr = "DELETE FROM tblKeywordCategories WHERE owner = " . $this->_id;
-		if (!$db->getResult($queryStr))	return false;
-
-		//Benachrichtigungen entfernen
-		$queryStr = "DELETE FROM tblNotify WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		/* Assign documents of the removed user to the given user */
-		$queryStr = "UPDATE tblFolders SET owner = " . $assignTo . " WHERE owner = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		$queryStr = "UPDATE tblDocuments SET owner = " . $assignTo . " WHERE owner = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		$queryStr = "UPDATE tblDocumentContent SET createdBy = " . $assignTo . " WHERE createdBy = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		// Remove private links on documents ...
-		$queryStr = "DELETE FROM tblDocumentLinks WHERE userID = " . $this->_id . " AND public = 0";
-		if (!$db->getResult($queryStr)) return false;
-
-		// ... but keep public links
-		$queryStr = "UPDATE tblDocumentLinks SET userID = " . $assignTo . " WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		// set administrator for deleted user's attachments
-		$queryStr = "UPDATE tblDocumentFiles SET userID = " . $assignTo . " WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		//Evtl. von diesem Benutzer gelockte Dokumente werden freigegeben
-		$queryStr = "DELETE FROM tblDocumentLocks WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		// Delete user from all groups
-		$queryStr = "DELETE FROM tblGroupMembers WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		// User aus allen ACLs streichen
-		$queryStr = "DELETE FROM tblACLs WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		// Delete image of user
-		$queryStr = "DELETE FROM tblUserImages WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		// Delete user itself
-		$queryStr = "DELETE FROM tblUsers WHERE id = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		// mandatory review/approve
-		$queryStr = "DELETE FROM tblMandatoryReviewers WHERE reviewerUserID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		$queryStr = "DELETE FROM tblMandatoryApprovers WHERE approverUserID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		$queryStr = "DELETE FROM tblMandatoryReviewers WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		$queryStr = "DELETE FROM tblMandatoryApprovers WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-		// set administrator for deleted user's events
-		$queryStr = "UPDATE tblEvents SET userID = " . $assignTo . " WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-
-
-		// TODO : update document status if reviewer/approver has been deleted
-		// "DELETE FROM tblDocumentApproveLog WHERE userID = " . $this->_id;
-		// "DELETE FROM tblDocumentReviewLog WHERE userID = " . $this->_id;
-
-
-		$reviewStatus = $this->getReviewStatus();
-		foreach ($reviewStatus["indstatus"] as $ri) {
-			$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
-				"VALUES ('". $ri["reviewID"] ."', '-2', 'Reviewer removed from process', NOW(), '". $user->getID() ."')";
-			$res=$db->getResult($queryStr);
-		}
-
-		$approvalStatus = $this->getApprovalStatus();
-		foreach ($approvalStatus["indstatus"] as $ai) {
-			$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
-				"VALUES ('". $ai["approveID"] ."', '-2', 'Approver removed from process', NOW(), '". $user->getID() ."')";
-			$res=$db->getResult($queryStr);
-		}
-
-//		unset($this);
-		return true;
-	} /* }}} */
-
-	/**
-	 * Make the user a member of a group
-	 * This function uses {@link LetoDMS_Group::addUser} but checks before if
-	 * the user is already a member of the group.
-	 *
-	 * @param object $group group to be the member of
-	 * @return boolean true on success or false in case of an error or the user
-	 *        is already a member of the group
-	 */
-	function joinGroup($group) { /* {{{ */
-		if ($group->isMember($this))
-			return false;
-
-		if (!$group->addUser($this))
-			return false;
-
-		unset($this->_groups);
-		return true;
-	} /* }}} */
-
-	/**
-	 * Removes the user from a group
-	 * This function uses {@link LetoDMS_Group::removeUser} but checks before if
-	 * the user is a member of the group at all.
-	 *
-	 * @param object $group group to leave
-	 * @return boolean true on success or false in case of an error or the user
-	 *        is not a member of the group
-	 */
-	function leaveGroup($group) { /* {{{ */
-		if (!$group->isMember($this))
-			return false;
-
-		if (!$group->removeUser($this))
-			return false;
-
-		unset($this->_groups);
-		return true;
-	} /* }}} */
-
-	/**
-	 * Get all groups the user is a member of
-	 *
-	 * @return array list of groups
-	 */
-	function getGroups() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if (!isset($this->_groups))
-		{
-			$queryStr = "SELECT `tblGroups`.*, `tblGroupMembers`.`userID` FROM `tblGroups` ".
-				"LEFT JOIN `tblGroupMembers` ON `tblGroups`.`id` = `tblGroupMembers`.`groupID` ".
-				"WHERE `tblGroupMembers`.`userID`='". $this->_id ."'";
-			$resArr = $db->getResultArray($queryStr);
-			if (is_bool($resArr) && $resArr == false)
-				return false;
-
-			$this->_groups = array();
-			foreach ($resArr as $row) {
-				$group = new LetoDMS_Core_Group($row["id"], $row["name"], $row["comment"]);
-				array_push($this->_groups, $group);
-			}
-		}
-		return $this->_groups;
-	} /* }}} */
-
-	/**
-	 * Checks if user is member of a given group
-	 *
-	 * @param object $group
-	 * @return boolean true if user is member of the given group otherwise false
-	 */
-	function isMemberOfGroup($group) { /* {{{ */
-		return $group->isMember($this);
-	} /* }}} */
-
-	/**
-	 * Check if user has an image in its profile
-	 *
-	 * @return boolean true if user has a picture of itself
-	 */
-	function hasImage() { /* {{{ */
-		if (!isset($this->_hasImage)) {
-			$db = $this->_dms->getDB();
-
-			$queryStr = "SELECT COUNT(*) AS num FROM tblUserImages WHERE userID = " . $this->_id;
-			$resArr = $db->getResultArray($queryStr);
-			if ($resArr === false)
-				return false;
-
-			if ($resArr[0]["num"] == 0)	$this->_hasImage = false;
-			else $this->_hasImage = true;
-		}
-
-		return $this->_hasImage;
-	} /* }}} */
-
-	/**
-	 * Get the image from the users profile
-	 *
-	 * @return array image data
-	 */
-	function getImage() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT * FROM tblUserImages WHERE userID = " . $this->_id;
-		$resArr = $db->getResultArray($queryStr);
-		if ($resArr === false)
-			return false;
-
-		if($resArr)
-			$resArr = $resArr[0];
-		return $resArr;
-	} /* }}} */
-
-	function setImage($tmpfile, $mimeType) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$fp = fopen($tmpfile, "rb");
-		if (!$fp) return false;
-		$content = fread($fp, filesize($tmpfile));
-		fclose($fp);
-
-		if ($this->hasImage())
-			$queryStr = "UPDATE tblUserImages SET image = '".base64_encode($content)."', mimeType = ".$db->qstr($mimeType)." WHERE userID = " . $this->_id;
-		else
-			$queryStr = "INSERT INTO tblUserImages (userID, image, mimeType) VALUES (" . $this->_id . ", '".base64_encode($content)."', ".$db->qstr($mimeType).")";
-		if (!$db->getResult($queryStr))
-			return false;
-
-		$this->_hasImage = true;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Get a list of reviews
-	 * This function returns a list of all reviews seperated by individual
-	 * and group reviews. If the document id
-	 * is passed, then only this document will be checked for approvals. The
-	 * same is true for the version of a document which limits the list
-	 * further.
-	 *
-	 * For a detaile description of the result array see
-	 * {link LetoDMS_User::getApprovalStatus}
-	 *
-	 * @param int $documentID optional document id for which to retrieve the
-	 *        reviews
-	 * @param int $version optional version of the document
-	 * @return array list of all reviews
-	 */
-	function getReviewStatus($documentID=null, $version=null) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-/*
-		if (!$db->createTemporaryTable("ttreviewid")) {
-			return false;
-		}
-*/
-		$status = array("indstatus"=>array(), "grpstatus"=>array());
-
-		// See if the user is assigned as an individual reviewer.
-		$queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
-			"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
-			"`tblDocumentReviewLog`.`userID` ".
-			"FROM `tblDocumentReviewers` ".
-			"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
-			"WHERE `tblDocumentReviewers`.`type`='0' ".
-			($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
-			($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
-			"AND `tblDocumentReviewers`.`required`='". $this->_id ."' ".
-			"ORDER BY `tblDocumentReviewLog`.`reviewLogID` DESC LIMIT 1";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr)>0) {
-			foreach ($resArr as $res)
-				$status["indstatus"][] = $res;
-		}
-
-		// See if the user is the member of a group that has been assigned to
-		// review the document version.
-		$queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
-			"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
-			"`tblDocumentReviewLog`.`userID` ".
-			"FROM `tblDocumentReviewers` ".
-			"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
-			"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentReviewers`.`required` ".
-			"WHERE `tblDocumentReviewers`.`type`='1' ".
-			($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
-			($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
-			"AND `tblGroupMembers`.`userID`='". $this->_id ."' ".
-			"ORDER BY `tblDocumentReviewLog`.`reviewLogID` DESC LIMIT 1";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr)>0) {
-			foreach ($resArr as $res)
-				$status["grpstatus"][] = $res;
-		}
-		return $status;
-	} /* }}} */
-
-	/**
-	 * Get a list of approvals
-	 * This function returns a list of all approvals seperated by individual
-	 * and group approvals. If the document id
-	 * is passed, then only this document will be checked for approvals. The
-	 * same is true for the version of a document which limits the list
-	 * further.
-	 *
-	 * The result array has two elements:
-	 * - indstatus: which contains the approvals by individuals (users)
-	 * - grpstatus: which contains the approvals by groups
-	 *
-	 * Each element is itself an array of approvals with the following elements:
-	 * - approveID: unique id of approval
-	 * - documentID: id of document, that needs to be approved
-	 * - version: version of document, that needs to be approved
-	 * - type: 0 for individual approval, 1 for group approval
-	 * - required: id of user who is required to do the approval
-	 * - status: 0 not approved, ....
-	 * - comment: comment given during approval
-	 * - date: date of approval
-	 * - userID: id of user who has done the approval
-	 *
-	 * @param int $documentID optional document id for which to retrieve the
-	 *        approvals
-	 * @param int $version optional version of the document
-	 * @return array list of all approvals
-	 */
-	function getApprovalStatus($documentID=null, $version=null) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-/*
-		if (!$db->createTemporaryTable("ttapproveid")) {
-			return false;
-		}
-*/
-		$status = array("indstatus"=>array(), "grpstatus"=>array());
-
-		// See if the user is assigned as an individual approver.
-		/*
-		$queryStr = "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
-			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
-			"`tblDocumentApproveLog`.`userID` ".
-			"FROM `tblDocumentApprovers` ".
-			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
-			"LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
-			"WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
-			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". $documentID ."' ").
-			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". $version ."' ").
-			"AND `tblDocumentApprovers`.`type`='0' ".
-			"AND `tblDocumentApprovers`.`required`='". $this->_id ."' ";
-*/
-		$queryStr =
-   "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
-			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
-			"`tblDocumentApproveLog`.`userID` ".
-			"FROM `tblDocumentApprovers` ".
-			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
-			"WHERE `tblDocumentApprovers`.`type`='0' ".
-			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
-			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
-			"AND `tblDocumentApprovers`.`required`='". $this->_id ."' ".
-			"ORDER BY `tblDocumentApproveLog`.`approveLogID` DESC LIMIT 1";
-
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr)>0) {
-			foreach ($resArr as $res)
-				$status["indstatus"][] = $res;
-		}
-
-		// See if the user is the member of a group that has been assigned to
-		// approve the document version.
-		/*
-		$queryStr = "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
-			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
-			"`tblDocumentApproveLog`.`userID` ".
-			"FROM `tblDocumentApprovers` ".
-			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
-			"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentApprovers`.`required` ".
-			"LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
-			"WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
-			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". $documentID ."' ").
-			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". $version ."' ").
-			"AND `tblDocumentApprovers`.`type`='1' ".
-			"AND `tblGroupMembers`.`userID`='". $this->_id ."'";
-			*/
-		$queryStr =
-			"SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
-			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
-			"`tblDocumentApproveLog`.`userID` ".
-			"FROM `tblDocumentApprovers` ".
-			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
-			"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentApprovers`.`required` ".
-			"WHERE `tblDocumentApprovers`.`type`='1' ".
-			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
-			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
-			"AND `tblGroupMembers`.`userID`='". $this->_id ."' ".
-			"ORDER BY `tblDocumentApproveLog`.`approveLogID` DESC LIMIT 1";
-		$resArr = $db->getResultArray($queryStr);
-		if (is_bool($resArr) && $resArr == false)
-			return false;
-		if (count($resArr)>0) {
-			foreach ($resArr as $res)
-				$status["grpstatus"][] = $res;
-		}
-		return $status;
-	} /* }}} */
-
-	/**
-	 * Get a list of mandatory reviewers
-	 * A user which isn't trusted completely may have assigned mandatory
-	 * reviewers (both users and groups).
-	 * Whenever the user inserts a new document the mandatory reviewers are
-	 * filled in as reviewers.
-	 *
-	 * @return array list of arrays with two elements containing the user id
-	 *         (reviewerUserID) and group id (reviewerGroupID) of the reviewer.
-	 */
-	function getMandatoryReviewers() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT * FROM tblMandatoryReviewers WHERE userID = " . $this->_id;
-		$resArr = $db->getResultArray($queryStr);
-
-		return $resArr;
-	} /* }}} */
-
-	/**
-	 * Get a list of mandatory approvers
-	 * See {link LetoDMS_User::getMandatoryReviewers}
-	 *
-	 * @return array list of arrays with two elements containing the user id
-	 *         (approverUserID) and group id (approverGroupID) of the approver.
-	 */
-	function getMandatoryApprovers() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "SELECT * FROM tblMandatoryApprovers WHERE userID = " . $this->_id;
-		$resArr = $db->getResultArray($queryStr);
-
-		return $resArr;
-	} /* }}} */
-
-	/**
-	 * Set a mandatory reviewer
-	 * This function sets a mandatory reviewer if it isn't already set.
-	 *
-	 * @param integer $id id of reviewer
-	 * @param boolean $isgroup true if $id is a group
-	 * @return boolean true on success, otherwise false
-	 */
-	function setMandatoryReviewer($id, $isgroup=false) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if ($isgroup){
-
-			$queryStr = "SELECT * FROM tblMandatoryReviewers WHERE userID = " . $this->_id . " AND reviewerGroupID = " . $id;
-			$resArr = $db->getResultArray($queryStr);
-			if (count($resArr)!=0) return true;
-
-			$queryStr = "INSERT INTO tblMandatoryReviewers (userID, reviewerGroupID) VALUES (" . $this->_id . ", " . $id .")";
-			$resArr = $db->getResult($queryStr);
-			if (is_bool($resArr) && !$resArr) return false;
-
-		}else{
-
-			$queryStr = "SELECT * FROM tblMandatoryReviewers WHERE userID = " . $this->_id . " AND reviewerUserID = " . $id;
-			$resArr = $db->getResultArray($queryStr);
-			if (count($resArr)!=0) return true;
-
-			$queryStr = "INSERT INTO tblMandatoryReviewers (userID, reviewerUserID) VALUES (" . $this->_id . ", " . $id .")";
-			$resArr = $db->getResult($queryStr);
-			if (is_bool($resArr) && !$resArr) return false;
-		}
-
-	} /* }}} */
-
-	/**
-	 * Set a mandatory approver
-	 * This function sets a mandatory approver if it isn't already set.
-	 *
-	 * @param integer $id id of approver
-	 * @param boolean $isgroup true if $id is a group
-	 * @return boolean true on success, otherwise false
-	 */
-	function setMandatoryApprover($id, $isgroup=false) { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		if ($isgroup){
-
-			$queryStr = "SELECT * FROM tblMandatoryApprovers WHERE userID = " . $this->_id . " AND approverGroupID = " . (int) $id;
-			$resArr = $db->getResultArray($queryStr);
-			if (count($resArr)!=0) return;
-
-			$queryStr = "INSERT INTO tblMandatoryApprovers (userID, approverGroupID) VALUES (" . $this->_id . ", " . $id .")";
-			$resArr = $db->getResult($queryStr);
-			if (is_bool($resArr) && !$resArr) return false;
-
-		}else{
-
-			$queryStr = "SELECT * FROM tblMandatoryApprovers WHERE userID = " . $this->_id . " AND approverUserID = " . (int) $id;
-			$resArr = $db->getResultArray($queryStr);
-			if (count($resArr)!=0) return;
-
-			$queryStr = "INSERT INTO tblMandatoryApprovers (userID, approverUserID) VALUES (" . $this->_id . ", " . $id .")";
-			$resArr = $db->getResult($queryStr);
-			if (is_bool($resArr) && !$resArr) return false;
-		}
-	} /* }}} */
-
-	/**
-	 * Deletes all mandatory reviewers
-	 *
-	 * @return boolean true on success, otherwise false
-	 */
-	function delMandatoryReviewers() { /* {{{ */
-		$db = $this->_dms->getDB();
-		$queryStr = "DELETE FROM tblMandatoryReviewers WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Deletes all mandatory approvers
-	 *
-	 * @return boolean true on success, otherwise false
-	 */
-	function delMandatoryApprovers() { /* {{{ */
-		$db = $this->_dms->getDB();
-
-		$queryStr = "DELETE FROM tblMandatoryApprovers WHERE userID = " . $this->_id;
-		if (!$db->getResult($queryStr)) return false;
-		return true;
-	} /* }}} */
-
-}
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.DBAccess.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.DBAccess.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.DBAccess.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.DBAccess.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,284 +0,0 @@
-<?php
-/**
- * Implementation of database access
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
- *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Include the adodb database abstraction
- */
-require_once "adodb/adodb.inc.php";
-
-/**
- * Class to represent the database access for the document management
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli, Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli, 2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_DatabaseAccess {
-	var $_driver;
-	var $_hostname;
-	var $_database;
-	var $_user;
-	var $_passw;
-	var $_conn;
-	var $_connected;
-	var $_ttreviewid;
-	var $_ttapproveid;
-	var $_ttstatid;
-	var $_ttcontentid;
-	
-	/*
-	Backup functions
-	*/
-
-	/**
-	 * Return list of all database tables
-	 *
-	 * This function is used to retrieve a list of database tables for backup
-	 *
-	 * @return array list of table names
-	 */
-	function TableList() {
-		return $this->_conn->MetaTables("TABLES");
-	}	
-
-	/**
-	 * Constructor of LetoDMS_Core_DatabaseAccess
-	 *
-	 * Sets all database parameters but does not connect.
-	 *
-	 * @param string $driver the database type e.g. mysql, sqlite
-	 * @param string $hostname host of database server
-	 * @param string $user name of user having access to database
-	 * @param string $passw password of user
-	 * @param string $database name of database
-	 */
-	function LetoDMS_Core_DatabaseAccess($driver, $hostname, $user, $passw, $database = false) {
-		$this->_driver = $driver;
-		$this->_hostname = $hostname;
-		$this->_database = $database;
-		$this->_user = $user;
-		$this->_passw = $passw;
-		$this->_connected = false;
-		// $tt*****id is a hack to ensure that we do not try to create the
-		// temporary table twice during a single connection. Can be fixed by
-		// using Views (MySQL 5.0 onward) instead of temporary tables.
-		// CREATE ... IF NOT EXISTS cannot be used because it has the
-		// unpleasant side-effect of performing the insert again even if the
-		// table already exists.
-		//
-		// See createTemporaryTable() method for implementation.
-		$this->_ttreviewid = false;
-		$this->_ttapproveid = false;
-		$this->_ttstatid = false;
-		$this->_ttcontentid = false;
-	}
-
-	/**
-	 * Connect to database
-	 *
-	 * @return boolean true if connection could be established, otherwise false
-	 */
-	function connect() { /* {{{ */
-		$this->_conn = ADONewConnection($this->_driver);
-		if ($this->_database)
-			$this->_conn->Connect($this->_hostname, $this->_user, $this->_passw, $this->_database);
-		else
-			$this->_conn->Connect($this->_hostname, $this->_user, $this->_passw);
-
-		if (!$this->_conn)
-			return false;
-
-		$this->_conn->SetFetchMode(ADODB_FETCH_ASSOC);
-		$this->_conn->Execute('SET NAMES utf8');
-		$this->_connected = true;
-		return true;
-	} /* }}} */
-
-	/**
-	 * Make sure a database connection exisits
-	 *
-	 * This function checks for a database connection. If it does not exists
-	 * it will reconnect.
-	 *
-	 * @return boolean true if connection is established, otherwise false
-	 */
-	function ensureConnected() { /* {{{ */
-		if (!$this->_connected) return $this->connect();
-		else return true;
-	} /* }}} */
-
-	/**
-	 * Sanitize String used in database operations
-	 *
-	 * @param string text
-	 * @return string sanitized string
-	 */
-	function qstr($text) { /* {{{ */
-		return $this->_conn->qstr($text);
-	} /* }}} */
-
-
-	/**
-	 * Execute SQL query and return result
-	 *
-	 * Call this function only with sql query which return data records.
-	 *
-	 * @param string $queryStr sql query
-	 * @return array/boolean data if query could be executed otherwise false
-	 */
-	function getResultArray($queryStr) { /* {{{ */
-		$resArr = array();
-		
-		$res = $this->_conn->Execute($queryStr);
-		if (!$res) {
-			print "<br>" . $this->getErrorMsg() . "<br>" . $queryStr . "</br>";
-			return false;
-		}
-		$resArr = $res->GetArray();
-		$res->Close();
-		return $resArr;
-	} /* }}} */
-
-	/**
-	 * Execute SQL query
-	 *
-	 * Call this function only with sql query which do not return data records.
-	 *
-	 * @param string $queryStr sql query
-	 * @return boolean true if query could be executed otherwise false
-	 */
-	function getResult($queryStr, $silent=false) { /* {{{ */
-		$res = $this->_conn->Execute($queryStr);
-		if (!$res && !$silent)
-			print "<br>" . $this->getErrorMsg() . "<br>" . $queryStr . "</br>";
-		
-		return $res;
-	} /* }}} */
-
-	/**
-	 * Return the id of the last instert record
-	 *
-	 * @return integer id used in last autoincrement
-	 */
-	function getInsertID() { /* {{{ */
-		return $this->_conn->Insert_ID();
-	} /* }}} */
-
-	function getErrorMsg() { /* {{{ */
-		return $this->_conn->ErrorMsg();
-	} /* }}} */
-
-	function getErrorNo() { /* {{{ */
-		return $this->_conn->ErrorNo();
-	} /* }}} */
-
-	/**
-	 * Create various temporary tables to speed up and simplify sql queries
-	 */
-	function createTemporaryTable($tableName, $override=false) { /* {{{ */
-		if (!strcasecmp($tableName, "ttreviewid")) {
-			$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttreviewid` (PRIMARY KEY (`reviewID`), INDEX (`maxLogID`)) ".
-				"SELECT `tblDocumentReviewLog`.`reviewID`, ".
-				"MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ".
-				"FROM `tblDocumentReviewLog` ".
-				"GROUP BY `tblDocumentReviewLog`.`reviewID` ".
-				"ORDER BY `tblDocumentReviewLog`.`reviewLogID`";
-			if (!$this->_ttreviewid) {
-				if (!$this->getResult($queryStr))
-					return false;
-				$this->_ttreviewid=true;
-			}
-			else {
-				if (is_bool($override) && $override) {
-					if (!$this->getResult("DELETE FROM `ttreviewid`"))
-						return false;
-					if (!$this->getResult($queryStr))
-						return false;
-				}
-			}
-			return $this->_ttreviewid;
-		}
-		else if (!strcasecmp($tableName, "ttapproveid")) {
-			$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttapproveid` (PRIMARY KEY (`approveID`), INDEX (`maxLogID`)) ".
-				"SELECT `tblDocumentApproveLog`.`approveID`, ".
-				"MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ".
-				"FROM `tblDocumentApproveLog` ".
-				"GROUP BY `tblDocumentApproveLog`.`approveID` ".
-				"ORDER BY `tblDocumentApproveLog`.`approveLogID`";
-			if (!$this->_ttapproveid) {
-				if (!$this->getResult($queryStr))
-					return false;
-				$this->_ttapproveid=true;
-			}
-			else {
-				if (is_bool($override) && $override) {
-					if (!$this->getResult("DELETE FROM `ttapproveid`"))
-						return false;
-					if (!$this->getResult($queryStr))
-						return false;
-				}
-			}
-			return $this->_ttapproveid;
-		}
-		else if (!strcasecmp($tableName, "ttstatid")) {
-			$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttstatid` (PRIMARY KEY (`statusID`), INDEX (`maxLogID`)) ".
-				"SELECT `tblDocumentStatusLog`.`statusID`, ".
-				"MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ".
-				"FROM `tblDocumentStatusLog` ".
-				"GROUP BY `tblDocumentStatusLog`.`statusID` ".
-				"ORDER BY `tblDocumentStatusLog`.`statusLogID`";
-			if (!$this->_ttstatid) {
-				if (!$this->getResult($queryStr))
-					return false;
-				$this->_ttstatid=true;
-			}
-			else {
-				if (is_bool($override) && $override) {
-					if (!$this->getResult("DELETE FROM `ttstatid`"))
-						return false;
-					if (!$this->getResult($queryStr))
-						return false;
-				}
-			}
-			return $this->_ttstatid;
-		}
-		else if (!strcasecmp($tableName, "ttcontentid")) {
-			$queryStr = "CREATE TEMPORARY TABLE `ttcontentid` (PRIMARY KEY (`document`), INDEX (`maxVersion`)) ".
-				"SELECT `tblDocumentContent`.`document`, ".
-				"MAX(`tblDocumentContent`.`version`) AS `maxVersion` ".
-				"FROM `tblDocumentContent` ".
-				"GROUP BY `tblDocumentContent`.`document` ".
-				"ORDER BY `tblDocumentContent`.`document`";
-			if (!$this->_ttcontentid) {
-				if (!$this->getResult($queryStr))
-					return false;
-				$this->_ttcontentid=true;
-			}
-			else {
-				if (is_bool($override) && $override) {
-					if (!$this->getResult("DELETE FROM `ttcontentid`"))
-						return false;
-					if (!$this->getResult($queryStr))
-						return false;
-				}
-			}
-			return $this->_ttcontentid;
-		}
-		return false;
-	} /* }}} */
-}
-
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.FileUtils.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.FileUtils.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core/inc.FileUtils.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core/inc.FileUtils.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,174 +0,0 @@
-<?php
-/**
- * Implementation of various file system operations
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @license    GPL 2
- * @version    @version@
- * @author     Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal,
- *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-
-/**
- * Class to represent a user in the document management system
- *
- * @category   DMS
- * @package    LetoDMS_Core
- * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
- * @copyright  Copyright (C) 2002-2005 Markus Westphal,
- *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
- *             2010 Uwe Steinmann
- * @version    Release: 3.3.4
- */
-class LetoDMS_Core_File {
-	function renameFile($old, $new) {
-		return @rename($old, $new);
-	}
-
-	function removeFile($file) {
-		return @unlink($file);
-	}
-
-	function copyFile($source, $target) {
-		return @copy($source, $target);
-	}
-
-	function moveFile($source, $target) {
-		if (!@copyFile($source, $target))
-			return false;
-		return @removeFile($source);
-	}
-
-	function renameDir($old, $new) {
-		return @rename($old, $new);
-	}
-
-	function makeDir($path) {
-		
-		if( !is_dir( $path ) ){
-			$res=@mkdir( $path , 0777, true);
-			if (!$res) return false;
-		}
-
-		return true;
-
-/* some old code 
-		if (strncmp($path, DIRECTORY_SEPARATOR, 1) == 0) {
-			$mkfolder = DIRECTORY_SEPARATOR;
-		}
-		else {
-			$mkfolder = "";
-		}
-		$path = preg_split( "/[\\\\\/]/" , $path );
-		for(  $i=0 ; isset( $path[$i] ) ; $i++ )
-		{
-			if(!strlen(trim($path[$i])))continue;
-			$mkfolder .= $path[$i];
-
-			if( !is_dir( $mkfolder ) ){
-				$res=@mkdir( "$mkfolder" ,  0777);
-				if (!$res) return false;
-			}
-			$mkfolder .= DIRECTORY_SEPARATOR;
-		}
-
-		return true;
-
-		// patch from alekseynfor safe_mod or open_basedir
-
-		global $settings;
-		$path = substr_replace ($path, "/", 0, strlen($settings->_contentDir));
-		$mkfolder = $settings->_contentDir;
-
-		$path = preg_split( "/[\\\\\/]/" , $path );
-
-		for(  $i=0 ; isset( $path[$i] ) ; $i++ )
-		{
-			if(!strlen(trim($path[$i])))continue;
-			$mkfolder .= $path[$i];
-
-			if( !is_dir( $mkfolder ) ){
-				$res= @mkdir( "$mkfolder" ,  0777);
-				if (!$res) return false;
-			}
-			$mkfolder .= DIRECTORY_SEPARATOR;
-		}
-
-		return true;
-*/
-	}
-
-	function removeDir($path) {
-		$handle = @opendir($path);
-		while ($entry = @readdir($handle) )
-		{
-			if ($entry == ".." || $entry == ".")
-				continue;
-			else if (is_dir($path . $entry))
-			{
-				if (!self::removeDir($path . $entry . "/"))
-					return false;
-			}
-			else
-			{
-				if (!@unlink($path . $entry))
-					return false;
-			}
-		}
-		@closedir($handle);
-		return @rmdir($path);
-	}
-
-	function copyDir($sourcePath, $targetPath) {
-		if (mkdir($targetPath, 0777)) {
-			$handle = @opendir($sourcePath);
-			while ($entry = @readdir($handle) ) {
-				if ($entry == ".." || $entry == ".")
-					continue;
-				else if (is_dir($sourcePath . $entry)) {
-					if (!self::copyDir($sourcePath . $entry . "/", $targetPath . $entry . "/"))
-						return false;
-				} else {
-					if (!@copy($sourcePath . $entry, $targetPath . $entry))
-						return false;
-				}
-			}
-			@closedir($handle);
-		}
-		else
-			return false;
-
-		return true;
-	}
-
-	function moveDir($sourcePath, $targetPath) {
-		if (!copyDir($sourcePath, $targetPath))
-			return false;
-		return removeDir($sourcePath);
-	}
-
-	// code by Kioob (php.net manual)
-	function gzcompressfile($source,$level=false) {
-		$dest=$source.'.gz';
-		$mode='wb'.$level;
-		$error=false;
-		if($fp_out=@gzopen($dest,$mode)) {
-			if($fp_in=@fopen($source,'rb')) {
-				while(!feof($fp_in))
-					@gzwrite($fp_out,fread($fp_in,1024*512));
-				@fclose($fp_in);
-			}
-			else $error=true;
-			@gzclose($fp_out);
-		}
-		else $error=true;
-
-		if($error) return false;
-		else return $dest;
-	}
-}
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/Core.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/Core.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,79 +0,0 @@
-<?php
-//    MyDMS. Document Management System
-//    Copyright (C) 2010 Uwe Steinmann
-//
-//    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.
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU General Public License for more details.
-//
-//    You should have received a copy of the GNU General Public License
-//    along with this program; if not, write to the Free Software
-//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-/**
- * @uses LetoDMS_DatabaseAccess
- */
-require_once('Core/inc.DBAccess.php');
-
-/**
- * @uses LetoDMS_DMS
- */
-require_once('Core/inc.ClassDMS.php');
-
-/**
- * @uses LetoDMS_Folder
- */
-require_once('Core/inc.ClassFolder.php');
-
-/**
- * @uses LetoDMS_Document
- */
-require_once('Core/inc.ClassDocument.php');
-
-/**
- * @uses LetoDMS_Group
- */
-require_once('Core/inc.ClassGroup.php');
-
-/**
- * @uses LetoDMS_User
- */
-require_once('Core/inc.ClassUser.php');
-
-/**
- * @uses LetoDMS_KeywordCategory
- */
-require_once('Core/inc.ClassKeywords.php');
-
-/**
- * @uses LetoDMS_DocumentCategory
- */
-require_once('Core/inc.ClassDocumentCategory.php');
-
-/**
- * @uses LetoDMS_Notification
- */
-require_once('Core/inc.ClassNotification.php');
-
-/**
- * @uses LetoDMS_UserAccess
- * @uses LetoDMS_GroupAccess
- */
-require_once('Core/inc.ClassAccess.php');
-
-/**
- */
-require_once('Core/inc.AccessUtils.php');
-
-/**
- * @uses LetoDMS_File
- */
-require_once('Core/inc.FileUtils.php');
-
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/tests/getfoldertree.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/tests/getfoldertree.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/tests/getfoldertree.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/tests/getfoldertree.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,25 +0,0 @@
-<?php
-include("config.php");
-include("LetoDMS/LetoDMS_Core.php");
-
-$db = new LetoDMS_Core_DatabaseAccess($g_config['type'], $g_config['hostname'], $g_config['user'], $g_config['passwd'], $g_config['name']);
-$db->connect() or die ("Could not connect to db-server \"" . $g_config['hostname'] . "\"");
-
-$dms = new LetoDMS_Core_DMS($db, $g_config['contentDir'], $g_config['contentOffsetDir']);
-
-function tree($folder, $indent='') {
-	echo $indent."D ".$folder->getName()."\n";
-	$subfolders = $folder->getSubFolders();
-	foreach($subfolders as $subfolder) {
-		tree($subfolder, $indent.'  ');
-	}
-	$documents = $folder->getDocuments();
-	foreach($documents as $document) {
-		echo $indent."  ".$document->getName()."\n";
-	}
-}
-
-$folder = $dms->getFolder(1);
-tree($folder);
-
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/tests/getusers.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/tests/getusers.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.4/tests/getusers.php	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.4/tests/getusers.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,14 +0,0 @@
-<?php
-include("config.php");
-include("LetoDMS/LetoDMS_Core.php");
-
-$db = new LetoDMS_Core_DatabaseAccess($g_config['type'], $g_config['hostname'], $g_config['user'], $g_config['passwd'], $g_config['name']);
-$db->connect() or die ("Could not connect to db-server \"" . $g_config['hostname'] . "\"");
-
-$dms = new LetoDMS_Core_DMS($db, $g_config['contentDir'], $g_config['contentOffsetDir']);
-
-$users = $dms->getAllUsers();
-foreach($users as $user)
-	echo $user->getId()." ".$user->getLogin()." ".$user->getFullname()."\n";
-
-?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.AccessUtils.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.AccessUtils.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.AccessUtils.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.AccessUtils.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Some definitions for access control
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal,
+ *             2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Used to indicate that a search should return all
+ * results in the ACL table. See {@link LetoDMS_Core_Folder::getAccessList()}
+ */
+define("M_ANY", -1);
+
+/**
+ * No rights at all
+ */
+define("M_NONE", 1);
+
+/**
+ * Read access only
+ */
+define("M_READ", 2);
+
+/**
+ * Read and write access only
+ */
+define("M_READWRITE", 3);
+
+/**
+ * Unrestricted access
+ */
+define("M_ALL", 4);
+
+define ("O_GTEQ", ">=");
+define ("O_LTEQ", "<=");
+define ("O_EQ", "=");
+
+define("T_FOLDER", 1);		//TargetType = Folder
+define("T_DOCUMENT", 2);	//    "      = Document
+
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassAccess.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassAccess.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassAccess.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassAccess.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Implementation of user and group access object
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Class to represent a user access right.
+ * This class cannot be used to modify access rights.
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_UserAccess { /* {{{ */
+	var $_user;
+	var $_mode;
+
+	function LetoDMS_Core_UserAccess($user, $mode) {
+		$this->_user = $user;
+		$this->_mode = $mode;
+	}
+
+	function getUserID() { return $this->_user->getID(); }
+
+	function getMode() { return $this->_mode; }
+
+	function isAdmin() {
+		return ($this->_mode == LetoDMS_Core_User::role_admin);
+	}
+
+	function getUser() {
+		return $this->_user;
+	}
+} /* }}} */
+
+
+/**
+ * Class to represent a group access right.
+ * This class cannot be used to modify access rights.
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_GroupAccess { /* {{{ */
+	var $_group;
+	var $_mode;
+
+	function LetoDMS_Core_GroupAccess($group, $mode) {
+		$this->_group = $group;
+		$this->_mode = $mode;
+	}
+
+	function getGroupID() { return $this->_group->getID(); }
+
+	function getMode() { return $this->_mode; }
+
+	function getGroup() {
+		return $this->_group;
+	}
+} /* }}} */
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassDMS.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassDMS.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassDMS.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassDMS.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,1256 @@
+<?php
+/**
+ * Implementation of the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2010, Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Include some files
+ */
+require_once("inc.DBAccess.php");
+require_once("inc.AccessUtils.php");
+require_once("inc.FileUtils.php");
+require_once("inc.ClassAccess.php");
+require_once("inc.ClassFolder.php");
+require_once("inc.ClassDocument.php");
+require_once("inc.ClassGroup.php");
+require_once("inc.ClassUser.php");
+require_once("inc.ClassKeywords.php");
+require_once("inc.ClassNotification.php");
+
+/**
+ * Class to represent the complete document management system.
+ * This class is needed to do most of the dms operations. It needs
+ * an instance of {@link LetoDMS_Core_DatabaseAccess} to access the
+ * underlying database. Many methods are factory functions which create
+ * objects representing the entities in the dms, like folders, documents,
+ * users, or groups.
+ *
+ * Each dms has its own database for meta data and a data store for document
+ * content. Both must be specified when creating a new instance of this class.
+ * All folders and documents are organized in a hierachy like
+ * a regular file system starting with a {@link $rootFolderID}
+ *
+ * This class does not enforce any access rights on documents and folders
+ * by design. It is up to the calling application to use the methods
+ * {@link LetoDMS_Core_Folder::getAccessMode} and
+ * {@link LetoDMS_Core_Document::getAccessMode} and interpret them as desired.
+ * Though, there are two convinient functions to filter a list of
+ * documents/folders for which users have access rights for. See
+ * {@link LetoDMS_Core_DMS::filterAccess}
+ * and {@link LetoDMS_Core_DMS::filterUsersByAccess}
+ *
+ * Though, this class has two methods to set the currently logged in user
+ * ({@link setUser} and {@link login}), none of them need to be called, because
+ * there is currently no class within the LetoDMS core which needs the logged
+ * in user.
+ *
+ * <code>
+ * <?php
+ * include("inc/inc.ClassDMS.php");
+ * $db = new LetoDMS_Core_DatabaseAccess($type, $hostname, $user, $passwd, $name);
+ * $db->connect() or die ("Could not connect to db-server");
+ * $dms = new LetoDMS_Core_DMS($db, $contentDir);
+ * $dms->setRootFolderID(1);
+ * ...
+ * ?>
+ * </code>
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2010, Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_DMS {
+	/**
+	 * @var object $db reference to database object. This must be an instance
+	 *      of {@link LetoDMS_Core_DatabaseAccess}.
+	 * @access protected
+	 */
+	protected $db;
+
+	/**
+	 * @var object $user reference to currently logged in user. This must be
+	 *      an instance of {@link LetoDMS_Core_User}. This variable is currently not
+	 *      used. It is set by {@link setUser}.
+	 * @access private
+	 */
+	private $user;
+
+	/**
+	 * @var string $contentDir location in the file system where all the
+	 *      document data is located. This should be an absolute path.
+	 * @access public
+	 */
+	public $contentDir;
+
+	/**
+	 * @var integer $rootFolderID ID of root folder
+	 * @access public
+	 */
+	public $rootFolderID;
+
+	/**
+	 * @var boolean $enableConverting set to true if conversion of content
+	 *      is desired
+	 * @access public
+	 */
+	public $enableConverting;
+
+	/**
+	 * @var array $convertFileTypes list of files types that shall be converted
+	 * @access public
+	 */
+	public $convertFileTypes;
+
+	/**
+	 * @var array $viewOnlineFileTypes list of files types that can be viewed
+	 *      online
+	 * @access public
+	 */
+	public $viewOnlineFileTypes;
+
+	/**
+	 * @var string $version version of pear package
+	 * @access public
+	 */
+	public $version;
+
+	/**
+	 * Filter objects out which are not accessible in a given mode by a user.
+	 *
+	 * @param array $objArr list of objects (either documents or folders)
+	 * @param object $user user for which access is checked
+	 * @param integer $minMode minimum access mode required
+	 * @return array filtered list of objects
+	 */
+	static function filterAccess($objArr, $user, $minMode) { /* {{{ */
+		if (!is_array($objArr)) {
+			return array();
+		}
+		$newArr = array();
+		foreach ($objArr as $obj) {
+			if ($obj->getAccessMode($user) >= $minMode)
+				array_push($newArr, $obj);
+		}
+		return $newArr;
+	} /* }}} */
+
+	/**
+	 * Filter users out which cannot access an object in a given mode.
+	 *
+	 * @param object $obj object that shall be accessed
+	 * @param array $users list of users which are to check for sufficient
+	 *        access rights
+	 * @param integer $minMode minimum access right on the object for each user
+	 * @return array filtered list of users
+	 */
+	static function filterUsersByAccess($obj, $users, $minMode) { /* {{{ */
+		$newArr = array();
+		foreach ($users as $currUser) {
+			if ($obj->getAccessMode($currUser) >= $minMode)
+				array_push($newArr, $currUser);
+		}
+		return $newArr;
+	} /* }}} */
+
+	/**
+	 * Create a new instance of the dms
+	 *
+	 * @param object $db object to access the underlying database
+	 * @param string $contentDir path in filesystem containing the data store
+	 *        all document contents is stored
+	 * @return object instance of LetoDMS_Core_DMS
+	 */
+	function __construct($db, $contentDir) { /* {{{ */
+		$this->db = $db;
+		if(substr($contentDir, -1) == '/')
+			$this->contentDir = $contentDir;
+		else
+			$this->contentDir = $contentDir.'/';
+		$this->rootFolderID = 1;
+		$this->maxDirID = 0; //31998;
+		$this->enableAdminRevApp = false;
+		$this->enableConverting = false;
+		$this->convertFileTypes = array();
+		$this->version = '3.3.9';
+		if($this->version[0] == '@')
+			$this->version = '3.3.9';
+	} /* }}} */
+
+	function getDB() { /* {{{ */
+		return $this->db;
+	} /* }}} */
+
+	/**
+	 * Return the database version
+	 *
+	 * @return array array with elements major, minor, subminor, date
+	 */
+	function getDBVersion() { /* {{{ */
+		$tbllist = $this->db->TableList();
+		$tbllist = explode(',',strtolower(join(',',$tbllist)));
+		if(!array_search('tblversion', $tbllist))
+			return false;
+		$queryStr = "SELECT * FROM tblVersion order by major,minor,subminor limit 1";
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr) != 1)
+			return false;
+		$resArr = $resArr[0];
+		return $resArr;
+	} /* }}} */
+
+	/**
+	 * Check if the version in the database is the same as of this package
+	 * Only the major and minor version number will be checked.
+	 *
+	 * @return boolean returns false if versions do not match, but returns
+	 *         true if version matches or table tblVersion does not exists.
+	 */
+	function checkVersion() { /* {{{ */
+		$tbllist = $this->db->TableList();
+		$tbllist = explode(',',strtolower(join(',',$tbllist)));
+		if(!array_search('tblversion', $tbllist))
+			return true;
+		$queryStr = "SELECT * FROM tblVersion order by major,minor,subminor limit 1";
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr) != 1)
+			return false;
+		$resArr = $resArr[0];
+		$ver = explode('.', $this->version);
+		if(($resArr['major'] != $ver[0]) || ($resArr['minor'] != $ver[1]))
+			return false;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Set id of root folder
+	 * This function must be called right after creating an instance of
+	 * LetoDMS_Core_DMS
+	 *
+	 * @param interger $id id of root folder
+	 */
+	function setRootFolderID($id) { /* {{{ */
+		$this->rootFolderID = $id;
+	} /* }}} */
+
+	/**
+	 * Set maximum number of subdirectories per directory
+	 *
+	 * The value of maxDirID is quite crucial because, all documents are
+	 * associated with a directory in the filesystem. Consequently, there is
+	 * maximum number of documents, because depending on the file system
+	 * the maximum number of subdirectories is limited. Since version 3.3.0 of
+	 * letodms an additional directory level has been introduced. All documents
+	 * from 1 to maxDirID-1 will be saved in 1/<docid>, documents from maxDirID
+	 * to 2*maxDirID-1 are stored in 2/<docid> and so on.
+	 *
+	 * This function must be called right after creating an instance of
+	 * LetoDMS_Core_DMS
+	 *
+	 * @param interger $id id of root folder
+	 */
+	function setMaxDirID($id) { /* {{{ */
+		$this->maxDirID = $id;
+	} /* }}} */
+
+	/**
+	 * Get root folder
+	 *
+	 * @return object/boolean return the object of the root folder or false if
+	 *        the root folder id was not set before with {@link setRootFolderID}.
+	 */
+	function getRootFolder() { /* {{{ */
+		if(!$this->rootFolderID) return false;
+		return $this->getFolder($this->rootFolderID);
+	} /* }}} */
+
+	function setEnableAdminRevApp($enable) { /* {{{ */
+		$this->enableAdminRevApp = $enable;
+	} /* }}} */
+
+	function setEnableConverting($enable) { /* {{{ */
+		$this->enableConverting = $enable;
+	} /* }}} */
+
+	function setConvertFileTypes($types) { /* {{{ */
+		$this->convertFileTypes = $types;
+	} /* }}} */
+
+	function setViewOnlineFileTypes($types) { /* {{{ */
+		$this->viewOnlineFileTypes = $types;
+	} /* }}} */
+
+	/**
+	 * Login as a user
+	 *
+	 * Checks if the given credentials are valid and returns a user object.
+	 * It also sets the property $user for later access on the currently
+	 * logged in user
+	 *
+	 * @param string $username login name of user
+	 * @param string $password password of user
+	 *
+	 * @return object instance of class LetoDMS_Core_User or false
+	 */
+	function login($username, $password) { /* {{{ */
+	} /* }}} */
+
+	/**
+	 * Set the logged in user
+	 *
+	 * If user authentication was done externally, this function can
+	 * be used to tell the dms who is currently logged in.
+	 *
+	 * @param object $user
+	 *
+	 */
+	function setUser($user) { /* {{{ */
+		$this->user = $user;
+	} /* }}} */
+
+	/**
+	 * Return a document by its id
+	 *
+	 * This function retrieves a document from the database by its id.
+	 *
+	 * @param integer $id internal id of document
+	 * @return object instance of LetoDMS_Core_Document or false
+	 */
+	function getDocument($id) { /* {{{ */
+		if (!is_numeric($id)) return false;
+
+		$queryStr = "SELECT * FROM tblDocuments WHERE id = " . (int) $id;
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr) != 1)
+			return false;
+		$resArr = $resArr[0];
+
+		// New Locking mechanism uses a separate table to track the lock.
+		$queryStr = "SELECT * FROM tblDocumentLocks WHERE document = " . (int) $id;
+		$lockArr = $this->db->getResultArray($queryStr);
+		if ((is_bool($lockArr) && $lockArr==false) || (count($lockArr)==0)) {
+			// Could not find a lock on the selected document.
+			$lock = -1;
+		}
+		else {
+			// A lock has been identified for this document.
+			$lock = $lockArr[0]["userID"];
+		}
+
+		$document = new LetoDMS_Core_Document($resArr["id"], $resArr["name"], $resArr["comment"], $resArr["date"], $resArr["expires"], $resArr["owner"], $resArr["folder"], $resArr["inheritAccess"], $resArr["defaultAccess"], $lock, $resArr["keywords"], $resArr["sequence"]);
+		$document->setDMS($this);
+		return $document;
+	} /* }}} */
+
+	/**
+	 * Returns all documents of a given user
+	 *
+	 * @param object $user
+	 * @return array list of documents
+	 */
+	function getDocumentsByUser($user) { /* {{{ */
+		$queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser` ".
+			"FROM `tblDocuments` ".
+			"LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ".
+			"WHERE `tblDocuments`.`owner` = " . $user->getID() . " ORDER BY `sequence`";
+
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		$documents = array();
+		foreach ($resArr as $row) {
+			$document = new LetoDMS_Core_Document($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], $row["lockUser"], $row["keywords"], $row["sequence"]);
+			$document->setDMS($this);
+			$documents[] = $document;
+		}
+		return $documents;
+	} /* }}} */
+
+	/**
+	 * Returns a document by its name
+	 *
+	 * This function searches a document by its name and restricts the search
+	 * to given folder if passed as the second parameter.
+	 *
+	 * @param string $name
+	 * @param object $folder
+	 * @return object/boolean found document or false
+	 */
+	function getDocumentByName($name, $folder=null) { /* {{{ */
+		if (!$name) return false;
+
+		$queryStr = "SELECT `tblDocuments`.*, `tblDocumentLocks`.`userID` as `lockUser` ".
+			"FROM `tblDocuments` ".
+			"LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ".
+			"WHERE `tblDocuments`.`name` = " . $this->db->qstr($name);
+		if($folder)
+			$queryStr .= " AND `tblDocuments`.`folder` = ". $folder->getID();
+		$queryStr .= " LIMIT 1";
+
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		if(!$resArr)
+			return false;
+
+		$row = $resArr[0];
+		$document = new LetoDMS_Core_Document($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], $row["lockUser"], $row["keywords"], $row["sequence"]);
+		$document->setDMS($this);
+		return $document;
+	} /* }}} */
+
+	/*
+	 * Search the database for documents
+	 *
+	 * @param query string seach query with space separated words
+	 * @param limit integer number of items in result set
+	 * @param offset integer index of first item in result set
+	 * @param logicalmode string either AND or OR
+	 * @param searchin array() list of fields to search in
+	 *        1 = keywords, 2=name, 3=comment
+	 * @param startFolder object search in the folder only (null for root folder)
+	 * @param owner object search for documents owned by this user
+	 * @param status array list of status
+	 * @param creationstartdate array search for documents created after this date
+	 * @param creationenddate array search for documents created before this date
+	 * @param categories array list of categories the documents must have assigned
+	 * @param mode int decide whether to search for documents/folders
+	 *        0x1 = documents only
+	 *        0x2 = folders only
+	 *        0x3 = both
+	 * @return array containing the elements total and docs
+	 */
+	function search($query, $limit=0, $offset=0, $logicalmode='AND', $searchin=array(), $startFolder=null, $owner=null, $status = array(), $creationstartdate=array(), $creationenddate=array(), $categories=array(), $mode=0x3) { /* {{{ */
+		// Split the search string into constituent keywords.
+		$tkeys=array();
+		if (strlen($query)>0) {
+			$tkeys = preg_split("/[\t\r\n ,]+/", $query);
+		}
+
+		// if none is checkd search all
+		if (count($searchin)==0)
+			$searchin=array( 0, 1, 2, 3);
+
+		/*--------- Do it all over again for folders -------------*/
+		if($mode & 0x2) {
+			$searchKey = "";
+			// Assemble the arguments for the concatenation function. This allows the
+			// search to be carried across all the relevant fields.
+			$concatFunction = "";
+			if (in_array(2, $searchin)) {
+				$concatFunction = (strlen($concatFunction) == 0 ? "" : $concatFunction.", ")."`tblFolders`.`name`";
+			}
+			if (in_array(3, $searchin)) {
+				$concatFunction = (strlen($concatFunction) == 0 ? "" : $concatFunction.", ")."`tblFolders`.`comment`";
+			}
+
+			if (strlen($concatFunction)>0 && count($tkeys)>0) {
+				$concatFunction = "CONCAT_WS(' ', ".$concatFunction.")";
+				foreach ($tkeys as $key) {
+					$key = trim($key);
+					if (strlen($key)>0) {
+						$searchKey = (strlen($searchKey)==0 ? "" : $searchKey." ".$logicalmode." ").$concatFunction." LIKE ".$this->db->qstr('%'.$key.'%');
+					}
+				}
+			}
+
+			// Check to see if the search has been restricted to a particular sub-tree in
+			// the folder hierarchy.
+			$searchFolder = "";
+			if ($startFolder) {
+				$searchFolder = "`tblFolders`.`folderList` LIKE '%:".$startFolder->getID().":%'";
+			}
+
+			// Check to see if the search has been restricted to a particular
+			// document owner.
+			$searchOwner = "";
+			if ($owner) {
+				$searchOwner = "`tblFolders`.`owner` = '".$owner->getId()."'";
+			}
+
+			// Is the search restricted to documents created between two specific dates?
+			$searchCreateDate = "";
+			if ($creationstartdate) {
+				$startdate = makeTimeStamp(0, 0, 0, $creationstartdate['year'], $creationstartdate["month"], $creationstartdate["day"]);
+				if ($startdate) {
+					$searchCreateDate .= "`tblFolders`.`date` >= ".$startdate;
+				}
+			}
+			if ($creationenddate) {
+				$stopdate = makeTimeStamp(23, 59, 59, $creationenddate["year"], $creationenddate["month"], $creationenddate["day"]);
+				if ($stopdate) {
+					if($startdate)
+						$searchCreateDate .= " AND ";
+					$searchCreateDate .= "`tblFolders`.`date` <= ".$stopdate;
+				}
+			}
+
+			$searchQuery = "FROM `tblFolders` WHERE 1=1";
+
+			if (strlen($searchKey)>0) {
+				$searchQuery .= " AND (".$searchKey.")";
+			}
+			if (strlen($searchFolder)>0) {
+				$searchQuery .= " AND ".$searchFolder;
+			}
+			if (strlen($searchOwner)>0) {
+				$searchQuery .= " AND (".$searchOwner.")";
+			}
+			if (strlen($searchCreateDate)>0) {
+				$searchQuery .= " AND (".$searchCreateDate.")";
+			}
+
+			// Count the number of rows that the search will produce.
+			$resArr = $this->db->getResultArray("SELECT COUNT(*) AS num ".$searchQuery);
+			$totalFolders = 0;
+			if (is_numeric($resArr[0]["num"]) && $resArr[0]["num"]>0) {
+				$totalFolders = (integer)$resArr[0]["num"];
+			}
+
+			// If there are no results from the count query, then there is no real need
+			// to run the full query. TODO: re-structure code to by-pass additional
+			// queries when no initial results are found.
+
+			// Only search if the offset is not beyond the number of folders
+			if($totalFolders > $offset) {
+				// Prepare the complete search query, including the LIMIT clause.
+				$searchQuery = "SELECT `tblFolders`.* ".$searchQuery;
+
+				if($limit) {
+					$searchQuery .= " LIMIT ".$offset.",".$limit;
+				}
+
+				// Send the complete search query to the database.
+				$resArr = $this->db->getResultArray($searchQuery);
+			} else {
+				$resArr = array();
+			}
+
+			// ------------------- Ausgabe der Ergebnisse ----------------------------
+			$numResults = count($resArr);
+			if ($numResults == 0) {
+				$folderresult = array('totalFolders'=>$totalFolders, 'folders'=>array());
+			} else {
+				foreach ($resArr as $folderArr) {
+					$folders[] = $this->getFolder($folderArr['id']);
+				}
+				$folderresult = array('totalFolders'=>$totalFolders, 'folders'=>$folders);
+			}
+		} else {
+			$folderresult = array('totalFolders'=>0, 'folders'=>array());
+		}
+
+		/*--------- Do it all over again for documents -------------*/
+
+		if($mode & 0x1) {
+			$searchKey = "";
+			// Assemble the arguments for the concatenation function. This allows the
+			// search to be carried across all the relevant fields.
+			$concatFunction = "";
+			if (in_array(1, $searchin)) {
+				$concatFunction = "`tblDocuments`.`keywords`";
+			}
+			if (in_array(2, $searchin)) {
+				$concatFunction = (strlen($concatFunction) == 0 ? "" : $concatFunction.", ")."`tblDocuments`.`name`";
+			}
+			if (in_array(3, $searchin)) {
+				$concatFunction = (strlen($concatFunction) == 0 ? "" : $concatFunction.", ")."`tblDocuments`.`comment`";
+			}
+
+			if (strlen($concatFunction)>0 && count($tkeys)>0) {
+				$concatFunction = "CONCAT_WS(' ', ".$concatFunction.")";
+				foreach ($tkeys as $key) {
+					$key = trim($key);
+					if (strlen($key)>0) {
+						$searchKey = (strlen($searchKey)==0 ? "" : $searchKey." ".$logicalmode." ").$concatFunction." LIKE ".$this->db->qstr('%'.$key.'%');
+					}
+				}
+			}
+
+			// Check to see if the search has been restricted to a particular sub-tree in
+			// the folder hierarchy.
+			$searchFolder = "";
+			if ($startFolder) {
+				$searchFolder = "`tblDocuments`.`folderList` LIKE '%:".$startFolder->getID().":%'";
+			}
+
+			// Check to see if the search has been restricted to a particular
+			// document owner.
+			$searchOwner = "";
+			if ($owner) {
+				$searchOwner = "`tblDocuments`.`owner` = '".$owner->getId()."'";
+			}
+
+			// Check to see if the search has been restricted to a particular
+			// document category.
+			$searchCategories = "";
+			if ($categories) {
+				$catids = array();
+				foreach($categories as $category)
+					$catids[] = $category->getId();
+				$searchCategories = "`tblDocumentCategory`.`categoryID` in (".implode(',', $catids).")";
+			}
+
+			// Is the search restricted to documents created between two specific dates?
+			$searchCreateDate = "";
+			if ($creationstartdate) {
+				$startdate = makeTimeStamp(0, 0, 0, $creationstartdate['year'], $creationstartdate["month"], $creationstartdate["day"]);
+				if ($startdate) {
+					$searchCreateDate .= "`tblDocuments`.`date` >= ".$startdate;
+				}
+			}
+			if ($creationenddate) {
+				$stopdate = makeTimeStamp(23, 59, 59, $creationenddate["year"], $creationenddate["month"], $creationenddate["day"]);
+				if ($stopdate) {
+					if($startdate)
+						$searchCreateDate .= " AND ";
+					$searchCreateDate .= "`tblDocuments`.`date` <= ".$stopdate;
+				}
+			}
+
+			// ---------------------- Suche starten ----------------------------------
+
+			//
+			// Construct the SQL query that will be used to search the database.
+			//
+
+			if (!$this->db->createTemporaryTable("ttcontentid") || !$this->db->createTemporaryTable("ttstatid")) {
+				return false;
+			}
+
+			$searchQuery = "FROM `tblDocumentContent` ".
+				"LEFT JOIN `tblDocuments` ON `tblDocuments`.`id` = `tblDocumentContent`.`document` ".
+				"LEFT JOIN `tblDocumentStatus` ON `tblDocumentStatus`.`documentID` = `tblDocumentContent`.`document` ".
+				"LEFT JOIN `tblDocumentStatusLog` ON `tblDocumentStatusLog`.`statusID` = `tblDocumentStatus`.`statusID` ".
+				"LEFT JOIN `ttstatid` ON `ttstatid`.`maxLogID` = `tblDocumentStatusLog`.`statusLogID` ".
+				"LEFT JOIN `ttcontentid` ON `ttcontentid`.`maxVersion` = `tblDocumentStatus`.`version` AND `ttcontentid`.`document` = `tblDocumentStatus`.`documentID` ".
+				"LEFT JOIN `tblDocumentLocks` ON `tblDocuments`.`id`=`tblDocumentLocks`.`document` ".
+				"LEFT JOIN `tblDocumentCategory` ON `tblDocuments`.`id`=`tblDocumentCategory`.`documentID` ".
+				"WHERE `ttstatid`.`maxLogID`=`tblDocumentStatusLog`.`statusLogID` ".
+				"AND `ttcontentid`.`maxVersion` = `tblDocumentContent`.`version`";
+
+			if (strlen($searchKey)>0) {
+				$searchQuery .= " AND (".$searchKey.")";
+			}
+			if (strlen($searchFolder)>0) {
+				$searchQuery .= " AND ".$searchFolder;
+			}
+			if (strlen($searchOwner)>0) {
+				$searchQuery .= " AND (".$searchOwner.")";
+			}
+			if (strlen($searchCategories)>0) {
+				$searchQuery .= " AND (".$searchCategories.")";
+			}
+			if (strlen($searchCreateDate)>0) {
+				$searchQuery .= " AND (".$searchCreateDate.")";
+			}
+
+			// status
+			if ($status) {
+				$searchQuery .= " AND `tblDocumentStatusLog`.`status` IN (".implode(',', $status).")";
+			}
+
+			// Count the number of rows that the search will produce.
+			$resArr = $this->db->getResultArray("SELECT COUNT(*) AS num ".$searchQuery);
+			$totalDocs = 0;
+			if (is_numeric($resArr[0]["num"]) && $resArr[0]["num"]>0) {
+				$totalDocs = (integer)$resArr[0]["num"];
+			}
+
+			// If there are no results from the count query, then there is no real need
+			// to run the full query. TODO: re-structure code to by-pass additional
+			// queries when no initial results are found.
+
+			// Prepare the complete search query, including the LIMIT clause.
+			$searchQuery = "SELECT `tblDocuments`.*, ".
+				"`tblDocumentContent`.`version`, ".
+				"`tblDocumentStatusLog`.`status`, `tblDocumentLocks`.`userID` as `lockUser` ".$searchQuery;
+
+			// calculate the remaining entrŅes of the current page
+			// If page is not full yet, get remaining entries
+			$remain = $limit - count($folderresult['folders']);
+			if($remain) {
+				if($remain == $limit)
+					$offset -= $totalFolders;
+				else
+					$offset = 0;
+				if($limit)
+					$searchQuery .= " LIMIT ".$offset.",".$remain;
+
+				// Send the complete search query to the database.
+				$resArr = $this->db->getResultArray($searchQuery);
+			} else {
+				$resArr = array();
+			}
+
+			// ------------------- Ausgabe der Ergebnisse ----------------------------
+			$numResults = count($resArr);
+			if ($numResults == 0) {
+				$docresult = array('totalDocs'=>$totalDocs, 'docs'=>array());
+			} else {
+				foreach ($resArr as $docArr) {
+					$docs[] = $this->getDocument($docArr['id']);
+				}
+				$docresult = array('totalDocs'=>$totalDocs, 'docs'=>$docs);
+			}
+		} else {
+			$docresult = array('totalDocs'=>0, 'docs'=>array());
+		}
+
+		if($limit) {
+			$totalPages = (integer)(($totalDocs+$totalFolders)/$limit);
+			if ((($totalDocs+$totalFolders)%$limit) > 0) {
+				$totalPages++;
+			}
+		} else {
+			$totalPages = 1;
+		}
+
+		return array_merge($docresult, $folderresult, array('totalPages'=>$totalPages));
+	} /* }}} */
+
+	/**
+	 * Return a folder by its id
+	 *
+	 * This function retrieves a folder from the database by its id.
+	 *
+	 * @param integer $id internal id of folder
+	 * @return object instance of LetoDMS_Core_Folder or false
+	 */
+	function getFolder($id) { /* {{{ */
+		if (!is_numeric($id)) return false;
+
+		$queryStr = "SELECT * FROM tblFolders WHERE id = " . (int) $id;
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		else if (count($resArr) != 1)
+			return false;
+
+		$resArr = $resArr[0];
+		$folder = new LetoDMS_Core_Folder($resArr["id"], $resArr["name"], $resArr["parent"], $resArr["comment"], $resArr["date"], $resArr["owner"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr["sequence"]);
+		$folder->setDMS($this);
+		return $folder;
+	} /* }}} */
+
+	/**
+	 * Return a folder by its name
+	 *
+	 * This function retrieves a folder from the database by its name. The
+	 * search covers the whole database. If
+	 * the parameter $folder is not null, it will search for the name
+	 * only within this parent folder. It will not be done recursively.
+	 *
+	 * @param string $name name of the folder
+	 * @param object $folder parent folder
+	 * @return object/boolean found folder or false
+	 */
+	function getFolderByName($name, $folder=null) { /* {{{ */
+		if (!$name) return false;
+
+		$queryStr = "SELECT * FROM tblFolders WHERE name = " . $this->db->qstr($name);
+		if($folder)
+			$queryStr .= " AND `parent` = ". $folder->getID();
+		$queryStr .= " LIMIT 1";
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+
+		if(!$resArr)
+			return false;
+
+		$resArr = $resArr[0];
+		$folder = new LetoDMS_Core_Folder($resArr["id"], $resArr["name"], $resArr["parent"], $resArr["comment"], $resArr["date"], $resArr["owner"], $resArr["inheritAccess"], $resArr["defaultAccess"], $resArr["sequence"]);
+		$folder->setDMS($this);
+		return $folder;
+	} /* }}} */
+
+	/**
+	 * Return a user by its id
+	 *
+	 * This function retrieves a user from the database by its id.
+	 *
+	 * @param integer $id internal id of user
+	 * @return object instance of LetoDMS_Core_User or false
+	 */
+	function getUser($id) { /* {{{ */
+		if (!is_numeric($id))
+			return false;
+
+		$queryStr = "SELECT * FROM tblUsers WHERE id = " . (int) $id;
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false) return false;
+		if (count($resArr) != 1) return false;
+
+		$resArr = $resArr[0];
+
+		$user = new LetoDMS_Core_User($resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $resArr["role"], $resArr["hidden"]);
+		$user->setDMS($this);
+		return $user;
+	} /* }}} */
+
+	/**
+	 * Return a user by its login
+	 *
+	 * This function retrieves a user from the database by its login.
+	 * If the second optional parameter $email is not empty, the user must
+	 * also have the given email.
+	 *
+	 * @param string $login internal login of user
+	 * @param string $email email of user
+	 * @return object instance of LetoDMS_Core_User or false
+	 */
+	function getUserByLogin($login, $email='') { /* {{{ */
+		$queryStr = "SELECT * FROM tblUsers WHERE login = ".$this->db->qstr($login);
+		if($email)
+			$queryStr .= " AND email=".$this->db->qstr($email);
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false) return false;
+		if (count($resArr) != 1) return false;
+
+		$resArr = $resArr[0];
+
+		$user = new LetoDMS_Core_User($resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $resArr["role"], $resArr["hidden"]);
+		$user->setDMS($this);
+		return $user;
+	} /* }}} */
+
+	/**
+	 * Return a user by its email
+	 *
+	 * This function retrieves a user from the database by its email.
+	 * It is needed when the user requests a new password.
+	 *
+	 * @param integer $email email address of user
+	 * @return object instance of LetoDMS_Core_User or false
+	 */
+	function getUserByEmail($email) { /* {{{ */
+		$queryStr = "SELECT * FROM tblUsers WHERE email = ".$this->db->qstr($email);
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false) return false;
+		if (count($resArr) != 1) return false;
+
+		$resArr = $resArr[0];
+
+		$user = new LetoDMS_Core_User($resArr["id"], $resArr["login"], $resArr["pwd"], $resArr["fullName"], $resArr["email"], $resArr["language"], $resArr["theme"], $resArr["comment"], $resArr["role"], $resArr["hidden"]);
+		$user->setDMS($this);
+		return $user;
+	} /* }}} */
+
+	/**
+	 * Return list of all users
+	 *
+	 * @return array of instances of LetoDMS_Core_User or false
+	 */
+	function getAllUsers() { /* {{{ */
+		$queryStr = "SELECT * FROM tblUsers ORDER BY login";
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+
+		$users = array();
+
+		for ($i = 0; $i < count($resArr); $i++) {
+			$user = new LetoDMS_Core_User($resArr[$i]["id"], $resArr[$i]["login"], $resArr[$i]["pwd"], $resArr[$i]["fullName"], $resArr[$i]["email"], (isset($resArr["language"])?$resArr["language"]:NULL), (isset($resArr["theme"])?$resArr["theme"]:NULL), $resArr[$i]["comment"], $resArr[$i]["role"], $resArr[$i]["hidden"]);
+			$user->setDMS($this);
+			$users[$i] = $user;
+		}
+
+		return $users;
+	} /* }}} */
+
+	/**
+	 * Add a new user
+	 *
+	 * @param string $login login name
+	 * @param string $pwd password of new user
+	 * @param string $email Email of new user
+	 * @param string $language language of new user
+	 * @param string $comment comment of new user
+	 * @param integer $role role of new user (can be 0=normal, 1=admin, 2=guest)
+	 * @param integer $isHidden hide user in all lists, if this is set login
+	 *        is still allowed
+	 * @return object of LetoDMS_Core_User
+	 */
+	function addUser($login, $pwd, $fullName, $email, $language, $theme, $comment, $role='0', $isHidden=0) { /* {{{ */
+		$db = $this->db;
+		if (is_object($this->getUserByLogin($login))) {
+			return false;
+		}
+		if($role == '')
+			$role = '0';
+		$queryStr = "INSERT INTO tblUsers (login, pwd, fullName, email, language, theme, comment, role, hidden) VALUES (".$db->qstr($login).", ".$db->qstr($pwd).", ".$db->qstr($fullName).", ".$db->qstr($email).", '".$language."', '".$theme."', ".$db->qstr($comment).", '".intval($role)."', '".intval($isHidden)."')";
+		$res = $this->db->getResult($queryStr);
+		if (!$res)
+			return false;
+
+		return $this->getUser($this->db->getInsertID());
+	} /* }}} */
+
+	/**
+	 * Get a group by its id
+	 *
+	 * @param integer $id id of group
+	 * @return object/boolean group or false if no group was found
+	 */
+	function getGroup($id) { /* {{{ */
+		if (!is_numeric($id))
+			return false;
+
+		$queryStr = "SELECT * FROM tblGroups WHERE id = " . (int) $id;
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		else if (count($resArr) != 1) //wenn, dann wohl eher 0 als > 1 ;-)
+			return false;
+
+		$resArr = $resArr[0];
+
+		$group = new LetoDMS_Core_Group($resArr["id"], $resArr["name"], $resArr["comment"]);
+		$group->setDMS($this);
+		return $group;
+	} /* }}} */
+
+	/**
+	 * Get a group by its name
+	 *
+	 * @param string $name name of group
+	 * @return object/boolean group or false if no group was found
+	 */
+	function getGroupByName($name) { /* {{{ */
+		$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` WHERE `tblGroups`.`name` = ".$this->db->qstr($name);
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		else if (count($resArr) != 1) //wenn, dann wohl eher 0 als > 1 ;-)
+			return false;
+
+		$resArr = $resArr[0];
+
+		$group = new LetoDMS_Core_Group($resArr["id"], $resArr["name"], $resArr["comment"]);
+		$group->setDMS($this);
+		return $group;
+	} /* }}} */
+
+	/**
+	 * Get a list of all groups
+	 *
+	 * @return array array of instances of {@link LetoDMS_Core_Group}
+	 */
+	function getAllGroups() { /* {{{ */
+		$queryStr = "SELECT * FROM tblGroups ORDER BY name";
+		$resArr = $this->db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+
+		$groups = array();
+
+		for ($i = 0; $i < count($resArr); $i++) {
+
+			$group = new LetoDMS_Core_Group($resArr[$i]["id"], $resArr[$i]["name"], $resArr[$i]["comment"]);
+			$group->setDMS($this);
+			$groups[$i] = $group;
+		}
+
+		return $groups;
+	} /* }}} */
+
+	/**
+	 * Create a new user group
+	 *
+	 * @param string $name name of group
+	 * @param string $comment comment of group
+	 * @return object/boolean instance of {@link LetoDMS_Core_Group} or false in
+	 *         case of an error.
+	 */
+	function addGroup($name, $comment) { /* {{{ */
+		if (is_object($this->getGroupByName($name))) {
+			return false;
+		}
+
+		$queryStr = "INSERT INTO tblGroups (name, comment) VALUES (".$this->db->qstr($name).", ".$this->db->qstr($comment).")";
+		if (!$this->db->getResult($queryStr))
+			return false;
+
+		return $this->getGroup($this->db->getInsertID());
+	} /* }}} */
+
+	function getKeywordCategory($id) { /* {{{ */
+		if (!is_numeric($id))
+			return false;
+
+		$queryStr = "SELECT * FROM tblKeywordCategories WHERE id = " . (int) $id;
+		$resArr = $this->db->getResultArray($queryStr);
+		if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1))
+			return false;
+
+		$resArr = $resArr[0];
+		$cat = new LetoDMS_Core_Keywordcategory($resArr["id"], $resArr["owner"], $resArr["name"]);
+		$cat->setDMS($this);
+		return $cat;
+	} /* }}} */
+
+	function getKeywordCategoryByName($name, $userID) { /* {{{ */
+		$queryStr = "SELECT * FROM tblKeywordCategories WHERE name = " . $this->db->qstr($name) . " AND owner = " . (int) $userID;
+		$resArr = $this->db->getResultArray($queryStr);
+		if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1))
+			return false;
+
+		$resArr = $resArr[0];
+		$cat = new LetoDMS_Core_Keywordcategory($resArr["id"], $resArr["owner"], $resArr["name"]);
+		$cat->setDMS($this);
+		return $cat;
+	} /* }}} */
+
+	function getAllKeywordCategories($userIDs = array()) { /* {{{ */
+		$queryStr = "SELECT * FROM tblKeywordCategories";
+		if ($userIDs)
+			$queryStr .= " WHERE owner in (".implode(',', $userIDs).")";
+
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		$categories = array();
+		foreach ($resArr as $row) {
+			$cat = new LetoDMS_Core_KeywordCategory($row["id"], $row["owner"], $row["name"]);
+			$cat->setDMS($this);
+			array_push($categories, $cat);
+		}
+
+		return $categories;
+	} /* }}} */
+
+	/**
+	 * This function should be replaced by getAllKeywordCategories()
+	 */
+	function getAllUserKeywordCategories($userID) { /* {{{ */
+		$queryStr = "SELECT * FROM tblKeywordCategories";
+		if ($userID != -1)
+			$queryStr .= " WHERE owner = " . (int) $userID;
+
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		$categories = array();
+		foreach ($resArr as $row) {
+			$cat = new LetoDMS_Core_KeywordCategory($row["id"], $row["owner"], $row["name"]);
+			$cat->setDMS($this);
+			array_push($categories, $cat);
+		}
+
+		return $categories;
+	} /* }}} */
+
+	function addKeywordCategory($userID, $name) { /* {{{ */
+		if (is_object($this->getKeywordCategoryByName($name, $userID))) {
+			return false;
+		}
+		$queryStr = "INSERT INTO tblKeywordCategories (owner, name) VALUES (".(int) $userID.", ".$this->db->qstr($name).")";
+		if (!$this->db->getResult($queryStr))
+			return false;
+
+		return $this->getKeywordCategory($this->db->getInsertID());
+	} /* }}} */
+
+	function getDocumentCategory($id) { /* {{{ */
+		if (!is_numeric($id))
+			return false;
+
+		$queryStr = "SELECT * FROM tblCategory WHERE id = " . (int) $id;
+		$resArr = $this->db->getResultArray($queryStr);
+		if ((is_bool($resArr) && !$resArr) || (count($resArr) != 1))
+			return false;
+
+		$resArr = $resArr[0];
+		$cat = new LetoDMS_Core_DocumentCategory($resArr["id"], $resArr["name"]);
+		$cat->setDMS($this);
+		return $cat;
+	} /* }}} */
+
+	function getDocumentCategories() { /* {{{ */
+		$queryStr = "SELECT * FROM tblCategory";
+
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		$categories = array();
+		foreach ($resArr as $row) {
+			$cat = new LetoDMS_Core_DocumentCategory($row["id"], $row["name"]);
+			$cat->setDMS($this);
+			array_push($categories, $cat);
+		}
+
+		return $categories;
+	} /* }}} */
+
+	/**
+	 * Get a category by its name
+	 *
+	 * The name of a category is by default unique.
+	 *
+	 * @param string $name human readable name of category
+	 * @return object instance of LetoDMS_Core_DocumentCategory
+	 */
+	function getDocumentCategoryByName($name) { /* {{{ */
+		$queryStr = "SELECT * FROM tblCategory where name=".$this->db->qstr($name);
+
+		$resArr = $this->db->getResultArray($queryStr);
+		if (!$resArr)
+			return false;
+
+		$row = $resArr[0];
+		$cat = new LetoDMS_Core_DocumentCategory($row["id"], $row["name"]);
+		$cat->setDMS($this);
+
+		return $cat;
+	} /* }}} */
+
+	function addDocumentCategory($name) { /* {{{ */
+		if (is_object($this->getDocumentCategoryByName($name))) {
+			return false;
+		}
+		$queryStr = "INSERT INTO tblCategory (name) VALUES (".$this->db-qstr($name).")";
+		if (!$this->db->getResult($queryStr))
+			return false;
+
+		return $this->getDocumentCategory($this->db->getInsertID());
+	} /* }}} */
+
+	/**
+	 * Get all notifications for a group
+	 *
+	 * @param object $group group for which notifications are to be retrieved
+	 * @param integer $type type of item (T_DOCUMENT or T_FOLDER)
+	 * @return array array of notifications
+	 */
+	function getNotificationsByGroup($group, $type=0) { /* {{{ */
+		$queryStr = "SELECT `tblNotify`.* FROM `tblNotify` ".
+		 "WHERE `tblNotify`.`groupID` = ". $group->getID();
+		if($type) {
+			$queryStr .= " AND `tblNotify`.`targetType` = ". (int) $type;
+		}
+
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		$notifications = array();
+		foreach ($resArr as $row) {
+			$not = new LetoDMS_Core_Notification($row["target"], $row["targetType"], $row["userID"], $row["groupID"]);
+			$not->setDMS($this);
+			array_push($notifications, $cat);
+		}
+
+		return $notifications;
+	} /* }}} */
+
+	/**
+	 * Get all notifications for a user
+	 *
+	 * @param object $user user for which notifications are to be retrieved
+	 * @param integer $type type of item (T_DOCUMENT or T_FOLDER)
+	 * @return array array of notifications
+	 */
+	function getNotificationsByUser($user, $type=0) { /* {{{ */
+		$queryStr = "SELECT `tblNotify`.* FROM `tblNotify` ".
+		 "WHERE `tblNotify`.`userID` = ". $user->getID();
+		if($type) {
+			$queryStr .= " AND `tblNotify`.`targetType` = ". (int) $type;
+		}
+
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		$notifications = array();
+		foreach ($resArr as $row) {
+			$not = new LetoDMS_Core_Notification($row["target"], $row["targetType"], $row["userID"], $row["groupID"]);
+			$not->setDMS($this);
+			array_push($notifications, $cat);
+		}
+
+		return $notifications;
+	} /* }}} */
+
+	/**
+	 * Create a token to request a new password.
+	 * This function will not delete the password but just creates an entry
+	 * in tblUserRequestPassword indicating a password request.
+	 *
+	 * @return string hash value of false in case of an error
+	 */
+	function createPasswordRequest($user) { /* {{{ */
+		$hash = md5(uniqid(time()));
+		$queryStr = "INSERT INTO tblUserPasswordRequest (userID, hash, `date`) VALUES (" . $user->getId() . ", " . $this->db->qstr($hash) .", now())";
+		$resArr = $this->db->getResult($queryStr);
+		if (is_bool($resArr) && !$resArr) return false;
+		return $hash;
+
+	} /* }}} */
+
+	/**
+	 * Check if hash for a password request is valid.
+	 * This function searches a previously create password request and
+	 * returns the user.
+	 *
+	 * @param string $hash
+	 */
+	function checkPasswordRequest($hash) { /* {{{ */
+		/* Get the password request from the database */
+		$queryStr = "SELECT * FROM tblUserPasswordRequest where hash=".$this->db->qstr($hash);
+		$resArr = $this->db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		if (count($resArr) != 1)
+			return false;
+		$resArr = $resArr[0];
+
+		return $this->getUser($resArr['userID']);
+
+	} /* }}} */
+
+	/**
+	 * Delete a password request
+	 *
+	 * @param string $hash
+	 */
+	function deletePasswordRequest($hash) { /* {{{ */
+		/* Delete the request, so nobody can use it a second time */
+		$queryStr = "DELETE FROM tblUserPasswordRequest WHERE hash=".$this->db->qstr($hash);
+		if (!$this->db->getResult($queryStr))
+			return false;
+		return true;
+	}
+}
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassDocumentCategory.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassDocumentCategory.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassDocumentCategory.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassDocumentCategory.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Implementation of document categories in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Class to represent a document category in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C)2011 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_DocumentCategory {
+	/**
+	 * @var integer $_id id of document category
+	 * @access protected
+	 */
+	var $_id;
+
+	/**
+	 * @var string $_name name of category
+	 * @access protected
+	 */
+	var $_name;
+
+	/**
+	 * @var object $_dms reference to dms this category belongs to
+	 * @access protected
+	 */
+	var $_dms;
+
+	function LetoDMS_Core_DocumentCategory($id, $name) {
+		$this->_id = $id;
+		$this->_name = $name;
+		$this->_dms = null;
+	}
+
+	function setDMS($dms) {
+		$this->_dms = $dms;
+	}
+
+	function getID() { return $this->_id; }
+
+	function getName() { return $this->_name; }
+
+	function setName($newName) {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblCategory SET name = ".$db->qstr($newName)." WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_name = $newName;
+		return true;
+	}
+
+	function isUsed() {
+		$db = $this->_dms->getDB();
+		
+		$queryStr = "SELECT * FROM tblDocumentCategory WHERE categoryID=".$this->_id;
+		$resArr = $db->getResultArray($queryStr);
+		if (is_array($resArr) && count($resArr) == 0)
+			return false;
+		return true;
+	}
+
+	function getCategories() {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT * FROM tblCategory";
+		return $db->getResultArray($queryStr);
+	}
+
+	function addCategory($keywords) {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "INSERT INTO tblCategory (category) VALUES (".$db->qstr($keywords).")";
+		return $db->getResult($queryStr);
+	}
+
+	function remove() {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE FROM tblCategory WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		return true;
+	}
+
+	function getDocumentsByCategory() {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT * FROM tblDocumentCategory where categoryID=".$this->_id;
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		$documents = array();
+		foreach ($resArr as $row) {
+			array_push($documents, $this->_dms->getDocument($row["id"]));
+		}
+		return $documents;
+	}
+
+}
+
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassDocument.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassDocument.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassDocument.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassDocument.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,2752 @@
+<?php
+/**
+ * Implementation of a document in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL2
+ * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
+ *             Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * The different states a document can be in
+ */
+define("S_DRAFT_REV", 0);
+define("S_DRAFT_APP", 1);
+define("S_RELEASED",  2);
+define("S_REJECTED", -1);
+define("S_OBSOLETE", -2);
+define("S_EXPIRED",  -3);
+
+/**
+ * Class to represent a document in the document management system
+ *
+ * A document in LetoDMS is similar to files in a regular file system.
+ * Documents may have any number of content elements
+ * ({@link LetoDMS_Core_DocumentContent}). These content elements are often
+ * called versions ordered in a timely manner. The most recent content element
+ * is the current version.
+ *
+ * Documents can be linked to other documents and can have attached files.
+ * The document content can be anything that can be stored in a regular
+ * file.
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
+ *             Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_Document { /* {{{ */
+	/**
+	 * @var integer unique id of document
+	 */
+	var $_id;
+
+	/**
+	 * @var string name of document
+	 */
+	var $_name;
+
+	/**
+	 * @var string comment of document
+	 */
+	var $_comment;
+
+	/**
+	 * @var integer unix timestamp of creation date
+	 */
+	var $_date;
+
+	/**
+	 * @var integer id of user who is the owner
+	 */
+	var $_ownerID;
+
+	/**
+	 * @var integer id of folder this document belongs to
+	 */
+	var $_folderID;
+
+	/**
+	 * @var integer timestamp of expiration date
+	 */
+	var $_expires;
+
+	/**
+	 * @var boolean true if access is inherited, otherwise false
+	 */
+	var $_inheritAccess;
+
+	/**
+	 * @var integer default access if access rights are not inherited
+	 */
+	var $_defaultAccess;
+
+	/**
+	 * @var array list of notifications for users and groups
+	 */
+	var $_notifyList;
+
+	/**
+	 * @var boolean true if document is locked, otherwise false
+	 */
+	var $_locked;
+
+	/**
+	 * @var string list of keywords
+	 */
+	var $_keywords;
+
+	/**
+	 * @var array list of categories
+	 */
+	var $_categories;
+
+	/**
+	 * @var integer position of document within the parent folder
+	 */
+	var $_sequence;
+
+	/**
+	 * @var object back reference to document management system
+	 */
+	var $_dms;
+
+	function LetoDMS_Core_Document($id, $name, $comment, $date, $expires, $ownerID, $folderID, $inheritAccess, $defaultAccess, $locked, $keywords, $sequence) { /* {{{ */
+		$this->_id = $id;
+		$this->_name = $name;
+		$this->_comment = $comment;
+		$this->_date = $date;
+		$this->_expires = $expires;
+		$this->_ownerID = $ownerID;
+		$this->_folderID = $folderID;
+		$this->_inheritAccess = $inheritAccess;
+		$this->_defaultAccess = $defaultAccess;
+		$this->_locked = ($locked == null || $locked == '' ? -1 : $locked);
+		$this->_keywords = $keywords;
+		$this->_sequence = $sequence;
+		$this->_categories = array();
+		$this->_notifyList = array();
+		$this->_dms = null;
+	} /* }}} */
+
+	/*
+	 * Set dms this document belongs to.
+	 *
+	 * Each document needs a reference to the dms it belongs to. It will be
+	 * set when the folder is created by LetoDMS::getDocument() or
+	 * LetoDMS::search(). The dms has a
+	 * references to the currently logged in user and the database connection.
+	 *
+	 * @param object $dms reference to dms
+	 */
+	function setDMS($dms) { /* {{{ */
+		$this->_dms = $dms;
+	} /* }}} */
+
+	/*
+	 * Return the directory of the document in the file system relativ
+	 * to the contentDir
+	 *
+	 * @return string directory of document
+	 */
+	function getDir() { /* {{{ */
+		if($this->_dms->maxDirID) {
+			$dirid = (int) (($this->_id-1) / $this->_dms->maxDirID) + 1; 
+			return $dirid."/".$this->_id."/";
+		} else {
+			return $this->_id."/";
+		}
+	} /* }}} */
+
+	/*
+	 * Return the internal id of the document
+	 *
+	 * @return integer id of document
+	 */
+	function getID() { return $this->_id; }
+
+	/*
+	 * Return the name of the document
+	 *
+	 * @return string name of document
+	 */
+	function getName() { return $this->_name; }
+
+	/*
+	 * Set the name of the document
+	 *
+	 * @param $newName string new name of document
+	 */
+	function setName($newName) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocuments SET name = ".$db->qstr($newName)." WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_name = $newName;
+		return true;
+	} /* }}} */
+
+	/*
+	 * Return the comment of the document
+	 *
+	 * @return string comment of document
+	 */
+	function getComment() { return $this->_comment; }
+
+	/*
+	 * Set the comment of the document
+	 *
+	 * @param $newComment string new comment of document
+	 */
+	function setComment($newComment) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocuments SET comment = ".$db->qstr($newComment)." WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_comment = $newComment;
+		return true;
+	} /* }}} */
+
+	function getKeywords() { return $this->_keywords; }
+
+	function setKeywords($newKeywords) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocuments SET keywords = ".$db->qstr($newKeywords)." WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_keywords = $newKeywords;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Retrieve a list of all categories this document belongs to
+	 *
+	 * @return array list of category objects
+	 */
+	function getCategories() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if(!$this->_categories) {
+			$queryStr = "SELECT * FROM tblCategory where id in (select categoryID from tblDocumentCategory where documentID = ".$this->_id.")";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$resArr)
+				return false;
+
+			foreach ($resArr as $row) {
+				$cat = new LetoDMS_Core_DocumentCategory($row['id'], $row['name']);
+				$cat->setDMS($this->_dms);
+				$this->_categories[] = $cat;
+			}
+		}
+		return $this->_categories;
+	} /* }}} */
+
+	/**
+	 * Set a list of categories for the document
+	 * This function will delete currently assigned categories and sets new
+	 * categories.
+	 *
+	 * @param array $newCategories list of category objects
+	 */
+	function setCategories($newCategories) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE from tblDocumentCategory WHERE documentID = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		foreach($newCategories as $cat) {
+			$queryStr = "INSERT INTO tblDocumentCategory (categoryID, documentID) VALUES (". $cat->getId() .", ". $this->_id .")";
+			if (!$db->getResult($queryStr))
+				return false;
+		}
+
+		$this->_categories = $newCategories;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Return creation date of the document
+	 *
+	 * @return integer unix timestamp of creation date
+	 */
+	function getDate() { /* {{{ */
+		return $this->_date;
+	} /* }}} */
+
+	/**
+	 * Return the parent folder of the document
+	 *
+	 * @return object parent folder
+	 */
+	function getFolder() { /* {{{ */
+		if (!isset($this->_folder))
+			$this->_folder = $this->_dms->getFolder($this->_folderID);
+		return $this->_folder;
+	} /* }}} */
+
+	/**
+	 * Set folder of a document
+	 *
+	 * This function basically moves a document from a folder to another
+	 * folder.
+	 *
+	 * @param object $newFolder
+	 * @return boolean false in case of an error, otherwise true
+	 */
+	function setFolder($newFolder) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocuments SET folder = " . $newFolder->getID() . " WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$this->_folderID = $newFolder->getID();
+		$this->_folder = $newFolder;
+
+		// Make sure that the folder search path is also updated.
+		$path = $newFolder->getPath();
+		$flist = "";
+		foreach ($path as $f) {
+			$flist .= ":".$f->getID();
+		}
+		if (strlen($flist)>1) {
+			$flist .= ":";
+		}
+		$queryStr = "UPDATE tblDocuments SET folderList = '" . $flist . "' WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Return owner of document
+	 *
+	 * @return object owner of document as an instance of {@link LetoDMS_Core_User}
+	 */
+	function getOwner() { /* {{{ */
+		if (!isset($this->_owner))
+			$this->_owner = $this->_dms->getUser($this->_ownerID);
+		return $this->_owner;
+	} /* }}} */
+
+	/**
+	 * Set owner of a document
+	 *
+	 * @param object $newOwner new owner
+	 * @return boolean true if successful otherwise false
+	 */
+	function setOwner($newOwner) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocuments set owner = " . $newOwner->getID() . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_ownerID = $newOwner->getID();
+		$this->_owner = $newOwner;
+		return true;
+	} /* }}} */
+
+	function getDefaultAccess() { /* {{{ */
+		if ($this->inheritsAccess()) {
+			$res = $this->getFolder();
+			if (!$res) return false;
+			return $this->_folder->getDefaultAccess();
+		}
+		return $this->_defaultAccess;
+	} /* }}} */
+
+	function setDefaultAccess($mode) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocuments set defaultAccess = " . (int) $mode . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_defaultAccess = $mode;
+
+		// If any of the notification subscribers no longer have read access,
+		// remove their subscription.
+		foreach ($this->_notifyList["users"] as $u) {
+			if ($this->getAccessMode($u) < M_READ) {
+				$this->removeNotify($u->getID(), true);
+			}
+		}
+		foreach ($this->_notifyList["groups"] as $g) {
+			if ($this->getGroupAccessMode($g) < M_READ) {
+				$this->removeNotify($g->getID(), false);
+			}
+		}
+
+		return true;
+	} /* }}} */
+
+	function inheritsAccess() { return $this->_inheritAccess; }
+
+	/**
+	 * Set inherited access mode
+	 * Setting inherited access mode will set or unset the internal flag which
+	 * controls if the access mode is inherited from the parent folder or not.
+	 * It will not modify the
+	 * access control list for the current object. It will remove all
+	 * notifications of users which do not even have read access anymore
+	 * after setting or unsetting inherited access.
+	 *
+	 * @param boolean $inheritAccess set to true for setting and false for
+	 *        unsetting inherited access mode
+	 * @return boolean true if operation was successful otherwise false
+	 */
+	function setInheritAccess($inheritAccess) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocuments SET inheritAccess = " . ($inheritAccess ? "1" : "0") . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_inheritAccess = ($inheritAccess ? "1" : "0");
+
+		// If any of the notification subscribers no longer have read access,
+		// remove their subscription.
+		if(isset($this->_notifyList["users"])) {
+			foreach ($this->_notifyList["users"] as $u) {
+				if ($this->getAccessMode($u) < M_READ) {
+					$this->removeNotify($u->getID(), true);
+				}
+			}
+		}
+		if(isset($this->_notifyList["groups"])) {
+			foreach ($this->_notifyList["groups"] as $g) {
+				if ($this->getGroupAccessMode($g) < M_READ) {
+					$this->removeNotify($g->getID(), false);
+				}
+			}
+		}
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Check if document expires
+	 *
+	 * @return boolean true if document has expiration date set, otherwise false
+	 */
+	function expires() { /* {{{ */
+		if (intval($this->_expires) == 0)
+			return false;
+		else
+			return true;
+	} /* }}} */
+
+	/**
+	 * Get expiration time of document
+	 *
+	 * @return integer/boolean expiration date as unix timestamp or false
+	 */
+	function getExpires() { /* {{{ */
+		if (intval($this->_expires) == 0)
+			return false;
+		else
+			return $this->_expires;
+	} /* }}} */
+
+	/**
+	 * Set expiration date as unix timestamp
+	 *
+	 * @param integer unix timestamp of expiration date
+	 */
+	function setExpires($expires) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$expires = (!$expires) ? 0 : $expires;
+
+		if ($expires == $this->_expires) {
+			// No change is necessary.
+			return true;
+		}
+
+		$queryStr = "UPDATE tblDocuments SET expires = " . (int) $expires . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_expires = $expires;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Check if the document has expired
+	 *
+	 * @return boolean true if document has expired otherwise false
+	 */
+	function hasExpired() { /* {{{ */
+		if (intval($this->_expires) == 0) return false;
+		if (time()>$this->_expires+24*60*60) return true;
+		return false;
+	} /* }}} */
+
+	// return true if status has changed (to reload page)
+	function verifyLastestContentExpriry(){ /* {{{ */
+		$lc=$this->getLatestContent();
+		if($lc) {
+			$st=$lc->getStatus();
+
+			if (($st["status"]==S_DRAFT_REV || $st["status"]==S_DRAFT_APP) && $this->hasExpired()){
+				$lc->setStatus(S_EXPIRED,"", $this->getOwner());
+				return true;
+			}
+			else if ($st["status"]==S_EXPIRED && !$this->hasExpired() ){
+				$lc->verifyStatus(true, $this->getOwner());
+				return true;
+			}
+		}
+		return false;
+	} /* }}} */
+
+	/**
+	 * Check if document is locked
+	 *
+	 * @return boolean true if locked otherwise false
+	 */
+	function isLocked() { return $this->_locked != -1; }
+
+	/**
+	 * Lock or unlock document
+	 *
+	 * @param $falseOrUser user object for locking or false for unlocking
+	 * @return boolean true if operation was successful otherwise false
+	 */
+	function setLocked($falseOrUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$lockUserID = -1;
+		if (is_bool($falseOrUser) && !$falseOrUser) {
+			$queryStr = "DELETE FROM tblDocumentLocks WHERE document = ".$this->_id;
+		}
+		else if (is_object($falseOrUser)) {
+			$queryStr = "INSERT INTO tblDocumentLocks (document, userID) VALUES (".$this->_id.", ".$falseOrUser->getID().")";
+			$lockUserID = $falseOrUser->getID();
+		}
+		else {
+			return false;
+		}
+		if (!$db->getResult($queryStr)) {
+			return false;
+		}
+		unset($this->_lockingUser);
+		$this->_locked = $lockUserID;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Get the user currently locking the document
+	 *
+	 * @return object user have a lock
+	 */
+	function getLockingUser() { /* {{{ */
+		if (!$this->isLocked())
+			return false;
+
+		if (!isset($this->_lockingUser))
+			$this->_lockingUser = $this->_dms->getUser($this->_locked);
+		return $this->_lockingUser;
+	} /* }}} */
+
+	function getSequence() { return $this->_sequence; }
+
+	function setSequence($seq) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocuments SET sequence = " . $seq . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_sequence = $seq;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Delete all entries for this document from the access control list
+	 *
+	 * @return boolean true if operation was successful otherwise false
+	 */
+	function clearAccessList() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE FROM tblACLs WHERE targetType = " . T_DOCUMENT . " AND target = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_accessList);
+		return true;
+	} /* }}} */
+
+	/**
+	 * Returns a list of access privileges
+	 *
+	 * If the document inherits the access privileges from the parent folder
+	 * those will be returned.
+	 * $mode and $op can be set to restrict the list of returned access
+	 * privileges. If $mode is set to M_ANY no restriction will apply
+	 * regardless of the value of $op. The returned array contains a list
+	 * of {@link LetoDMS_Core_UserAccess} and
+	 * {@link LetoDMS_Core_GroupAccess} objects. Even if the document
+	 * has no access list the returned array contains the two elements
+	 * 'users' and 'groups' which are than empty. The methode returns false
+	 * if the function fails.
+	 * 
+	 * @param integer $mode access mode (defaults to M_ANY)
+	 * @param integer $op operation (defaults to O_EQ)
+	 * @return array multi dimensional array
+	 */
+	function getAccessList($mode = M_ANY, $op = O_EQ) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if ($this->inheritsAccess()) {
+			$res = $this->getFolder();
+			if (!$res) return false;
+			return $this->_folder->getAccessList($mode, $op);
+		}
+
+		if (!isset($this->_accessList[$mode])) {
+			if ($op!=O_GTEQ && $op!=O_LTEQ && $op!=O_EQ) {
+				return false;
+			}
+			$modeStr = "";
+			if ($mode!=M_ANY) {
+				$modeStr = " AND mode".$op.(int)$mode;
+			}
+			$queryStr = "SELECT * FROM tblACLs WHERE targetType = ".T_DOCUMENT.
+				" AND target = " . $this->_id .	$modeStr . " ORDER BY targetType";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$resArr)
+				return false;
+
+			$this->_accessList[$mode] = array("groups" => array(), "users" => array());
+			foreach ($resArr as $row) {
+				if ($row["userID"] != -1)
+					array_push($this->_accessList[$mode]["users"], new LetoDMS_Core_UserAccess($this->_dms->getUser($row["userID"]), $row["mode"]));
+				else //if ($row["groupID"] != -1)
+					array_push($this->_accessList[$mode]["groups"], new LetoDMS_Core_GroupAccess($this->_dms->getGroup($row["groupID"]), $row["mode"]));
+			}
+		}
+
+		return $this->_accessList[$mode];
+	} /* }}} */
+
+	/**
+	 * Add access right to folder
+	 * This function may change in the future. Instead of passing the a flag
+	 * and a user/group id a user or group object will be expected.
+	 *
+	 * @param integer $mode access mode
+	 * @param integer $userOrGroupID id of user or group
+	 * @param integer $isUser set to 1 if $userOrGroupID is the id of a
+	 *        user
+	 */
+	function addAccess($mode, $userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		$queryStr = "INSERT INTO tblACLs (target, targetType, ".$userOrGroup.", mode) VALUES
+					(".$this->_id.", ".T_DOCUMENT.", " . (int) $userOrGroupID . ", " .(int) $mode. ")";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_accessList);
+
+		// Update the notify list, if necessary.
+		if ($mode == M_NONE) {
+			$this->removeNotify($userOrGroupID, $isUser);
+		}
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Change access right of document
+	 * This function may change in the future. Instead of passing the a flag
+	 * and a user/group id a user or group object will be expected.
+	 *
+	 * @param integer $newMode access mode
+	 * @param integer $userOrGroupID id of user or group
+	 * @param integer $isUser set to 1 if $userOrGroupID is the id of a
+	 *        user
+	 */
+	function changeAccess($newMode, $userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		$queryStr = "UPDATE tblACLs SET mode = " . (int) $newMode . " WHERE targetType = ".T_DOCUMENT." AND target = " . $this->_id . " AND " . $userOrGroup . " = " . (int) $userOrGroupID;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_accessList);
+
+		// Update the notify list, if necessary.
+		if ($newMode == M_NONE) {
+			$this->removeNotify($userOrGroupID, $isUser);
+		}
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Remove access rights for a user or group
+	 *
+	 * @param integer $userOrGroupID ID of user or group
+	 * @param boolean $isUser true if $userOrGroupID is a user id, false if it
+	 *        is a group id.
+	 * @return boolean true on success, otherwise false
+	 */
+	function removeAccess($userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		$queryStr = "DELETE FROM tblACLs WHERE targetType = ".T_DOCUMENT." AND target = ".$this->_id." AND ".$userOrGroup." = " . (int) $userOrGroupID;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_accessList);
+
+		// Update the notify list, if the user looses access rights.
+		$mode = ($isUser ? $this->getAccessMode($this->_dms->getUser($userOrGroupID)) : $this->getGroupAccessMode($this->_dms->getGroup($userOrGroupID)));
+		if ($mode == M_NONE) {
+			$this->removeNotify($userOrGroupID, $isUser);
+		}
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Returns the greatest access privilege for a given user
+	 *
+	 * This function returns the access mode for a given user. An administrator
+	 * and the owner of the folder has unrestricted access. A guest user has
+	 * read only access or no access if access rights are further limited
+	 * by access control lists. All other users have access rights according
+	 * to the access control lists or the default access. This function will
+	 * recursive check for access rights of parent folders if access rights
+	 * are inherited.
+	 *
+	 * The function searches the access control list for entries of
+	 * user $user. If it finds more than one entry it will return the
+	 * one allowing the greatest privileges, but user rights will always
+	 * precede group rights. If there is no entry in the
+	 * access control list, it will return the default access mode.
+	 * The function takes inherited access rights into account.
+	 * For a list of possible access rights see @file inc.AccessUtils.php
+	 *
+	 * @param $user object instance of class LetoDMS_Core_User
+	 * @return integer access mode
+	 */
+	function getAccessMode($user) { /* {{{ */
+		/* Administrators have unrestricted access */
+		if ($user->isAdmin()) return M_ALL;
+
+		/* The owner of the document has unrestricted access */
+		if ($user->getID() == $this->_ownerID) return M_ALL;
+
+		/* The guest users do not have more than read access */
+		if ($user->isGuest()) {
+			$mode = $this->getDefaultAccess();
+			if ($mode >= M_READ) return M_READ;
+			else return M_NONE;
+		}
+
+		/* Check ACLs */
+		$accessList = $this->getAccessList();
+		if (!$accessList) return false;
+
+		foreach ($accessList["users"] as $userAccess) {
+			if ($userAccess->getUserID() == $user->getID()) {
+				return $userAccess->getMode();
+			}
+		}
+		/* Get the highest right defined by a group */
+		$result = 0;
+		foreach ($accessList["groups"] as $groupAccess) {
+			if ($user->isMemberOfGroup($groupAccess->getGroup())) {
+				if ($groupAccess->getMode() > $result)
+					$result = $groupAccess->getMode();
+//					return $groupAccess->getMode();
+			}
+		}
+		if($result)
+			return $result;
+		$result = $this->getDefaultAccess();
+		return $result;
+	} /* }}} */
+
+	/**
+	 * Returns the greatest access privilege for a given group
+	 *
+	 * This function searches the access control list for entries of
+	 * group $group. If it finds more than one entry it will return the
+	 * one allowing the greatest privileges. If there is no entry in the
+	 * access control list, it will return the default access mode.
+	 * The function takes inherited access rights into account.
+	 * For a list of possible access rights see @file inc.AccessUtils.php
+	 *
+	 * @param $group object instance of class LetoDMS_Core_Group
+	 * @return integer access mode
+	 */
+	function getGroupAccessMode($group) { /* {{{ */
+		$highestPrivileged = M_NONE;
+
+		//ACLs durchforsten
+		$foundInACL = false;
+		$accessList = $this->getAccessList();
+		if (!$accessList)
+			return false;
+
+		foreach ($accessList["groups"] as $groupAccess) {
+			if ($groupAccess->getGroupID() == $group->getID()) {
+				$foundInACL = true;
+				if ($groupAccess->getMode() > $highestPrivileged)
+					$highestPrivileged = $groupAccess->getMode();
+				if ($highestPrivileged == M_ALL) // max access right -> skip the rest
+					return $highestPrivileged;
+			}
+		}
+
+		if ($foundInACL)
+			return $highestPrivileged;
+
+		//Standard-Berechtigung verwenden
+		return $this->getDefaultAccess();
+	} /* }}} */
+
+	/**
+	 * Returns a list of all notifications
+	 *
+	 * The returned list has two elements called 'users' and 'groups'. Each one
+	 * is an array itself countaining objects of class LetoDMS_Core_User and
+	 * LetoDMS_Core_Group.
+	 *
+	 * @return array list of notifications
+	 */
+	function getNotifyList() { /* {{{ */
+		if (empty($this->_notifyList)) {
+			$db = $this->_dms->getDB();
+
+			$queryStr ="SELECT * FROM tblNotify WHERE targetType = " . T_DOCUMENT . " AND target = " . $this->_id;
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && $resArr == false)
+				return false;
+
+			$this->_notifyList = array("groups" => array(), "users" => array());
+			foreach ($resArr as $row)
+			{
+				if ($row["userID"] != -1)
+					array_push($this->_notifyList["users"], $this->_dms->getUser($row["userID"]) );
+				else //if ($row["groupID"] != -1)
+					array_push($this->_notifyList["groups"], $this->_dms->getGroup($row["groupID"]) );
+			}
+		}
+		return $this->_notifyList;
+	} /* }}} */
+
+	/**
+	 * Add a user/group to the notification list
+	 * This function does not check if the currently logged in user
+	 * is allowed to add a notification. This must be checked by the calling
+	 * application.
+	 *
+	 * @param $userOrGroupID integer id of user or group to add
+	 * @param $isUser integer 1 if $userOrGroupID is a user,
+	 *                0 if $userOrGroupID is a group
+	 * @return integer  0: Update successful.
+	 *                 -1: Invalid User/Group ID.
+	 *                 -2: Target User / Group does not have read access.
+	 *                 -3: User is already subscribed.
+	 *                 -4: Database / internal error.
+	 */
+	function addNotify($userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$userOrGroup = ($isUser ? "userID" : "groupID");
+
+		/* Verify that user / group exists. */
+		$obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
+		if (!is_object($obj)) {
+			return -1;
+		}
+
+		/* Verify that the requesting user has permission to add the target to
+		 * the notification system.
+		 */
+		/*
+		 * The calling application should enforce the policy on who is allowed
+		 * to add someone to the notification system. If is shall remain here
+		 * the currently logged in user should be passed to this function
+		 *
+		GLOBAL $user;
+		if ($user->isGuest()) {
+			return -2;
+		}
+		if (!$user->isAdmin()) {
+			if ($isUser) {
+				if ($user->getID() != $obj->getID()) {
+					return -2;
+				}
+			}
+			else {
+				if (!$obj->isMember($user)) {
+					return -2;
+				}
+			}
+		}
+		 */
+
+		/* Verify that target user / group has read access to the document. */
+		if ($isUser) {
+			// Users are straightforward to check.
+			if ($this->getAccessMode($obj) < M_READ) {
+				return -2;
+			}
+		}
+		else {
+			// Groups are a little more complex.
+			if ($this->getDefaultAccess() >= M_READ) {
+				// If the default access is at least READ-ONLY, then just make sure
+				// that the current group has not been explicitly excluded.
+				$acl = $this->getAccessList(M_NONE, O_EQ);
+				$found = false;
+				foreach ($acl["groups"] as $group) {
+					if ($group->getGroupID() == $userOrGroupID) {
+						$found = true;
+						break;
+					}
+				}
+				if ($found) {
+					return -2;
+				}
+			}
+			else {
+				// The default access is restricted. Make sure that the group has
+				// been explicitly allocated access to the document.
+				$acl = $this->getAccessList(M_READ, O_GTEQ);
+				if (is_bool($acl)) {
+					return -4;
+				}
+				$found = false;
+				foreach ($acl["groups"] as $group) {
+					if ($group->getGroupID() == $userOrGroupID) {
+						$found = true;
+						break;
+					}
+				}
+				if (!$found) {
+					return -2;
+				}
+			}
+		}
+		/* Check to see if user/group is already on the list. */
+		$queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
+			"AND `tblNotify`.`targetType` = '".T_DOCUMENT."' ".
+			"AND `tblNotify`.`".$userOrGroup."` = '".(int) $userOrGroupID."'";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr)) {
+			return -4;
+		}
+		if (count($resArr)>0) {
+			return -3;
+		}
+
+		$queryStr = "INSERT INTO tblNotify (target, targetType, " . $userOrGroup . ") VALUES (" . $this->_id . ", " . T_DOCUMENT . ", " . (int) $userOrGroupID . ")";
+		if (!$db->getResult($queryStr))
+			return -4;
+
+		unset($this->_notifyList);
+		return 0;
+	} /* }}} */
+
+	/**
+	 * Remove a user or group from the notification list
+	 * This function does not check if the currently logged in user
+	 * is allowed to remove a notification. This must be checked by the calling
+	 * application.
+	 *
+	 * @param $userOrGroupID id of user or group
+	 * @param $isUser boolean true if a user is passed in $userOrGroupID, false
+	 *        if a group is passed in $userOrGroupID
+	 * @return integer 0 if operation was succesful
+	 *                 -1 if the userid/groupid is invalid
+	 *                 -3 if the user/group is already subscribed
+	 *                 -4 in case of an internal database error
+	 */
+	function removeNotify($userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		/* Verify that user / group exists. */
+		$obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
+		if (!is_object($obj)) {
+			return -1;
+		}
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		/* Verify that the requesting user has permission to add the target to
+		 * the notification system.
+		 */
+		/*
+		 * The calling application should enforce the policy on who is allowed
+		 * to add someone to the notification system. If is shall remain here
+		 * the currently logged in user should be passed to this function
+		 *
+		GLOBAL $user;
+		if ($user->isGuest()) {
+			return -2;
+		}
+		if (!$user->isAdmin()) {
+			if ($isUser) {
+				if ($user->getID() != $obj->getID()) {
+					return -2;
+				}
+			}
+			else {
+				if (!$obj->isMember($user)) {
+					return -2;
+				}
+			}
+		}
+		 */
+
+		/* Check to see if the target is in the database. */
+		$queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
+			"AND `tblNotify`.`targetType` = '".T_DOCUMENT."' ".
+			"AND `tblNotify`.`".$userOrGroup."` = '".(int) $userOrGroupID."'";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr)) {
+			return -4;
+		}
+		if (count($resArr)==0) {
+			return -3;
+		}
+
+		$queryStr = "DELETE FROM tblNotify WHERE target = " . $this->_id . " AND targetType = " . T_DOCUMENT . " AND " . $userOrGroup . " = " . (int) $userOrGroupID;
+		if (!$db->getResult($queryStr))
+			return -4;
+
+		unset($this->_notifyList);
+		return 0;
+	} /* }}} */
+
+	/**
+	 * Add content to a document
+	 *
+	 * Each document may have any number of content elements attached to it.
+	 * Each content element has a version number. Newer versions (greater
+	 * version number) replace older versions.
+	 *
+	 * @param string $comment comment
+	 * @param object $user user who shall be the owner of this content
+	 * @param string $tmpFile file containing the actuall content
+	 * @param string $orgFileName original file name
+	 * @param string $mimeType MimeType of the content
+	 * @param array $reviewers list of reviewers
+	 * @param array $approvers list of approvers
+	 * @param integer $version version number of content or 0 if next higher version shall be used.
+	 * @return bool/array false in case of an error or a result set
+	 */
+	function addContent($comment, $user, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers=array(), $approvers=array(), $version=0) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		// the doc path is id/version.filetype
+		$dir = $this->getDir();
+
+		$date = mktime();
+
+		/* The version field in table tblDocumentContent used to be auto
+		 * increment but that requires the field to be primary as well if
+		 * innodb is used. That's why the version is now determined here.
+		 */
+		if ((int)$version<1) {
+			$queryStr = "SELECT MAX(version) as m from tblDocumentContent where document = ".$this->_id;
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$res)
+				return false;
+
+			$version = $resArr[0]['m']+1;
+		}
+
+		$queryStr = "INSERT INTO tblDocumentContent (document, version, comment, date, createdBy, dir, orgFileName, fileType, mimeType) VALUES ".
+						"(".$this->_id.", ".(int)$version.",".$db->qstr($comment).", ".$date.", ".$user->getID().", ".$db->qstr($dir).", ".$db->qstr($orgFileName).", ".$db->qstr($fileType).", ".$db->qstr($mimeType).")";
+		if (!$db->getResult($queryStr)) return false;
+
+		// copy file
+		if (!LetoDMS_Core_File::makeDir($this->_dms->contentDir . $dir)) return false;
+		if (!LetoDMS_Core_File::copyFile($tmpFile, $this->_dms->contentDir . $dir . $version . $fileType)) return false;
+
+		unset($this->_content);
+		unset($this->_latestContent);
+		$docResultSet = new LetoDMS_Core_AddContentResultSet(new LetoDMS_Core_DocumentContent($this, $version, $comment, $date, $user->getID(), $dir, $orgFileName, $fileType, $mimeType));
+
+		// TODO - verify
+		if ($this->_dms->enableConverting && in_array($docResultSet->_content->getFileType(), array_keys($this->_dms->convertFileTypes)))
+			$docResultSet->_content->convert(); // Even if if fails, do not return false
+
+		$queryStr = "INSERT INTO `tblDocumentStatus` (`documentID`, `version`) ".
+			"VALUES (". $this->_id .", ". (int) $version .")";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$statusID = $db->getInsertID();
+
+		// Add reviewers into the database. Reviewers must review the document
+		// and submit comments, if appropriate. Reviewers can also recommend that
+		// a document be rejected.
+		$pendingReview=false;
+		$reviewRes = array();
+		foreach (array("i", "g") as $i){
+			if (isset($reviewers[$i])) {
+				foreach ($reviewers[$i] as $reviewerID) {
+					$reviewer=($i=="i" ?$this->_dms->getUser($reviewerID) : $this->_dms->getGroup($reviewerID));
+					$res = ($i=="i" ? $docResultSet->_content->addIndReviewer($reviewer, $user, true) : $docResultSet->_content->addGrpReviewer($reviewer, $user, true));
+					$docResultSet->addReviewer($reviewer, $i, $res);
+					// If no error is returned, or if the error is just due to email
+					// failure, mark the state as "pending review".
+					if ($res==0 || $res=-3 || $res=-4) {
+						$pendingReview=true;
+					}
+				}
+			}
+		}
+		// Add approvers to the database. Approvers must also review the document
+		// and make a recommendation on its release as an approved version.
+		$pendingApproval=false;
+		$approveRes = array();
+		foreach (array("i", "g") as $i){
+			if (isset($approvers[$i])) {
+				foreach ($approvers[$i] as $approverID) {
+					$approver=($i=="i" ? $this->_dms->getUser($approverID) : $this->_dms->getGroup($approverID));
+					$res=($i=="i" ? $docResultSet->_content->addIndApprover($approver, $user, !$pendingReview) : $docResultSet->_content->addGrpApprover($approver, $user, !$pendingReview));
+					$docResultSet->addApprover($approver, $i, $res);
+					if ($res==0 || $res=-3 || $res=-4) {
+						$pendingApproval=true;
+					}
+				}
+			}
+		}
+
+		// If there are no reviewers or approvers, the document is automatically
+		// promoted to the released state.
+		if ($pendingReview) {
+			$status = S_DRAFT_REV;
+			$comment = "";
+		}
+		else if ($pendingApproval) {
+			$status = S_DRAFT_APP;
+			$comment = "";
+		}
+		else {
+			$status = S_RELEASED;
+			$comment="";
+		}
+		$queryStr = "INSERT INTO `tblDocumentStatusLog` (`statusID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $statusID ."', '". $status."', 'New document content submitted". $comment ."', NOW(), '". $user->getID() ."')";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$docResultSet->setStatus($status,$comment,$user);
+
+		return $docResultSet;
+	} /* }}} */
+
+	/**
+	 * Return all content elements of a document
+	 *
+	 * This functions returns an array of content elements ordered by version
+	 *
+	 * @return array list of objects of class LetoDMS_Core_DocumentContent
+	 */
+	function getContent() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!isset($this->_content)) {
+			$queryStr = "SELECT * FROM tblDocumentContent WHERE document = ".$this->_id." ORDER BY version";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$res)
+				return false;
+
+			$this->_content = array();
+			foreach ($resArr as $row)
+				array_push($this->_content, new LetoDMS_Core_DocumentContent($this, $row["version"], $row["comment"], $row["date"], $row["createdBy"], $row["dir"], $row["orgFileName"], $row["fileType"], $row["mimeType"]));
+		}
+
+		return $this->_content;
+	} /* }}} */
+
+	/**
+	 * Return the content element of a document with a given version number
+	 *
+	 * @param integer $version version number of content element
+	 * @return object object of class LetoDMS_Core_DocumentContent
+	 */
+	function getContentByVersion($version) { /* {{{ */
+		if (!is_numeric($version)) return false;
+
+		if (isset($this->_content)) {
+			foreach ($this->_content as $revision) {
+				if ($revision->getVersion() == $version)
+					return $revision;
+			}
+			return false;
+		}
+
+		$db = $this->_dms->getDB();
+		$queryStr = "SELECT * FROM tblDocumentContent WHERE document = ".$this->_id." AND version = " . (int) $version;
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$res)
+			return false;
+		if (count($resArr) != 1)
+			return false;
+
+		$resArr = $resArr[0];
+		return new LetoDMS_Core_DocumentContent($this, $resArr["version"], $resArr["comment"], $resArr["date"], $resArr["createdBy"], $resArr["dir"], $resArr["orgFileName"], $resArr["fileType"], $resArr["mimeType"]);
+	} /* }}} */
+
+	function getLatestContent() { /* {{{ */
+		if (!isset($this->_latestContent)) {
+			$db = $this->_dms->getDB();
+			$queryStr = "SELECT * FROM tblDocumentContent WHERE document = ".$this->_id." ORDER BY version DESC LIMIT 0,1";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$resArr)
+				return false;
+			if (count($resArr) != 1)
+				return false;
+
+			$resArr = $resArr[0];
+			$this->_latestContent = new LetoDMS_Core_DocumentContent($this, $resArr["version"], $resArr["comment"], $resArr["date"], $resArr["createdBy"], $resArr["dir"], $resArr["orgFileName"], $resArr["fileType"], $resArr["mimeType"]);
+		}
+		return $this->_latestContent;
+	} /* }}} */
+
+	function removeContent($version) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$emailList = array();
+		$emailList[] = $version->_userID;
+
+		if (file_exists( $this->_dms->contentDir.$version->getPath() ))
+			if (!LetoDMS_Core_File::removeFile( $this->_dms->contentDir.$version->getPath() ))
+				return false;
+
+		$status = $version->getStatus();
+		$stID = $status["statusID"];
+
+		$queryStr = "DELETE FROM tblDocumentContent WHERE `document` = " . $this->getID() .	" AND `version` = " . $version->_version;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$queryStr = "DELETE FROM `tblDocumentStatusLog` WHERE `statusID` = '".$stID."'";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$queryStr = "DELETE FROM `tblDocumentStatus` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$status = $version->getReviewStatus();
+		$stList = "";
+		foreach ($status as $st) {
+			$stList .= (strlen($stList)==0 ? "" : ", "). "'".$st["reviewID"]."'";
+			if ($st["status"]==0 && !in_array($st["required"], $emailList)) {
+				$emailList[] = $st["required"];
+			}
+		}
+		if (strlen($stList)>0) {
+			$queryStr = "DELETE FROM `tblDocumentReviewLog` WHERE `tblDocumentReviewLog`.`reviewID` IN (".$stList.")";
+			if (!$db->getResult($queryStr))
+				return false;
+		}
+		$queryStr = "DELETE FROM `tblDocumentReviewers` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'";
+		if (!$db->getResult($queryStr))
+			return false;
+		$status = $version->getApprovalStatus();
+		$stList = "";
+		foreach ($status as $st) {
+			$stList .= (strlen($stList)==0 ? "" : ", "). "'".$st["approveID"]."'";
+			if ($st["status"]==0 && !in_array($st["required"], $emailList)) {
+				$emailList[] = $st["required"];
+			}
+		}
+		if (strlen($stList)>0) {
+			$queryStr = "DELETE FROM `tblDocumentApproveLog` WHERE `tblDocumentApproveLog`.`approveID` IN (".$stList.")";
+			if (!$db->getResult($queryStr))
+				return false;
+		}
+		$queryStr = "DELETE FROM `tblDocumentApprovers` WHERE `documentID` = '". $this->getID() ."' AND `version` = '" . $version->_version."'";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		return true;
+	} /* }}} */
+
+	function getDocumentLink($linkID) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!is_numeric($linkID)) return false;
+
+		$queryStr = "SELECT * FROM tblDocumentLinks WHERE document = " . $this->_id ." AND id = " . (int) $linkID;
+		$resArr = $db->getResultArray($queryStr);
+		if ((is_bool($resArr) && !$resArr) || count($resArr)==0)
+			return false;
+
+		$resArr = $resArr[0];
+		$document = $this->_dms->getDocument($resArr["document"]);
+		$target = $this->_dms->getDocument($resArr["target"]);
+		return new LetoDMS_Core_DocumentLink($resArr["id"], $document, $target, $resArr["userID"], $resArr["public"]);
+	} /* }}} */
+
+	function getDocumentLinks() { /* {{{ */
+		if (!isset($this->_documentLinks)) {
+			$db = $this->_dms->getDB();
+
+			$queryStr = "SELECT * FROM tblDocumentLinks WHERE document = " . $this->_id;
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$resArr)
+				return false;
+			$this->_documentLinks = array();
+
+			foreach ($resArr as $row) {
+				$target = $this->_dms->getDocument($row["target"]);
+				array_push($this->_documentLinks, new LetoDMS_Core_DocumentLink($row["id"], $this, $target, $row["userID"], $row["public"]));
+			}
+		}
+		return $this->_documentLinks;
+	} /* }}} */
+
+	function addDocumentLink($targetID, $userID, $public) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$public = ($public) ? "1" : "0";
+
+		$queryStr = "INSERT INTO tblDocumentLinks(document, target, userID, public) VALUES (".$this->_id.", ".(int)$targetID.", ".(int)$userID.", ".(int)$public.")";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_documentLinks);
+		return true;
+	} /* }}} */
+
+	function removeDocumentLink($linkID) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!is_numeric($linkID)) return false;
+
+		$queryStr = "DELETE FROM tblDocumentLinks WHERE document = " . $this->_id ." AND id = " . (int) $linkID;
+		if (!$db->getResult($queryStr)) return false;
+		unset ($this->_documentLinks);
+		return true;
+	} /* }}} */
+
+	function getDocumentFile($ID) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!is_numeric($ID)) return false;
+
+		$queryStr = "SELECT * FROM tblDocumentFiles WHERE document = " . $this->_id ." AND id = " . (int) $ID;
+		$resArr = $db->getResultArray($queryStr);
+		if ((is_bool($resArr) && !$resArr) || count($resArr)==0) return false;
+
+		$resArr = $resArr[0];
+		return new LetoDMS_Core_DocumentFile($resArr["id"], $this, $resArr["userID"], $resArr["comment"], $resArr["date"], $resArr["dir"], $resArr["fileType"], $resArr["mimeType"], $resArr["orgFileName"], $resArr["name"]);
+	} /* }}} */
+
+	function getDocumentFiles() { /* {{{ */
+		if (!isset($this->_documentFiles)) {
+			$db = $this->_dms->getDB();
+
+			$queryStr = "SELECT * FROM tblDocumentFiles WHERE document = " . $this->_id." ORDER BY `date` DESC";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$resArr) return false;
+
+			$this->_documentFiles = array();
+
+			foreach ($resArr as $row) {
+				array_push($this->_documentFiles, new LetoDMS_Core_DocumentFile($row["id"], $this, $row["userID"], $row["comment"], $row["date"], $row["dir"], $row["fileType"], $row["mimeType"], $row["orgFileName"], $row["name"]));
+			}
+		}
+		return $this->_documentFiles;
+	} /* }}} */
+
+	function addDocumentFile($name, $comment, $user, $tmpFile, $orgFileName,$fileType, $mimeType ) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$dir = $this->getDir();
+
+		$queryStr = "INSERT INTO tblDocumentFiles (comment, date, dir, document, fileType, mimeType, orgFileName, userID, name) VALUES ".
+			"(".$db->qstr($comment).", '".mktime()."', ".$db->qstr($dir).", ".$this->_id.", ".$db->qstr($fileType).", ".$db->qstr($mimeType).", ".$db->qstr($orgFileName).",".$user->getID().",".$db->qstr($name).")";
+		if (!$db->getResult($queryStr)) return false;
+
+		$id = $db->getInsertID();
+
+		$file = $this->getDocumentFile($id);
+		if (is_bool($file) && !$file) return false;
+
+		// copy file
+		if (!LetoDMS_Core_File::makeDir($this->_dms->contentDir . $dir)) return false;
+		if (!LetoDMS_Core_File::copyFile($tmpFile, $this->_dms->contentDir . $file->getPath() )) return false;
+
+		return true;
+	} /* }}} */
+
+	function removeDocumentFile($ID) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!is_numeric($ID)) return false;
+
+		$file = $this->getDocumentFile($ID);
+		if (is_bool($file) && !$file) return false;
+
+		if (file_exists( $this->_dms->contentDir . $file->getPath() )){
+			if (!LetoDMS_Core_File::removeFile( $this->_dms->contentDir . $file->getPath() ))
+				return false;
+		}
+
+		$name=$file->getName();
+		$comment=$file->getcomment();
+
+		$queryStr = "DELETE FROM tblDocumentFiles WHERE document = " . $this->getID() . " AND id = " . (int) $ID;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset ($this->_documentFiles);
+
+		return true;
+	} /* }}} */
+
+	function remove() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$res = $this->getContent();
+		if (is_bool($res) && !$res) return false;
+
+		// FIXME: call a new function removeContent instead
+		foreach ($this->_content as $version)
+			if (!$this->removeContent($version))
+				return false;
+
+		// remove document file
+		$res = $this->getDocumentFiles();
+		if (is_bool($res) && !$res) return false;
+
+		foreach ($res as $documentfile)
+			if(!$this->removeDocumentFile($documentfile->getId()))
+				return false;
+
+		// TODO: versioning file?
+
+		if (file_exists( $this->_dms->contentDir . $this->getDir() ))
+			if (!LetoDMS_Core_File::removeDir( $this->_dms->contentDir . $this->getDir() ))
+				return false;
+
+		$queryStr = "DELETE FROM tblDocuments WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblACLs WHERE target = " . $this->_id . " AND targetType = " . T_DOCUMENT;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblDocumentLinks WHERE document = " . $this->_id . " OR target = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblDocumentLocks WHERE document = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblDocumentFiles WHERE document = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblDocumentCategory WHERE documentID = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		// Delete the notification list.
+		$queryStr = "DELETE FROM tblNotify WHERE target = " . $this->_id . " AND targetType = " . T_DOCUMENT;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		return true;
+	} /* }}} */
+
+	function getApproversList() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!isset($this->_approversList)) {
+
+			$this->_approversList = array("groups" => array(), "users" => array());
+			$userIDs = "";
+			$groupIDs = "";
+			$defAccess  = $this->getDefaultAccess();
+
+			if ($defAccess<M_READ) {
+				// Get the list of all users and groups that are listed in the ACL as
+				// having read access to the document.
+				$tmpList = $this->getAccessList(M_READ, O_GTEQ);
+			}
+			else {
+				// Get the list of all users and groups that DO NOT have read access
+				// to the document.
+				$tmpList = $this->getAccessList(M_NONE, O_LTEQ);
+			}
+			foreach ($tmpList["groups"] as $group) {
+				$groupIDs .= (strlen($groupIDs)==0 ? "" : ", ") . $group->getGroupID();
+			}
+			foreach ($tmpList["users"] as $c_user) {
+
+				if (!$this->_dms->enableAdminRevApp && $c_user->isAdmin()) continue;
+				$userIDs .= (strlen($userIDs)==0 ? "" : ", ") . $c_user->getUserID();
+			}
+
+			// Construct a query against the users table to identify those users
+			// that have read access to this document, either directly through an
+			// ACL entry, by virtue of ownership or by having administrative rights
+			// on the database.
+			$queryStr="";
+			if ($defAccess < M_READ) {
+				if (strlen($groupIDs)>0) {
+					$queryStr = "(SELECT `tblUsers`.* FROM `tblUsers` ".
+						"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
+						"WHERE `tblGroupMembers`.`groupID` IN (". $groupIDs .") ".
+						"AND `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest.")";
+				}
+				$queryStr .= (strlen($queryStr)==0 ? "" : " UNION ").
+					"(SELECT `tblUsers`.* FROM `tblUsers` ".
+					"WHERE (`tblUsers`.`role` != ".LetoDMS_Core_User::role_guest.") ".
+					"AND ((`tblUsers`.`id` = ". $this->_ownerID . ") ".
+					"OR (`tblUsers`.`role` = ".LetoDMS_Core_User::role_admin.")".
+					(strlen($userIDs) == 0 ? "" : " OR (`tblUsers`.`id` IN (". $userIDs ."))").
+					")) ORDER BY `login`";
+			}
+			else {
+				if (strlen($groupIDs)>0) {
+					$queryStr = "(SELECT `tblUsers`.* FROM `tblUsers` ".
+						"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
+						"WHERE `tblGroupMembers`.`groupID` NOT IN (". $groupIDs .")".
+						"AND `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest .
+						(strlen($userIDs) == 0 ? ")" : " AND (`tblUsers`.`id` NOT IN (". $userIDs .")))");
+				}
+				$queryStr .= (strlen($queryStr)==0 ? "" : " UNION ").
+					"(SELECT `tblUsers`.* FROM `tblUsers` ".
+					"WHERE (`tblUsers`.`id` = ". $this->_ownerID . ") ".
+					"OR (`tblUsers`.`role` = ".LetoDMS_Core_User::role_admin."))".
+					"UNION ".
+					"(SELECT `tblUsers`.* FROM `tblUsers` ".
+					"WHERE `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest .
+					(strlen($userIDs) == 0 ? ")" : " AND (`tblUsers`.`id` NOT IN (". $userIDs .")))").
+					" ORDER BY `login`";
+			}
+			$resArr = $db->getResultArray($queryStr);
+			if (!is_bool($resArr)) {
+				foreach ($resArr as $row) {
+					$user = $this->_dms->getUser($row['id']);
+					if (!$this->_dms->enableAdminRevApp && $user->isAdmin()) continue;
+					$this->_approversList["users"][] = $user;
+				}
+			}
+
+			// Assemble the list of groups that have read access to the document.
+			$queryStr="";
+			if ($defAccess < M_READ) {
+				if (strlen($groupIDs)>0) {
+					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
+						"WHERE `tblGroups`.`id` IN (". $groupIDs .")";
+				}
+			}
+			else {
+				if (strlen($groupIDs)>0) {
+					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
+						"WHERE `tblGroups`.`id` NOT IN (". $groupIDs .")";
+				}
+				else {
+					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups`";
+				}
+			}
+			if (strlen($queryStr)>0) {
+				$resArr = $db->getResultArray($queryStr);
+				if (!is_bool($resArr)) {
+					foreach ($resArr as $row) {
+						$group = $this->_dms->getGroup($row["id"]);
+						$this->_approversList["groups"][] = $group;
+					}
+				}
+			}
+		}
+		return $this->_approversList;
+	} /* }}} */
+
+	/**
+	 * Get the internally used folderList which stores the ids of folders from
+	 * the root folder to the parent folder.
+	 *
+	 * @return string column separated list of folder ids
+	 */
+	function getFolderList() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT folderList FROM tblDocuments where id = ".$this->_id;
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+
+		return $resArr[0]['folderList'];
+	} /* }}} */
+
+	/**
+	 * Checks the internal data of the document and repairs it.
+	 * Currently, this function only repairs an incorrect folderList
+	 *
+	 * @return boolean true on success, otherwise false
+	 */
+	function repair() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$curfolderlist = $this->getFolderList();
+
+		// calculate the folderList of the folder
+		$parent = $this->getFolder();
+		$pathPrefix="";
+		$path = $parent->getPath();
+		foreach ($path as $f) {
+			$pathPrefix .= ":".$f->getID();
+		}
+		if (strlen($pathPrefix)>1) {
+			$pathPrefix .= ":";
+		}
+		if($curfolderlist != $pathPrefix) {
+			$queryStr = "UPDATE tblDocuments SET folderList='".$pathPrefix."' WHERE id = ". $this->_id;
+			$res = $db->getResult($queryStr);
+			if (!$res)
+				return false;
+		}
+		return true;
+	} /* }}} */
+} /* }}} */
+
+
+/**
+ * Class to represent content of a document
+ *
+ * Each document has content attached to it, often called a 'version' of the
+ * document. The document content represents a file on the disk with some
+ * meta data stored in the database. A document content has a version number
+ * which is incremented with each replacement of the old content. Old versions
+ * are kept unless they are explicitly deleted by
+ * {@link LetoDMS_Core_Document::removeContent()}.
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
+ *             Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal,
+ *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_DocumentContent { /* {{{ */
+
+	// if status is released and there are reviewers set status draft_rev
+	// if status is released or draft_rev and there are approves set status draft_app
+	// if status is draft and there are no approver and no reviewers set status to release
+	function verifyStatus($ignorecurrentstatus=false, $user=null) { /* {{{ */
+
+		unset($this->_status);
+		$st=$this->getStatus();
+
+		if (!$ignorecurrentstatus && ($st["status"]==S_OBSOLETE || $st["status"]==S_REJECTED || $st["status"]==S_EXPIRED )) return;
+
+		$pendingReview=false;
+		unset($this->_reviewStatus);  // force to be reloaded from DB
+		$reviewStatus=$this->getReviewStatus();
+		if (is_array($reviewStatus) && count($reviewStatus)>0) {
+			foreach ($reviewStatus as $r){
+				if ($r["status"]==0){
+					$pendingReview=true;
+					break;
+				}
+			}
+		}
+		$pendingApproval=false;
+		unset($this->_approvalStatus);  // force to be reloaded from DB
+		$approvalStatus=$this->getApprovalStatus();
+		if (is_array($approvalStatus) && count($approvalStatus)>0) {
+			foreach ($approvalStatus as $a){
+				if ($a["status"]==0){
+					$pendingApproval=true;
+					break;
+				}
+			}
+		}
+		if ($pendingReview) $this->setStatus(S_DRAFT_REV,"",$user);
+		else if ($pendingApproval) $this->setStatus(S_DRAFT_APP,"",$user);
+		else $this->setStatus(S_RELEASED,"",$user);
+	} /* }}} */
+
+	function LetoDMS_Core_DocumentContent($document, $version, $comment, $date, $userID, $dir, $orgFileName, $fileType, $mimeType) { /* {{{ */
+		$this->_document = $document;
+		$this->_version = (int) $version;
+		$this->_comment = $comment;
+		$this->_date = $date;
+		$this->_userID = (int) $userID;
+		$this->_dir = $dir;
+		$this->_orgFileName = $orgFileName;
+		$this->_fileType = $fileType;
+		$this->_mimeType = $mimeType;
+	} /* }}} */
+
+	function getVersion() { return $this->_version; }
+	function getComment() { return $this->_comment; }
+	function getDate() { return $this->_date; }
+	function getOriginalFileName() { return $this->_orgFileName; }
+	function getFileType() { return $this->_fileType; }
+	function getFileName(){ return "data" . $this->_fileType; }
+	function getDir() { return $this->_dir; }
+	function getMimeType() { return $this->_mimeType; }
+	function getUser() { /* {{{ */
+		if (!isset($this->_user))
+			$this->_user = $this->_document->_dms->getUser($this->_userID);
+		return $this->_user;
+	} /* }}} */
+	function getPath() { return $this->_document->getDir() . $this->_version . $this->_fileType; }
+
+	function setComment($newComment) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$queryStr = "UPDATE tblDocumentContent SET comment = ".$db->qstr($newComment)." WHERE `document` = " . $this->_document->getID() .	" AND `version` = " . $this->_version;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_comment = $newComment;
+
+		return true;
+	} /* }}} */
+
+	function convert() { /* {{{ */
+		if (file_exists($this->_document->_dms->contentDir . $this->_document->getID() .'/' . "index.html"))
+			return true;
+
+		if (!in_array($this->_fileType, array_keys($this->_document->_dms->convertFileTypes)))
+			return false;
+
+		$source = $this->_document->_dms->contentDir . $this->_document->getID() .'/' . $this->getFileName();
+		$target = $this->_document->_dms->contentDir . $this->_document->getID() .'/' . "index.html";
+	//	$source = str_replace("/", "\\", $source);
+	//	$target = str_replace("/", "\\", $target);
+
+		$command = $this->_document->_dms->convertFileTypes[$this->_fileType];
+		$command = str_replace("{SOURCE}", "\"$source\"", $command);
+		$command = str_replace("{TARGET}", "\"$target\"", $command);
+
+		$output = array();
+		$res = 0;
+		exec($command, $output, $res);
+
+		if ($res != 0) {
+			print (implode("\n", $output));
+			return false;
+		}
+		return true;
+	} /* }}} */
+
+	/* FIXME: this function should not be part of the DMS. It lies in the duty
+	 * of the application whether a file can viewed online or not.
+	 */
+	function viewOnline() { /* {{{ */
+		if (!isset($this->_document->_dms->_viewOnlineFileTypes) || !is_array($this->_document->_dms->_viewOnlineFileTypes)) {
+			return false;
+		}
+
+		if (in_array(strtolower($this->_fileType), $this->_document->_dms->_viewOnlineFileTypes))
+			return true;
+
+		if ($this->_document->_dms->enableConverting && in_array($this->_fileType, array_keys($this->_document->_dms->convertFileTypes)))
+			if ($this->wasConverted()) return true;
+
+		return false;
+	} /* }}} */
+
+	function wasConverted() { /* {{{ */
+		return file_exists($this->_document->_dms->contentDir . $this->_document->getID() .'/' . "index.html");
+	} /* }}} */
+
+	function getURL() { /* {{{ */
+		if (!$this->viewOnline())return false;
+
+		if (in_array(strtolower($this->_fileType), $this->_document->_dms->_viewOnlineFileTypes))
+			return "/" . $this->_document->getID() . "/" . $this->_version . "/" . $this->getOriginalFileName();
+		else
+			return "/" . $this->_document->getID() . "/" . $this->_version . "/index.html";
+	} /* }}} */
+
+	/**
+	 * Get the latest status of the content
+	 *
+	 * The status of the content reflects its current review and approval
+	 * state. A status can be a negative or positive number or 0. A negative
+	 * numbers indicate a missing approval, review or an obsolete content.
+	 * Positive numbers indicate some kind of approval but not necessarily
+	 * a release.
+	 * S_DRAFT_REV, 0
+	 * S_DRAFT_APP, 1
+	 * S_RELEASED, 2
+	 * S_REJECTED, -1
+	 * S_OBSOLETE, -2
+	 * S_EXPIRED, -3
+	 * When a content is inserted and does not need approval nor review,
+	 * then its status is set to S_RELEASED immediately. Any change of
+	 * the status is monitored in the table tblDocumentStatusLog. This
+	 * function will always return the latest entry for the content.
+	 */
+	function getStatus($limit=1) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		if (!is_numeric($limit)) return false;
+
+		// Retrieve the current overall status of the content represented by
+		// this object.
+		if (!isset($this->_status)) {
+		/*
+			if (!$db->createTemporaryTable("ttstatid", $forceTemporaryTable)) {
+				return false;
+			}
+			$queryStr="SELECT `tblDocumentStatus`.*, `tblDocumentStatusLog`.`status`, ".
+				"`tblDocumentStatusLog`.`comment`, `tblDocumentStatusLog`.`date`, ".
+				"`tblDocumentStatusLog`.`userID` ".
+				"FROM `tblDocumentStatus` ".
+				"LEFT JOIN `tblDocumentStatusLog` USING (`statusID`) ".
+				"LEFT JOIN `ttstatid` ON `ttstatid`.`maxLogID` = `tblDocumentStatusLog`.`statusLogID` ".
+				"WHERE `ttstatid`.`maxLogID`=`tblDocumentStatusLog`.`statusLogID` ".
+				"AND `tblDocumentStatus`.`documentID` = '". $this->_document->getID() ."' ".
+				"AND `tblDocumentStatus`.`version` = '". $this->_version ."' ";
+		*/
+			$queryStr=
+				"SELECT `tblDocumentStatus`.*, `tblDocumentStatusLog`.`status`, ".
+				"`tblDocumentStatusLog`.`comment`, `tblDocumentStatusLog`.`date`, ".
+				"`tblDocumentStatusLog`.`userID` ".
+				"FROM `tblDocumentStatus` ".
+				"LEFT JOIN `tblDocumentStatusLog` USING (`statusID`) ".
+				"WHERE `tblDocumentStatus`.`documentID` = '". $this->_document->getID() ."' ".
+				"AND `tblDocumentStatus`.`version` = '". $this->_version ."' ".
+				"ORDER BY `tblDocumentStatusLog`.`statusLogID` DESC LIMIT ".(int) $limit;
+
+			$res = $db->getResultArray($queryStr);
+			if (is_bool($res) && !$res)
+				return false;
+			if (count($res)!=1)
+				return false;
+			$this->_status = $res[0];
+		}
+		return $this->_status;
+	} /* }}} */
+
+	/**
+	 * Set the status of the content
+	 * Setting the status means to add another entry into the table
+	 * tblDocumentStatusLog
+	 *
+	 * @param integer $status new status of content
+	 * @param string $comment comment for this status change
+	 * @param object $updateUser user initiating the status change
+	 * @return boolean true on success, otherwise false
+	 */
+	function setStatus($status, $comment, $updateUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		if (!is_numeric($status)) return false;
+
+		/* return an error if $updateuser is not set */
+		if(!$updateUser)
+			return false;
+
+		// If the supplied value lies outside of the accepted range, return an
+		// error.
+		if ($status < -3 || $status > 2) {
+			return false;
+		}
+
+		// Retrieve the current overall status of the content represented by
+		// this object, if it hasn't been done already.
+		if (!isset($this->_status)) {
+			$this->getStatus();
+		}
+		if ($this->_status["status"]==$status) {
+			return false;
+		}
+		$queryStr = "INSERT INTO `tblDocumentStatusLog` (`statusID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $this->_status["statusID"] ."', '". (int) $status ."', ".$db->qstr($comment).", NOW(), '". $updateUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res)
+			return false;
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Get the current review status of the document content
+	 * The review status is a list of reviewers and its current status
+	 *
+	 * @param integer $limit the number of recent status changes per reviewer
+	 * @return array list of review status
+	 */
+	function getReviewStatus($limit=1) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		if (!is_numeric($limit)) return false;
+
+		// Retrieve the current status of each assigned reviewer for the content
+		// represented by this object.
+		if (!isset($this->_reviewStatus)) {
+			/* First get a list of all reviews for this document content */
+			$queryStr=
+				"SELECT reviewID FROM tblDocumentReviewers WHERE `version`='".$this->_version
+				."' AND `documentID` = '". $this->_document->getID() ."' ";
+			$recs = $db->getResultArray($queryStr);
+			if (is_bool($recs) && !$recs)
+				return false;
+			$this->_reviewStatus = array();
+			if($recs) {
+				foreach($recs as $rec) {
+					$queryStr=
+						"SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
+						"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
+						"`tblDocumentReviewLog`.`userID`, `tblUsers`.`fullName`, `tblGroups`.`name` AS `groupName` ".
+						"FROM `tblDocumentReviewers` ".
+						"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
+						"LEFT JOIN `tblUsers` on `tblUsers`.`id` = `tblDocumentReviewers`.`required`".
+						"LEFT JOIN `tblGroups` on `tblGroups`.`id` = `tblDocumentReviewers`.`required`".
+						"WHERE `tblDocumentReviewers`.`reviewID` = '". $rec['reviewID'] ."' ".
+						"ORDER BY `tblDocumentReviewLog`.`reviewLogID` DESC LIMIT ".(int) $limit;
+
+					$res = $db->getResultArray($queryStr);
+					if (is_bool($res) && !$res) {
+						unset($this->_reviewStatus);
+						return false;
+					}
+					$this->_reviewStatus = array_merge($this->_reviewStatus, $res);
+				}
+			}
+		}
+		return $this->_reviewStatus;
+	} /* }}} */
+
+	function getApprovalStatus($limit=1) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		if (!is_numeric($limit)) return false;
+
+		// Retrieve the current status of each assigned approver for the content
+		// represented by this object.
+		if (!isset($this->_approvalStatus)) {
+			/* First get a list of all approvals for this document content */
+			$queryStr=
+				"SELECT approveId FROM tblDocumentApprovers WHERE `version`='".$this->_version
+				."' AND `documentID` = '". $this->_document->getID() ."' ";
+			$recs = $db->getResultArray($queryStr);
+			if (is_bool($recs) && !$recs)
+				return false;
+			$this->_approvalStatus = array();
+			if($recs) {
+				foreach($recs as $rec) {
+					$queryStr=
+						"SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
+						"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
+						"`tblDocumentApproveLog`.`userID`, `tblUsers`.`fullName`, `tblGroups`.`name` AS `groupName` ".
+						"FROM `tblDocumentApprovers` ".
+						"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
+						"LEFT JOIN `tblUsers` on `tblUsers`.`id` = `tblDocumentApprovers`.`required` ".
+						"LEFT JOIN `tblGroups` on `tblGroups`.`id` = `tblDocumentApprovers`.`required`".
+						"WHERE `tblDocumentApprovers`.`approveId` = '". $rec['approveId'] ."' ".
+						"ORDER BY `tblDocumentApproveLog`.`approveLogId` DESC LIMIT ".(int) $limit;
+
+					$res = $db->getResultArray($queryStr);
+					if (is_bool($res) && !$res) {
+						unset($this->_approvalStatus);
+						return false;
+					}
+					$this->_approvalStatus = array_merge($this->_approvalStatus, $res);
+				}
+			}
+		}
+		return $this->_approvalStatus;
+	} /* }}} */
+
+	function addIndReviewer($user, $requestUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$userID = $user->getID();
+
+		// Get the list of users and groups with write access to this document.
+		if (!isset($this->_approversList)) {
+			$this->_approversList = $this->_document->getApproversList();
+		}
+		$approved = false;
+		foreach ($this->_approversList["users"] as $appUser) {
+			if ($userID == $appUser->getID()) {
+				$approved = true;
+				break;
+			}
+		}
+		if (!$approved) {
+			return -2;
+		}
+
+		// Check to see if the user has already been added to the review list.
+		$reviewStatus = $user->getReviewStatus($this->_document->getID(), $this->_version);
+		if (is_bool($reviewStatus) && !$reviewStatus) {
+			return -1;
+		}
+		if (count($reviewStatus["indstatus"]) > 0 && $reviewStatus["indstatus"][0]["status"]!=-2) {
+			// User is already on the list of reviewers; return an error.
+			return -3;
+		}
+
+		// Add the user into the review database.
+		if (! isset($reviewStatus["indstatus"][0]["status"])|| (isset($reviewStatus["indstatus"][0]["status"]) && $reviewStatus["indstatus"][0]["status"]!=-2)) {
+			$queryStr = "INSERT INTO `tblDocumentReviewers` (`documentID`, `version`, `type`, `required`) ".
+				"VALUES ('". $this->_document->getID() ."', '". $this->_version ."', '0', '". $userID ."')";
+			$res = $db->getResult($queryStr);
+			if (is_bool($res) && !$res) {
+				return -1;
+			}
+			$reviewID = $db->getInsertID();
+		}
+		else {
+			$reviewID = isset($reviewStatus["indstatus"][0]["reviewID"])?$reviewStatus["indstatus"][0]["reviewID"]:NULL;
+		}
+
+		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $reviewID ."', '0', '', NOW(), '". $requestUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res) {
+			return -1;
+		}
+
+		// Add reviewer to event notification table.
+		//$this->_document->addNotify($userID, true);
+
+		return 0;
+	} /* }}} */
+
+	function addGrpReviewer($group, $requestUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$groupID = $group->getID();
+
+		// Get the list of users and groups with write access to this document.
+		if (!isset($this->_approversList)) {
+			// TODO: error checking.
+			$this->_approversList = $this->_document->getApproversList();
+		}
+		$approved = false;
+		foreach ($this->_approversList["groups"] as $appGroup) {
+			if ($groupID == $appGroup->getID()) {
+				$approved = true;
+				break;
+			}
+		}
+		if (!$approved) {
+			return -2;
+		}
+
+		// Check to see if the group has already been added to the review list.
+		$reviewStatus = $group->getReviewStatus($this->_document->getID(), $this->_version);
+		if (is_bool($reviewStatus) && !$reviewStatus) {
+			return -1;
+		}
+		if (count($reviewStatus) > 0 && $reviewStatus[0]["status"]!=-2) {
+			// Group is already on the list of reviewers; return an error.
+			return -3;
+		}
+
+		// Add the group into the review database.
+		if (!isset($reviewStatus[0]["status"]) || (isset($reviewStatus[0]["status"]) && $reviewStatus[0]["status"]!=-2)) {
+			$queryStr = "INSERT INTO `tblDocumentReviewers` (`documentID`, `version`, `type`, `required`) ".
+				"VALUES ('". $this->_document->getID() ."', '". $this->_version ."', '1', '". $groupID ."')";
+			$res = $db->getResult($queryStr);
+			if (is_bool($res) && !$res) {
+				return -1;
+			}
+			$reviewID = $db->getInsertID();
+		}
+		else {
+			$reviewID = isset($reviewStatus[0]["reviewID"])?$reviewStatus[0]["reviewID"]:NULL;
+		}
+
+		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $reviewID ."', '0', '', NOW(), '". $requestUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res) {
+			return -1;
+		}
+
+		// Add reviewer to event notification table.
+		//$this->_document->addNotify($groupID, false);
+
+		return 0;
+	} /* }}} */
+
+	function setReviewByInd($user, $requestUser, $status, $comment) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		// Check to see if the user can be removed from the review list.
+		$reviewStatus = $user->getReviewStatus($this->_document->getID(), $this->_version);
+		if (is_bool($reviewStatus) && !$reviewStatus) {
+			return -1;
+		}
+		if (count($reviewStatus["indstatus"])==0) {
+			// User is not assigned to review this document. No action required.
+			// Return an error.
+			return -3;
+		}
+		if ($reviewStatus["indstatus"][0]["status"]==-2) {
+			// User has been deleted from reviewers
+			return -4;
+		}
+		// Check if the status is really different from the current status
+		if ($reviewStatus["indstatus"][0]["status"] == $status)
+			return 0;
+
+		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`,
+  	  `comment`, `date`, `userID`) ".
+			"VALUES ('". $reviewStatus["indstatus"][0]["reviewID"] ."', '".
+			(int) $status ."', ".$db->qstr($comment).", NOW(), '".
+			$requestUser->getID() ."')";
+		$res=$db->getResult($queryStr);
+		if (is_bool($res) && !$res)
+			return -1;
+		else
+			return 0;
+ } /* }}} */
+
+	function setReviewByGrp($group, $requestUser, $status, $comment) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		// Check to see if the user can be removed from the review list.
+		$reviewStatus = $group->getReviewStatus($this->_document->getID(), $this->_version);
+		if (is_bool($reviewStatus) && !$reviewStatus) {
+			return -1;
+		}
+		if (count($reviewStatus)==0) {
+			// User is not assigned to review this document. No action required.
+			// Return an error.
+			return -3;
+		}
+		if ($reviewStatus[0]["status"]==-2) {
+			// Group has been deleted from reviewers
+			return -4;
+		}
+
+		// Check if the status is really different from the current status
+		if ($reviewStatus[0]["status"] == $status)
+			return 0;
+
+		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`,
+  	  `comment`, `date`, `userID`) ".
+			"VALUES ('". $reviewStatus[0]["reviewID"] ."', '".
+			(int) $status ."', ".$db->qstr($comment).", NOW(), '".
+			$requestUser->getID() ."')";
+		$res=$db->getResult($queryStr);
+		if (is_bool($res) && !$res)
+			return -1;
+		else
+			return 0;
+ } /* }}} */
+
+	function addIndApprover($user, $requestUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$userID = $user->getID();
+
+		// Get the list of users and groups with write access to this document.
+		if (!isset($this->_approversList)) {
+			// TODO: error checking.
+			$this->_approversList = $this->_document->getApproversList();
+		}
+		$approved = false;
+		foreach ($this->_approversList["users"] as $appUser) {
+			if ($userID == $appUser->getID()) {
+				$approved = true;
+				break;
+			}
+		}
+		if (!$approved) {
+			return -2;
+		}
+
+		// Check to see if the user has already been added to the approvers list.
+		$approvalStatus = $user->getApprovalStatus($this->_document->getID(), $this->_version);
+		if (is_bool($approvalStatus) && !$approvalStatus) {
+			return -1;
+		}
+		if (count($approvalStatus["indstatus"]) > 0 && $approvalStatus["indstatus"][0]["status"]!=-2) {
+			// User is already on the list of approvers; return an error.
+			return -3;
+		}
+
+		if ( !isset($approvalStatus["indstatus"][0]["status"]) || (isset($approvalStatus["indstatus"][0]["status"]) && $approvalStatus["indstatus"][0]["status"]!=-2)) {
+			// Add the user into the approvers database.
+			$queryStr = "INSERT INTO `tblDocumentApprovers` (`documentID`, `version`, `type`, `required`) ".
+				"VALUES ('". $this->_document->getID() ."', '". $this->_version ."', '0', '". $userID ."')";
+			$res = $db->getResult($queryStr);
+			if (is_bool($res) && !$res) {
+				return -1;
+			}
+			$approveID = $db->getInsertID();
+		}
+		else {
+			$approveID = isset($approvalStatus["indstatus"][0]["approveID"]) ? $approvalStatus["indstatus"][0]["approveID"] : NULL;
+		}
+
+		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $approveID ."', '0', '', NOW(), '". $requestUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res) {
+			return -1;
+		}
+
+		return 0;
+	} /* }}} */
+
+	function addGrpApprover($group, $requestUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$groupID = $group->getID();
+
+		// Get the list of users and groups with write access to this document.
+		if (!isset($this->_approversList)) {
+			// TODO: error checking.
+			$this->_approversList = $this->_document->getApproversList();
+		}
+		$approved = false;
+		foreach ($this->_approversList["groups"] as $appGroup) {
+			if ($groupID == $appGroup->getID()) {
+				$approved = true;
+				break;
+			}
+		}
+		if (!$approved) {
+			return -2;
+		}
+
+		// Check to see if the group has already been added to the approver list.
+		$approvalStatus = $group->getApprovalStatus($this->_document->getID(), $this->_version);
+		if (is_bool($approvalStatus) && !$approvalStatus) {
+			return -1;
+		}
+		if (count($approvalStatus) > 0 && $approvalStatus[0]["status"]!=-2) {
+			// Group is already on the list of approvers; return an error.
+			return -3;
+		}
+
+		// Add the group into the approver database.
+		if (!isset($approvalStatus[0]["status"]) || (isset($approvalStatus[0]["status"]) && $approvalStatus[0]["status"]!=-2)) {
+			$queryStr = "INSERT INTO `tblDocumentApprovers` (`documentID`, `version`, `type`, `required`) ".
+				"VALUES ('". $this->_document->getID() ."', '". $this->_version ."', '1', '". $groupID ."')";
+			$res = $db->getResult($queryStr);
+			if (is_bool($res) && !$res) {
+				return -1;
+			}
+			$approveID = $db->getInsertID();
+		}
+		else {
+			$approveID = isset($approvalStatus[0]["approveID"])?$approvalStatus[0]["approveID"]:NULL;
+		}
+
+		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $approveID ."', '0', '', NOW(), '". $requestUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res) {
+			return -1;
+		}
+
+		// Add approver to event notification table.
+		//$this->_document->addNotify($groupID, false);
+
+		return 0;
+	} /* }}} */
+
+	/**
+	 * Sets approval status of a document content for a user
+	 * This function can be used to approve or reject a document content, or
+	 * to reset its approval state. The user initiating the approval may
+	 * not be the user filled in as an approver of the document content.
+	 * In most cases this will be but an admin may set the approval for
+	 * somebody else.
+	 * It is first checked if the user is in the list of approvers at all.
+	 * Then it is check if the approval status is already -2. In both cases
+	 * the function returns with an error.
+	 *
+	 * @param object $user user in charge for doing the approval
+	 * @param object $requestUser user actually calling this function
+	 * @param integer $status the status of the approval, possible values are
+	 *        0=unprocessed (maybe used to reset a status)
+	 *        1=approved,
+	 *       -1=rejected,
+	 *       -2=user is deleted (use {link
+	 *       LetoDMS_Core_DocumentContent::delIndApprover} instead)
+	 * @param string $comment approval comment
+	 * @return integer 0 on success, < 0 in case of an error
+	 */
+	function setApprovalByInd($user, $requestUser, $status, $comment) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		// Check to see if the user can be removed from the approval list.
+		$approvalStatus = $user->getApprovalStatus($this->_document->getID(), $this->_version);
+		if (is_bool($approvalStatus) && !$approvalStatus) {
+			return -1;
+		}
+		if (count($approvalStatus["indstatus"])==0) {
+			// User is not assigned to approve this document. No action required.
+			// Return an error.
+			return -3;
+		}
+		if ($approvalStatus["indstatus"][0]["status"]==-2) {
+			// User has been deleted from approvers
+			return -4;
+		}
+		// Check if the status is really different from the current status
+		if ($approvalStatus["indstatus"][0]["status"] == $status)
+			return 0;
+
+		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`,
+  	  `comment`, `date`, `userID`) ".
+			"VALUES ('". $approvalStatus["indstatus"][0]["approveID"] ."', '".
+			(int) $status ."', ".$db->qstr($comment).", NOW(), '".
+			$requestUser->getID() ."')";
+		$res=$db->getResult($queryStr);
+		if (is_bool($res) && !$res)
+			return -1;
+		else
+			return 0;
+ } /* }}} */
+
+	/**
+	 * Sets approval status of a document content for a group
+	 * The functions behaves like
+	 * {link LetoDMS_Core_DocumentContent::setApprovalByInd} but does it for
+	 * group instead of a user
+	 */
+	function setApprovalByGrp($group, $requestUser, $status, $comment) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		// Check to see if the user can be removed from the approval list.
+		$approvalStatus = $group->getApprovalStatus($this->_document->getID(), $this->_version);
+		if (is_bool($approvalStatus) && !$approvalStatus) {
+			return -1;
+		}
+		if (count($approvalStatus)==0) {
+			// User is not assigned to approve this document. No action required.
+			// Return an error.
+			return -3;
+		}
+		if ($approvalStatus[0]["status"]==-2) {
+			// Group has been deleted from approvers
+			return -4;
+		}
+
+		// Check if the status is really different from the current status
+		if ($approvalStatus[0]["status"] == $status)
+			return 0;
+
+		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`,
+  	  `comment`, `date`, `userID`) ".
+			"VALUES ('". $approvalStatus[0]["approveID"] ."', '".
+			(int) $status ."', ".$db->qstr($comment).", NOW(), '".
+			$requestUser->getID() ."')";
+		$res=$db->getResult($queryStr);
+		if (is_bool($res) && !$res)
+			return -1;
+		else
+			return 0;
+ } /* }}} */
+
+	function delIndReviewer($user, $requestUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$userID = $user->getID();
+
+		// Check to see if the user can be removed from the review list.
+		$reviewStatus = $user->getReviewStatus($this->_document->getID(), $this->_version);
+		if (is_bool($reviewStatus) && !$reviewStatus) {
+			return -1;
+		}
+		if (count($reviewStatus["indstatus"])==0) {
+			// User is not assigned to review this document. No action required.
+			// Return an error.
+			return -3;
+		}
+		if ($reviewStatus["indstatus"][0]["status"]!=0) {
+			// User has already submitted a review or has already been deleted;
+			// return an error.
+			return -3;
+		}
+
+		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $reviewStatus["indstatus"][0]["reviewID"] ."', '-2', '', NOW(), '". $requestUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res) {
+			return -1;
+		}
+
+		return 0;
+	} /* }}} */
+
+	function delGrpReviewer($group, $requestUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$groupID = $group->getID();
+
+		// Check to see if the user can be removed from the review list.
+		$reviewStatus = $group->getReviewStatus($this->_document->getID(), $this->_version);
+		if (is_bool($reviewStatus) && !$reviewStatus) {
+			return -1;
+		}
+		if (count($reviewStatus)==0) {
+			// User is not assigned to review this document. No action required.
+			// Return an error.
+			return -3;
+		}
+		if ($reviewStatus[0]["status"]!=0) {
+			// User has already submitted a review or has already been deleted;
+			// return an error.
+			return -3;
+		}
+
+		$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $reviewStatus[0]["reviewID"] ."', '-2', '', NOW(), '". $requestUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res) {
+			return -1;
+		}
+
+		return 0;
+	} /* }}} */
+
+	function delIndApprover($user, $requestUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$userID = $user->getID();
+
+		// Check to see if the user can be removed from the approval list.
+		$approvalStatus = $user->getApprovalStatus($this->_document->getID(), $this->_version);
+		if (is_bool($approvalStatus) && !$approvalStatus) {
+			return -1;
+		}
+		if (count($approvalStatus["indstatus"])==0) {
+			// User is not assigned to approve this document. No action required.
+			// Return an error.
+			return -3;
+		}
+		if ($approvalStatus["indstatus"][0]["status"]!=0) {
+			// User has already submitted an approval or has already been deleted;
+			// return an error.
+			return -3;
+		}
+
+		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $approvalStatus["indstatus"][0]["approveID"] ."', '-2', '', NOW(), '". $requestUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res) {
+			return -1;
+		}
+
+		return 0;
+	} /* }}} */
+
+	function delGrpApprover($group, $requestUser) { /* {{{ */
+		$db = $this->_document->_dms->getDB();
+
+		$groupID = $group->getID();
+
+		// Check to see if the user can be removed from the approver list.
+		$approvalStatus = $group->getApprovalStatus($this->_document->getID(), $this->_version);
+		if (is_bool($approvalStatus) && !$approvalStatus) {
+			return -1;
+		}
+		if (count($approvalStatus)==0) {
+			// User is not assigned to approve this document. No action required.
+			// Return an error.
+			return -3;
+		}
+		if ($approvalStatus[0]["status"]!=0) {
+			// User has already submitted an approval or has already been deleted;
+			// return an error.
+			return -3;
+		}
+
+		$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
+			"VALUES ('". $approvalStatus[0]["approveID"] ."', '-2', '', NOW(), '". $requestUser->getID() ."')";
+		$res = $db->getResult($queryStr);
+		if (is_bool($res) && !$res) {
+			return -1;
+		}
+
+		return 0;
+	} /* }}} */
+} /* }}} */
+
+
+/**
+ * Class to represent a link between two document
+ *
+ * Document links are to establish a reference from one document to
+ * another document. The owner of the document link may not be the same
+ * as the owner of one of the documents.
+ * Use {@link LetoDMS_Core_Document::addDocumentLink()} to add a reference
+ * to another document.
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
+ *             Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal,
+ *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_DocumentLink { /* {{{ */
+	var $_id;
+	var $_document;
+	var $_target;
+	var $_userID;
+	var $_public;
+
+	function LetoDMS_Core_DocumentLink($id, $document, $target, $userID, $public) {
+		$this->_id = $id;
+		$this->_document = $document;
+		$this->_target = $target;
+		$this->_userID = $userID;
+		$this->_public = $public;
+	}
+
+	function getID() { return $this->_id; }
+
+	function getDocument() {
+		return $this->_document;
+	}
+
+	function getTarget() {
+		return $this->_target;
+	}
+
+	function getUser() {
+		if (!isset($this->_user))
+			$this->_user = $this->_document->_dms->getUser($this->_userID);
+		return $this->_user;
+	}
+
+	function isPublic() { return $this->_public; }
+
+} /* }}} */
+
+/**
+ * Class to represent a file attached to a document
+ *
+ * Beside the regular document content arbitrary files can be attached
+ * to a document. This is a similar concept as attaching files to emails.
+ * The owner of the attached file and the document may not be the same.
+ * Use {@link LetoDMS_Core_Document::addDocumentFile()} to attach a file.
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
+ *             Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal,
+ *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_DocumentFile { /* {{{ */
+	var $_id;
+	var $_document;
+	var $_userID;
+	var $_comment;
+	var $_date;
+	var $_dir;
+	var $_fileType;
+	var $_mimeType;
+	var $_orgFileName;
+	var $_name;
+
+	function LetoDMS_Core_DocumentFile($id, $document, $userID, $comment, $date, $dir, $fileType, $mimeType, $orgFileName,$name) {
+		$this->_id = $id;
+		$this->_document = $document;
+		$this->_userID = $userID;
+		$this->_comment = $comment;
+		$this->_date = $date;
+		$this->_dir = $dir;
+		$this->_fileType = $fileType;
+		$this->_mimeType = $mimeType;
+		$this->_orgFileName = $orgFileName;
+		$this->_name = $name;
+	}
+
+	function getID() { return $this->_id; }
+	function getDocument() { return $this->_document; }
+	function getUserID() { return $this->_userID; }
+	function getComment() { return $this->_comment; }
+	function getDate() { return $this->_date; }
+	function getDir() { return $this->_dir; }
+	function getFileType() { return $this->_fileType; }
+	function getMimeType() { return $this->_mimeType; }
+	function getOriginalFileName() { return $this->_orgFileName; }
+	function getName() { return $this->_name; }
+
+	function getUser() {
+		if (!isset($this->_user))
+			$this->_user = $this->_document->_dms->getUser($this->_userID);
+		return $this->_user;
+	}
+
+	function getPath() {
+		return $this->_document->getDir() . "f" .$this->_id . $this->_fileType;
+	}
+
+} /* }}} */
+
+//
+// Perhaps not the cleanest object ever devised, it exists to encapsulate all
+// of the data generated during the addition of new content to the database.
+// The object stores a copy of the new DocumentContent object, the newly assigned
+// reviewers and approvers and the status.
+//
+/**
+ * Class to represent a list of document contents
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
+ *             Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal,
+ *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_AddContentResultSet { /* {{{ */
+
+	var $_indReviewers;
+	var $_grpReviewers;
+	var $_indApprovers;
+	var $_grpApprovers;
+	var $_content;
+	var $_status;
+
+	function LetoDMS_Core_AddContentResultSet($content) {
+
+		$this->_content = $content;
+		$this->_indReviewers = null;
+		$this->_grpReviewers = null;
+		$this->_indApprovers = null;
+		$this->_grpApprovers = null;
+		$this->_status = null;
+	}
+
+	function addReviewer($reviewer, $type, $status) {
+
+		if (!is_object($reviewer) || (strcasecmp($type, "i") && strcasecmp($type, "g")) && !is_integer($status)){
+			return false;
+		}
+		if (!strcasecmp($type, "i")) {
+			if (strcasecmp(get_class($reviewer), "LetoDMS_Core_User")) {
+				return false;
+			}
+			if ($this->_indReviewers == null) {
+				$this->_indReviewers = array();
+			}
+			$this->_indReviewers[$status][] = $reviewer;
+		}
+		if (!strcasecmp($type, "g")) {
+			if (strcasecmp(get_class($reviewer), "LetoDMS_Core_Group")) {
+				return false;
+			}
+			if ($this->_grpReviewers == null) {
+				$this->_grpReviewers = array();
+			}
+			$this->_grpReviewers[$status][] = $reviewer;
+		}
+		return true;
+	}
+
+	function addApprover($approver, $type, $status) {
+
+		if (!is_object($approver) || (strcasecmp($type, "i") && strcasecmp($type, "g")) && !is_integer($status)){
+			return false;
+		}
+		if (!strcasecmp($type, "i")) {
+			if (strcasecmp(get_class($approver), "LetoDMS_Core_User")) {
+				return false;
+			}
+			if ($this->_indApprovers == null) {
+				$this->_indApprovers = array();
+			}
+			$this->_indApprovers[$status][] = $approver;
+		}
+		if (!strcasecmp($type, "g")) {
+			if (strcasecmp(get_class($approver), "LetoDMS_Core_Group")) {
+				return false;
+			}
+			if ($this->_grpApprovers == null) {
+				$this->_grpApprovers = array();
+			}
+			$this->_grpApprovers[$status][] = $approver;
+		}
+		return true;
+	}
+
+	function setStatus($status) {
+		if (!is_integer($status)) {
+			return false;
+		}
+		if ($status<-3 || $status>2) {
+			return false;
+		}
+		$this->_status = $status;
+		return true;
+	}
+
+	function getStatus() {
+		return $this->_status;
+	}
+
+	function getReviewers($type) {
+		if (strcasecmp($type, "i") && strcasecmp($type, "g")) {
+			return false;
+		}
+		if (!strcasecmp($type, "i")) {
+			return ($this->_indReviewers == null ? array() : $this->_indReviewers);
+		}
+		else {
+			return ($this->_grpReviewers == null ? array() : $this->_grpReviewers);
+		}
+	}
+
+	function getApprovers($type) {
+		if (strcasecmp($type, "i") && strcasecmp($type, "g")) {
+			return false;
+		}
+		if (!strcasecmp($type, "i")) {
+			return ($this->_indApprovers == null ? array() : $this->_indApprovers);
+		}
+		else {
+			return ($this->_grpApprovers == null ? array() : $this->_grpApprovers);
+		}
+	}
+} /* }}} */
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassFolder.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassFolder.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassFolder.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassFolder.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,1204 @@
+<?php
+/**
+ * Implementation of a folder in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL2
+ * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli,
+ *             Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Class to represent a folder in the document management system
+ *
+ * A folder in LetoDMS is equivalent to a directory in a regular file
+ * system. It can contain further subfolders and documents. Each folder
+ * has a single parent except for the root folder which has no parent.
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_Folder {
+	/**
+	 * @var integer unique id of folder
+	 */
+	var $_id;
+
+	/**
+	 * @var string name of folder
+	 */
+	var $_name;
+
+	/**
+	 * @var integer id of parent folder
+	 */
+	var $_parentID;
+
+	/**
+	 * @var string comment of document
+	 */
+	var $_comment;
+
+	/**
+	 * @var integer id of user who is the owner
+	 */
+	var $_ownerID;
+
+	/**
+	 * @var boolean true if access is inherited, otherwise false
+	 */
+	var $_inheritAccess;
+
+	/**
+	 * @var integer default access if access rights are not inherited
+	 */
+	var $_defaultAccess;
+
+	/**
+	 * @var array list of notifications for users and groups
+	 */
+	var $_notifyList;
+
+	/**
+	 * @var integer position of folder within the parent folder
+	 */
+	var $_sequence;
+
+	/**
+	 * @var object back reference to document management system
+	 */
+	var $_dms;
+
+	function LetoDMS_Core_Folder($id, $name, $parentID, $comment, $date, $ownerID, $inheritAccess, $defaultAccess, $sequence) { /* {{{ */
+		$this->_id = $id;
+		$this->_name = $name;
+		$this->_parentID = $parentID;
+		$this->_comment = $comment;
+		$this->_date = $date;
+		$this->_ownerID = $ownerID;
+		$this->_inheritAccess = $inheritAccess;
+		$this->_defaultAccess = $defaultAccess;
+		$this->_sequence = $sequence;
+		$this->_notifyList = array();
+		$this->_dms = null;
+	} /* }}} */
+
+	/*
+	 * Set dms this folder belongs to.
+	 *
+	 * Each folder needs a reference to the dms it belongs to. It will be
+	 * set when the folder is created by LetoDMS::getFolder(). The dms has a
+	 * references to the currently logged in user and the database connection.
+	 *
+	 * @param object $dms reference to dms
+	 */
+	function setDMS($dms) { /* {{{ */
+		$this->_dms = $dms;
+	} /* }}} */
+
+	/*
+	 * Get the internal id of the folder.
+	 *
+	 * @return integer id of folder
+	 */
+	function getID() { return $this->_id; }
+
+	/*
+	 * Get the name of the folder.
+	 *
+	 * @return string name of folder
+	 */
+	function getName() { return $this->_name; }
+
+	/*
+	 * Set the name of the folder.
+	 *
+	 * @param string $newName set a new name of the folder
+	 */
+	function setName($newName) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblFolders SET name = " . $db->qstr($newName) . " WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_name = $newName;
+
+		return true;
+	} /* }}} */
+
+	function getComment() { return $this->_comment; }
+
+	function setComment($newComment) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblFolders SET comment = " . $db->qstr($newComment) . " WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_comment = $newComment;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Return creation date of folder
+	 *
+	 * @return integer unix timestamp of creation date
+	 */
+	function getDate() { /* {{{ */
+		return $this->_date;
+	} /* }}} */
+
+	/**
+	 * Returns the parent
+	 *
+	 * @return object parent folder or false if there is no parent folder
+	 */
+	function getParent() { /* {{{ */
+		if ($this->_id == $this->_dms->rootFolderID || empty($this->_parentID)) {
+			return false;
+		}
+
+		if (!isset($this->_parent)) {
+			$this->_parent = $this->_dms->getFolder($this->_parentID);
+		}
+		return $this->_parent;
+	} /* }}} */
+
+	/**
+	 * Set a new folder
+	 *
+	 * This function moves a folder from one parent folder into another parent
+	 * folder. It will fail if the root folder is moved.
+	 *
+	 * @param object new parent folder
+	 * @return boolean true if operation was successful otherwise false
+	 */
+	function setParent($newParent) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if ($this->_id == $this->_dms->rootFolderID || empty($this->_parentID)) {
+			return false;
+		}
+
+		// Update the folderList of the folder
+		$pathPrefix="";
+		$path = $newParent->getPath();
+		foreach ($path as $f) {
+			$pathPrefix .= ":".$f->getID();
+		}
+		if (strlen($pathPrefix)>1) {
+			$pathPrefix .= ":";
+		}
+		$queryStr = "UPDATE tblFolders SET parent = ".$newParent->getID().", folderList='".$pathPrefix."' WHERE id = ". $this->_id;
+		$res = $db->getResult($queryStr);
+		if (!$res)
+			return false;
+		$this->_parentID = $newParent->getID();
+		$this->_parent = $newParent;
+
+		// Must also ensure that any documents in this folder tree have their
+		// folderLists updated.
+		$pathPrefix="";
+		$path = $this->getPath();
+		foreach ($path as $f) {
+			$pathPrefix .= ":".$f->getID();
+		}
+		if (strlen($pathPrefix)>1) {
+			$pathPrefix .= ":";
+		}
+
+		$queryStr = "SELECT `tblDocuments`.`id`, `tblDocuments`.`folderList` FROM `tblDocuments` WHERE `folderList` LIKE '%:".$this->_id.":%'";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+
+		foreach ($resArr as $row) {
+			$newPath = preg_replace("/^.*:".$this->_id.":(.*$)/", $pathPrefix."\\1", $row["folderList"]);
+			$queryStr="UPDATE `tblDocuments` SET `folderList` = '".$newPath."' WHERE `tblDocuments`.`id` = '".$row["id"]."'";
+			$res = $db->getResult($queryStr);
+		}
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Returns the owner
+	 *
+	 * @return object owner of the folder
+	 */
+	function getOwner() { /* {{{ */
+		if (!isset($this->_owner))
+			$this->_owner = $this->_dms->getUser($this->_ownerID);
+		return $this->_owner;
+	} /* }}} */
+
+	/**
+	 * Set the owner
+	 *
+	 * @param object new owner of the folder
+	 * @return boolean true if successful otherwise false
+	 */
+	function setOwner($newOwner) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblFolders set owner = " . $newOwner->getID() . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_ownerID = $newOwner->getID();
+		$this->_owner = $newOwner;
+		return true;
+	} /* }}} */
+
+	function getDefaultAccess() { /* {{{ */
+		if ($this->inheritsAccess()) {
+			$res = $this->getParent();
+			if (!$res) return false;
+			return $this->_parent->getDefaultAccess();
+		}
+
+		return $this->_defaultAccess;
+	} /* }}} */
+
+	function setDefaultAccess($mode) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblFolders set defaultAccess = " . (int) $mode . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_defaultAccess = $mode;
+
+		// If any of the notification subscribers no longer have read access,
+		// remove their subscription.
+		if (empty($this->_notifyList))
+			$this->getNotifyList();
+		foreach ($this->_notifyList["users"] as $u) {
+			if ($this->getAccessMode($u) < M_READ) {
+				$this->removeNotify($u->getID(), true);
+			}
+		}
+		foreach ($this->_notifyList["groups"] as $g) {
+			if ($this->getGroupAccessMode($g) < M_READ) {
+				$this->removeNotify($g->getID(), false);
+			}
+		}
+
+		return true;
+	} /* }}} */
+
+	function inheritsAccess() { return $this->_inheritAccess; }
+
+	function setInheritAccess($inheritAccess) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$inheritAccess = ($inheritAccess) ? "1" : "0";
+
+		$queryStr = "UPDATE tblFolders SET inheritAccess = " . (int) $inheritAccess . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_inheritAccess = $inheritAccess;
+
+		// If any of the notification subscribers no longer have read access,
+		// remove their subscription.
+		if (empty($this->_notifyList))
+			$this->getNotifyList();
+		foreach ($this->_notifyList["users"] as $u) {
+			if ($this->getAccessMode($u) < M_READ) {
+				$this->removeNotify($u->getID(), true);
+			}
+		}
+		foreach ($this->_notifyList["groups"] as $g) {
+			if ($this->getGroupAccessMode($g) < M_READ) {
+				$this->removeNotify($g->getID(), false);
+			}
+		}
+
+		return true;
+	} /* }}} */
+
+	function getSequence() { return $this->_sequence; }
+
+	function setSequence($seq) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblFolders SET sequence = " . $seq . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_sequence = $seq;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Returns a list of subfolders
+	 * This function does not check for access rights. Use
+	 * {@link LetoDMS_Core_DMS::filterAccess} for checking each folder against
+	 * the currently logged in user and the access rights.
+	 *
+	 * @param string $orderby if set to 'n' the list is ordered by name, otherwise
+	 *        it will be ordered by sequence
+	 * @return array list of folder objects or false in case of an error
+	 */
+	function getSubFolders($orderby="") { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!isset($this->_subFolders)) {
+			if ($orderby=="n") $queryStr = "SELECT * FROM tblFolders WHERE parent = " . $this->_id . " ORDER BY name";
+			else $queryStr = "SELECT * FROM tblFolders WHERE parent = " . $this->_id . " ORDER BY sequence";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && $resArr == false)
+				return false;
+
+			$this->_subFolders = array();
+			for ($i = 0; $i < count($resArr); $i++)
+//				$this->_subFolders[$i] = new LetoDMS_Core_Folder($resArr[$i]["id"], $resArr[$i]["name"], $resArr[$i]["parent"], $resArr[$i]["comment"], $resArr[$i]["owner"], $resArr[$i]["inheritAccess"], $resArr[$i]["defaultAccess"], $resArr[$i]["sequence"]);
+				$this->_subFolders[$i] = $this->_dms->getFolder($resArr[$i]["id"]);
+		}
+
+		return $this->_subFolders;
+	} /* }}} */
+
+	function addSubFolder($name, $comment, $owner, $sequence) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		// Set the folderList of the folder
+		$pathPrefix="";
+		$path = $this->getPath();
+		foreach ($path as $f) {
+			$pathPrefix .= ":".$f->getID();
+		}
+		if (strlen($pathPrefix)>1) {
+			$pathPrefix .= ":";
+		}
+		//inheritAccess = true, defaultAccess = M_READ
+		$queryStr = "INSERT INTO tblFolders (name, parent, folderList, comment, date, owner, inheritAccess, defaultAccess, sequence) ".
+					"VALUES (".$db->qstr($name).", ".$this->_id.", ".$db->qstr($pathPrefix).", ".$db->qstr($comment).", ".mktime().", ".$owner->getID().", 1, ".M_READ.", ". $sequence.")";
+		if (!$db->getResult($queryStr))
+			return false;
+		$newFolder = $this->_dms->getFolder($db->getInsertID());
+		unset($this->_subFolders);
+
+		return $newFolder;
+	} /* }}} */
+
+	/**
+	 * Returns an array of all parents, grand parent, etc. up to root folder.
+	 * The folder itself is the last element of the array.
+	 *
+	 * @return array Array of parents
+	 */
+	function getPath() { /* {{{ */
+		if (!isset($this->_parentID) || ($this->_parentID == "") || ($this->_parentID == 0)) {
+			return array($this);
+		}
+		else {
+			$res = $this->getParent();
+			if (!$res) return false;
+
+			$path = $this->_parent->getPath();
+			if (!$path) return false;
+
+			array_push($path, $this);
+			return $path;
+		}
+	} /* }}} */
+
+	/**
+	 * Returns a unix file system path
+	 *
+	 * @return string path separated with '/'
+	 */
+	function getFolderPathPlain() { /* {{{ */
+		$path="";
+		$folderPath = $this->getPath();
+		for ($i = 0; $i  < count($folderPath); $i++) {
+			$path .= $folderPath[$i]->getName();
+			if ($i +1 < count($folderPath))
+				$path .= " / ";
+		}
+		return $path;
+	} /* }}} */
+
+	/**
+	 * Check, if this folder is a subfolder of a given folder
+	 *
+	 * @param object $folder parent folder
+	 * @return boolean true if folder is a subfolder
+	 */
+	function isDescendant($folder) { /* {{{ */
+		if ($this->_parentID == $folder->getID())
+			return true;
+		elseif (isset($this->_parentID)) {
+			$res = $this->getParent();
+			if (!$res) return false;
+
+			return $this->_parent->isDescendant($folder);
+		} else
+			return false;
+	} /* }}} */
+
+	/**
+	 * Get all documents of the folder
+	 * This function does not check for access rights. Use
+	 * {@link LetoDMS_Core_DMS::filterAccess} for checking each document against
+	 * the currently logged in user and the access rights.
+	 *
+	 * @param string $orderby if set to 'n' the list is ordered by name, otherwise
+	 *        it will be ordered by sequence
+	 * @return array list of documents or false in case of an error
+	 */
+	function getDocuments($orderby="") { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!isset($this->_documents)) {
+			if ($orderby=="n") $queryStr = "SELECT * FROM tblDocuments WHERE folder = " . $this->_id . " ORDER BY name";
+			else $queryStr = "SELECT * FROM tblDocuments WHERE folder = " . $this->_id . " ORDER BY sequence";
+
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$resArr)
+				return false;
+
+			$this->_documents = array();
+			foreach ($resArr as $row) {
+//				array_push($this->_documents, new LetoDMS_Core_Document($row["id"], $row["name"], $row["comment"], $row["date"], $row["expires"], $row["owner"], $row["folder"], $row["inheritAccess"], $row["defaultAccess"], isset($row["lockUser"])?$row["lockUser"]:NULL, $row["keywords"], $row["sequence"]));
+				array_push($this->_documents, $this->_dms->getDocument($row["id"]));
+			}
+		}
+		return $this->_documents;
+	} /* }}} */
+
+	// $comment will be used for both document and version leaving empty the version_comment 
+	/**
+	 * Add a new document to the folder
+	 * This function will add a new document and its content from a given file. 
+	 * It does not check for access rights on the folder. The new documents
+	 * default access right is read only and the access right is inherited.
+	 *
+	 * @param string $name name of new document
+	 * @param string $comment comment of new document
+	 * @param integer $expires expiration date as a unix timestamp or 0 for no
+	 *        expiration date
+	 * @param object $owner owner of the new document
+	 * @param string $keywords keywords of new document
+	 * @param array $categories list of category ids
+	 * @param string $tmpFile the path of the file containing the content
+	 * @param string $orgFileName the original file name
+	 * @param string $fileType usually the extension of the filename
+	 * @param string $mimeType mime type of the content
+	 * @param float $sequence position of new document within the folder
+	 * @param array $reviewers list of users who must review this document
+	 * @param array $approvers list of users who must approve this document
+	 * @param string $reqversion version number of the content
+	 * @param string $version_comment comment of the content. If left empty
+	 *        the $comment will be used.
+	 * @return array/boolean false in case of error, otherwise an array
+	 *        containing two elements. The first one is the new document, the
+	 *        second one is the result set returned when inserting the content.
+	 */
+	function addDocument($name, $comment, $expires, $owner, $keywords, $categories, $tmpFile, $orgFileName, $fileType, $mimeType, $sequence, $reviewers=array(), $approvers=array(),$reqversion,$version_comment="") { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$expires = (!$expires) ? 0 : $expires;
+
+		// Must also ensure that the document has a valid folderList.
+		$pathPrefix="";
+		$path = $this->getPath();
+		foreach ($path as $f) {
+			$pathPrefix .= ":".$f->getID();
+		}
+		if (strlen($pathPrefix)>1) {
+			$pathPrefix .= ":";
+		}
+
+		$queryStr = "INSERT INTO tblDocuments (name, comment, date, expires, owner, folder, folderList, inheritAccess, defaultAccess, locked, keywords, sequence) VALUES ".
+					"(".$db->qstr($name).", ".$db->qstr($comment).", " . mktime().", ".(int) $expires.", ".$owner->getID().", ".$this->_id.",".$db->qstr($pathPrefix).", 1, ".M_READ.", -1, ".$db->qstr($keywords).", " . $sequence . ")";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$document = $this->_dms->getDocument($db->getInsertID());
+
+		if ($version_comment!="")
+			$res = $document->addContent($version_comment, $owner, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers, $approvers,$reqversion);
+		else $res = $document->addContent($comment, $owner, $tmpFile, $orgFileName, $fileType, $mimeType, $reviewers, $approvers,$reqversion);
+
+		if (is_bool($res) && !$res) {
+			$queryStr = "DELETE FROM tblDocuments WHERE id = " . $document->getID();
+			$db->getResult($queryStr);
+			return false;
+		}
+
+		if($categories) {
+			$document->setCategories($categories);
+		}
+		return array($document, $res);
+	} /* }}} */
+
+	function remove() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		// Do not delete the root folder.
+		if ($this->_id == $this->_dms->rootFolderID || !isset($this->_parentID) || ($this->_parentID == null) || ($this->_parentID == "") || ($this->_parentID == 0)) {
+			return false;
+		}
+
+		//Entfernen der Unterordner und Dateien
+		$res = $this->getSubFolders();
+		if (is_bool($res) && !$res) return false;
+		$res = $this->getDocuments();
+		if (is_bool($res) && !$res) return false;
+
+		foreach ($this->_subFolders as $subFolder) {
+			$res = $subFolder->remove(FALSE);
+			if (!$res) return false;
+		}
+
+		foreach ($this->_documents as $document) {
+			$res = $document->remove(FALSE);
+			if (!$res) return false;
+		}
+
+		//Entfernen der Datenbankeinträge
+		$queryStr = "DELETE FROM tblFolders WHERE id =  " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblACLs WHERE target = ". $this->_id. " AND targetType = " . T_FOLDER;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$queryStr = "DELETE FROM tblNotify WHERE target = ". $this->_id. " AND targetType = " . T_FOLDER;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Returns a list of access privileges
+	 *
+	 * If the document inherits the access privileges from the parent folder
+	 * those will be returned.
+	 * $mode and $op can be set to restrict the list of returned access
+	 * privileges. If $mode is set to M_ANY no restriction will apply
+	 * regardless of the value of $op. The returned array contains a list
+	 * of {@link LetoDMS_Core_UserAccess} and
+	 * {@link LetoDMS_Core_GroupAccess} objects. Even if the document
+	 * has no access list the returned array contains the two elements
+	 * 'users' and 'groups' which are than empty. The methode returns false
+	 * if the function fails.
+	 * 
+	 * @param integer $mode access mode (defaults to M_ANY)
+	 * @param integer $op operation (defaults to O_EQ)
+	 * @return array multi dimensional array
+	 */
+	function getAccessList($mode = M_ANY, $op = O_EQ) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if ($this->inheritsAccess()) {
+			$res = $this->getParent();
+			if (!$res) return false;
+			return $this->_parent->getAccessList($mode, $op);
+		}
+
+		if (!isset($this->_accessList[$mode])) {
+			if ($op!=O_GTEQ && $op!=O_LTEQ && $op!=O_EQ) {
+				return false;
+			}
+			$modeStr = "";
+			if ($mode!=M_ANY) {
+				$modeStr = " AND mode".$op.(int)$mode;
+			}
+			$queryStr = "SELECT * FROM tblACLs WHERE targetType = ".T_FOLDER.
+				" AND target = " . $this->_id .	$modeStr . " ORDER BY targetType";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && !$resArr)
+				return false;
+
+			$this->_accessList[$mode] = array("groups" => array(), "users" => array());
+			foreach ($resArr as $row) {
+				if ($row["userID"] != -1)
+					array_push($this->_accessList[$mode]["users"], new LetoDMS_Core_UserAccess($this->_dms->getUser($row["userID"]), $row["mode"]));
+				else //if ($row["groupID"] != -1)
+					array_push($this->_accessList[$mode]["groups"], new LetoDMS_Core_GroupAccess($this->_dms->getGroup($row["groupID"]), $row["mode"]));
+			}
+		}
+
+		return $this->_accessList[$mode];
+	} /* }}} */
+
+	/**
+	 * Delete all entries for this folder from the access control list
+	 *
+	 * @return boolean true if operation was successful otherwise false
+	 */
+	function clearAccessList() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE FROM tblACLs WHERE targetType = " . T_FOLDER . " AND target = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_accessList);
+		return true;
+	} /* }}} */
+
+	/**
+	 * Add access right to folder
+	 * This function may change in the future. Instead of passing the a flag
+	 * and a user/group id a user or group object will be expected.
+	 *
+	 * @param integer $mode access mode
+	 * @param integer $userOrGroupID id of user or group
+	 * @param integer $isUser set to 1 if $userOrGroupID is the id of a
+	 *        user
+	 */
+	function addAccess($mode, $userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		$queryStr = "INSERT INTO tblACLs (target, targetType, ".$userOrGroup.", mode) VALUES 
+					(".$this->_id.", ".T_FOLDER.", " . (int) $userOrGroupID . ", " .(int) $mode. ")";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_accessList);
+
+		// Update the notify list, if necessary.
+		if ($mode == M_NONE) {
+			$this->removeNotify($userOrGroupID, $isUser);
+		}
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Change access right of folder
+	 * This function may change in the future. Instead of passing the a flag
+	 * and a user/group id a user or group object will be expected.
+	 *
+	 * @param integer $newMode access mode
+	 * @param integer $userOrGroupID id of user or group
+	 * @param integer $isUser set to 1 if $userOrGroupID is the id of a
+	 *        user
+	 */
+	function changeAccess($newMode, $userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		$queryStr = "UPDATE tblACLs SET mode = " . (int) $newMode . " WHERE targetType = ".T_FOLDER." AND target = " . $this->_id . " AND " . $userOrGroup . " = " . (int) $userOrGroupID;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_accessList);
+
+		// Update the notify list, if necessary.
+		if ($newMode == M_NONE) {
+			$this->removeNotify($userOrGroupID, $isUser);
+		}
+
+		return true;
+	} /* }}} */
+
+	function removeAccess($userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		$queryStr = "DELETE FROM tblACLs WHERE targetType = ".T_FOLDER." AND target = ".$this->_id." AND ".$userOrGroup." = " . (int) $userOrGroupID;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		unset($this->_accessList);
+
+		// Update the notify list, if necessary.
+		$mode = ($isUser ? $this->getAccessMode($this->_dms->getUser($userOrGroupID)) : $this->getGroupAccessMode($this->_dms->getGroup($userOrGroupID)));
+		if ($mode == M_NONE) {
+			$this->removeNotify($userOrGroupID, $isUser);
+		}
+
+		return true;
+	} /* }}} */
+
+	/**
+	 * Get the access mode of a user on the folder
+	 *
+	 * This function returns the access mode for a given user. An administrator
+	 * and the owner of the folder has unrestricted access. A guest user has
+	 * read only access or no access if access rights are further limited
+	 * by access control lists. All other users have access rights according
+	 * to the access control lists or the default access. This function will
+	 * recursive check for access rights of parent folders if access rights
+	 * are inherited.
+	 *
+	 * This function returns the access mode for a given user. An administrator
+	 * and the owner of the folder has unrestricted access. A guest user has
+	 * read only access or no access if access rights are further limited
+	 * by access control lists. All other users have access rights according
+	 * to the access control lists or the default access. This function will
+	 * recursive check for access rights of parent folders if access rights
+	 * are inherited.
+	 *
+	 * @param object $user user for which access shall be checked
+	 * @return integer access mode
+	 */
+	function getAccessMode($user) { /* {{{ */
+		/* Admins have full access */
+		if ($user->isAdmin()) return M_ALL;
+
+		/* User has full access if he/she is the owner of the document */
+		if ($user->getID() == $this->_ownerID) return M_ALL;
+
+		/* Guest has read access by default, if guest login is allowed at all */
+		if ($user->isGuest()) {
+			$mode = $this->getDefaultAccess();
+			if ($mode >= M_READ) return M_READ;
+			else return M_NONE;
+		}
+
+		/* check ACLs */
+		$accessList = $this->getAccessList();
+		if (!$accessList) return false;
+
+		foreach ($accessList["users"] as $userAccess) {
+			if ($userAccess->getUserID() == $user->getID()) {
+				return $userAccess->getMode();
+			}
+		}
+		/* Get the highest right defined by a group */
+		$result = 0;
+		foreach ($accessList["groups"] as $groupAccess) {
+			if ($user->isMemberOfGroup($groupAccess->getGroup())) {
+				if ($groupAccess->getMode() > $result)
+					$result = $groupAccess->getMode();
+//					return $groupAccess->getMode();
+			}
+		}
+		if($result)
+			return $result;
+		$result = $this->getDefaultAccess();
+		return $result;
+	} /* }}} */
+
+	/**
+	 * Get the access mode for a group on the folder
+	 * This function returns the access mode for a given group. The algorithmn
+	 * applied to get the access mode is the same as describe at
+	 * {@link getAccessMode}
+	 *
+	 * @param object $group group for which access shall be checked
+	 * @return integer access mode
+	 */
+	function getGroupAccessMode($group) { /* {{{ */
+		$highestPrivileged = M_NONE;
+		$foundInACL = false;
+		$accessList = $this->getAccessList();
+		if (!$accessList)
+			return false;
+
+		foreach ($accessList["groups"] as $groupAccess) {
+			if ($groupAccess->getGroupID() == $group->getID()) {
+				$foundInACL = true;
+				if ($groupAccess->getMode() > $highestPrivileged)
+					$highestPrivileged = $groupAccess->getMode();
+				if ($highestPrivileged == M_ALL) /* no need to check further */
+					return $highestPrivileged;
+			}
+		}
+		if ($foundInACL)
+			return $highestPrivileged;
+
+		/* Take default access */
+		return $this->getDefaultAccess();
+	} /* }}} */
+
+	/**
+	 * Get a list of all notification
+	 * This function returns all users and groups that have registerd a
+	 * notification for the folder
+	 *
+	 * @return array array with a the elements 'users' and 'groups' which
+	 *        contain a list of users and groups.
+	 */
+	function getNotifyList() { /* {{{ */
+		if (empty($this->_notifyList)) {
+			$db = $this->_dms->getDB();
+
+			$queryStr ="SELECT * FROM tblNotify WHERE targetType = " . T_FOLDER . " AND target = " . $this->_id;
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && $resArr == false)
+				return false;
+
+			$this->_notifyList = array("groups" => array(), "users" => array());
+			foreach ($resArr as $row)
+			{
+				if ($row["userID"] != -1)
+					array_push($this->_notifyList["users"], $this->_dms->getUser($row["userID"]) );
+				else //if ($row["groupID"] != -1)
+					array_push($this->_notifyList["groups"], $this->_dms->getGroup($row["groupID"]) );
+			}
+		}
+		return $this->_notifyList;
+	} /* }}} */
+
+	/*
+	 * Add a user/group to the notification list
+	 * This function does not check if the currently logged in user
+	 * is allowed to add a notification. This must be checked by the calling
+	 * application.
+	 *
+	 * @param integer $userOrGroupID
+	 * @param boolean $isUser true if $userOrGroupID is a user id otherwise false
+	 * @return integer error code
+	 *    -1: Invalid User/Group ID.
+	 *    -2: Target User / Group does not have read access.
+	 *    -3: User is already subscribed.
+	 *    -4: Database / internal error.
+	 *     0: Update successful.
+	 */
+	function addNotify($userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		/* Verify that user / group exists */
+		$obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
+		if (!is_object($obj)) {
+			return -1;
+		}
+
+		/* Verify that the requesting user has permission to add the target to
+		 * the notification system.
+		 */
+		/*
+		 * The calling application should enforce the policy on who is allowed
+		 * to add someone to the notification system. If is shall remain here
+		 * the currently logged in user should be passed to this function
+		 *
+		GLOBAL $user;
+		if ($user->isGuest()) {
+			return -2;
+		}
+		if (!$user->isAdmin()) {
+			if ($isUser) {
+				if ($user->getID() != $obj->getID()) {
+					return -2;
+				}
+			}
+			else {
+				if (!$obj->isMember($user)) {
+					return -2;
+				}
+			}
+		}
+		*/
+
+		//
+		// Verify that user / group has read access to the document.
+		//
+		if ($isUser) {
+			// Users are straightforward to check.
+			if ($this->getAccessMode($obj) < M_READ) {
+				return -2;
+			}
+		}
+		else {
+			// FIXME: Why not check the access list first and if this returns
+			// not result, then use the default access?
+			// Groups are a little more complex.
+			if ($this->getDefaultAccess() >= M_READ) {
+				// If the default access is at least READ-ONLY, then just make sure
+				// that the current group has not been explicitly excluded.
+				$acl = $this->getAccessList(M_NONE, O_EQ);
+				$found = false;
+				foreach ($acl["groups"] as $group) {
+					if ($group->getGroupID() == $userOrGroupID) {
+						$found = true;
+						break;
+					}
+				}
+				if ($found) {
+					return -2;
+				}
+			}
+			else {
+				// The default access is restricted. Make sure that the group has
+				// been explicitly allocated access to the document.
+				$acl = $this->getAccessList(M_READ, O_GTEQ);
+				if (is_bool($acl)) {
+					return -4;
+				}
+				$found = false;
+				foreach ($acl["groups"] as $group) {
+					if ($group->getGroupID() == $userOrGroupID) {
+						$found = true;
+						break;
+					}
+				}
+				if (!$found) {
+					return -2;
+				}
+			}
+		}
+		//
+		// Check to see if user/group is already on the list.
+		//
+		$queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
+			"AND `tblNotify`.`targetType` = '".T_FOLDER."' ".
+			"AND `tblNotify`.`".$userOrGroup."` = '". (int) $userOrGroupID."'";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr)) {
+			return -4;
+		}
+		if (count($resArr)>0) {
+			return -3;
+		}
+
+		$queryStr = "INSERT INTO tblNotify (target, targetType, " . $userOrGroup . ") VALUES (" . $this->_id . ", " . T_FOLDER . ", " .  (int) $userOrGroupID . ")";
+		if (!$db->getResult($queryStr))
+			return -4;
+
+		unset($this->_notifyList);
+		return 0;
+	} /* }}} */
+
+	/*
+	 * Removes notify for a user or group to folder
+	 * This function does not check if the currently logged in user
+	 * is allowed to remove a notification. This must be checked by the calling
+	 * application.
+	 *
+	 * @param integer $userOrGroupID
+	 * @param boolean $isUser true if $userOrGroupID is a user id otherwise false
+	 * @return integer error code
+	 *    -1: Invalid User/Group ID.
+	 *    -3: User is not subscribed.
+	 *    -4: Database / internal error.
+	 *     0: Update successful.
+	 */
+	function removeNotify($userOrGroupID, $isUser) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		/* Verify that user / group exists. */
+		$obj = ($isUser ? $this->_dms->getUser($userOrGroupID) : $this->_dms->getGroup($userOrGroupID));
+		if (!is_object($obj)) {
+			return -1;
+		}
+
+		$userOrGroup = ($isUser) ? "userID" : "groupID";
+
+		/* Verify that the requesting user has permission to add the target to
+		 * the notification system.
+		 */
+		/*
+		 * The calling application should enforce the policy on who is allowed
+		 * to add someone to the notification system. If is shall remain here
+		 * the currently logged in user should be passed to this function
+		 *
+		GLOBAL  $user;
+		if ($user->isGuest()) {
+			return -2;
+		}
+		if (!$user->isAdmin()) {
+			if ($isUser) {
+				if ($user->getID() != $obj->getID()) {
+					return -2;
+				}
+			}
+			else {
+				if (!$obj->isMember($user)) {
+					return -2;
+				}
+			}
+		}
+		*/
+
+		//
+		// Check to see if the target is in the database.
+		//
+		$queryStr = "SELECT * FROM `tblNotify` WHERE `tblNotify`.`target` = '".$this->_id."' ".
+			"AND `tblNotify`.`targetType` = '".T_FOLDER."' ".
+			"AND `tblNotify`.`".$userOrGroup."` = '". (int) $userOrGroupID."'";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr)) {
+			return -4;
+		}
+		if (count($resArr)==0) {
+			return -3;
+		}
+
+		$queryStr = "DELETE FROM tblNotify WHERE target = " . $this->_id . " AND targetType = " . T_FOLDER . " AND " . $userOrGroup . " = " .  (int) $userOrGroupID;
+		if (!$db->getResult($queryStr))
+			return -4;
+
+		unset($this->_notifyList);
+		return 0;
+	} /* }}} */
+
+	function getApproversList() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!isset($this->_approversList)) {
+			$this->_approversList = array("groups" => array(), "users" => array());
+			$userIDs = "";
+			$groupIDs = "";
+			$defAccess  = $this->getDefaultAccess();
+
+			if ($defAccess<M_READ) {
+				// Get the list of all users and groups that are listed in the ACL as
+				// having write access to the folder.
+				$tmpList = $this->getAccessList(M_READ, O_GTEQ);
+			}
+			else {
+				// Get the list of all users and groups that DO NOT have write access
+				// to the folder.
+				$tmpList = $this->getAccessList(M_NONE, O_LTEQ);
+			}
+			foreach ($tmpList["groups"] as $groupAccess) {
+				$groupIDs .= (strlen($groupIDs)==0 ? "" : ", ") . $groupAccess->getGroupID();
+			}
+			foreach ($tmpList["users"] as $userAccess) {
+				$user = $userAccess->getUser();
+				if (!$user->isGuest()) {
+					$userIDs .= (strlen($userIDs)==0 ? "" : ", ") . $userAccess->getUserID();
+				}
+			}
+
+			// Construct a query against the users table to identify those users
+			// that have write access to this folder, either directly through an
+			// ACL entry, by virtue of ownership or by having administrative rights
+			// on the database.
+			$queryStr="";
+			if ($defAccess < M_READ) {
+				if (strlen($groupIDs)>0) {
+					$queryStr = "(SELECT `tblUsers`.* FROM `tblUsers` ".
+						"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
+						"WHERE `tblGroupMembers`.`groupID` IN (". $groupIDs .") ".
+						"AND `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest.")";
+				}
+				$queryStr .= (strlen($queryStr)==0 ? "" : " UNION ").
+					"(SELECT `tblUsers`.* FROM `tblUsers` ".
+					"WHERE (`tblUsers`.`role` != ".LetoDMS_Core_User::role_guest.") ".
+					"AND ((`tblUsers`.`id` = ". $this->_ownerID . ") ".
+					"OR (`tblUsers`.`role` = ".LetoDMS_Core_User::role_admin.")".
+					(strlen($userIDs) == 0 ? "" : " OR (`tblUsers`.`id` IN (". $userIDs ."))").
+					")) ORDER BY `login`";
+			}
+			else {
+				if (strlen($groupIDs)>0) {
+					$queryStr = "(SELECT `tblUsers`.* FROM `tblUsers` ".
+						"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
+						"WHERE `tblGroupMembers`.`groupID` NOT IN (". $groupIDs .")".
+						"AND `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest." ".
+						(strlen($userIDs) == 0 ? ")" : " AND (`tblUsers`.`id` NOT IN (". $userIDs .")))");
+				}
+				$queryStr .= (strlen($queryStr)==0 ? "" : " UNION ").
+					"(SELECT `tblUsers`.* FROM `tblUsers` ".
+					"WHERE (`tblUsers`.`id` = ". $this->_ownerID . ") ".
+					"OR (`tblUsers`.`role` = ".LetoDMS_Core_User::role_admin."))".
+					"UNION ".
+					"(SELECT `tblUsers`.* FROM `tblUsers` ".
+					"WHERE `tblUsers`.`role` != ".LetoDMS_Core_User::role_guest." ".
+					(strlen($userIDs) == 0 ? ")" : " AND (`tblUsers`.`id` NOT IN (". $userIDs .")))").
+					" ORDER BY `login`";
+			}
+			$resArr = $db->getResultArray($queryStr);
+			if (!is_bool($resArr)) {
+				foreach ($resArr as $row) {
+					$user = $this->_dms->getUser($row['id']);
+					if (!$this->_dms->enableAdminRevApp && $user->isAdmin()) continue;					
+					$this->_approversList["users"][] = $user;
+				}
+			}
+
+			// Assemble the list of groups that have write access to the folder.
+			$queryStr="";
+			if ($defAccess < M_READ) {
+				if (strlen($groupIDs)>0) {
+					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
+						"WHERE `tblGroups`.`id` IN (". $groupIDs .")";
+				}
+			}
+			else {
+				if (strlen($groupIDs)>0) {
+					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups` ".
+						"WHERE `tblGroups`.`id` NOT IN (". $groupIDs .")";
+				}
+				else {
+					$queryStr = "SELECT `tblGroups`.* FROM `tblGroups`";
+				}
+			}
+			if (strlen($queryStr)>0) {
+				$resArr = $db->getResultArray($queryStr);
+				if (!is_bool($resArr)) {
+					foreach ($resArr as $row) {
+						$group = $this->_dms->getGroup($row["id"]);
+						$this->_approversList["groups"][] = $group;
+					}
+				}
+			}
+		}
+		return $this->_approversList;
+	} /* }}} */
+
+	/**
+	 * Get the internally used folderList which stores the ids of folders from
+	 * the root folder to the parent folder.
+	 *
+	 * @return string column separated list of folder ids
+	 */
+	function getFolderList() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT folderList FROM tblFolders where id = ".$this->_id;
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && !$resArr)
+			return false;
+		return $resArr[0]['folderList'];
+	} /* }}} */
+
+	/**
+	 * Checks the internal data of the folder and repairs it.
+	 * Currently, this function only repairs an incorrect folderList
+	 *
+	 * @return boolean true on success, otherwise false
+	 */
+	function repair() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$curfolderlist = $this->getFolderList();
+
+		// calculate the folderList of the folder
+		$parent = $this->getParent();
+		$pathPrefix="";
+		$path = $parent->getPath();
+		foreach ($path as $f) {
+			$pathPrefix .= ":".$f->getID();
+		}
+		if (strlen($pathPrefix)>1) {
+			$pathPrefix .= ":";
+		}
+		if($curfolderlist != $pathPrefix) {
+			$queryStr = "UPDATE tblFolders SET folderList='".$pathPrefix."' WHERE id = ". $this->_id;
+			$res = $db->getResult($queryStr);
+			if (!$res)
+				return false;
+		}
+		return true;
+	} /* }}} */
+
+}
+
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassGroup.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassGroup.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassGroup.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassGroup.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,296 @@
+<?php
+/**
+ * Implementation of the group object in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Class to represent a user group in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_Group {
+	/**
+	 * The id of the user group
+	 *
+	 * @var integer
+	 */
+	var $_id;
+
+	/**
+	 * The name of the user group
+	 *
+	 * @var string
+	 */
+	var $_name;
+
+	/**
+	 * Back reference to DMS this user group belongs to
+	 *
+	 * @var object
+	 */
+	var $_dms;
+
+	function LetoDMS_Core_Group($id, $name, $comment) { /* {{{ */
+		$this->_id = $id;
+		$this->_name = $name;
+		$this->_comment = $comment;
+		$this->_dms = null;
+	} /* }}} */
+
+	function setDMS($dms) { /* {{{ */
+		$this->_dms = $dms;
+	} /* }}} */
+
+	function getID() { return $this->_id; }
+
+	function getName() { return $this->_name; }
+
+	function setName($newName) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblGroups SET name = ".$db->qstr($newName)." WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_name = $newName;
+		return true;
+	} /* }}} */
+
+	function getComment() { return $this->_comment; }
+
+	function setComment($newComment) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblGroups SET comment = ".$db->qstr($newComment)." WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_comment = $newComment;
+		return true;
+	} /* }}} */
+
+	function getUsers() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!isset($this->_users)) {
+			$queryStr = "SELECT `tblUsers`.* FROM `tblUsers` ".
+				"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
+				"WHERE `tblGroupMembers`.`groupID` = '". $this->_id ."'";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && $resArr == false)
+				return false;
+
+			$this->_users = array();
+
+			foreach ($resArr as $row) {
+				$user = new LetoDMS_Core_User($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $row["role"], $row['hidden']);
+				array_push($this->_users, $user);
+			}
+		}
+		return $this->_users;
+	} /* }}} */
+
+	function getManagers() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT `tblUsers`.* FROM `tblUsers` ".
+			"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`userID`=`tblUsers`.`id` ".
+			"WHERE `tblGroupMembers`.`groupID` = '". $this->_id ."' AND tblGroupMembers.manager = 1";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+
+		$managers = array();
+
+		foreach ($resArr as $row) {
+			$user = new LetoDMS_Core_User($row["id"], $row["login"], $row["pwd"], $row["fullName"], $row["email"], $row["language"], $row["theme"], $row["comment"], $row["role"], $row['hidden']);
+			array_push($managers, $user);
+		}
+		return $managers;
+	} /* }}} */
+
+	function addUser($user,$asManager=false) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "INSERT INTO tblGroupMembers (groupID, userID, manager) VALUES (".$this->_id.", ".$user->getID(). ", " . ($asManager?"1":"0") ." )";
+		$res = $db->getResult($queryStr);
+
+		if ($res) return false;
+
+		unset($this->_users);
+		return true;
+	} /* }}} */
+
+	function removeUser($user) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE FROM tblGroupMembers WHERE groupID = ".$this->_id." AND userID = ".$user->getID();
+		$res = $db->getResult($queryStr);
+
+		if ($res) return false;
+		unset($this->_users);
+		return true;
+	} /* }}} */
+
+	// $asManager=false: verify if user is in group
+	// $asManager=true : verify if user is in group as manager
+	function isMember($user,$asManager=false) { /* {{{ */
+		if (isset($this->_users)&&!$asManager) {
+			foreach ($this->_users as $usr)
+				if ($usr->getID() == $user->getID())
+					return true;
+			return false;
+		}
+
+		$db = $this->_dms->getDB();
+		if ($asManager) $queryStr = "SELECT * FROM tblGroupMembers WHERE groupID = " . $this->_id . " AND userID = " . $user->getID() . " AND manager = 1";
+		else $queryStr = "SELECT * FROM tblGroupMembers WHERE groupID = " . $this->_id . " AND userID = " . $user->getID();
+
+		$resArr = $db->getResultArray($queryStr);
+
+		if (is_bool($resArr) && $resArr == false) return false;
+		if (count($resArr) != 1) return false;
+
+		return true;
+	} /* }}} */
+
+	function toggleManager($user) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!$this->isMember($user)) return false;
+
+		if ($this->isMember($user,true)) $queryStr = "UPDATE tblGroupMembers SET manager = 0 WHERE groupID = ".$this->_id." AND userID = ".$user->getID();
+		else $queryStr = "UPDATE tblGroupMembers SET manager = 1 WHERE groupID = ".$this->_id." AND userID = ".$user->getID();
+
+		if (!$db->getResult($queryStr)) return false;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Delete user group
+	 * This function deletes the user group and all it references, like access
+	 * control lists, notifications, as a child of other groups, etc.
+	 *
+	 * @param object $user the user doing the removal (needed for entry in
+	 *        review log.
+	 * @return boolean true on success or false in case of an error
+	 */
+	function remove($user) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE FROM tblGroups WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblGroupMembers WHERE groupID = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblACLs WHERE groupID = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblNotify WHERE groupID = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblMandatoryReviewers WHERE reviewerGroupID = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+		$queryStr = "DELETE FROM tblMandatoryApprovers WHERE approverGroupID = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		// TODO : update document status if reviewer/approver has been deleted
+
+
+		$reviewStatus = $this->getReviewStatus();
+		foreach ($reviewStatus as $r) {
+			$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
+				"VALUES ('". $r["reviewID"] ."', '-2', 'Review group removed from process', NOW(), '". $user->getID() ."')";
+			$res=$db->getResult($queryStr);
+		}
+
+		$approvalStatus = $this->getApprovalStatus();
+		foreach ($approvalStatus as $a) {
+			$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
+				"VALUES ('". $a["approveID"] ."', '-2', 'Approval group removed from process', NOW(), '". $user->getID() ."')";
+			$res=$db->getResult($queryStr);
+		}
+
+		return true;
+	} /* }}} */
+
+	function getReviewStatus($documentID=null, $version=null) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!$db->createTemporaryTable("ttreviewid")) {
+			return false;
+		}
+
+		$status = array();
+
+		// See if the group is assigned as a reviewer.
+		$queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
+			"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
+			"`tblDocumentReviewLog`.`userID` ".
+			"FROM `tblDocumentReviewers` ".
+			"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
+			"LEFT JOIN `ttreviewid` on `ttreviewid`.`maxLogID` = `tblDocumentReviewLog`.`reviewLogID` ".
+			"WHERE `ttreviewid`.`maxLogID`=`tblDocumentReviewLog`.`reviewLogID` ".
+			($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
+			($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
+			"AND `tblDocumentReviewers`.`type`='1' ".
+			"AND `tblDocumentReviewers`.`required`='". $this->_id ."' ";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr)>0) {
+			foreach ($resArr as $res)
+				$status[] = $res;
+		}
+		return $status;
+	} /* }}} */
+
+	function getApprovalStatus($documentID=null, $version=null) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!$db->createTemporaryTable("ttapproveid")) {
+			return false;
+		}
+
+		$status = array();
+
+		// See if the group is assigned as an approver.
+		$queryStr = "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
+			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
+			"`tblDocumentApproveLog`.`userID` ".
+			"FROM `tblDocumentApprovers` ".
+			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
+			"LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
+			"WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
+			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
+			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
+			"AND `tblDocumentApprovers`.`type`='1' ".
+			"AND `tblDocumentApprovers`.`required`='". $this->_id ."' ";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr)>0) {
+			foreach ($resArr as $res)
+				$status[] = $res;
+		}
+
+		return $status;
+	} /* }}} */
+}
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassKeywords.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassKeywords.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassKeywords.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassKeywords.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,137 @@
+<?php
+/**
+ * Implementation of keyword categories in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Class to represent a keyword category in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_KeywordCategory {
+	/**
+	 * @var integer $_id id of keyword category
+	 * @access protected
+	 */
+	var $_id;
+
+	/**
+	 * @var integer $_ownerID id of user who is the owner
+	 * @access protected
+	 */
+	var $_ownerID;
+
+	/**
+	 * @var string $_name name of category
+	 * @access protected
+	 */
+	var $_name;
+
+	/**
+	 * @var object $_dms reference to dms this category belongs to
+	 * @access protected
+	 */
+	var $_dms;
+
+	function LetoDMS_Core_KeywordCategory($id, $ownerID, $name) {
+		$this->_id = $id;
+		$this->_name = $name;
+		$this->_ownerID = $ownerID;
+		$this->_dms = null;
+	}
+
+	function setDMS($dms) {
+		$this->_dms = $dms;
+	}
+
+	function getID() { return $this->_id; }
+
+	function getName() { return $this->_name; }
+
+	function getOwner() {
+		if (!isset($this->_owner))
+			$this->_owner = $this->_dms->getUser($this->_ownerID);
+		return $this->_owner;
+	}
+
+	function setName($newName) {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblKeywordCategories SET name = ".$db->qstr($newName)." WHERE id = ". $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_name = $newName;
+		return true;
+	}
+
+	function setOwner($user) {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblKeywordCategories SET owner = " . $user->getID() . " WHERE id " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_ownerID = $user->getID();
+		$this->_owner = $user;
+		return true;
+	}
+
+	function getKeywordLists() {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT * FROM tblKeywords WHERE category = " . $this->_id;
+		return $db->getResultArray($queryStr);
+	}
+
+	function editKeywordList($listID, $keywords) {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblKeywords SET keywords = ".$db->qstr($keywords)." WHERE id = $listID";
+		return $db->getResult($queryStr);
+	}
+
+	function addKeywordList($keywords) {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "INSERT INTO tblKeywords (category, keywords) VALUES (" . $this->_id . ", ".$db->qstr($keywords).")";
+		return $db->getResult($queryStr);
+	}
+
+	function removeKeywordList($listID) {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE FROM tblKeywords WHERE id = $listID";
+		return $db->getResult($queryStr);
+	}
+
+	function remove() {
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE FROM tblKeywords WHERE category = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$queryStr = "DELETE FROM tblKeywordCategories WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		return true;
+	}
+}
+
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassNotification.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassNotification.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassNotification.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassNotification.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Implementation of a notification object
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Class to represent a notification
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_Notification { /* {{{ */
+	/**
+	 * @var integer id of target (document or folder)
+	 *
+	 * @access protected
+	 */
+	var $_target;
+
+	/**
+	 * @var integer document or folder
+	 *
+	 * @access protected
+	 */
+	var $_targettype;
+
+	/**
+	 * @var integer id of user to notify
+	 *
+	 * @access protected
+	 */
+	var $_userid;
+
+	/**
+	 * @var integer id of group to notify
+	 *
+	 * @access protected
+	 */
+	var $_groupid;
+
+	/**
+	 * @var object reference to the dms instance this user belongs to
+	 *
+	 * @access protected
+	 */
+	var $_dms;
+
+	function LetoDMS_Core_Notification($target, $targettype, $userid, $groupid) {
+		$this->_target = $target;
+		$this->_targettype = $targettype;
+		$this->_userid = $userid;
+		$this->_groupid = $groupid;
+	}
+
+	function setDMS($dms) {
+		$this->_dms = $dms;
+	}
+
+	function getTarget() { return $this->_target; }
+
+	function getTargetType() { return $this->_targettype; }
+
+	function getUser() { return $this->_dms->getUser($this->_userid); }
+
+	function getGroup() { return $this->_dms->getGroup($this->_groupid); }
+} /* }}} */
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassUser.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassUser.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.ClassUser.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.ClassUser.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,848 @@
+<?php
+/**
+ * Implementation of the user object in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Class to represent a user in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_User {
+	/**
+	 * @var integer id of user
+	 *
+	 * @access protected
+	 */
+	var $_id;
+
+	/**
+	 * @var string login name of user
+	 *
+	 * @access protected
+	 */
+	var $_login;
+
+	/**
+	 * @var string password of user as saved in database (md5)
+	 *
+	 * @access protected
+	 */
+	var $_pwd;
+
+	/**
+	 * @var string full human readable name of user
+	 *
+	 * @access protected
+	 */
+	var $_fullName;
+
+	/**
+	 * @var string email address of user
+	 *
+	 * @access protected
+	 */
+	var $_email;
+
+	/**
+	 * @var string prefered language of user
+	 *      possible values are 'English', 'German', 'Chinese_ZH_TW', 'Czech'
+	 *      'Francais', 'Hungarian', 'Italian', 'Portuguese_BR', 'Slovak', 
+	 *      'Spanish'
+	 *
+	 * @access protected
+	 */
+	var $_language;
+
+	/**
+	 * @var string preselected theme of user
+	 *
+	 * @access protected
+	 */
+	var $_theme;
+
+	/**
+	 * @var string comment of user
+	 *
+	 * @access protected
+	 */
+	var $_comment;
+
+	/**
+	 * @var string role of user. Can be one of LetoDMS_Core_User::role_user,
+	 *      LetoDMS_Core_User::role_admin, LetoDMS_Core_User::role_guest
+	 *
+	 * @access protected
+	 */
+	var $_role;
+
+	/**
+	 * @var string true if user shall be hidden
+	 *
+	 * @access protected
+	 */
+	var $_isHidden;
+
+	/**
+	 * @var object reference to the dms instance this user belongs to
+	 *
+	 * @access protected
+	 */
+	var $_dms;
+
+	const role_user = '0';
+	const role_admin = '1';
+	const role_guest = '2';
+
+	function LetoDMS_Core_User($id, $login, $pwd, $fullName, $email, $language, $theme, $comment, $role, $isHidden=0) {
+		$this->_id = $id;
+		$this->_login = $login;
+		$this->_pwd = $pwd;
+		$this->_fullName = $fullName;
+		$this->_email = $email;
+		$this->_language = $language;
+		$this->_theme = $theme;
+		$this->_comment = $comment;
+		$this->_role = $role;
+		$this->_isHidden = $isHidden;
+		$this->_dms = null;
+	}
+
+	function setDMS($dms) {
+		$this->_dms = $dms;
+	}
+
+	function getID() { return $this->_id; }
+
+	function getLogin() { return $this->_login; }
+
+	function setLogin($newLogin) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET login =".$db->qstr($newLogin)." WHERE id = " . $this->_id;
+		$res = $db->getResult($queryStr);
+		if (!$res)
+			return false;
+
+		$this->_login = $newLogin;
+		return true;
+	} /* }}} */
+
+	function getFullName() { return $this->_fullName; }
+
+	function setFullName($newFullName) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET fullname = ".$db->qstr($newFullName)." WHERE id = " . $this->_id;
+		$res = $db->getResult($queryStr);
+		if (!$res)
+			return false;
+
+		$this->_fullName = $newFullName;
+		return true;
+	} /* }}} */
+
+	function getPwd() { return $this->_pwd; }
+
+	function setPwd($newPwd) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET pwd =".$db->qstr($newPwd)." WHERE id = " . $this->_id;
+		$res = $db->getResult($queryStr);
+		if (!$res)
+			return false;
+
+		$this->_pwd = $newPwd;
+		return true;
+	} /* }}} */
+
+	function getEmail() { return $this->_email; }
+
+	function setEmail($newEmail) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET email =".$db->qstr($newEmail)." WHERE id = " . $this->_id;
+		$res = $db->getResult($queryStr);
+		if (!$res)
+			return false;
+
+		$this->_email = $newEmail;
+		return true;
+	} /* }}} */
+
+	function getLanguage() { return $this->_language; }
+
+	function setLanguage($newLanguage) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET language =".$db->qstr($newLanguage)." WHERE id = " . $this->_id;
+		$res = $db->getResult($queryStr);
+		if (!$res)
+			return false;
+
+		$this->_language = $newLanguage;
+		return true;
+	} /* }}} */
+
+	function getTheme() { return $this->_theme; }
+
+	function setTheme($newTheme) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET theme =".$db->qstr($newTheme)." WHERE id = " . $this->_id;
+		$res = $db->getResult($queryStr);
+		if (!$res)
+			return false;
+
+		$this->_theme = $newTheme;
+		return true;
+	} /* }}} */
+
+	function getComment() { return $this->_comment; }
+
+	function setComment($newComment) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET comment =".$db->qstr($newComment)." WHERE id = " . $this->_id;
+		$res = $db->getResult($queryStr);
+		if (!$res)
+			return false;
+
+		$this->_comment = $newComment;
+		return true;
+	} /* }}} */
+
+	function getRole() { return $this->_role; }
+
+	function setRole($newrole) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET role = " . $newrole . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_role = $newrole;
+		return true;
+	} /* }}} */
+
+	function isAdmin() { return ($this->_role == LetoDMS_Core_User::role_admin); }
+
+	function setAdmin($isAdmin) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET role = " . LetoDMS_Core_User::role_admin . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_role = LetoDMS_Core_User::role_admin;
+		return true;
+	} /* }}} */
+
+	function isGuest() { return ($this->_role == LetoDMS_Core_User::role_guest); }
+
+	function setGuest($isGuest) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "UPDATE tblUsers SET role = " . LetoDMS_Core_User::role_guest . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_role = LetoDMS_Core_User::role_guest;
+		return true;
+	} /* }}} */
+
+	function isHidden() { return $this->_isHidden; }
+
+	function setHidden($isHidden) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$isHidden = ($isHidden) ? "1" : "0";
+		$queryStr = "UPDATE tblUsers SET hidden = " . $isHidden . " WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_isHidden = $isHidden;
+		return true;
+	}	 /* }}} */
+
+	/**
+	 * Remove the user and also remove all its keywords, notifies, etc.
+	 * Do not remove folders and documents of the user, but assign them
+	 * to a different user.
+	 *
+	 * @param object $user the user doing the removal (needed for entry in
+	 *        review log.
+	 * @param object $assignToUser the user who is new owner of folders and
+	 *        documents which previously were owned by the delete user.
+	 * @return boolean true on success or false in case of an error
+	 */
+	function remove($user, $assignToUser=null) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		/* Records like folders and documents that formely have belonged to
+		 * the user will assign to another user. If no such user is set,
+		 * the function now returns false and will not use the admin user
+		 * anymore.
+		 */
+		if(!$assignToUser)
+			return;
+		$assignTo = $assignToUser->getID();
+
+		// delete private keyword lists
+		$queryStr = "SELECT tblKeywords.id FROM tblKeywords, tblKeywordCategories WHERE tblKeywords.category = tblKeywordCategories.id AND tblKeywordCategories.owner = " . $this->_id;
+		$resultArr = $db->getResultArray($queryStr);
+		if (count($resultArr) > 0) {
+			$queryStr = "DELETE FROM tblKeywords WHERE ";
+			for ($i = 0; $i < count($resultArr); $i++) {
+				$queryStr .= "id = " . $resultArr[$i]["id"];
+				if ($i + 1 < count($resultArr))
+					$queryStr .= " OR ";
+			}
+			if (!$db->getResult($queryStr))	return false;
+		}
+
+		$queryStr = "DELETE FROM tblKeywordCategories WHERE owner = " . $this->_id;
+		if (!$db->getResult($queryStr))	return false;
+
+		//Benachrichtigungen entfernen
+		$queryStr = "DELETE FROM tblNotify WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		/* Assign documents of the removed user to the given user */
+		$queryStr = "UPDATE tblFolders SET owner = " . $assignTo . " WHERE owner = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		$queryStr = "UPDATE tblDocuments SET owner = " . $assignTo . " WHERE owner = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		$queryStr = "UPDATE tblDocumentContent SET createdBy = " . $assignTo . " WHERE createdBy = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		// Remove private links on documents ...
+		$queryStr = "DELETE FROM tblDocumentLinks WHERE userID = " . $this->_id . " AND public = 0";
+		if (!$db->getResult($queryStr)) return false;
+
+		// ... but keep public links
+		$queryStr = "UPDATE tblDocumentLinks SET userID = " . $assignTo . " WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		// set administrator for deleted user's attachments
+		$queryStr = "UPDATE tblDocumentFiles SET userID = " . $assignTo . " WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		//Evtl. von diesem Benutzer gelockte Dokumente werden freigegeben
+		$queryStr = "DELETE FROM tblDocumentLocks WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		// Delete user from all groups
+		$queryStr = "DELETE FROM tblGroupMembers WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		// User aus allen ACLs streichen
+		$queryStr = "DELETE FROM tblACLs WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		// Delete image of user
+		$queryStr = "DELETE FROM tblUserImages WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		// Delete user itself
+		$queryStr = "DELETE FROM tblUsers WHERE id = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		// mandatory review/approve
+		$queryStr = "DELETE FROM tblMandatoryReviewers WHERE reviewerUserID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		$queryStr = "DELETE FROM tblMandatoryApprovers WHERE approverUserID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		$queryStr = "DELETE FROM tblMandatoryReviewers WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		$queryStr = "DELETE FROM tblMandatoryApprovers WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+		// set administrator for deleted user's events
+		$queryStr = "UPDATE tblEvents SET userID = " . $assignTo . " WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+
+
+		// TODO : update document status if reviewer/approver has been deleted
+		// "DELETE FROM tblDocumentApproveLog WHERE userID = " . $this->_id;
+		// "DELETE FROM tblDocumentReviewLog WHERE userID = " . $this->_id;
+
+
+		$reviewStatus = $this->getReviewStatus();
+		foreach ($reviewStatus["indstatus"] as $ri) {
+			$queryStr = "INSERT INTO `tblDocumentReviewLog` (`reviewID`, `status`, `comment`, `date`, `userID`) ".
+				"VALUES ('". $ri["reviewID"] ."', '-2', 'Reviewer removed from process', NOW(), '". $user->getID() ."')";
+			$res=$db->getResult($queryStr);
+		}
+
+		$approvalStatus = $this->getApprovalStatus();
+		foreach ($approvalStatus["indstatus"] as $ai) {
+			$queryStr = "INSERT INTO `tblDocumentApproveLog` (`approveID`, `status`, `comment`, `date`, `userID`) ".
+				"VALUES ('". $ai["approveID"] ."', '-2', 'Approver removed from process', NOW(), '". $user->getID() ."')";
+			$res=$db->getResult($queryStr);
+		}
+
+//		unset($this);
+		return true;
+	} /* }}} */
+
+	/**
+	 * Make the user a member of a group
+	 * This function uses {@link LetoDMS_Group::addUser} but checks before if
+	 * the user is already a member of the group.
+	 *
+	 * @param object $group group to be the member of
+	 * @return boolean true on success or false in case of an error or the user
+	 *        is already a member of the group
+	 */
+	function joinGroup($group) { /* {{{ */
+		if ($group->isMember($this))
+			return false;
+
+		if (!$group->addUser($this))
+			return false;
+
+		unset($this->_groups);
+		return true;
+	} /* }}} */
+
+	/**
+	 * Removes the user from a group
+	 * This function uses {@link LetoDMS_Group::removeUser} but checks before if
+	 * the user is a member of the group at all.
+	 *
+	 * @param object $group group to leave
+	 * @return boolean true on success or false in case of an error or the user
+	 *        is not a member of the group
+	 */
+	function leaveGroup($group) { /* {{{ */
+		if (!$group->isMember($this))
+			return false;
+
+		if (!$group->removeUser($this))
+			return false;
+
+		unset($this->_groups);
+		return true;
+	} /* }}} */
+
+	/**
+	 * Get all groups the user is a member of
+	 *
+	 * @return array list of groups
+	 */
+	function getGroups() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if (!isset($this->_groups))
+		{
+			$queryStr = "SELECT `tblGroups`.*, `tblGroupMembers`.`userID` FROM `tblGroups` ".
+				"LEFT JOIN `tblGroupMembers` ON `tblGroups`.`id` = `tblGroupMembers`.`groupID` ".
+				"WHERE `tblGroupMembers`.`userID`='". $this->_id ."'";
+			$resArr = $db->getResultArray($queryStr);
+			if (is_bool($resArr) && $resArr == false)
+				return false;
+
+			$this->_groups = array();
+			foreach ($resArr as $row) {
+				$group = new LetoDMS_Core_Group($row["id"], $row["name"], $row["comment"]);
+				array_push($this->_groups, $group);
+			}
+		}
+		return $this->_groups;
+	} /* }}} */
+
+	/**
+	 * Checks if user is member of a given group
+	 *
+	 * @param object $group
+	 * @return boolean true if user is member of the given group otherwise false
+	 */
+	function isMemberOfGroup($group) { /* {{{ */
+		return $group->isMember($this);
+	} /* }}} */
+
+	/**
+	 * Check if user has an image in its profile
+	 *
+	 * @return boolean true if user has a picture of itself
+	 */
+	function hasImage() { /* {{{ */
+		if (!isset($this->_hasImage)) {
+			$db = $this->_dms->getDB();
+
+			$queryStr = "SELECT COUNT(*) AS num FROM tblUserImages WHERE userID = " . $this->_id;
+			$resArr = $db->getResultArray($queryStr);
+			if ($resArr === false)
+				return false;
+
+			if ($resArr[0]["num"] == 0)	$this->_hasImage = false;
+			else $this->_hasImage = true;
+		}
+
+		return $this->_hasImage;
+	} /* }}} */
+
+	/**
+	 * Get the image from the users profile
+	 *
+	 * @return array image data
+	 */
+	function getImage() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT * FROM tblUserImages WHERE userID = " . $this->_id;
+		$resArr = $db->getResultArray($queryStr);
+		if ($resArr === false)
+			return false;
+
+		if($resArr)
+			$resArr = $resArr[0];
+		return $resArr;
+	} /* }}} */
+
+	function setImage($tmpfile, $mimeType) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$fp = fopen($tmpfile, "rb");
+		if (!$fp) return false;
+		$content = fread($fp, filesize($tmpfile));
+		fclose($fp);
+
+		if ($this->hasImage())
+			$queryStr = "UPDATE tblUserImages SET image = '".base64_encode($content)."', mimeType = ".$db->qstr($mimeType)." WHERE userID = " . $this->_id;
+		else
+			$queryStr = "INSERT INTO tblUserImages (userID, image, mimeType) VALUES (" . $this->_id . ", '".base64_encode($content)."', ".$db->qstr($mimeType).")";
+		if (!$db->getResult($queryStr))
+			return false;
+
+		$this->_hasImage = true;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Get a list of reviews
+	 * This function returns a list of all reviews seperated by individual
+	 * and group reviews. If the document id
+	 * is passed, then only this document will be checked for approvals. The
+	 * same is true for the version of a document which limits the list
+	 * further.
+	 *
+	 * For a detaile description of the result array see
+	 * {link LetoDMS_User::getApprovalStatus}
+	 *
+	 * @param int $documentID optional document id for which to retrieve the
+	 *        reviews
+	 * @param int $version optional version of the document
+	 * @return array list of all reviews
+	 */
+	function getReviewStatus($documentID=null, $version=null) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+/*
+		if (!$db->createTemporaryTable("ttreviewid")) {
+			return false;
+		}
+*/
+		$status = array("indstatus"=>array(), "grpstatus"=>array());
+
+		// See if the user is assigned as an individual reviewer.
+		$queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
+			"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
+			"`tblDocumentReviewLog`.`userID` ".
+			"FROM `tblDocumentReviewers` ".
+			"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
+			"WHERE `tblDocumentReviewers`.`type`='0' ".
+			($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
+			($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
+			"AND `tblDocumentReviewers`.`required`='". $this->_id ."' ".
+			"ORDER BY `tblDocumentReviewLog`.`reviewLogID` DESC LIMIT 1";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr)>0) {
+			foreach ($resArr as $res)
+				$status["indstatus"][] = $res;
+		}
+
+		// See if the user is the member of a group that has been assigned to
+		// review the document version.
+		$queryStr = "SELECT `tblDocumentReviewers`.*, `tblDocumentReviewLog`.`status`, ".
+			"`tblDocumentReviewLog`.`comment`, `tblDocumentReviewLog`.`date`, ".
+			"`tblDocumentReviewLog`.`userID` ".
+			"FROM `tblDocumentReviewers` ".
+			"LEFT JOIN `tblDocumentReviewLog` USING (`reviewID`) ".
+			"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentReviewers`.`required` ".
+			"WHERE `tblDocumentReviewers`.`type`='1' ".
+			($documentID==null ? "" : "AND `tblDocumentReviewers`.`documentID` = '". (int) $documentID ."' ").
+			($version==null ? "" : "AND `tblDocumentReviewers`.`version` = '". (int) $version ."' ").
+			"AND `tblGroupMembers`.`userID`='". $this->_id ."' ".
+			"ORDER BY `tblDocumentReviewLog`.`reviewLogID` DESC LIMIT 1";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr)>0) {
+			foreach ($resArr as $res)
+				$status["grpstatus"][] = $res;
+		}
+		return $status;
+	} /* }}} */
+
+	/**
+	 * Get a list of approvals
+	 * This function returns a list of all approvals seperated by individual
+	 * and group approvals. If the document id
+	 * is passed, then only this document will be checked for approvals. The
+	 * same is true for the version of a document which limits the list
+	 * further.
+	 *
+	 * The result array has two elements:
+	 * - indstatus: which contains the approvals by individuals (users)
+	 * - grpstatus: which contains the approvals by groups
+	 *
+	 * Each element is itself an array of approvals with the following elements:
+	 * - approveID: unique id of approval
+	 * - documentID: id of document, that needs to be approved
+	 * - version: version of document, that needs to be approved
+	 * - type: 0 for individual approval, 1 for group approval
+	 * - required: id of user who is required to do the approval
+	 * - status: 0 not approved, ....
+	 * - comment: comment given during approval
+	 * - date: date of approval
+	 * - userID: id of user who has done the approval
+	 *
+	 * @param int $documentID optional document id for which to retrieve the
+	 *        approvals
+	 * @param int $version optional version of the document
+	 * @return array list of all approvals
+	 */
+	function getApprovalStatus($documentID=null, $version=null) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+/*
+		if (!$db->createTemporaryTable("ttapproveid")) {
+			return false;
+		}
+*/
+		$status = array("indstatus"=>array(), "grpstatus"=>array());
+
+		// See if the user is assigned as an individual approver.
+		/*
+		$queryStr = "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
+			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
+			"`tblDocumentApproveLog`.`userID` ".
+			"FROM `tblDocumentApprovers` ".
+			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
+			"LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
+			"WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
+			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". $documentID ."' ").
+			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". $version ."' ").
+			"AND `tblDocumentApprovers`.`type`='0' ".
+			"AND `tblDocumentApprovers`.`required`='". $this->_id ."' ";
+*/
+		$queryStr =
+   "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
+			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
+			"`tblDocumentApproveLog`.`userID` ".
+			"FROM `tblDocumentApprovers` ".
+			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
+			"WHERE `tblDocumentApprovers`.`type`='0' ".
+			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
+			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
+			"AND `tblDocumentApprovers`.`required`='". $this->_id ."' ".
+			"ORDER BY `tblDocumentApproveLog`.`approveLogID` DESC LIMIT 1";
+
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr)>0) {
+			foreach ($resArr as $res)
+				$status["indstatus"][] = $res;
+		}
+
+		// See if the user is the member of a group that has been assigned to
+		// approve the document version.
+		/*
+		$queryStr = "SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
+			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
+			"`tblDocumentApproveLog`.`userID` ".
+			"FROM `tblDocumentApprovers` ".
+			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
+			"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentApprovers`.`required` ".
+			"LEFT JOIN `ttapproveid` on `ttapproveid`.`maxLogID` = `tblDocumentApproveLog`.`approveLogID` ".
+			"WHERE `ttapproveid`.`maxLogID`=`tblDocumentApproveLog`.`approveLogID` ".
+			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". $documentID ."' ").
+			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". $version ."' ").
+			"AND `tblDocumentApprovers`.`type`='1' ".
+			"AND `tblGroupMembers`.`userID`='". $this->_id ."'";
+			*/
+		$queryStr =
+			"SELECT `tblDocumentApprovers`.*, `tblDocumentApproveLog`.`status`, ".
+			"`tblDocumentApproveLog`.`comment`, `tblDocumentApproveLog`.`date`, ".
+			"`tblDocumentApproveLog`.`userID` ".
+			"FROM `tblDocumentApprovers` ".
+			"LEFT JOIN `tblDocumentApproveLog` USING (`approveID`) ".
+			"LEFT JOIN `tblGroupMembers` ON `tblGroupMembers`.`groupID` = `tblDocumentApprovers`.`required` ".
+			"WHERE `tblDocumentApprovers`.`type`='1' ".
+			($documentID==null ? "" : "AND `tblDocumentApprovers`.`documentID` = '". (int) $documentID ."' ").
+			($version==null ? "" : "AND `tblDocumentApprovers`.`version` = '". (int) $version ."' ").
+			"AND `tblGroupMembers`.`userID`='". $this->_id ."' ".
+			"ORDER BY `tblDocumentApproveLog`.`approveLogID` DESC LIMIT 1";
+		$resArr = $db->getResultArray($queryStr);
+		if (is_bool($resArr) && $resArr == false)
+			return false;
+		if (count($resArr)>0) {
+			foreach ($resArr as $res)
+				$status["grpstatus"][] = $res;
+		}
+		return $status;
+	} /* }}} */
+
+	/**
+	 * Get a list of mandatory reviewers
+	 * A user which isn't trusted completely may have assigned mandatory
+	 * reviewers (both users and groups).
+	 * Whenever the user inserts a new document the mandatory reviewers are
+	 * filled in as reviewers.
+	 *
+	 * @return array list of arrays with two elements containing the user id
+	 *         (reviewerUserID) and group id (reviewerGroupID) of the reviewer.
+	 */
+	function getMandatoryReviewers() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT * FROM tblMandatoryReviewers WHERE userID = " . $this->_id;
+		$resArr = $db->getResultArray($queryStr);
+
+		return $resArr;
+	} /* }}} */
+
+	/**
+	 * Get a list of mandatory approvers
+	 * See {link LetoDMS_User::getMandatoryReviewers}
+	 *
+	 * @return array list of arrays with two elements containing the user id
+	 *         (approverUserID) and group id (approverGroupID) of the approver.
+	 */
+	function getMandatoryApprovers() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "SELECT * FROM tblMandatoryApprovers WHERE userID = " . $this->_id;
+		$resArr = $db->getResultArray($queryStr);
+
+		return $resArr;
+	} /* }}} */
+
+	/**
+	 * Set a mandatory reviewer
+	 * This function sets a mandatory reviewer if it isn't already set.
+	 *
+	 * @param integer $id id of reviewer
+	 * @param boolean $isgroup true if $id is a group
+	 * @return boolean true on success, otherwise false
+	 */
+	function setMandatoryReviewer($id, $isgroup=false) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if ($isgroup){
+
+			$queryStr = "SELECT * FROM tblMandatoryReviewers WHERE userID = " . $this->_id . " AND reviewerGroupID = " . $id;
+			$resArr = $db->getResultArray($queryStr);
+			if (count($resArr)!=0) return true;
+
+			$queryStr = "INSERT INTO tblMandatoryReviewers (userID, reviewerGroupID) VALUES (" . $this->_id . ", " . $id .")";
+			$resArr = $db->getResult($queryStr);
+			if (is_bool($resArr) && !$resArr) return false;
+
+		}else{
+
+			$queryStr = "SELECT * FROM tblMandatoryReviewers WHERE userID = " . $this->_id . " AND reviewerUserID = " . $id;
+			$resArr = $db->getResultArray($queryStr);
+			if (count($resArr)!=0) return true;
+
+			$queryStr = "INSERT INTO tblMandatoryReviewers (userID, reviewerUserID) VALUES (" . $this->_id . ", " . $id .")";
+			$resArr = $db->getResult($queryStr);
+			if (is_bool($resArr) && !$resArr) return false;
+		}
+
+	} /* }}} */
+
+	/**
+	 * Set a mandatory approver
+	 * This function sets a mandatory approver if it isn't already set.
+	 *
+	 * @param integer $id id of approver
+	 * @param boolean $isgroup true if $id is a group
+	 * @return boolean true on success, otherwise false
+	 */
+	function setMandatoryApprover($id, $isgroup=false) { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		if ($isgroup){
+
+			$queryStr = "SELECT * FROM tblMandatoryApprovers WHERE userID = " . $this->_id . " AND approverGroupID = " . (int) $id;
+			$resArr = $db->getResultArray($queryStr);
+			if (count($resArr)!=0) return;
+
+			$queryStr = "INSERT INTO tblMandatoryApprovers (userID, approverGroupID) VALUES (" . $this->_id . ", " . $id .")";
+			$resArr = $db->getResult($queryStr);
+			if (is_bool($resArr) && !$resArr) return false;
+
+		}else{
+
+			$queryStr = "SELECT * FROM tblMandatoryApprovers WHERE userID = " . $this->_id . " AND approverUserID = " . (int) $id;
+			$resArr = $db->getResultArray($queryStr);
+			if (count($resArr)!=0) return;
+
+			$queryStr = "INSERT INTO tblMandatoryApprovers (userID, approverUserID) VALUES (" . $this->_id . ", " . $id .")";
+			$resArr = $db->getResult($queryStr);
+			if (is_bool($resArr) && !$resArr) return false;
+		}
+	} /* }}} */
+
+	/**
+	 * Deletes all mandatory reviewers
+	 *
+	 * @return boolean true on success, otherwise false
+	 */
+	function delMandatoryReviewers() { /* {{{ */
+		$db = $this->_dms->getDB();
+		$queryStr = "DELETE FROM tblMandatoryReviewers WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Deletes all mandatory approvers
+	 *
+	 * @return boolean true on success, otherwise false
+	 */
+	function delMandatoryApprovers() { /* {{{ */
+		$db = $this->_dms->getDB();
+
+		$queryStr = "DELETE FROM tblMandatoryApprovers WHERE userID = " . $this->_id;
+		if (!$db->getResult($queryStr)) return false;
+		return true;
+	} /* }}} */
+
+}
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.DBAccess.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.DBAccess.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.DBAccess.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.DBAccess.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,291 @@
+<?php
+/**
+ * Implementation of database access
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe,
+ *             2010 Matteo Lucarelli, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Include the adodb database abstraction
+ */
+require_once "adodb/adodb.inc.php";
+
+/**
+ * Class to represent the database access for the document management
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Matteo Lucarelli, Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal, 2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli, 2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_DatabaseAccess {
+	var $_debug;
+	var $_driver;
+	var $_hostname;
+	var $_database;
+	var $_user;
+	var $_passw;
+	var $_conn;
+	var $_connected;
+	var $_ttreviewid;
+	var $_ttapproveid;
+	var $_ttstatid;
+	var $_ttcontentid;
+	
+	/*
+	Backup functions
+	*/
+
+	/**
+	 * Return list of all database tables
+	 *
+	 * This function is used to retrieve a list of database tables for backup
+	 *
+	 * @return array list of table names
+	 */
+	function TableList() {
+		return $this->_conn->MetaTables("TABLES");
+	}	
+
+	/**
+	 * Constructor of LetoDMS_Core_DatabaseAccess
+	 *
+	 * Sets all database parameters but does not connect.
+	 *
+	 * @param string $driver the database type e.g. mysql, sqlite
+	 * @param string $hostname host of database server
+	 * @param string $user name of user having access to database
+	 * @param string $passw password of user
+	 * @param string $database name of database
+	 */
+	function LetoDMS_Core_DatabaseAccess($driver, $hostname, $user, $passw, $database = false) {
+		$this->_driver = $driver;
+		$this->_hostname = $hostname;
+		$this->_database = $database;
+		$this->_user = $user;
+		$this->_passw = $passw;
+		$this->_connected = false;
+		// $tt*****id is a hack to ensure that we do not try to create the
+		// temporary table twice during a single connection. Can be fixed by
+		// using Views (MySQL 5.0 onward) instead of temporary tables.
+		// CREATE ... IF NOT EXISTS cannot be used because it has the
+		// unpleasant side-effect of performing the insert again even if the
+		// table already exists.
+		//
+		// See createTemporaryTable() method for implementation.
+		$this->_ttreviewid = false;
+		$this->_ttapproveid = false;
+		$this->_ttstatid = false;
+		$this->_ttcontentid = false;
+		$this->_debug = false;
+	}
+
+	/**
+	 * Connect to database
+	 *
+	 * @return boolean true if connection could be established, otherwise false
+	 */
+	function connect() { /* {{{ */
+		$this->_conn = ADONewConnection($this->_driver);
+		if ($this->_database)
+			$this->_conn->Connect($this->_hostname, $this->_user, $this->_passw, $this->_database);
+		else
+			$this->_conn->Connect($this->_hostname, $this->_user, $this->_passw);
+
+		if (!$this->_conn)
+			return false;
+
+		$this->_conn->SetFetchMode(ADODB_FETCH_ASSOC);
+		$this->_conn->Execute('SET NAMES utf8');
+		$this->_connected = true;
+		return true;
+	} /* }}} */
+
+	/**
+	 * Make sure a database connection exisits
+	 *
+	 * This function checks for a database connection. If it does not exists
+	 * it will reconnect.
+	 *
+	 * @return boolean true if connection is established, otherwise false
+	 */
+	function ensureConnected() { /* {{{ */
+		if (!$this->_connected) return $this->connect();
+		else return true;
+	} /* }}} */
+
+	/**
+	 * Sanitize String used in database operations
+	 *
+	 * @param string text
+	 * @return string sanitized string
+	 */
+	function qstr($text) { /* {{{ */
+		return $this->_conn->qstr($text);
+	} /* }}} */
+
+
+	/**
+	 * Execute SQL query and return result
+	 *
+	 * Call this function only with sql query which return data records.
+	 *
+	 * @param string $queryStr sql query
+	 * @return array/boolean data if query could be executed otherwise false
+	 */
+	function getResultArray($queryStr) { /* {{{ */
+		$resArr = array();
+		
+		$res = $this->_conn->Execute($queryStr);
+		if (!$res) {
+			if($this->_debug)
+				echo "error: ".$queryStr."<br />";
+			return false;
+		}
+		$resArr = $res->GetArray();
+		$res->Close();
+		return $resArr;
+	} /* }}} */
+
+	/**
+	 * Execute SQL query
+	 *
+	 * Call this function only with sql query which do not return data records.
+	 *
+	 * @param string $queryStr sql query
+	 * @param boolean $silent not used anymore. This was used when this method
+	 *        still issued an error message
+	 * @return boolean true if query could be executed otherwise false
+	 */
+	function getResult($queryStr, $silent=false) { /* {{{ */
+		$res = $this->_conn->Execute($queryStr);
+		if(!$res) {
+			if($this->_debug)
+				echo "error: ".$queryStr."<br />";
+		}
+		
+		return $res;
+	} /* }}} */
+
+	/**
+	 * Return the id of the last instert record
+	 *
+	 * @return integer id used in last autoincrement
+	 */
+	function getInsertID() { /* {{{ */
+		return $this->_conn->Insert_ID();
+	} /* }}} */
+
+	function getErrorMsg() { /* {{{ */
+		return $this->_conn->ErrorMsg();
+	} /* }}} */
+
+	function getErrorNo() { /* {{{ */
+		return $this->_conn->ErrorNo();
+	} /* }}} */
+
+	/**
+	 * Create various temporary tables to speed up and simplify sql queries
+	 */
+	function createTemporaryTable($tableName, $override=false) { /* {{{ */
+		if (!strcasecmp($tableName, "ttreviewid")) {
+			$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttreviewid` (PRIMARY KEY (`reviewID`), INDEX (`maxLogID`)) ".
+				"SELECT `tblDocumentReviewLog`.`reviewID`, ".
+				"MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ".
+				"FROM `tblDocumentReviewLog` ".
+				"GROUP BY `tblDocumentReviewLog`.`reviewID` ".
+				"ORDER BY `tblDocumentReviewLog`.`reviewLogID`";
+			if (!$this->_ttreviewid) {
+				if (!$this->getResult($queryStr))
+					return false;
+				$this->_ttreviewid=true;
+			}
+			else {
+				if (is_bool($override) && $override) {
+					if (!$this->getResult("DELETE FROM `ttreviewid`"))
+						return false;
+					if (!$this->getResult($queryStr))
+						return false;
+				}
+			}
+			return $this->_ttreviewid;
+		}
+		else if (!strcasecmp($tableName, "ttapproveid")) {
+			$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttapproveid` (PRIMARY KEY (`approveID`), INDEX (`maxLogID`)) ".
+				"SELECT `tblDocumentApproveLog`.`approveID`, ".
+				"MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ".
+				"FROM `tblDocumentApproveLog` ".
+				"GROUP BY `tblDocumentApproveLog`.`approveID` ".
+				"ORDER BY `tblDocumentApproveLog`.`approveLogID`";
+			if (!$this->_ttapproveid) {
+				if (!$this->getResult($queryStr))
+					return false;
+				$this->_ttapproveid=true;
+			}
+			else {
+				if (is_bool($override) && $override) {
+					if (!$this->getResult("DELETE FROM `ttapproveid`"))
+						return false;
+					if (!$this->getResult($queryStr))
+						return false;
+				}
+			}
+			return $this->_ttapproveid;
+		}
+		else if (!strcasecmp($tableName, "ttstatid")) {
+			$queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttstatid` (PRIMARY KEY (`statusID`), INDEX (`maxLogID`)) ".
+				"SELECT `tblDocumentStatusLog`.`statusID`, ".
+				"MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ".
+				"FROM `tblDocumentStatusLog` ".
+				"GROUP BY `tblDocumentStatusLog`.`statusID` ".
+				"ORDER BY `tblDocumentStatusLog`.`statusLogID`";
+			if (!$this->_ttstatid) {
+				if (!$this->getResult($queryStr))
+					return false;
+				$this->_ttstatid=true;
+			}
+			else {
+				if (is_bool($override) && $override) {
+					if (!$this->getResult("DELETE FROM `ttstatid`"))
+						return false;
+					if (!$this->getResult($queryStr))
+						return false;
+				}
+			}
+			return $this->_ttstatid;
+		}
+		else if (!strcasecmp($tableName, "ttcontentid")) {
+			$queryStr = "CREATE TEMPORARY TABLE `ttcontentid` (PRIMARY KEY (`document`), INDEX (`maxVersion`)) ".
+				"SELECT `tblDocumentContent`.`document`, ".
+				"MAX(`tblDocumentContent`.`version`) AS `maxVersion` ".
+				"FROM `tblDocumentContent` ".
+				"GROUP BY `tblDocumentContent`.`document` ".
+				"ORDER BY `tblDocumentContent`.`document`";
+			if (!$this->_ttcontentid) {
+				if (!$this->getResult($queryStr))
+					return false;
+				$this->_ttcontentid=true;
+			}
+			else {
+				if (is_bool($override) && $override) {
+					if (!$this->getResult("DELETE FROM `ttcontentid`"))
+						return false;
+					if (!$this->getResult($queryStr))
+						return false;
+				}
+			}
+			return $this->_ttcontentid;
+		}
+		return false;
+	} /* }}} */
+}
+
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.FileUtils.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.FileUtils.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core/inc.FileUtils.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core/inc.FileUtils.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,174 @@
+<?php
+/**
+ * Implementation of various file system operations
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @license    GPL 2
+ * @version    @version@
+ * @author     Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal,
+ *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+
+/**
+ * Class to represent a user in the document management system
+ *
+ * @category   DMS
+ * @package    LetoDMS_Core
+ * @author     Markus Westphal, Malcolm Cowe, Uwe Steinmann <uwe@steinmann.cx>
+ * @copyright  Copyright (C) 2002-2005 Markus Westphal,
+ *             2006-2008 Malcolm Cowe, 2010 Matteo Lucarelli,
+ *             2010 Uwe Steinmann
+ * @version    Release: 3.3.9
+ */
+class LetoDMS_Core_File {
+	function renameFile($old, $new) {
+		return @rename($old, $new);
+	}
+
+	function removeFile($file) {
+		return @unlink($file);
+	}
+
+	function copyFile($source, $target) {
+		return @copy($source, $target);
+	}
+
+	function moveFile($source, $target) {
+		if (!@copyFile($source, $target))
+			return false;
+		return @removeFile($source);
+	}
+
+	function renameDir($old, $new) {
+		return @rename($old, $new);
+	}
+
+	function makeDir($path) {
+		
+		if( !is_dir( $path ) ){
+			$res=@mkdir( $path , 0777, true);
+			if (!$res) return false;
+		}
+
+		return true;
+
+/* some old code 
+		if (strncmp($path, DIRECTORY_SEPARATOR, 1) == 0) {
+			$mkfolder = DIRECTORY_SEPARATOR;
+		}
+		else {
+			$mkfolder = "";
+		}
+		$path = preg_split( "/[\\\\\/]/" , $path );
+		for(  $i=0 ; isset( $path[$i] ) ; $i++ )
+		{
+			if(!strlen(trim($path[$i])))continue;
+			$mkfolder .= $path[$i];
+
+			if( !is_dir( $mkfolder ) ){
+				$res=@mkdir( "$mkfolder" ,  0777);
+				if (!$res) return false;
+			}
+			$mkfolder .= DIRECTORY_SEPARATOR;
+		}
+
+		return true;
+
+		// patch from alekseynfor safe_mod or open_basedir
+
+		global $settings;
+		$path = substr_replace ($path, "/", 0, strlen($settings->_contentDir));
+		$mkfolder = $settings->_contentDir;
+
+		$path = preg_split( "/[\\\\\/]/" , $path );
+
+		for(  $i=0 ; isset( $path[$i] ) ; $i++ )
+		{
+			if(!strlen(trim($path[$i])))continue;
+			$mkfolder .= $path[$i];
+
+			if( !is_dir( $mkfolder ) ){
+				$res= @mkdir( "$mkfolder" ,  0777);
+				if (!$res) return false;
+			}
+			$mkfolder .= DIRECTORY_SEPARATOR;
+		}
+
+		return true;
+*/
+	}
+
+	function removeDir($path) {
+		$handle = @opendir($path);
+		while ($entry = @readdir($handle) )
+		{
+			if ($entry == ".." || $entry == ".")
+				continue;
+			else if (is_dir($path . $entry))
+			{
+				if (!self::removeDir($path . $entry . "/"))
+					return false;
+			}
+			else
+			{
+				if (!@unlink($path . $entry))
+					return false;
+			}
+		}
+		@closedir($handle);
+		return @rmdir($path);
+	}
+
+	function copyDir($sourcePath, $targetPath) {
+		if (mkdir($targetPath, 0777)) {
+			$handle = @opendir($sourcePath);
+			while ($entry = @readdir($handle) ) {
+				if ($entry == ".." || $entry == ".")
+					continue;
+				else if (is_dir($sourcePath . $entry)) {
+					if (!self::copyDir($sourcePath . $entry . "/", $targetPath . $entry . "/"))
+						return false;
+				} else {
+					if (!@copy($sourcePath . $entry, $targetPath . $entry))
+						return false;
+				}
+			}
+			@closedir($handle);
+		}
+		else
+			return false;
+
+		return true;
+	}
+
+	function moveDir($sourcePath, $targetPath) {
+		if (!copyDir($sourcePath, $targetPath))
+			return false;
+		return removeDir($sourcePath);
+	}
+
+	// code by Kioob (php.net manual)
+	function gzcompressfile($source,$level=false) {
+		$dest=$source.'.gz';
+		$mode='wb'.$level;
+		$error=false;
+		if($fp_out=@gzopen($dest,$mode)) {
+			if($fp_in=@fopen($source,'rb')) {
+				while(!feof($fp_in))
+					@gzwrite($fp_out,fread($fp_in,1024*512));
+				@fclose($fp_in);
+			}
+			else $error=true;
+			@gzclose($fp_out);
+		}
+		else $error=true;
+
+		if($error) return false;
+		else return $dest;
+	}
+}
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/Core.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/Core.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,79 @@
+<?php
+//    MyDMS. Document Management System
+//    Copyright (C) 2010 Uwe Steinmann
+//
+//    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.
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program; if not, write to the Free Software
+//    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+/**
+ * @uses LetoDMS_DatabaseAccess
+ */
+require_once('Core/inc.DBAccess.php');
+
+/**
+ * @uses LetoDMS_DMS
+ */
+require_once('Core/inc.ClassDMS.php');
+
+/**
+ * @uses LetoDMS_Folder
+ */
+require_once('Core/inc.ClassFolder.php');
+
+/**
+ * @uses LetoDMS_Document
+ */
+require_once('Core/inc.ClassDocument.php');
+
+/**
+ * @uses LetoDMS_Group
+ */
+require_once('Core/inc.ClassGroup.php');
+
+/**
+ * @uses LetoDMS_User
+ */
+require_once('Core/inc.ClassUser.php');
+
+/**
+ * @uses LetoDMS_KeywordCategory
+ */
+require_once('Core/inc.ClassKeywords.php');
+
+/**
+ * @uses LetoDMS_DocumentCategory
+ */
+require_once('Core/inc.ClassDocumentCategory.php');
+
+/**
+ * @uses LetoDMS_Notification
+ */
+require_once('Core/inc.ClassNotification.php');
+
+/**
+ * @uses LetoDMS_UserAccess
+ * @uses LetoDMS_GroupAccess
+ */
+require_once('Core/inc.ClassAccess.php');
+
+/**
+ */
+require_once('Core/inc.AccessUtils.php');
+
+/**
+ * @uses LetoDMS_File
+ */
+require_once('Core/inc.FileUtils.php');
+
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/tests/getfoldertree.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/tests/getfoldertree.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/tests/getfoldertree.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/tests/getfoldertree.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,25 @@
+<?php
+include("config.php");
+include("LetoDMS/LetoDMS_Core.php");
+
+$db = new LetoDMS_Core_DatabaseAccess($g_config['type'], $g_config['hostname'], $g_config['user'], $g_config['passwd'], $g_config['name']);
+$db->connect() or die ("Could not connect to db-server \"" . $g_config['hostname'] . "\"");
+
+$dms = new LetoDMS_Core_DMS($db, $g_config['contentDir'], $g_config['contentOffsetDir']);
+
+function tree($folder, $indent='') {
+	echo $indent."D ".$folder->getName()."\n";
+	$subfolders = $folder->getSubFolders();
+	foreach($subfolders as $subfolder) {
+		tree($subfolder, $indent.'  ');
+	}
+	$documents = $folder->getDocuments();
+	foreach($documents as $document) {
+		echo $indent."  ".$document->getName()."\n";
+	}
+}
+
+$folder = $dms->getFolder(1);
+tree($folder);
+
+?>
diff -Nru php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/tests/getusers.php php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/tests/getusers.php
--- php-letodms-core-3.3.4/LetoDMS_Core-3.3.9/tests/getusers.php	1970-01-01 01:00:00.000000000 +0100
+++ php-letodms-core-3.3.9/LetoDMS_Core-3.3.9/tests/getusers.php	2012-09-19 09:33:07.000000000 +0200
@@ -0,0 +1,14 @@
+<?php
+include("config.php");
+include("LetoDMS/LetoDMS_Core.php");
+
+$db = new LetoDMS_Core_DatabaseAccess($g_config['type'], $g_config['hostname'], $g_config['user'], $g_config['passwd'], $g_config['name']);
+$db->connect() or die ("Could not connect to db-server \"" . $g_config['hostname'] . "\"");
+
+$dms = new LetoDMS_Core_DMS($db, $g_config['contentDir'], $g_config['contentOffsetDir']);
+
+$users = $dms->getAllUsers();
+foreach($users as $user)
+	echo $user->getId()." ".$user->getLogin()." ".$user->getFullname()."\n";
+
+?>
diff -Nru php-letodms-core-3.3.4/package.xml php-letodms-core-3.3.9/package.xml
--- php-letodms-core-3.3.4/package.xml	2012-04-17 08:44:18.000000000 +0200
+++ php-letodms-core-3.3.9/package.xml	2012-09-19 09:33:07.000000000 +0200
@@ -18,11 +18,11 @@
   <email />
   <active>no</active>
  </lead>
- <date>2012-04-17</date>
- <time>06:44:18</time>
+ <date>2012-09-19</date>
+ <time>07:33:07</time>
  <version>
-  <release>3.3.4</release>
-  <api>3.3.4</api>
+  <release>3.3.9</release>
+  <api>3.3.9</api>
  </version>
  <stability>
   <release>beta</release>
@@ -30,44 +30,44 @@
  </stability>
  <license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
  <notes>
-- fixed bug in LetoDMS_Core_DocumentFile::getPath()
+- version update to be in sync with letodms application
  </notes>
  <contents>
   <dir baseinstalldir="LetoDMS" name="/">
-   <file baseinstalldir="LetoDMS" md5sum="d00b58672d62990b5c4aee123653ebf7" name="Core/inc.ClassDocument.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="5e0f636e61edfdb7cfec30ff66fc6d3f" name="Core/inc.ClassDocument.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="e9da5e1e9d5d5ac693bfb547e71e0a07" name="Core/inc.ClassFolder.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="be85a7a47ad3767012dae31d25c00fbb" name="Core/inc.ClassFolder.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="1b09214d87b32001a28a8577a3223ec5" name="Core/inc.ClassDMS.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="1f4ec21ccf8f11bd77b5590c066dd79e" name="Core/inc.ClassDMS.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="7921b6d8477fe353c9ff45ddff909f04" name="Core/inc.ClassUser.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="c6e9058c552b9098615595ccd3a55d11" name="Core/inc.ClassUser.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="1e3d197adbc80a3208d9bc2773d3f791" name="Core/inc.ClassGroup.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="964b69e374adf3522c6c49512142a2ac" name="Core/inc.ClassGroup.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="f419ef04da7b685c8f11150843411a69" name="Core/inc.DBAccess.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="0e34c996849453c8f7b392289707ddf2" name="Core/inc.DBAccess.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="73e65928fc303b13d0895eb61fc1ce10" name="Core/inc.AccessUtils.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="5c1177789ce8de9ce925a98d1421c225" name="Core/inc.AccessUtils.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="0621837ebe96a8df4ef49a96658bc14d" name="Core/inc.FileUtils.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="dd02945d571e51b2391d4d204afe121d" name="Core/inc.FileUtils.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="2faf9f3ab7b2f5e5da764cb8b0aa96fc" name="Core/inc.ClassAccess.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="fc4dbf12294df7166927eeb02b3cfdd2" name="Core/inc.ClassAccess.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="a67b226f68dbab283347c034f4f46dc3" name="Core/inc.ClassKeywords.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="5460864e664ded06d97da519984dbd7b" name="Core/inc.ClassKeywords.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="59314c43b99d6f430ac5c70b40cc3cbd" name="Core/inc.ClassNotification.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="7ad6a69b614f4ae0c0211e375eaddaf0" name="Core/inc.ClassNotification.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
-   <file baseinstalldir="LetoDMS" md5sum="35399597280db21ec5ae9544618121c4" name="Core/inc.ClassDocumentCategory.php" role="php">
+   <file baseinstalldir="LetoDMS" md5sum="aa2c3ca651a59bf34f90eba4bdff303e" name="Core/inc.ClassDocumentCategory.php" role="php">
     <tasks:replace from="@package_version@" to="version" type="package-info" />
    </file>
    <file baseinstalldir="LetoDMS" md5sum="3eacf969a09e3aabb0f859836d973903" name="tests/getfoldertree.php" role="test" />
@@ -91,33 +91,33 @@
  <changelog>
   <release>
    <version>
-    <release>3.2.0</release>
-    <api>3.2.0</api>
+    <release>3.0.0</release>
+    <api>3.0.0</api>
    </version>
    <stability>
     <release>stable</release>
     <api>stable</api>
    </stability>
-   <date>2011-07-23</date>
-   <time>08:05:38</time>
+   <date>2010-04-27</date>
    <license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
    <notes>
-New release
+Initial release
    </notes>
   </release>
   <release>
    <version>
-    <release>3.0.0</release>
-    <api>3.0.0</api>
+    <release>3.2.0</release>
+    <api>3.2.0</api>
    </version>
    <stability>
     <release>stable</release>
     <api>stable</api>
    </stability>
-   <date>2010-04-27</date>
+   <date>2011-07-23</date>
+   <time>08:05:38</time>
    <license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
    <notes>
-Initial release
+New release
    </notes>
   </release>
   <release>
@@ -187,5 +187,81 @@
 - fixed bug in LetoDMS_Core_Document::getPath()
    </notes>
   </release>
+  <release>
+   <date>2012-04-11</date>
+   <time>13:34:30</time>
+   <version>
+    <release>3.3.4</release>
+    <api>3.3.4</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>stable</api>
+   </stability>
+   <license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
+   <notes>
+- fixed bug in LetoDMS_Core_DocumentFile::getPath()
+   </notes>
+  </release>
+  <release>
+   <date>2012-04-30</date>
+   <time>17:11:05</time>
+   <version>
+    <release>3.3.5</release>
+    <api>3.3.5</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>stable</api>
+   </stability>
+   <license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
+   <notes>
+- minor corrections
+   </notes>
+  </release>
+  <release>
+   <date>2012-07-16</date>
+   <date>2012-08-25</date>
+   <time>16:04:58</time>
+   <time>22:07:58</time>
+   <version>
+    <release>3.3.6</release>
+    <api>3.3.6</api>
+   </version>
+   <version>
+    <release>3.3.7</release>
+    <api>3.3.7</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>stable</api>
+   </stability>
+   <stability>
+    <release>beta</release>
+    <api>stable</api>
+   </stability>
+   <license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
+   <license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
+   <notes>
+
+   </notes>
+   <release />
+  </release>
+  <release>
+   <date>2012-09-16</date>
+   <time>22:14:08</time>
+   <version>
+    <release>3.3.8</release>
+    <api>3.3.8</api>
+   </version>
+   <stability>
+    <release>beta</release>
+    <api>stable</api>
+   </stability>
+   <license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
+   <notes>
+- more sql injection protection in LetoDMS_Core_User
+   </notes>
+  </release>
  </changelog>
 </package>
