[FEATURE] Make use of File Abstraction Layer in Backend
authorTYPO3 FAL Team <typo3v4@typo3.org>
Fri, 20 Apr 2012 16:29:32 +0000 (18:29 +0200)
committerOliver Hader <oliver.hader@typo3.org>
Sat, 28 Apr 2012 13:14:56 +0000 (15:14 +0200)
Change-Id: I41ba039e98e077fdd5e4a9aff73fe194f3356308
Resolves: #33751
Releases: 6.0
Reviewed-on: http://review.typo3.org/10655
Reviewed-by: Susanne Moog
Tested-by: Susanne Moog
Reviewed-by: Tolleiv Nietsch
Tested-by: Tolleiv Nietsch
Reviewed-by: Oliver Hader
Tested-by: Oliver Hader
37 files changed:
t3lib/class.t3lib_basicfilefunc.php
t3lib/class.t3lib_befunc.php
t3lib/class.t3lib_clipboard.php
t3lib/class.t3lib_extfilefunc.php
t3lib/class.t3lib_foldertree.php
t3lib/class.t3lib_recordlist.php
t3lib/class.t3lib_refindex.php
t3lib/class.t3lib_tceforms.php
t3lib/class.t3lib_tceforms_inline.php
t3lib/class.t3lib_tcemain.php
t3lib/class.t3lib_tstemplate.php
t3lib/class.t3lib_userauthgroup.php
t3lib/jsfunc.inline.js
t3lib/thumbs.php
tests/t3lib/class.t3lib_extfilefuncTest.php [new file with mode: 0644]
typo3/alt_clickmenu.php
typo3/alt_file_navframe.php
typo3/browse_links.php
typo3/browser.php
typo3/class.browse_links.php
typo3/class.db_list.inc
typo3/class.file_list.inc
typo3/class.filelistfoldertree.php
typo3/file_edit.php
typo3/file_newfolder.php
typo3/file_rename.php
typo3/file_upload.php
typo3/js/browse_links.js
typo3/js/tree.js
typo3/jsfunc.placeholder.js [new file with mode: 0644]
typo3/show_item.php
typo3/sysext/beuser/mod/index.php
typo3/sysext/filelist/mod1/file_list.php
typo3/sysext/setup/ext_tables.php
typo3/sysext/setup/locallang_csh_mod.xlf
typo3/sysext/setup/mod/locallang.xlf
typo3/thumbs.php

index 07cf342..355ca03 100644 (file)
@@ -93,6 +93,7 @@ class t3lib_basicFileFunctions {
         * @see typo3/init.php, t3lib_userAuthGroup::returnFilemounts()
         */
        function init($mounts, $f_ext) {
+               t3lib_div::logDeprecatedFunction('All methods in this class should not be used anymore since TYPO3 6.0. Please use corresponding t3lib_file_Storage (fetched via BE_USERS->getFileStorages()), as all functions should be found there (in a cleaner manner).');
                $this->f_ext['webspace']['allow'] = t3lib_div::uniqueList(strtolower($f_ext['webspace']['allow']));
                $this->f_ext['webspace']['deny'] = t3lib_div::uniqueList(strtolower($f_ext['webspace']['deny']));
                $this->f_ext['ftpspace']['allow'] = t3lib_div::uniqueList(strtolower($f_ext['ftpspace']['allow']));
@@ -127,6 +128,7 @@ class t3lib_basicFileFunctions {
         * @return      array           Information about the file in the filepath
         */
        function getTotalFileInfo($wholePath) {
+                       // @todo: deprecate this function, and replace its use in the storage/mounts
                $theuser = getmyuid();
                $info = t3lib_div::split_fileref($wholePath);
                $info['tstamp'] = @filemtime($wholePath);
@@ -226,6 +228,7 @@ class t3lib_basicFileFunctions {
         * @return      boolean
         */
        function checkFileNameLen($fileName) {
+                       // @todo: should go into the LocalDriver in a protected way (not important to the outside world)
                return strlen($fileName) <= $this->maxInputNameLen;
        }
 
@@ -236,6 +239,7 @@ class t3lib_basicFileFunctions {
         * @return      string          Returns the cleaned up directory name if OK, otherwise FALSE.
         */
        function is_directory($theDir) {
+                       // @todo: should go into the LocalDriver in a protected way (not important to the outside world)
                if ($this->isPathValid($theDir)) {
                        $theDir = $this->cleanDirectoryName($theDir);
                        if (@is_dir($theDir)) {
@@ -253,6 +257,7 @@ class t3lib_basicFileFunctions {
         * @see t3lib_div::validPathStr()
         */
        function isPathValid($theFile) {
+                       // @todo: should go into the LocalDriver in a protected way (not important to the outside world)
                return t3lib_div::validPathStr($theFile);
        }
 
@@ -268,6 +273,7 @@ class t3lib_basicFileFunctions {
         * @see t3lib_TCEmain::checkValue()
         */
        function getUniqueName($theFile, $theDest, $dontCheckForUnique = 0) {
+                       // @todo: should go into the LocalDriver in a protected way (not important to the outside world)
                $theDest = $this->is_directory($theDest); // $theDest is cleaned up
                $origFileInfo = t3lib_div::split_fileref($theFile); // Fetches info about path, name, extention of $theFile
                if ($theDest) {
@@ -311,6 +317,7 @@ class t3lib_basicFileFunctions {
         * @see init()
         */
        function checkPathAgainstMounts($thePath) {
+                       // @todo: deprecate this function, now done in the Storage object
                if ($thePath && $this->isPathValid($thePath) && is_array($this->mounts)) {
                        foreach ($this->mounts as $k => $val) {
                                if (t3lib_div::isFirstPartOfStr($thePath, $val['path'])) {
@@ -326,6 +333,7 @@ class t3lib_basicFileFunctions {
         * @return      string          The key to the first mount inside PATH_site."fileadmin" found, otherwise nothing is returned.
         */
        function findFirstWebFolder() {
+                       // @todo: where and when to use this function?
                if (is_array($this->mounts)) {
                        foreach ($this->mounts as $k => $val) {
                                if (t3lib_div::isFirstPartOfStr($val['path'], PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'])) {
@@ -343,6 +351,7 @@ class t3lib_basicFileFunctions {
         * @return      string          The processed input path
         */
        function blindPath($thePath) {
+                       // @todo: where and when to use this function?
                $k = $this->checkPathAgainstMounts($thePath);
                if ($k) {
                        $name = '';
@@ -359,6 +368,7 @@ class t3lib_basicFileFunctions {
         * @return      string          Returns the path if found, otherwise nothing if error.
         */
        function findTempFolder() {
+                       // @todo: where and when to use this function?
                if ($this->tempFN && is_array($this->mounts)) {
                        foreach ($this->mounts as $k => $val) {
                                $tDir = $val['path'] . $this->tempFN;
@@ -383,6 +393,7 @@ class t3lib_basicFileFunctions {
         * @return      string          Output string
         */
        function cleanDirectoryName($theDir) {
+                       // @todo: should go into the LocalDriver in a protected way (not important to the outside world)
                return preg_replace('/[\/\. ]*$/', '', $this->rmDoubleSlash($theDir));
        }
 
@@ -393,6 +404,7 @@ class t3lib_basicFileFunctions {
         * @return      string          Returns the converted string
         */
        function rmDoubleSlash($string) {
+                       // @todo: should go into the LocalDriver in a protected way (not important to the outside world)
                return str_replace('//', '/', $string);
        }
 
@@ -403,6 +415,8 @@ class t3lib_basicFileFunctions {
         * @return      string          Output string with a slash in the end (if not already there)
         */
        function slashPath($path) {
+                       // @todo: should go into the LocalDriver in a protected way (not important to the outside world)
+                       // @todo: should be done with rtrim($path, '/') . '/';
                if (substr($path, -1) != '/') {
                        return $path . '/';
                }
index 1c5a250..79e9c25 100644 (file)
@@ -1547,29 +1547,21 @@ final class t3lib_BEfunc {
         * @param       string          Table name for $row (present in TCA)
         * @param       string          $field is pointing to the field with the list of image files
         * @param       string          Back path prefix for image tag src="" field
-        * @param       string          Optional: $thumbScript os by default 'thumbs.php' if you don't set it otherwise
+        * @param       string          Optional: $thumbScript - not used anymore since FAL
         * @param       string          Optional: $uploaddir is the directory relative to PATH_site where the image files from the $field value is found (Is by default set to the entry in $GLOBALS['TCA'] for that field! so you don't have to!)
         * @param       boolean         If set, uploaddir is NOT prepended with "../"
         * @param       string          Optional: $tparams is additional attributes for the image tags
         * @param       integer         Optional: $size is [w]x[h] of the thumbnail. 56 is default.
-        * @return      string          Thumbnail image tag.
+        * @param boolean $linkInfoPopup Whether to wrap with a link opening the info popup
+        * @return string Thumbnail image tag.
         */
-       public static function thumbCode($row, $table, $field, $backPath, $thumbScript = '', $uploaddir = NULL, $abs = 0, $tparams = '', $size = '') {
+       public static function thumbCode($row, $table, $field, $backPath, $thumbScript = '', $uploaddir = NULL, $abs = 0, $tparams = '', $size = '', $linkInfoPopup = TRUE) {
                        // Load table.
                t3lib_div::loadTCA($table);
+               $tcaConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
 
-                       // Find uploaddir automatically
-               $uploaddir = (is_null($uploaddir)) ? $GLOBALS['TCA'][$table]['columns'][$field]['config']['uploadfolder'] : $uploaddir;
-               $uploaddir = preg_replace('#/$#', '', $uploaddir);
-
-                       // Set thumbs-script:
-               if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails']) {
-                       $thumbScript = 'gfx/notfound_thumb.gif';
-               } elseif (!$thumbScript) {
-                       $thumbScript = 'thumbs.php';
-               }
                        // Check and parse the size parameter
-               $sizeParts = array();
+               $sizeParts = array(64, 64);
                if ($size = trim($size)) {
                        $sizeParts = explode('x', $size . 'x' . $size);
                        if (!intval($sizeParts[0])) {
@@ -1577,63 +1569,110 @@ final class t3lib_BEfunc {
                        }
                }
 
-                       // Traverse files:
-               $thumbs = explode(',', $row[$field]);
                $thumbData = '';
-               foreach ($thumbs as $theFile) {
-                       if (trim($theFile)) {
-                               $fI = t3lib_div::split_fileref($theFile);
-                               $ext = $fI['fileext'];
-                                       // New 190201 start
-                               $max = 0;
-                               if (t3lib_div::inList('gif,jpg,png', $ext)) {
-                                       $imgInfo = @getimagesize(PATH_site . $uploaddir . '/' . $theFile);
-                                       if (is_array($imgInfo)) {
-                                               $max = max($imgInfo[0], $imgInfo[1]);
-                                       }
-                               }
-                                       // use the original image if it's size fits to the thumbnail size
-                               if ($max && $max <= (count($sizeParts) && max($sizeParts) ? max($sizeParts) : 56)) {
-                                       $theFile = $url = ($abs ? '' : '../') . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
-                                       $onClick = 'top.launchView(\'' . $theFile . '\',\'\',\'' . $backPath . '\');return false;';
-                                       $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '"><img src="' . $backPath . $url . '" ' . $imgInfo[3] . ' hspace="2" border="0" title="' . trim($url) . '"' . $tparams . ' alt="" /></a> ';
-                                       // New 190201 stop
-                               } elseif ($ext == 'ttf' || t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $ext)) {
-                                       $theFile_abs = PATH_site . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
-                                       $theFile = ($abs ? '' : '../') . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
-
-                                       if (!is_readable($theFile_abs)) {
-                                               $flashMessage = t3lib_div::makeInstance(
-                                                       't3lib_FlashMessage',
-                                                               $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_missing_text') . ' <abbr title="' . $theFile_abs . '">' . $theFile . '</abbr>',
-                                                       $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_missing'),
-                                                       t3lib_FlashMessage::ERROR
-                                               );
-                                               $thumbData .= $flashMessage->render();
-                                               continue;
-                                       }
 
-                                       $check = basename($theFile_abs) . ':' . filemtime($theFile_abs) . ':' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
-                                       $params = '&file=' . rawurlencode($theFile);
-                                       $params .= $size ? '&size=' . $size : '';
-                                       $params .= '&md5sum=' . md5($check);
+                       // FAL references
+               if ($tcaConfig['type'] === 'inline') {
+                       $referenceUids = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                               'uid',
+                               'sys_file_reference',
+                                       'tablenames = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($table, 'sys_file_reference')
+                                               . ' AND fieldname=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($field, 'sys_file_reference')
+                                               . ' AND uid_foreign=' . intval($row['uid'])
+                                               . self::deleteClause('sys_file_reference')
+                                               . self::versioningPlaceholderClause('sys_file_reference')
+                       );
+
+                       foreach ($referenceUids as $referenceUid) {
+                               $fileReferenceObject = t3lib_file_Factory::getInstance()->getFileReferenceObject($referenceUid['uid']);
+                               $fileObject = $fileReferenceObject->getOriginalFile();
+
+                                       // web image
+                               if (t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileReferenceObject->getExtension())) {
+                                       $imageUrl = $fileObject->process(t3lib_file_ProcessedFile::CONTEXT_IMAGEPREVIEW, array(
+                                               'width'  => $sizeParts[0],
+                                               'height' => $sizeParts[1],
+                                       ))->getPublicUrl(TRUE);
+                                       $imgTag = '<img src="' . $imageUrl . '" alt="' . htmlspecialchars($fileReferenceObject->getName()) . '" />';
 
-                                       $url = $thumbScript . '?' . $params;
-                                       $onClick = 'top.launchView(\'' . $theFile . '\',\'\',\'' . $backPath . '\');return false;';
-                                       $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '"><img src="' . htmlspecialchars($backPath . $url) . '" hspace="2" border="0" title="' . trim($theFile) . '"' . $tparams . ' alt="" /></a> ';
                                } else {
                                                // Icon
-                                       $theFile = ($abs ? '' : '../') . ($uploaddir ? $uploaddir . '/' : '') . trim($theFile);
-                                       $fileIcon = t3lib_iconWorks::getSpriteIconForFile(
-                                               strtolower($ext),
-                                               array('title' => htmlspecialchars(trim($theFile)))
+                                       $imgTag = t3lib_iconWorks::getSpriteIconForFile(
+                                               strtolower($fileObject->getExtension()),
+                                               array('title' => $fileObject->getName())
                                        );
+                               }
+
+                               if ($linkInfoPopup) {
+                                       $onClick = 'top.launchView(\'_FILE\',\'' . $fileObject->getUid() . '\',\'' . $backPath . '\'); return false;';
+                                       $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $imgTag . '</a> ';
+                               } else {
+                                       $thumbData .= $imgTag;
+                               }
+                       }
+
+                       // Regular file references (as it only uses old syntax for thumbcode)
+               } else {
+                               // Find uploaddir automatically
+                       if (is_null($uploaddir)) {
+                               $uploaddir = $GLOBALS['TCA'][$table]['columns'][$field]['config']['uploadfolder'];
+                       }
+                       $uploaddir = rtrim($uploaddir, '/');
+
+                               // Traverse files:
+                       $thumbs = t3lib_div::trimExplode(',', $row[$field], TRUE);
+                       $thumbData = '';
+
+                       foreach ($thumbs as $theFile) {
+                               if ($theFile) {
+                                       $fileName = trim($uploaddir . '/' . $theFile, '/');
+                                       $fileObject = t3lib_file_Factory::getInstance()->retrieveFileOrFolderObject($fileName);
+
+                                       $fileExtension = $fileObject->getExtension();
+
+                                       if ($fileExtension == 'ttf' || t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileExtension)) {
+                                               $imageUrl = $fileObject->process(t3lib_file_ProcessedFile::CONTEXT_IMAGEPREVIEW, array(
+                                                       'width'  => $sizeParts[0],
+                                                       'height' => $sizeParts[1],
+                                               ))->getPublicUrl(TRUE);
+
+                                               if (!$fileObject->checkActionPermission('read')) {
+                                                       /** @var $flashMessage t3lib_FlashMessage */
+                                                       $flashMessage = t3lib_div::makeInstance(
+                                                               't3lib_FlashMessage',
+                                                               $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_missing_text') . ' <abbr title="' . htmlspecialchars($fileObject->getName()) . '">' . htmlspecialchars($fileObject->getName()) . '</abbr>',
+                                                               $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xml:warning.file_missing'),
+                                                               t3lib_FlashMessage::ERROR
+                                                       );
+                                                       $thumbData .= $flashMessage->render();
+                                                       continue;
+                                               }
+
+                                               $image = '<img src="' . htmlspecialchars($imageUrl) . '" hspace="2" border="0" title="' . htmlspecialchars($fileObject->getName()) . '"' . $tparams . ' alt="" />';
+                                               if ($linkInfoPopup) {
+                                                       $onClick = 'top.launchView(\'_FILE\', \'' . $fileName . '\',\'\',\'' . $backPath . '\');return false;';
+                                                       $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $image . '</a> ';
+                                               } else {
+                                                       $thumbData .= $image;
+                                               }
+                                       } else {
+                                                       // Gets the icon
+                                               $fileIcon = t3lib_iconWorks::getSpriteIconForFile(
+                                                       $fileExtension,
+                                                       array('title' => $fileObject->getName())
+                                               );
 
-                                       $onClick = 'top.launchView(\'' . $theFile . '\',\'\',\'' . $backPath . '\');return false;';
-                                       $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $fileIcon . '</a> ';
+                                               if ($linkInfoPopup) {
+                                                       $onClick = 'top.launchView(\'_FILE\', \'' . $fileName . '\',\'\',\'' . $backPath . '\'); return false;';
+                                                       $thumbData .= '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' . $fileIcon . '</a> ';
+                                               } else {
+                                                       $thumbData .= $fileIcon;
+                                               }
+                                       }
                                }
                        }
                }
+
                return $thumbData;
        }
 
index 6374a7f..0026daf 100644 (file)
@@ -360,20 +360,28 @@ class t3lib_clipboard {
                                        $bgColClass = ($table == '_FILE' && $this->fileMode) || ($table != '_FILE' && !$this->fileMode) ? 'bgColor4-20' : 'bgColor4';
 
                                        if ($table == '_FILE') { // Rendering files/directories on the clipboard:
-                                               if (file_exists($v) && t3lib_div::isAllowedAbsPath($v)) {
-                                                       $fI = pathinfo($v);
-                                                       $icon = is_dir($v) ? 'folder.gif' : t3lib_BEfunc::getFileIcon(strtolower($fI['extension']));
-                                                       $size = ' (' . t3lib_div::formatSize(filesize($v)) . 'bytes)';
-                                                       $icon = t3lib_iconWorks::getSpriteIconForFile(is_dir($v) ? 'folder' : strtolower($fI['extension']), array('style' => 'margin: 0 20px;', 'title' => htmlspecialchars($fI['basename'] . $size)));
-                                                       $thumb = $this->clipData['_setThumb'] ? (t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fI['extension']) ? t3lib_BEfunc::getThumbNail($this->backPath . 'thumbs.php', $v, ' vspace="4"') : '') : '';
+                                               $fileObject = t3lib_file_Factory::getInstance()->retrieveFileOrFolderObject($v);
+                                               if ($fileObject) {
+                                                       $thumb = '';
+                                                       $folder = $fileObject instanceof t3lib_file_Folder;
+                                                       $size = ($folder ? '' : '(' . t3lib_div::formatSize($fileObject->getSize()) . 'bytes)');
+                                                       $icon = t3lib_iconWorks::getSpriteIconForFile(
+                                                               $folder ? 'folder' : strtolower($fileObject->getExtension()),
+                                                               array('style' => 'margin: 0 20px;', 'title' => $fileObject->getName() . ' ' . $size)
+                                                       );
+
+                                                       if ($this->clipData['_setThumb'] && t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
+                                                               $thumb = '<br />' . t3lib_BEfunc::getThumbNail($this->backPath . 'thumbs.php', $v, ' vspace="4"');
+                                                       }
+
 
                                                        $lines[] = '
                                                                <tr>
                                                                        <td class="' . $bgColClass . '">' . $icon . '</td>
-                                                                       <td class="' . $bgColClass . '" nowrap="nowrap" width="95%">&nbsp;' . $this->linkItemText(htmlspecialchars(t3lib_div::fixed_lgd_cs(basename($v), $GLOBALS['BE_USER']->uc['titleLen'])), $v) .
-                                                                       ($pad == 'normal' ? (' <strong>(' . ($this->clipData['normal']['mode'] == 'copy' ? $this->clLabel('copy', 'cm') : $this->clLabel('cut', 'cm')) . ')</strong>') : '') . '&nbsp;' . ($thumb ? '<br />' . $thumb : '') . '</td>
+                                                                       <td class="' . $bgColClass . '" nowrap="nowrap" width="95%">&nbsp;' . $this->linkItemText(htmlspecialchars(t3lib_div::fixed_lgd_cs($fileObject->getName(), $GLOBALS['BE_USER']->uc['titleLen'])), $fileObject->getName()) .
+                                                                       ($pad == 'normal' ? (' <strong>(' . ($this->clipData['normal']['mode'] == 'copy' ? $this->clLabel('copy', 'cm') : $this->clLabel('cut', 'cm')) . ')</strong>') : '') . '&nbsp;' . $thumb . '</td>
                                                                        <td class="' . $bgColClass . '" align="center" nowrap="nowrap">' .
-                                                                       '<a href="#" onclick="' . htmlspecialchars('top.launchView(\'' . $v . '\', \'\'); return false;') . '">' . t3lib_iconWorks::getSpriteIcon('actions-document-info', array('title' => $this->clLabel('info', 'cm'))) . '</a>' .
+                                                                       '<a href="#" onclick="' . htmlspecialchars('top.launchView(\'' . $table . '\', \'' . $v . '\'); return false;') . '">' . t3lib_iconWorks::getSpriteIcon('actions-document-info', array('title' => $this->clLabel('info', 'cm'))) . '</a>' .
                                                                        '<a href="' . htmlspecialchars($this->removeUrl('_FILE', t3lib_div::shortmd5($v))) . '#clip_head">' . t3lib_iconWorks::getSpriteIcon('actions-selection-delete', array('title' => $this->clLabel('removeItem'))) . '</a>' .
                                                                        '</td>
                                                                </tr>';
@@ -780,7 +788,7 @@ class t3lib_clipboard {
                                                $this->changed = 1;
                                        }
                                } else {
-                                       if (!$v || !file_exists($v)) {
+                                       if (!$v || t3lib_file_Factory::getInstance()->retrieveFileOrFolderObject($v) === NULL) {
                                                unset($this->clipData[$this->current]['el'][$k]);
                                                $this->changed = 1;
                                        }
index 139aaa1..c54901c 100644 (file)
@@ -66,9 +66,6 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
 
                // External static variables:
                // Notice; some of these are overridden in the start() method with values from $GLOBALS['TYPO3_CONF_VARS']['BE']
-       var $maxCopyFileSize = 10000; // max copy size (kb) for files
-       var $maxMoveFileSize = 10000; // max move size (kb) for files
-       var $maxUploadFileSize = 10000; // max upload size (kb) for files. Remember that PHP has an inner limit often set to 2 MB
        var $unzipPath = ''; // Path to unzip-program (with trailing '/')
        var $dontCheckForUnique = 0; // If set, the uploaded files will overwrite existing files.
 
@@ -90,34 +87,40 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
        );
 
        var $recyclerFN = '_recycler_'; // This is regarded to be the recycler folder
-       var $useRecycler = 1; // 0 = no, 1 = if available, 2 = always
 
-               // Internal, static:
-       var $PHPFileFunctions = 0; // If set, all fileoperations are done by the default PHP-functions. This is necessary under windows! On UNIX the system commands by exec() can be used
-       var $dont_use_exec_commands = 0; // This is necessary under windows!
+       /**
+        * Whether to use recycler (0 = no, 1 = if available, 2 = always)
+        *
+        * @var integer
+        * @deprecated since TYPO3 6.0
+        */
+       var $useRecycler = 1;
 
                // Internal, dynamic:
        var $internalUploadMap = array(); // Will contain map between upload ID and the final filename
 
        var $lastError = '';
 
+       /**
+        * @var array
+        */
+       protected $fileCmdMap;
+
+       /**
+        * The File Factory
+        *
+        * @var t3lib_file_Factory
+        */
+       protected $fileFactory;
 
        /**
         * Initialization of the class
         *
-        * @param       array           The $file array with the commands to execute. See "TYPO3 Core API" document
-        * @return      void
+        * @param array $fileCmds Array with the commands to execute. See "TYPO3 Core API" document
+        * @return void
         */
        function start($fileCmds) {
 
-                       // Configure settings from TYPO3_CONF_VARS:
-               if (TYPO3_OS == 'WIN' || $GLOBALS['TYPO3_CONF_VARS']['BE']['disable_exec_function']) {
-                       $this->PHPFileFunctions = 1;
-                       $this->dont_use_exec_commands = 1;
-               } else {
-                       $this->PHPFileFunctions = $GLOBALS['TYPO3_CONF_VARS']['BE']['usePHPFileFunctions'];
-               }
-
                $unzipPath = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path']);
                if (substr($unzipPath, -1) !== '/' && is_dir($unzipPath)) {
                        // Make sure the path ends with a slash
@@ -125,12 +128,8 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
                }
                $this->unzipPath = $unzipPath;
 
-               $maxFileSize = intval($GLOBALS['TYPO3_CONF_VARS']['BE']['maxFileSize']);
-               if ($maxFileSize > 0) {
-                       $this->maxCopyFileSize = $maxFileSize;
-                       $this->maxMoveFileSize = $maxFileSize;
-               }
-               $this->maxUploadFileSize = t3lib_div::getMaxUploadFileSize();
+                       // Initialize Object Factory
+               $this->fileFactory = t3lib_file_Factory::getInstance();
 
                        // Initializing file processing commands:
                $this->fileCmdMap = $fileCmds;
@@ -306,14 +305,20 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
         *
         * @param       string          Takes a valid Path ($theFile)
         * @return      string          Returns the path (without trailing slash) of the closest recycle-folder if found. Else FALSE.
+        *
+        * @todo To be put in Storage with a better concept
+        * @deprecated since TYPO3 6.0, use t3lib_file_Storage method instead
         */
        function findRecycler($theFile) {
+               t3lib_div::logDeprecatedFunction();
+
                if ($this->isPathValid($theFile)) {
                        $theFile = $this->cleanDirectoryName($theFile);
                        $fI = t3lib_div::split_fileref($theFile);
                        $c = 0;
-                       while ($this->checkPathAgainstMounts($fI['path']) && $c < 20) {
+                               // !!! Method has been put in the storage, can be saftely removed
                                $rDir = $fI['path'] . $this->recyclerFN;
+                       while ($this->checkPathAgainstMounts($fI['path']) && $c < 20) {
                                if (@is_dir($rDir) && $this->recyclerFN != $fI['file']) {
                                        return $rDir;
                                }
@@ -358,510 +363,406 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
         * @return      boolean         Returns TRUE upon success
         */
        function func_delete($cmds) {
+               $result = FALSE;
+
                if (!$this->isInit) {
-                       return FALSE;
+                       return $result;
                }
 
-                       // Checking path:
-               $theFile = $cmds['data'];
-               if (!$this->isPathValid($theFile)) {
-                       $this->writelog(4, 2, 101, 'Target "%s" had invalid path (".." and "//" is not allowed in path).', array($theFile));
-                       return FALSE;
-               }
+                       // Example indentifier for $cmds['data'] => "4:mypath/tomyfolder/myfile.jpg"
+                       // for backwards compatibility: the combined file identifier was the path+filename
+               $fileObject = $this->getFileObject($cmds['data']);
 
-                       // Recycler moving or not?
-               if ($this->useRecycler && $recyclerPath = $this->findRecycler($theFile)) {
-                               // If a recycler is found, the deleted items is moved to the recycler and not just deleted.
-                       $newCmds = array();
-                       $newCmds['data'] = $theFile;
-                       $newCmds['target'] = $recyclerPath;
-                       $newCmds['altName'] = 1;
-                       $this->func_move($newCmds);
-                       $this->writelog(4, 0, 4, 'Item "%s" moved to recycler at "%s"', array($theFile, $recyclerPath));
-                       return TRUE;
-               } elseif ($this->useRecycler != 2) { // if $this->useRecycler==2 then we cannot delete for real!!
-                       if (@is_file($theFile)) { // If we are deleting a file...
-                               if (!$this->actionPerms['deleteFile']) {
-                                       $this->writelog(4, 1, 112, 'You are not allowed to delete files', '');
-                                       return FALSE;
-                               }
-                               if (!$this->checkPathAgainstMounts($theFile)) {
-                                       $this->writelog(4, 1, 111, 'Target was not within your mountpoints! T="%s"', array($theFile));
-                                       return FALSE;
-                               }
-                               if (@unlink($theFile)) {
-                                       $this->writelog(4, 0, 1, 'File "%s" deleted', array($theFile));
-                                       return TRUE;
-                               } else {
-                                       $this->writelog(4, 1, 110, 'Could not delete file "%s". Write-permission problem?', array($theFile));
-                               }
-                               // FINISHED deleting file
+                       // @todo implement the recycler feature which has been removed from the original implementation
+                       // $this->writelog(4, 0, 4, 'Item "%s" moved to recycler at "%s"', array($theFile, $recyclerPath));
 
-                       } elseif (@is_dir($theFile)) { // if we're deleting a folder
-                               if (!$this->actionPerms['deleteFolder']) {
-                                       $this->writelog(4, 1, 123, 'You are not allowed to delete directories', '');
-                                       return FALSE;
-                               }
+                       // Copies the file
+               if ($fileObject instanceof t3lib_file_File) {
+                       $refIndexRecords = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                               '*',
+                               'sys_refindex',
+                               "ref_table='sys_file' AND ref_uid=" . $fileObject->getUid()
+                       );
 
-                               $theFile = $this->is_directory($theFile);
-                               if (!$theFile) {
-                                       $this->writelog(4, 2, 122, 'Target seemed not to be a directory! (Shouldn\'t happen here!)', '');
-                                       return FALSE;
-                               }
-                               if (!$this->checkPathAgainstMounts($theFile)) {
-                                       $this->writelog(4, 1, 121, 'Target was not within your mountpoints! T="%s"', array($theFile));
-                                       return FALSE;
-                               }
-                                       // I choose not to append '/' to $theFile here as this will prevent us from deleting mounts!! (which makes sense to me...)
-                               if ($this->actionPerms['deleteFolderRecursively']) {
-                                       if (t3lib_div::rmdir($theFile, TRUE)) {
-                                               $this->writelog(4, 0, 2, 'Directory "%s" deleted recursively!', array($theFile));
-                                               return TRUE;
-                                       } else {
-                                               $this->writelog(4, 2, 119, 'Directory "%s" WAS NOT deleted recursively! Write-permission problem?', array($theFile));
-                                       }
-                               } else {
-                                       if (@rmdir($theFile)) {
-                                               $this->writelog(4, 0, 3, 'Directory "%s" deleted', array($theFile));
-                                               return TRUE;
-                                       } else {
-                                               $this->writelog(4, 1, 120, 'Could not delete directory! Write-permission problem? Is directory "%s" empty? (You are not allowed to delete directories recursively).', array($theFile));
+                       if (count($refIndexRecords) > 0) {
+                               $shortcutContent = array();
+
+                               foreach ($refIndexRecords as $row) {
+                                       $shortcutRecord = NULL;
+                                       $shortcutRecord = t3lib_BEfunc::getRecord($row['tablename'], $row['recuid']);
+                                       if (is_array($shortcutRecord) && $row['tablename'] !== 'sys_file_reference') {
+                                               $icon = t3lib_iconWorks::getSpriteIconForRecord($row['tablename'], $shortcutRecord);
+
+                                               $onClick = 'showClickmenu("' . $row['tablename'] . '", "' . $row['recuid'] . '", "1", "+info,history,edit,delete", "|", "");return false;';
+                                               $shortcutContent[] = '<a href="#" oncontectmenu="' . htmlspecialchars($onClick) . '" onclick="' . htmlspecialchars($onClick) . '">' . $icon . '</a>' .
+                                                       htmlspecialchars(t3lib_BEfunc::getRecordTitle($row['tablename'], $shortcutRecord) . '  [' . t3lib_BEfunc::getRecordPath($shortcutRecord['pid'], '', 80) . ']');
                                        }
                                }
-                               // FINISHED copying directory
+
+                               $out = '<p>The file cannot be deleted since it is still used at the following places:<br />' .
+                                               implode('<br />', $shortcutContent) . '</p>';
+
+                               $flashMessage = t3lib_div::makeInstance(
+                                       't3lib_flashMessage',
+                                       $out,
+                                       'File not deleted',
+                                       t3lib_FlashMessage::WARNING,
+                                       TRUE
+                               );
+                               t3lib_FlashMessageQueue::addMessage($flashMessage);
+                               return;
 
                        } else {
-                               $this->writelog(4, 2, 130, 'The item was not a file or directory! "%s"', array($theFile));
+                               try {
+                                       $result = $fileObject->delete();
+                               } catch (t3lib_file_exception_InsufficientFileAccessPermissionsException $e) {
+                                       $this->writelog(4, 1, 112, 'You are not allowed to access the file', array($fileObject->getIdentifier()));
+                               } catch (t3lib_file_exception_NotInMountPointException $e) {
+                                       $this->writelog(4, 1, 111, 'Target was not within your mountpoints! T="%s"', array($fileObject->getIdentifier()));
+                               } catch (RuntimeException $e) {
+                                       $this->writelog(4, 1, 110, 'Could not delete file "%s". Write-permission problem?', array($fileObject->getIdentifier()));
+                               }
+                                       // Log success
+                               $this->writelog(4, 0, 1, 'File "%s" deleted', array($fileObject->getIdentifier()));
                        }
+                       // Working on a folder
                } else {
-                       $this->writelog(4, 1, 131, 'No recycler found!', '');
+                       try {
+                               /** @var $fileObject t3lib_file_FolderInterface */
+                               $result = $fileObject->delete(TRUE);
+                       } catch (t3lib_file_exception_InsufficientFileAccessPermissionsException $e) {
+                               $this->writelog(4, 1, 123, 'You are not allowed to access the directory', array($fileObject->getIdentifier()));
+                       } catch (t3lib_file_exception_NotInMountPointException $e) {
+                               $this->writelog(4, 1, 121, 'Target was not within your mountpoints! T="%s"', array($fileObject->getIdentifier()));
+                       } catch (RuntimeException $e) {
+                               $this->writelog(4, 1, 120, 'Could not delete directory! Write-permission problem? Is directory "%s" empty? (You are not allowed to delete directories recursively).', array($fileObject->getIdentifier()));
+                       }
+
+                               // Log success
+                       $this->writelog(4, 0, 3, 'Directory "%s" deleted', array($fileObject->getIdentifier()));
                }
+
+               return $result;
+       }
+
+       /**
+        * Gets a File or a Folder object from an identifier [storage]:[fileId]
+        *
+        * @param string $identifier
+        * @return t3lib_file_Folder|t3lib_file_File
+        */
+       protected function getFileObject($identifier) {
+               $object = $this->fileFactory->retrieveFileOrFolderObject($identifier);
+
+               if (!is_object($object)) {
+                       throw new t3lib_file_exception_InvalidFileException(
+                               'The item ' . $identifier . ' was not a file or directory!!',
+                               1320122453
+                       );
+               }
+
+               return $object;
        }
 
        /**
         * Copying files and folders (action=2)
         *
-        * @param       array           $cmds['data'] is the file/folder to copy. $cmds['target'] is the path where to copy to. $cmds['altName'] (boolean): If set, another filename is found in case the target already exists
-        * @return      string          Returns the new filename upon success
+        * $cmds['data'] (string): The file/folder to copy
+        * + example "4:mypath/tomyfolder/myfile.jpg")
+        * + for backwards compatibility: the identifier was the path+filename
+        * $cmds['target'] (string): The path where to copy to.
+        * + example "2:targetpath/targetfolder/"
+        * $cmds['altName'] (string): Use an alternative name if the target already exists
+        *
+        * @param array $cmds Command details as described above
+        * @return t3lib_file_File
         */
-       function func_copy($cmds) {
+       protected function func_copy($cmds) {
                if (!$this->isInit) {
                        return FALSE;
                }
 
-                       // Initialize and check basic conditions:
-               $theFile = $cmds['data'];
-               $theDest = $this->is_directory($cmds['target']); // Clean up destination directory
-               $altName = $cmds['altName'];
-               if (!$theDest) {
+               $sourceFileObject = $this->getFileObject($cmds['data']);
+               /** @var $targetFolderObject t3lib_file_Folder */
+               $targetFolderObject = $this->getFileObject($cmds['target']);
+
+                       // basic check
+               if (!($targetFolderObject instanceof t3lib_file_Folder)) {
                        $this->writelog(2, 2, 100, 'Destination "%s" was not a directory', array($cmds['target']));
                        return FALSE;
                }
-               if (!$this->isPathValid($theFile) || !$this->isPathValid($theDest)) {
-                       $this->writelog(2, 2, 101, 'Target or destination had invalid path (".." and "//" is not allowed in path). T="%s", D="%s"', array($theFile, $theDest));
-                       return FALSE;
-               }
 
-                       // Processing of file or directory.
-               if (@is_file($theFile)) { // If we are copying a file...
-                       if (!$this->actionPerms['copyFile']) {
+                       // if this is TRUE, we append _XX to the file name if
+               $appendSuffixOnConflict = (string) $cmds['altName'];
+               $resultObject = NULL;
+
+                       // copying the file
+               if ($sourceFileObject instanceof t3lib_file_File) {
+                       try {
+                               $conflictMode = ($appendSuffixOnConflict !== '') ? 'renameNewFile' : 'cancel';
+                               $resultObject = $sourceFileObject->copyTo($targetFolderObject, NULL, $conflictMode);
+                       } catch (t3lib_file_exception_InsufficientUserPermissionsException $e) {
                                $this->writelog(2, 1, 114, 'You are not allowed to copy files', '');
-                               return FALSE;
-                       }
-                       if (filesize($theFile) >= ($this->maxCopyFileSize * 1024)) {
-                               $this->writelog(2, 1, 113, 'File "%s" exceeds the size-limit of %s bytes', array($theFile, $this->maxCopyFileSize * 1024));
-                               return FALSE;
-                       }
-                       $fI = t3lib_div::split_fileref($theFile);
-                       if ($altName) { // If altName is set, we're allowed to create a new filename if the file already existed
-                               $theDestFile = $this->getUniqueName($fI['file'], $theDest);
-                               $fI = t3lib_div::split_fileref($theDestFile);
-                       } else {
-                               $theDestFile = $theDest . '/' . $fI['file'];
-                       }
-                       if (!$theDestFile || file_exists($theDestFile)) {
-                               $this->writelog(2, 1, 112, 'File "%s" already exists!', array($theDestFile));
-                               return FALSE;
-                       }
-                       if (!$this->checkIfAllowed($fI['fileext'], $theDest, $fI['file'])) {
-                               $this->writelog(2, 1, 111, 'Extension of file name "%s" is not allowed in "%s"!', array($fI['file'], $theDest . '/'));
-                               return FALSE;
-                       }
-                       if (!$this->checkPathAgainstMounts($theDestFile) || !$this->checkPathAgainstMounts($theFile)) {
-                               $this->writelog(2, 1, 110, 'Target or destination was not within your mountpoints! T="%s", D="%s"', array($theFile, $theDestFile));
-                               return FALSE;
+                       } catch (t3lib_file_exception_InsufficientFileAccessPermissionsException $e) {
+                               $this->writelog(2, 1, 110, 'Could not access all necessary resources. Source file or destination maybe was not within your mountpoints? T="%s", D="%s"', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_IllegalFileExtensionException $e) {
+                               $this->writelog(2, 1, 111, 'Extension of file name "%s" is not allowed in "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_ExistingTargetFileNameException $e) {
+                               $this->writelog(2, 1, 112, 'File "%s" already exists in folder "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
+                       } catch (RuntimeException $e) {
+                               $this->writelog(2, 2, 109, 'File "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
                        }
-                       if ($this->PHPFileFunctions) {
-                               copy($theFile, $theDestFile);
-                       } else {
-                               $cmd = 'cp ' . escapeshellarg($theFile) . ' ' . escapeshellarg($theDestFile);
-                               t3lib_utility_Command::exec($cmd);
-                       }
-                       t3lib_div::fixPermissions($theDestFile);
-                       clearstatcache();
-                       if (@is_file($theDestFile)) {
-                               $this->writelog(2, 0, 1, 'File "%s" copied to "%s"', array($theFile, $theDestFile));
-                               return $theDestFile;
-                       } else {
-                               $this->writelog(2, 2, 109, 'File "%s" WAS NOT copied to "%s"! Write-permission problem?', array($theFile, $theDestFile));
-                               return FALSE;
-                       }
-                       // FINISHED copying file
 
-               } elseif (@is_dir($theFile) && !$this->dont_use_exec_commands) { // if we're copying a folder
-                       if (!$this->actionPerms['copyFolder']) {
+                       $this->writelog(2, 0, 1, 'File "%s" copied to "%s"', array($sourceFileObject->getIdentifier(), $resultObject->getIdentifier()));
+
+               } else { // Else means this is a Folder
+                       $sourceFolderObject = $sourceFileObject;
+
+                       try {
+                               $conflictMode = ($appendSuffixOnConflict !== '') ? 'renameNewFile' : 'cancel';
+                               $resultObject = $sourceFolderObject->copyTo($targetFolderObject, NULL, $conflictMode);
+                       } catch (t3lib_file_exception_InsufficientUserPermissionsException $e) {
                                $this->writelog(2, 1, 125, 'You are not allowed to copy directories', '');
-                               return FALSE;
+                       } catch (t3lib_file_exception_InsufficientFileAccessPermissionsException $e) {
+                               $this->writelog(2, 1, 110, 'Could not access all necessary resources. Source file or destination maybe was not within your mountpoints? T="%s", D="%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_InsufficientFolderAccessPermissionsException $e) {
+                               $this->writelog(2, 1, 121, 'You don\'t have full access to the destination directory "%s"!', array($targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_InvalidTargetFolderException $e) {
+                               $this->writelog(2, 1, 122, 'Destination cannot be inside the target! D="%s", T="%s"', array($targetFolderObject->getIdentifier(), $sourceFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_ExistingTargetFolderException $e) {
+                               $this->writelog(2, 1, 123, 'Target "%s" already exists!', array($targetFolderObject->getIdentifier()));
+                       } catch (RuntimeException $e) {
+                               $this->writelog(2, 2, 119, 'Directory "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
                        }
-                       $theFile = $this->is_directory($theFile);
-                       if (!$theFile) {
-                               $this->writelog(2, 2, 124, 'Target seemed not to be a directory! (Shouldn\'t happen here!)', '');
-                               return FALSE;
-                       }
-                       $fI = t3lib_div::split_fileref($theFile);
-                       if ($altName) { // If altName is set, we're allowed to create a new filename if the file already existed
-                               $theDestFile = $this->getUniqueName($fI['file'], $theDest);
-                               $fI = t3lib_div::split_fileref($theDestFile);
-                       } else {
-                               $theDestFile = $theDest . '/' . $fI['file'];
-                       }
-                       if (!$theDestFile || file_exists($theDestFile)) {
-                               $this->writelog(2, 1, 123, 'Target "%s" already exists!', array($theDestFile));
-                               return FALSE;
-                       }
-                       if (t3lib_div::isFirstPartOfStr($theDestFile . '/', $theFile . '/')) {
-                               $this->writelog(2, 1, 122, 'Destination cannot be inside the target! D="%s", T="%s"', array($theDestFile . '/', $theFile . '/'));
-                               return FALSE;
-                       }
-                               // Check if the one folder is inside the other or on the same level... to target/dest is the same?
-                       if (!$this->checkIfFullAccess($theDest) && $this->is_webPath($theDestFile) !== $this->is_webPath($theFile)) { // no copy of folders between spaces
-                               $this->writelog(2, 1, 121, 'You don\'t have full access to the destination directory "%s"!', array($theDest . '/'));
-                               return FALSE;
-                       }
-                       if (!$this->checkPathAgainstMounts($theDestFile) || !$this->checkPathAgainstMounts($theFile)) {
-                               $this->writelog(2, 1, 120, 'Target or destination was not within your mountpoints! T="%s", D="%s"', array($theFile, $theDestFile));
-                               return FALSE;
-                       }
-                               // No way to do this under windows!
-                       $cmd = 'cp -R ' . escapeshellarg($theFile) . ' ' . escapeshellarg($theDestFile);
-                       t3lib_utility_Command::exec($cmd);
-                       clearstatcache();
-                       if (@is_dir($theDestFile)) {
-                               $this->writelog(2, 0, 2, 'Directory "%s" copied to "%s"', array($theFile, $theDestFile));
-                               return $theDestFile;
-                       } else {
-                               $this->writelog(2, 2, 119, 'Directory "%s" WAS NOT copied to "%s"! Write-permission problem?', array($theFile, $theDestFile));
-                               return FALSE;
-                       }
-                       // FINISHED copying directory
 
-               } else {
-                       $this->writelog(2, 2, 130, 'The item "%s" was not a file or directory!', array($theFile));
+                       $this->writelog(2, 0, 2, 'Directory "%s" copied to "%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
                }
+
+               return $resultObject;
        }
 
        /**
         * Moving files and folders (action=3)
         *
-        * @param       array           $cmds['data'] is the file/folder to move. $cmds['target'] is the path where to move to. $cmds['altName'] (boolean): If set, another filename is found in case the target already exists
-        * @return      string          Returns the new filename upon success
+        * $cmds['data'] (string): The file/folder to move
+        * + example "4:mypath/tomyfolder/myfile.jpg")
+        * + for backwards compatibility: the identifier was the path+filename
+        * $cmds['target'] (string): The path where to move to.
+        * + example "2:targetpath/targetfolder/"
+        * $cmds['altName'] (string): Use an alternative name if the target already exists
+        *
+        * @param array $cmds Command details as described above
+        * @return t3lib_file_File
         */
-       function func_move($cmds) {
+       protected function func_move($cmds) {
                if (!$this->isInit) {
                        return FALSE;
                }
 
-                       // Initialize and check basic conditions:
-               $theFile = $cmds['data'];
-               $theDest = $this->is_directory($cmds['target']); // Clean up destination directory
-               $altName = $cmds['altName'];
-               if (!$theDest) {
+               $sourceFileObject = $this->getFileObject($cmds['data']);
+               $targetFolderObject = $this->getFileObject($cmds['target']);
+
+                       // basic check
+               if (!($targetFolderObject instanceof t3lib_file_Folder)) {
                        $this->writelog(3, 2, 100, 'Destination "%s" was not a directory', array($cmds['target']));
                        return FALSE;
                }
-               if (!$this->isPathValid($theFile) || !$this->isPathValid($theDest)) {
-                       $this->writelog(3, 2, 101, 'Target or destination had invalid path (".." and "//" is not allowed in path). T="%s", D="%s"', array($theFile, $theDest));
-                       return FALSE;
-               }
 
-                       // Processing of file or directory:
-               if (@is_file($theFile)) { // If we are moving a file...
-                       if (!$this->actionPerms['moveFile']) {
+               $alternativeName = (string) $cmds['altName'];
+               $resultObject = NULL;
+
+                       // moving the file
+               if ($sourceFileObject instanceof t3lib_file_File) {
+                       try {
+                               if ($alternativeName !== '') {
+                                               // don't allow overwriting existing files, but find a new name
+                                       $resultObject = $sourceFileObject->moveTo($targetFolderObject, $alternativeName, 'renameNewFile');
+                               } else {
+                                               // don't allow overwriting existing files
+                                       $resultObject = $sourceFileObject->moveTo($targetFolderObject, NULL, 'cancel');
+                               }
+                       } catch (t3lib_file_exception_InsufficientUserPermissionsException $e) {
                                $this->writelog(3, 1, 114, 'You are not allowed to move files', '');
-                               return FALSE;
-                       }
-                       if (filesize($theFile) >= ($this->maxMoveFileSize * 1024)) {
-                               $this->writelog(3, 1, 113, 'File "%s" exceeds the size-limit of %s bytes', array($theFile, $this->maxMoveFileSize * 1024));
-                               return FALSE;
-                       }
-                       $fI = t3lib_div::split_fileref($theFile);
-                       if ($altName) { // If altName is set, we're allowed to create a new filename if the file already existed
-                               $theDestFile = $this->getUniqueName($fI['file'], $theDest);
-                               $fI = t3lib_div::split_fileref($theDestFile);
-                       } else {
-                               $theDestFile = $theDest . '/' . $fI['file'];
-                       }
-                       if (!$theDestFile || file_exists($theDestFile)) {
-                               $this->writelog(3, 1, 112, 'File "%s" already exists!', array($theDestFile));
-                               return FALSE;
-                       }
-                       if (!$this->checkIfAllowed($fI['fileext'], $theDest, $fI['file'])) {
-                               $this->writelog(3, 1, 111, 'Extension of file name "%s" is not allowed in "%s"!', array($fI['file'], $theDest . '/'));
-                               return FALSE;
+                       } catch (t3lib_file_exception_InsufficientFileAccessPermissionsException $e) {
+                               $this->writelog(3, 1, 110, 'Could not access all necessary resources. Source file or destination maybe was not within your mountpoints? T="%s", D="%s"', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_IllegalFileExtensionException $e) {
+                               $this->writelog(3, 1, 111, 'Extension of file name "%s" is not allowed in "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_ExistingTargetFileNameException $e) {
+                               $this->writelog(3, 1, 112, 'File "%s" already exists in folder "%s"!', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
+                       } catch (RuntimeException $e) {
+                               $this->writelog(3, 2, 109, 'File "%s" WAS NOT copied to "%s"! Write-permission problem?', array($sourceFileObject->getIdentifier(), $targetFolderObject->getIdentifier()));
                        }
-                       if (!$this->checkPathAgainstMounts($theDestFile) || !$this->checkPathAgainstMounts($theFile)) {
-                               $this->writelog(3, 1, 110, 'Target or destination was not within your mountpoints! T="%s", D="%s"', array($theFile, $theDestFile));
-                               return FALSE;
-                       }
-                       if ($this->PHPFileFunctions) {
-                               @rename($theFile, $theDestFile);
-                       } else {
-                               $cmd = 'mv ' . escapeshellarg($theFile) . ' ' . escapeshellarg($theDestFile);
-                               t3lib_utility_Command::exec($cmd);
-                       }
-                       clearstatcache();
-                       if (@is_file($theDestFile)) {
-                               $this->writelog(3, 0, 1, 'File "%s" moved to "%s"', array($theFile, $theDestFile));
-                               return $theDestFile;
-                       } else {
-                               $this->writelog(3, 2, 109, 'File "%s" WAS NOT moved to "%s"! Write-permission problem?', array($theFile, $theDestFile));
-                               return FALSE;
-                       }
-                       // FINISHED moving file
 
-               } elseif (@is_dir($theFile)) { // if we're moving a folder
-                       if (!$this->actionPerms['moveFolder']) {
+                       $this->writelog(3, 0, 1, 'File "%s" moved to "%s"', array($sourceFileObject->getIdentifier(), $resultObject->getIdentifier()));
+
+               } else { // Else means this is a Folder
+                       $sourceFolderObject = $sourceFileObject;
+
+                       try {
+                               if ($alternativeName !== '') {
+                                               // don't allow overwriting existing files, but find a new name
+                                       $resultObject = $sourceFolderObject->moveTo($targetFolderObject, $alternativeName, 'renameNewFile');
+                               } else {
+                                               // don't allow overwriting existing files
+                                       $resultObject = $sourceFolderObject->moveTo($targetFolderObject, NULL, 'renameNewFile');
+                               }
+                       } catch (t3lib_file_exception_InsufficientUserPermissionsException $e) {
                                $this->writelog(3, 1, 125, 'You are not allowed to move directories', '');
-                               return FALSE;
-                       }
-                       $theFile = $this->is_directory($theFile);
-                       if (!$theFile) {
-                               $this->writelog(3, 2, 124, 'Target seemed not to be a directory! (Shouldn\'t happen here!)', '');
-                               return FALSE;
-                       }
-                       $fI = t3lib_div::split_fileref($theFile);
-                       if ($altName) { // If altName is set, we're allowed to create a new filename if the file already existed
-                               $theDestFile = $this->getUniqueName($fI['file'], $theDest);
-                               $fI = t3lib_div::split_fileref($theDestFile);
-                       } else {
-                               $theDestFile = $theDest . '/' . $fI['file'];
+                       } catch (t3lib_file_exception_InsufficientFileAccessPermissionsException $e) {
+                               $this->writelog(3, 1, 110, 'Could not access all necessary resources. Source file or destination maybe was not within your mountpoints? T="%s", D="%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_InsufficientFolderAccessPermissionsException $e) {
+                               $this->writelog(3, 1, 121, 'You don\'t have full access to the destination directory "%s"!', array($targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_InvalidTargetFolderException $e) {
+                               $this->writelog(3, 1, 122, 'Destination cannot be inside the target! D="%s", T="%s"', array($targetFolderObject->getIdentifier(), $sourceFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_ExistingTargetFolderException $e) {
+                               $this->writelog(3, 1, 123, 'Target "%s" already exists!', array($targetFolderObject->getIdentifier()));
+                       } catch (RuntimeException $e) {
+                               $this->writelog(3, 2, 119, 'Directory "%s" WAS NOT moved to "%s"! Write-permission problem?', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
                        }
-                       if (!$theDestFile || file_exists($theDestFile)) {
-                               $this->writelog(3, 1, 123, 'Target "%s" already exists!', array($theDestFile));
-                               return FALSE;
-                       }
-                       if (t3lib_div::isFirstPartOfStr($theDestFile . '/', $theFile . '/')) { // Check if the one folder is inside the other or on the same level... to target/dest is the same?
-                               $this->writelog(3, 1, 122, 'Destination cannot be inside the target! D="%s", T="%s"', array($theDestFile . '/', $theFile . '/'));
-                               return FALSE;
-                       }
-                       if (!$this->checkIfFullAccess($theDest) && $this->is_webPath($theDestFile) != $this->is_webPath($theFile)) { // // no moving of folders between spaces
-                               $this->writelog(3, 1, 121, 'You don\'t have full access to the destination directory "%s"!', array($theDest . '/'));
-                               return FALSE;
-                       }
-                       if (!$this->checkPathAgainstMounts($theDestFile) || !$this->checkPathAgainstMounts($theFile)) {
-                               $this->writelog(3, 1, 120, 'Target or destination was not within your mountpoints! T="%s", D="%s"', array($theFile, $theDestFile));
-                               return FALSE;
-                       }
-                       if ($this->PHPFileFunctions) {
-                               @rename($theFile, $theDestFile);
-                       } else {
-                               $cmd = 'mv ' . escapeshellarg($theFile) . ' ' . escapeshellarg($theDestFile);
-                               $errArr = array();
-                               t3lib_utility_Command::exec($cmd, $errArr);
-                       }
-                       clearstatcache();
-                       if (@is_dir($theDestFile)) {
-                               $this->writelog(3, 0, 2, 'Directory "%s" moved to "%s"', array($theFile, $theDestFile));
-                               return $theDestFile;
-                       } else {
-                               $this->writelog(3, 2, 119, 'Directory "%s" WAS NOT moved to "%s"! Write-permission problem?', array($theFile, $theDestFile));
-                               return FALSE;
-                       }
-                       // FINISHED moving directory
 
-               } else {
-                       $this->writelog(3, 2, 130, 'The item "%s" was not a file or directory!', array($theFile));
+                       $this->writelog(3, 0, 2, 'Directory "%s" moved to "%s"', array($sourceFolderObject->getIdentifier(), $targetFolderObject->getIdentifier()));
                }
+
+               return $resultObject;
        }
 
        /**
         * Renaming files or foldes (action=5)
         *
-        * @param       array           $cmds['data'] is the new name. $cmds['target'] is the target (file or dir).
-        * @return      string          Returns the new filename upon success
+        * $cmds['data'] (string): The file/folder to copy
+        * + example "4:mypath/tomyfolder/myfile.jpg")
+        * + for backwards compatibility: the identifier was the path+filename
+        * $cmds['target'] (string): New name of the file/folder
+        *
+        * @param array $cmds Command details as described above
+        * @return t3lib_file_File Returns the new file upon success
         */
        function func_rename($cmds) {
                if (!$this->isInit) {
                        return FALSE;
                }
 
-               $theNewName = $this->cleanFileName($cmds['data']);
-               if (!$theNewName) {
-                       return FALSE;
-               }
-               if (!$this->checkFileNameLen($theNewName)) {
-                       $this->writelog(5, 1, 124, 'New name "%s" was too long (max %s characters)', array($theNewName, $this->maxInputNameLen));
-                       return FALSE;
-               }
-               $theTarget = $cmds['target'];
-               $type = filetype($theTarget);
-               if ($type != 'file' && $type != 'dir') { // $type MUST BE file or dir
-                       $this->writelog(5, 2, 123, 'Target "%s" was neither a directory nor a file!', array($theTarget));
-                       return FALSE;
-               }
-               $fileInfo = t3lib_div::split_fileref($theTarget); // Fetches info about path, name, extention of $theTarget
-               if ($fileInfo['file'] == $theNewName) { // The name should be different from the current. And the filetype must be allowed
-                       $this->writelog(5, 1, 122, 'Old and new name is the same (%s)', array($theNewName));
-                       return FALSE;
-               }
-               $theRenameName = $fileInfo['path'] . $theNewName;
-               if (!$this->checkPathAgainstMounts($fileInfo['path'])) {
-                       $this->writelog(5, 1, 121, 'Destination path "%s" was not within your mountpoints!', array($fileInfo['path']));
-                       return FALSE;
-               }
-               if (file_exists($theRenameName)) {
-                       $this->writelog(5, 1, 120, 'Destination "%s" existed already!', array($theRenameName));
-                       return FALSE;
-               }
-               switch ($type) {
-                       case 'file':
-                               if (!$this->actionPerms['renameFile']) {
-                                       $this->writelog(5, 1, 102, 'You are not allowed to rename files!', '');
-                                       return FALSE;
-                               }
-                               $fI = t3lib_div::split_fileref($theRenameName);
-                               if (!$this->checkIfAllowed($fI['fileext'], $fileInfo['path'], $fI['file'])) {
-                                       $this->writelog(5, 1, 101, 'Extension of file name "%s" was not allowed!', array($fI['file']));
-                                       return FALSE;
-                               }
-                               if (@rename($theTarget, $theRenameName)) {
-                                       $this->writelog(5, 0, 1, 'File renamed from "%s" to "%s"', array($fileInfo['file'], $theNewName));
-                                       return $theRenameName;
-                               } else {
-                                       $this->writelog(5, 1, 100, 'File "%s" was not renamed! Write-permission problem in "%s"?', array($theTarget, $fileInfo['path']));
-                                       return FALSE;
-                               }
-
-                               break;
-
-                       case 'dir':
-                               if (!$this->actionPerms['renameFolder']) {
-                                       $this->writelog(5, 1, 111, 'You are not allowed to rename directories!', '');
-                                       return FALSE;
-                               }
-                               if (@rename($theTarget, $theRenameName)) {
-                                       $this->writelog(5, 0, 2, 'Directory renamed from "%s" to "%s"', array($fileInfo['file'], $theNewName));
-                                       return $theRenameName;
-                               } else {
-                                       $this->writelog(5, 1, 110, 'Directory "%s" was not renamed! Write-permission problem in "%s"?', array($theTarget, $fileInfo['path']));
-                                       return FALSE;
-                               }
-
-                               break;
-               }
+               $sourceFileObject = $this->getFileObject($cmds['data']);
+               $targetFile = $cmds['target'];
+               $resultObject = NULL;
+
+               if ($sourceFileObject instanceof t3lib_file_File) {
+                       try {
+                                       // Try to rename the File
+                               $resultObject = $sourceFileObject->rename($targetFile);
+                       } catch (t3lib_file_exception_InsufficientUserPermissionsException $e) {
+                               $this->writelog(5, 1, 102, 'You are not allowed to rename files!', '');
+                       } catch (t3lib_file_exception_IllegalFileExtensionException $e) {
+                               $this->writelog(5, 1, 101, 'Extension of file name "%s" was not allowed!', array($targetFile));
+                       } catch (t3lib_file_exception_ExistingTargetFileNameException $e) {
+                               $this->writelog(5, 1, 120, 'Destination "%s" existed already!', array($targetFile));
+                       } catch (t3lib_file_exception_NotInMountPointException $e) {
+                               $this->writelog(5, 1, 121, 'Destination path "%s" was not within your mountpoints!', array($targetFile));
+                       } catch (RuntimeException $e) {
+                                       $this->writelog(5, 1, 100, 'File "%s" was not renamed! Write-permission problem in "%s"?', array($sourceFileObject->getName(), $targetFile));
+                       }
+                       $this->writelog(5, 0, 1, 'File renamed from "%s" to "%s"', array($sourceFileObject->getName(), $targetFile));
+
+               } else { // Else means this is a Folder
+                       try {
+                                       // Try to rename the Folder
+                               $resultObject = $sourceFileObject->rename($targetFile);
+                       } catch (t3lib_file_exception_InsufficientUserPermissionsException $e) {
+                               $this->writelog(5, 1, 111, 'You are not allowed to rename directories!', '');
+                       } catch (t3lib_file_exception_ExistingTargetFileNameException $e) {
+                               $this->writelog(5, 1, 120, 'Destination "%s" existed already!', array($targetFile));
+                       } catch (t3lib_file_exception_NotInMountPointException $e) {
+                               $this->writelog(5, 1, 121, 'Destination path "%s" was not within your mountpoints!', array($targetFile));
+                       } catch (RuntimeException $e) {
+                                       $this->writelog(5, 1, 110, 'Directory "%s" was not renamed! Write-permission problem in "%s"?', array($sourceFileObject->getName(), $targetFile));
+                       }
+                       $this->writelog(5, 0, 2, 'Directory renamed from "%s" to "%s"', array($sourceFileObject->getName(), $targetFile));
+               }
+
+               return $resultObject;
        }
 
        /**
         * This creates a new folder. (action=6)
         *
-        * @param       array           $cmds['data'] is the foldername. $cmds['target'] is the path where to create it.
-        * @return      string          Returns the new foldername upon success
+        * $cmds['data'] (string): The new folder name
+        * $cmds['target'] (string): The path where to copy to.
+        * + example "2:targetpath/targetfolder/"
+        *
+        * @param array $cmds Command details as described above
+        * @return t3lib_file_Folder Returns the new foldername upon success
         */
        function func_newfolder($cmds) {
                if (!$this->isInit) {
                        return FALSE;
                }
 
-               $theFolder = $this->cleanFileName($cmds['data']);
-               if (!isset($theFolder) || trim($theFolder) == '') {
-                       return FALSE;
-               }
-               if (!$this->checkFileNameLen($theFolder)) {
-                       $this->writelog(6, 1, 105, 'New name "%s" was too long (max %s characters)', array($theFolder, $this->maxInputNameLen));
-                       return FALSE;
-               }
-               $theTarget = $this->is_directory($cmds['target']); // Check the target dir
-               if (!$theTarget) {
+               $targetFolderObject = $this->getFileObject($cmds['target']);
+
+               if (!($targetFolderObject instanceof t3lib_file_Folder)) {
                        $this->writelog(6, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
                        return FALSE;
                }
-               if (!$this->actionPerms['newFolder']) {
+
+               $resultObject = NULL;
+
+               try {
+                       $folderName = $cmds['data'];
+                       $resultObject = $targetFolderObject->createFolder($folderName);
+                       $this->writelog(6, 0, 1, 'Directory "%s" created in "%s"', array($folderName, $targetFolderObject->getIdentifier() . '/'));
+               } catch (t3lib_file_exception_InsufficientFolderWritePermissionsException $e) {
                        $this->writelog(6, 1, 103, 'You are not allowed to create directories!', '');
-                       return FALSE;
-               }
-               $theNewFolder = $theTarget . '/' . $theFolder;
-               if (!$this->checkPathAgainstMounts($theNewFolder)) {
-                       $this->writelog(6, 1, 102, 'Destination path "%s" was not within your mountpoints!', array($theTarget . '/'));
-                       return FALSE;
-               }
-               if (file_exists($theNewFolder)) {
-                       $this->writelog(6, 1, 101, 'File or directory "%s" existed already!', array($theNewFolder));
-                       return FALSE;
-               }
-               if (t3lib_div::mkdir($theNewFolder)) {
-                       $this->writelog(6, 0, 1, 'Directory "%s" created in "%s"', array($theFolder, $theTarget . '/'));
-                       return $theNewFolder;
-               } else {
-                       $this->writelog(6, 1, 100, 'Directory "%s" not created. Write-permission problem in "%s"?', array($theFolder, $theTarget . '/'));
-                       return FALSE;
+               } catch (t3lib_file_exception_NotInMountPointException $e) {
+                       $this->writelog(6, 1, 102, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier() . '/'));
+               } catch (t3lib_file_exception_ExistingTargetFolderException $e) {
+                       $this->writelog(6, 1, 101, 'File or directory "%s" existed already!', array($folderName));
+               } catch (RuntimeException $e) {
+                       $this->writelog(6, 1, 100, 'Directory "%s" not created. Write-permission problem in "%s"?', array($folderName, $targetFolderObject->getIdentifier() . '/'));
                }
+
+               return $resultObject;
        }
 
        /**
         * This creates a new file. (action=8)
+        * $cmds['data'] (string): The new file name
+        * $cmds['target'] (string): The path where to create it.
+        * + example "2:targetpath/targetfolder/"
         *
-        * @param       array           $cmds['data'] is the new filename. $cmds['target'] is the path where to create it
+        * @param array $cmds Command details as described above
         * @return      string          Returns the new filename upon success
         */
        function func_newfile($cmds) {
-               $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
                if (!$this->isInit) {
                        return FALSE;
                }
-               $newName = $this->cleanFileName($cmds['data']);
-               if (!$newName) {
-                       return FALSE;
-               }
-               if (!$this->checkFileNameLen($newName)) {
-                       $this->writelog(8, 1, 105, 'New name "%s" was too long (max %s characters)', array($newName, $this->maxInputNameLen));
-                       return FALSE;
-               }
-               $theTarget = $this->is_directory($cmds['target']); // Check the target dir
-               $fileInfo = t3lib_div::split_fileref($theTarget); // Fetches info about path, name, extention of $theTarget
-               if (!$theTarget) {
+
+               $targetFolderObject = $this->getFileObject($cmds['target']);
+
+               if (!($targetFolderObject instanceof t3lib_file_Folder)) {
                        $this->writelog(8, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
                        return FALSE;
                }
-               if (!$this->actionPerms['newFile']) {
+
+               $resultObject = NULL;
+
+               try {
+                       $fileName = $cmds['data'];
+                       $resultObject = $targetFolderObject->createFile($fileName);
+                       $this->writelog(8, 0, 1, 'File created: "%s"', array($fileName));
+               } catch (t3lib_file_exception_InsufficientFolderWritePermissionsException $e) {
                        $this->writelog(8, 1, 103, 'You are not allowed to create files!', '');
-                       return FALSE;
-               }
-               $theNewFile = $theTarget . '/' . $newName;
-               if (!$this->checkPathAgainstMounts($theNewFile)) {
-                       $this->writelog(8, 1, 102, 'Destination path "%s" was not within your mountpoints!', array($theTarget . '/'));
-                       return FALSE;
-               }
-               if (file_exists($theNewFile)) {
-                       $this->writelog(8, 1, 101, 'File "%s" existed already!', array($theNewFile));
-                       return FALSE;
-               }
-               $fI = t3lib_div::split_fileref($theNewFile);
-               if (!$this->checkIfAllowed($fI['fileext'], $fileInfo['path'], $fI['file'])) {
-                       $this->writelog(8, 1, 106, 'Extension of file name "%s" was not allowed!', array($fI['file']));
-                       return FALSE;
-               }
-               if (!t3lib_div::inList($extList, $fI['fileext'])) {
-                       $this->writelog(8, 1, 107, 'File extension "%s" is not a textfile format! (%s)', array($fI['fileext'], $extList));
-                       return FALSE;
-               }
-               if (t3lib_div::writeFile($theNewFile, '')) {
-                       clearstatcache();
-                       $this->writelog(8, 0, 1, 'File created: "%s"', array($fI['file']));
-                       return $theNewFile;
-               } else {
-                       $this->writelog(8, 1, 100, 'File "%s" was not created! Write-permission problem in "%s"?', array($fI['file'], $theTarget));
-                       return FALSE;
+               } catch (t3lib_file_exception_NotInMountPointException $e) {
+                       $this->writelog(8, 1, 102, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier()));
+               } catch (t3lib_file_exception_ExistingTargetFileNameException $e) {
+                       $this->writelog(8, 1, 101, 'File existed already in "%s"!', array($targetFolderObject->getIdentifier()));
+               } catch (t3lib_file_exception_InvalidFileNameException $e) {
+                       $this->writelog(8, 1, 106, 'File name "%s" was not allowed!', $fileName);
+               } catch (RuntimeException $e) {
+                       $this->writelog(8, 1, 100, 'File "%s" was not created! Write-permission problem in "%s"?', array($fileName, $targetFolderObject->getIdentifier()));
                }
+
+               return $resultObject;
        }
 
        /**
@@ -874,45 +775,64 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
                if (!$this->isInit) {
                        return FALSE;
                }
-               $theTarget = $cmds['target'];
+
+                       // Example indentifier for $cmds['target'] => "4:mypath/tomyfolder/myfile.jpg"
+                       // for backwards compatibility: the combined file identifier was the path+filename
+               $fileIdentifier = $cmds['target'];
+               $fileObject = $this->getFileObject($fileIdentifier);
+
+                       // Example indentifier for $cmds['target'] => "2:targetpath/targetfolder/"
                $content = $cmds['data'];
-               $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
-               $type = filetype($theTarget);
-               if ($type != 'file') { // $type MUST BE file
-                       $this->writelog(9, 2, 123, 'Target "%s" was not a file!', array($theTarget));
-                       return FALSE;
-               }
-               $fileInfo = t3lib_div::split_fileref($theTarget); // Fetches info about path, name, extention of $theTarget
-               $fI = $fileInfo;
-               if (!$this->checkPathAgainstMounts($fileInfo['path'])) {
-                       $this->writelog(9, 1, 121, 'Destination path "%s" was not within your mountpoints!', array($fileInfo['path']));
-                       return FALSE;
-               }
-               if (!$this->actionPerms['editFile']) {
-                       $this->writelog(9, 1, 104, 'You are not allowed to edit files!', '');
-                       return FALSE;
-               }
-               $fI = t3lib_div::split_fileref($theTarget);
-               if (!$this->checkIfAllowed($fI['fileext'], $fileInfo['path'], $fI['file'])) {
-                       $this->writelog(9, 1, 103, 'Extension of file name "%s" was not allowed!', array($fI['file']));
+
+               if (!$fileObject instanceof t3lib_file_File) {
+                       $this->writelog(9, 2, 123, 'Target "%s" was not a file!', array($fileIdentifier));
                        return FALSE;
                }
-               if (!t3lib_div::inList($extList, $fileInfo['fileext'])) {
-                       $this->writelog(9, 1, 102, 'File extension "%s" is not a textfile format! (%s)', array($fI['fileext'], $extList));
+
+               $extList = $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'];
+               if (!t3lib_div::inList($extList, $fileObject->getExtension())) {
+                       $this->writelog(9, 1, 102, 'File extension "%s" is not a textfile format! (%s)', array($fileObject->getExtension(), $extList));
                        return FALSE;
                }
-               if (t3lib_div::writeFile($theTarget, $content)) {
+
+               try {
+                       $fileObject->setContents($content);
                        clearstatcache();
-                       $this->writelog(9, 0, 1, 'File saved to "%s", bytes: %s, MD5: %s ', array($fileInfo['file'], @filesize($theTarget), md5($content)));
+                       $this->writelog(9, 0, 1, 'File saved to "%s", bytes: %s, MD5: %s ', array($fileObject->getIdentifier(), $fileObject->getSize(), md5($content)));
                        return TRUE;
-               } else {
-                       $this->writelog(9, 1, 100, 'File "%s" was not saved! Write-permission problem in "%s"?', array($theTarget, $fileInfo['path']));
+               } catch (t3lib_file_exception_InsufficientUserPermissionsException $e) {
+                       $this->writelog(9, 1, 104, 'You are not allowed to edit files!', '');
+                       return FALSE;
+               } catch (t3lib_file_exception_InsufficientFileWritePermissionsException $e) {
+                       $this->writelog(9, 1, 100, 'File "%s" was not saved! Write-permission problem?', array($fileObject->getIdentifier()));
                        return FALSE;
                }
        }
 
        /**
         * Upload of files (action=1)
+        * when having multiple uploads (HTML5-style), the array $_FILES looks like this:
+        *      Array(
+        *              [upload_1] => Array(
+        *                              [name] => Array(
+        *                                              [0] => GData - Content-Elemente und Media-Gallery.pdf
+        *                                              [1] => CMS Expo 2011.txt
+        *                                      )
+        *                              [type] => Array(
+        *                                              [0] => application/pdf
+        *                                              [1] => text/plain
+        *                                      )
+        *                              [tmp_name] => Array(
+        *                                              [0] => /Applications/MAMP/tmp/php/phpNrOB43
+        *                                              [1] => /Applications/MAMP/tmp/php/phpD2HQAK
+        *                                      )
+        *                              [size] => Array(
+        *                                              [0] => 373079
+        *                                              [1] => 1291
+        *                                      )
+        *                      )
+        *      )
+        * in HTML you'd need sth like this: <input type="file" name="upload_1[]" multiple="true" />
         *
         * @param       array           $cmds['data'] is the ID-number (points to the global var that holds the filename-ref  ($_FILES['upload_'.$id]['name']). $cmds['target'] is the target directory, $cmds['charset'] is the the character set of the file name (utf-8 is needed for JS-interaction)
         * @return      string          Returns the new filename upon success
@@ -921,51 +841,68 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
                if (!$this->isInit) {
                        return FALSE;
                }
-               $id = $cmds['data'];
-               if (!$_FILES['upload_' . $id]['name']) {
+
+               $uploadPosition = $cmds['data'];
+               $uploadedFileData = $_FILES['upload_' . $uploadPosition];
+
+               if (empty($uploadedFileData['name']) || (is_array($uploadedFileData['name']) && empty($uploadedFileData['name'][0]))) {
                        $this->writelog(1, 2, 108, 'No file was uploaded!', '');
                        return FALSE;
                }
-               $theFile = $_FILES['upload_' . $id]['tmp_name']; // filename of the uploaded file
-               $theFileSize = $_FILES['upload_' . $id]['size']; // filesize of the uploaded file
-               $theName = $this->cleanFileName(stripslashes($_FILES['upload_' . $id]['name']), (isset($cmds['charset']) ? $cmds['charset'] : '')); // The original filename
-               if (!is_uploaded_file($theFile) || !$theName) { // Check the file
-                       $this->writelog(1, 2, 106, 'The upload has failed, no uploaded file found!', '');
-                       return FALSE;
-               }
-               if (!$this->actionPerms['uploadFile']) {
-                       $this->writelog(1, 1, 105, 'You are not allowed to upload files!', '');
-                       return FALSE;
-               }
-               if ($theFileSize >= ($this->maxUploadFileSize * 1024)) {
-                       $this->writelog(1, 1, 104, 'The uploaded file exceeds the size-limit of %s bytes', array($this->maxUploadFileSize * 1024));
-                       return FALSE;
-               }
-               $fI = t3lib_div::split_fileref($theName);
-               $theTarget = $this->is_directory($cmds['target']); // Check the target dir
-               if (!$theTarget || !$this->checkPathAgainstMounts($theTarget . '/')) {
-                       $this->writelog(1, 1, 103, 'Destination path "%s" was not within your mountpoints!', array($theTarget . '/'));
-                       return FALSE;
-               }
-               if (!$this->checkIfAllowed($fI['fileext'], $theTarget, $fI['file'])) {
-                       $this->writelog(1, 1, 102, 'Extension of file name "%s" is not allowed in "%s"!', array($fI['file'], $theTarget . '/'));
-                       return FALSE;
-               }
-               $theNewFile = $this->getUniqueName($theName, $theTarget, $this->dontCheckForUnique);
-               if (!$theNewFile) {
-                       $this->writelog(1, 1, 101, 'No unique filename available in "%s"!', array($theTarget . '/'));
-                       return FALSE;
-               }
-               t3lib_div::upload_copy_move($theFile, $theNewFile);
-               clearstatcache();
-               if (@is_file($theNewFile)) {
-                       $this->internalUploadMap[$id] = $theNewFile;
-                       $this->writelog(1, 0, 1, 'Uploading file "%s" to "%s"', array($theName, $theNewFile, $id));
-                       return $theNewFile;
-               } else {
-                       $this->writelog(1, 1, 100, 'Uploaded file could not be moved! Write-permission problem in "%s"?', array($theTarget . '/'));
-                       return FALSE;
+
+                       // Example indentifier for $cmds['target'] => "2:targetpath/targetfolder/"
+               $targetFolderObject = $this->getFileObject($cmds['target']);
+
+                       // uploading with non HTML-5-style, thus, make an array out of it, so we can loop over it
+               if (!is_array($uploadedFileData['name'])) {
+                       $uploadedFileData = array(
+                               'name' => array($uploadedFileData['name']),
+                               'type' => array($uploadedFileData['type']),
+                               'tmp_name' => array($uploadedFileData['tmp_name']),
+                               'size' => array($uploadedFileData['size']),
+                       );
                }
+
+               $resultObjects = array();
+
+               $numberOfUploadedFilesForPosition = count($uploadedFileData['name']);
+                       // loop through all uploaded files
+               for ($i = 0; $i < $numberOfUploadedFilesForPosition; $i++) {
+                       $fileInfo = array(
+                               'name'     => $uploadedFileData['name'][$i],
+                               'type'     => $uploadedFileData['type'][$i],
+                               'tmp_name' => $uploadedFileData['tmp_name'][$i],
+                               'size'     => $uploadedFileData['size'][$i],
+                       );
+                       try {
+
+                                       // @todo can be improved towards conflict mode naming
+                               if ($this->dontCheckForUnique) {
+                                       $conflictMode = 'replace';
+                               } else {
+                                       $conflictMode = 'cancel';
+                               }
+                               $resultObjects[] = $targetFolderObject->addUploadedFile($fileInfo, $conflictMode);
+                               $this->writelog(1, 0, 1, 'Uploading file "%s" to "%s"', array($fileInfo['name'], $targetFolderObject->getIdentifier()));
+
+                       } catch (t3lib_file_exception_UploadException $e) {
+                               $this->writelog(1, 2, 106, 'The upload has failed, no uploaded file found!', '');
+                       } catch (t3lib_file_exception_InsufficientUserPermissionsException $e) {
+                               $this->writelog(1, 1, 105, 'You are not allowed to upload files!', '');
+                       } catch (t3lib_file_exception_UploadSizeException $e) {
+                               $this->writelog(1, 1, 104, 'The uploaded file "%s" exceeds the size-limit', array($fileInfo['name']));
+                       } catch (t3lib_file_exception_InsufficientFolderWritePermissionsException $e) {
+                               $this->writelog(1, 1, 103, 'Destination path "%s" was not within your mountpoints!', array($targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_IllegalFileExtensionException $e) {
+                               $this->writelog(1, 1, 102, 'Extension of file name "%s" is not allowed in "%s"!', array($fileInfo['name'], $targetFolderObject->getIdentifier()));
+                       } catch (t3lib_file_exception_ExistingTargetFileNameException $e) {
+                               $this->writelog(1, 1, 101, 'No unique filename available in "%s"!', array($targetFolderObject->getIdentifier()));
+                       } catch (RuntimeException $e) {
+                               $this->writelog(1, 1, 100, 'Uploaded file could not be moved! Write-permission problem in "%s"?', array($targetFolderObject->getIdentifier()));
+                       }
+               }
+
+               return $resultObjects;
        }
 
        /**
@@ -990,6 +927,7 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
                        $cmds['target'] = $fI['path'];
                }
                        // Clean up destination directory
+                       // !!! Method has been put in the local driver, can be saftely removed
                $theDest = $this->is_directory($cmds['target']);
                if (!$theDest) {
                        $this->writelog(7, 2, 104, 'Destination "%s" was not a directory', array($cmds['target']));
@@ -1007,6 +945,7 @@ class t3lib_extFileFunctions extends t3lib_basicFileFunctions {
                        $this->writelog(7, 1, 101, 'You don\'t have full access to the destination directory "%s"!', array($theDest));
                        return FALSE;
                }
+                       // !!! Method has been put in the sotrage driver, can be saftely removed
                if ($this->checkPathAgainstMounts($theFile) && $this->checkPathAgainstMounts($theDest . '/')) {
                                // No way to do this under windows.
                        $cmd = $this->unzipPath . 'unzip -qq ' . escapeshellarg($theFile) . ' -d ' . escapeshellarg($theDest);
index 009460b..df47822 100644 (file)
 class t3lib_folderTree extends t3lib_treeView {
 
        /**
-        * Constructor function of the class
+        * @var t3lib_file_storage[]
+        * the users' file Storages
+        */
+       protected $storages = NULL;
+
+       /**
+        * @var array
+        */
+       protected $storageHashNumbers;
+
+       /**
+        * Indicates, whether the AJAX call was successful,
+        * i.e. the requested page has been found
         *
-        * @return      void
+        * @var boolean
         */
-       function __construct() {
+       protected $ajaxStatus = FALSE;
+
+       /**
+        * Constructor function of the class
+        */
+       public function __construct() {
                parent::init();
 
-               $this->MOUNTS = $GLOBALS['FILEMOUNTS'];
+               $this->storages = $GLOBALS['BE_USER']->getFileStorages();
 
                $this->treeName = 'folder';
                $this->titleAttrib = ''; //don't apply any title
@@ -61,236 +78,491 @@ class t3lib_folderTree extends t3lib_treeView {
        }
 
        /**
+        * Generate the plus/minus icon for the browsable tree.
+        *
+        * @param t3lib_file_Folder $folderObject Entry folder object
+        * @param integer $subFolderCounter The current entry number
+        * @param integer $totalSubFolders The total number of entries. If equal to $a, a "bottom" element is returned.
+        * @param integer $nextCount The number of sub-elements to the current element.
+        * @param boolean $isExpanded The element was expanded to render subelements if this flag is set.
+        * @return string Image tag with the plus/minus icon.
+        * @internal
+        * @see t3lib_pageTree::PMicon()
+        */
+       public function PMicon(t3lib_file_Folder $folderObject, $subFolderCounter, $totalSubFolders, $nextCount, $isExpanded) {
+               $PM   = ($nextCount ? ($isExpanded ? 'minus' : 'plus') : 'join');
+               $BTM  = ($subFolderCounter == $totalSubFolders ? 'bottom' : '');
+               $icon = '<img' . t3lib_iconWorks::skinImg(
+                               $this->backPath, 'gfx/ol/' . $PM . $BTM . '.gif',
+                               'width="18" height="16"'
+                       ) . ' alt="" />';
+
+               if ($nextCount) {
+                       $cmd = $this->generateExpandCollapseParameter($this->bank, !$isExpanded, $folderObject);
+                       $icon = $this->PMiconATagWrap($icon, $cmd, !$isExpanded);
+               }
+               return $icon;
+       }
+
+       /**
+        * Wrap the plus/minus icon in a link
+        *
+        * @param string $icon HTML string to wrap, probably an image tag.
+        * @param string $cmd Command for 'PM' get var
+        * @param boolean $isExpand Whether to be expanded
+        * @return string Link-wrapped input string
+        * @internal
+        */
+       public function PMiconATagWrap($icon, $cmd, $isExpand = TRUE) {
+               if ($this->thisScript) {
+                               // Activates dynamic AJAX based tree
+                       $js = htmlspecialchars('Tree.load(\'' . $cmd . '\', ' . intval($isExpand) . ', this);');
+                       return '<a class="pm" onclick="' . $js . '">' . $icon . '</a>';
+               } else {
+                       return $icon;
+               }
+       }
+
+       /**
         * Wrapping the folder icon
         *
-        * @param       string          The image tag for the icon
-        * @param       array           The row for the current element
-        * @return      string          The processed icon input value.
-        * @access private
+        * @param string $icon The image tag for the icon
+        * @param t3lib_file_Folder $folderObject The row for the current element
+        * @return string The processed icon input value.
+        * @internal
         */
-       function wrapIcon($icon, $row) {
+       public function wrapIcon($icon, t3lib_file_Folder $folderObject) {
                        // Add title attribute to input icon tag
-               $theFolderIcon = $this->addTagAttributes($icon, ($this->titleAttrib ? $this->titleAttrib . '="' . $this->getTitleAttrib($row) . '"' : ''));
+               $theFolderIcon = $this->addTagAttributes($icon, ($this->titleAttrib ? $this->titleAttrib . '="' . $this->getTitleAttrib($folderObject) . '"' : ''));
 
                        // Wrap icon in click-menu link.
                if (!$this->ext_IconMode) {
-                       $theFolderIcon = $GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon($theFolderIcon, $row['path'], '', 0);
+                       $theFolderIcon = $GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon($theFolderIcon, $folderObject->getCombinedIdentifier(), '', 0);
                } elseif (!strcmp($this->ext_IconMode, 'titlelink')) {
-                       $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($row) . '\',this,\'' . $this->domIdPrefix . $this->getId($row) . '\',' . $this->bank . ');';
+                       $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($folderObject) . '\',this,\'' . $this->domIdPrefix . $this->getId($folderObject) . '\',' . $this->bank . ');';
                        $theFolderIcon = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $theFolderIcon . '</a>';
                }
+
                return $theFolderIcon;
        }
 
        /**
         * Wrapping $title in a-tags.
         *
-        * @param       string          Title string
-        * @param       string          Item record
-        * @param       integer         Bank pointer (which mount point number)
-        * @return      string
-        * @access private
+        * @param string $title Title string
+        * @param t3lib_file_Folder     $folderObject the folder record
+        * @param integer $bank Bank pointer (which mount point number)
+        * @return string
+        * @internal
         */
-       function wrapTitle($title, $row, $bank = 0) {
-               $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($row) . '\',this,\'' . $this->domIdPrefix . $this->getId($row) . '\',' . $bank . ');';
-               $CSM = ' oncontextmenu="' . htmlspecialchars($GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon('', $row['path'], '', 0, '', '', TRUE)) . '"';
-               return '<a href="#" title="' . htmlspecialchars($row['title']) . '" onclick="' . htmlspecialchars($aOnClick) . '"' . $CSM . '>' . $title . '</a>';
+       public function wrapTitle($title, t3lib_file_Folder $folderObject, $bank = 0) {
+               $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($folderObject) . '\', this, \'' . $this->domIdPrefix . $this->getId($folderObject) . '\', ' . $bank . ');';
+               $CSM = ' oncontextmenu="'.htmlspecialchars($GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon('', $folderObject->getCombinedIdentifier(), '', 0, '&bank=' . $this->bank, '', TRUE)) . '"';
+               return '<a href="#" title="' . htmlspecialchars($title) . '" onclick="' . htmlspecialchars($aOnClick) . '"' . $CSM . '>' . $title . '</a>';
        }
 
        /**
         * Returns the id from the record - for folders, this is an md5 hash.
         *
-        * @param       array           Record array
-        * @return      integer         The "uid" field value.
+        * @param t3lib_file_Folder $folderObject The folder object
+        * @return integer The "uid" field value.
         */
-       function getId($v) {
-               return t3lib_div::md5Int($v['path']);
+       public function getId(t3lib_file_Folder $folderObject) {
+               return t3lib_div::md5Int($folderObject->getCombinedIdentifier());
        }
 
        /**
         * Returns jump-url parameter value.
         *
-        * @param       array           The record array.
-        * @return      string          The jump-url parameter.
+        * @param t3lib_file_Folder $folderObject The folder object
+        * @return string The jump-url parameter.
         */
-       function getJumpToParam($v) {
-               return rawurlencode($v['path']);
+       public function getJumpToParam(t3lib_file_Folder $folderObject) {
+               return rawurlencode($folderObject->getCombinedIdentifier());
        }
 
        /**
         * Returns the title for the input record. If blank, a "no title" labele (localized) will be returned.
         * '_title' is used for setting an alternative title for folders.
         *
-        * @param       array           The input row array (where the key "_title" is used for the title)
-        * @param       integer         Title length (30)
-        * @return      string          The title.
+        * @param array $row The input row array (where the key "_title" is used for the title)
+        * @param integer $titleLen Title length (30)
+        * @return string The title
         */
-       function getTitleStr($row, $titleLen = 30) {
+       public function getTitleStr($row, $titleLen = 30) {
                return $row['_title'] ? $row['_title'] : parent::getTitleStr($row, $titleLen);
        }
 
        /**
+        * Returns the value for the image "title" attribute
+        *
+        * @param t3lib_file_Folder $folderObject The folder to be used
+        * @return      string The attribute value (is htmlspecialchared() already)
+        */
+       function getTitleAttrib(t3lib_file_Folder $folderObject) {
+               return htmlspecialchars($folderObject->getName());
+       }
+
+       /**
         * Will create and return the HTML code for a browsable tree of folders.
         * Is based on the mounts found in the internal array ->MOUNTS (set in the constructor)
         *
-        * @return      string          HTML code for the browsable tree
+        * @return string HTML code for the browsable tree
         */
-       function getBrowsableTree() {
-
+       public function getBrowsableTree() {
                        // Get stored tree structure AND updating it if needed according to incoming PM GET var.
                $this->initializePositionSaving();
 
                        // Init done:
-               $titleLen = intval($this->BE_USER->uc['titleLen']);
-               $treeArr = array();
+               $treeItems = array();
 
                        // Traverse mounts:
-               foreach ($this->MOUNTS as $key => $val) {
-                       $md5_uid = md5($val['path']);
-                       $specUID = hexdec(substr($md5_uid, 0, 6));
-                       $this->specUIDmap[$specUID] = $val['path'];
+               foreach ($this->storages as $storageObject) {
+                       $this->getBrowseableTreeForStorage($storageObject);
+
+                               // Add tree:
+                       $treeItems = array_merge($treeItems, $this->tree);
+
+                               // if this is an AJAX call, don't run through all mounts, only
+                               // show the expansion of the current one, not the rest of the mounts
+                       if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
+                               // @todo: currently the AJAX script runs through all storages thus, if something is expanded on storage #2, it does not work, the break stops this, the goal should be that only the $this->storages iterates over the selected storage/bank
+                               // break;
+                       }
+               }
+
+               return $this->printTree($treeItems);
+       }
+
+       /**
+        * Get a tree for one storage
+        *
+        * @param t3lib_file_Storage $storageObject
+        * @return void
+        */
+       public function getBrowseableTreeForStorage(t3lib_file_Storage $storageObject) {
+                       // if there are filemounts, show each, otherwise just the rootlevel folder
+               $fileMounts = $storageObject->getFileMounts();
+               $rootLevelFolders = array();
+               if (count($fileMounts)) {
+                       foreach ($fileMounts as $fileMountInfo) {
+                               $rootLevelFolders[] = array(
+                                       'folder' => $fileMountInfo['folder'],
+                                       'name' => $fileMountInfo['title']
+                               );
+                       }
+               } else {
+                       $rootLevelFolders[] = array(
+                               'folder' => $storageObject->getRootLevelFolder(),
+                               'name' => $storageObject->getName()
+                       );
+               }
+
+                       // clean the tree
+               $this->reset();
+               
+                       // go through all "root level folders" of this tree (can be the rootlevel folder or any file mount points)
+               foreach ($rootLevelFolders as $rootLevelFolderInfo) {
+                       /** @var $rootLevelFolder t3lib_file_Folder */
+                       $rootLevelFolder = $rootLevelFolderInfo['folder'];
+                       $rootLevelFolderName = $rootLevelFolderInfo['name'];
+                       $folderHashSpecUID = t3lib_div::md5int($rootLevelFolder->getCombinedIdentifier());
+                       $this->specUIDmap[$folderHashSpecUID] = $rootLevelFolder->getCombinedIdentifier();
+
+                               // hash key
+                       $storageHashNumber = $this->getShortHashNumberForStorage($storageObject, $rootLevelFolder);
 
                                // Set first:
-                       $this->bank = $val['nkey'];
-                       $isOpen = $this->stored[$val['nkey']][$specUID] || $this->expandFirst;
-                       $this->reset();
+                       $this->bank = $storageHashNumber;
+                       $isOpen = $this->stored[$storageHashNumber][$folderHashSpecUID] || $this->expandFirst;
 
                                // Set PM icon:
-                       $cmd = $this->bank . '_' . ($isOpen ? '0_' : '1_') . $specUID . '_' . $this->treeName;
-                       $icon = '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . ($isOpen ? 'minus' : 'plus') . 'only.gif', 'width="18" height="16"') . ' alt="" />';
+                       $cmd = $this->generateExpandCollapseParameter($this->bank, !$isOpen, $rootLevelFolder);
+                       if (!$storageObject->isBrowsable() || $this->getNumberOfSubfolders($storageObject->getRootLevelFolder()) === 0) {
+                               $rootIcon = 'blank';
+                       } elseif (!$isOpen) {
+                               $rootIcon = 'plusonly';
+                       } else {
+                               $rootIcon = 'minusonly';
+                       }
+                       $icon = '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $rootIcon . '.gif') . ' alt="" />';
                        $firstHtml = $this->PM_ATagWrap($icon, $cmd);
 
-                       switch ($val['type']) {
-                               case 'user':
-                                       $icon = 'gfx/i/_icon_ftp_user.gif';
-                               break;
-                               case 'group':
-                                       $icon = 'gfx/i/_icon_ftp_group.gif';
-                               break;
-                               case 'readonly':
-                                       $icon = 'gfx/i/_icon_ftp_readonly.gif';
-                               break;
-                               default:
-                                       $icon = 'gfx/i/_icon_ftp.gif';
-                               break;
+                               // @todo: create sprite icons for user/group mounts etc
+                       if ($storageObject->isBrowsable() === FALSE) {
+                               $icon = 'apps-filetree-folder-locked';
+                       } else {
+                               $icon = 'apps-filetree-root';
                        }
 
-                               // Preparing rootRec for the mount
-                       $firstHtml .= $this->wrapIcon('<img' . t3lib_iconWorks::skinImg($this->backPath, $icon, 'width="18" height="16"') . ' alt="" />', $val);
-                       $row = array();
-                       $row['path'] = $val['path'];
-                       $row['uid'] = $specUID;
-                       $row['title'] = $val['name'];
+                               // mark a storage which is not online, as offline
+                               // maybe someday there will be a special icon for this
+                       if ($storageObject->isOnline() === FALSE) {
+                               $rootLevelFolderName .= ' (' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file.xlf:sys_file_storage.isOffline') . ')';
+                       }
 
-                               // Add the root of the mount to ->tree
-                       $this->tree[] = array('HTML' => $firstHtml, 'row' => $row, 'bank' => $this->bank);
+                               // Preparing rootRec for the mount
+                       $firstHtml .= $this->wrapIcon(t3lib_iconWorks::getSpriteIcon($icon), $rootLevelFolder);
+                       $row = array(
+                               'uid'    => $folderHashSpecUID,
+                               'title'  => $rootLevelFolderName,
+                               'path'   => $rootLevelFolder->getCombinedIdentifier(),
+                               'folder' => $rootLevelFolder
+                       );
+
+                               // Add the storage root to ->tree
+                       $this->tree[] = array(
+                               'HTML'   => $firstHtml,
+                               'row'    => $row,
+                               'bank'   => $this->bank,
+                                       // hasSub is TRUE when the root of the storage is expanded
+                               'hasSub' => ($isOpen && $storageObject->isBrowsable())
+                       );
 
                                // If the mount is expanded, go down:
-                       if ($isOpen) {
+                       if ($isOpen && $storageObject->isBrowsable()) {
                                        // Set depth:
-                               $depthD = '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/blank.gif', 'width="18" height="16"') . ' alt="" />';
-                               $this->getFolderTree($val['path'], 999, $depthD, $val['type']);
+                               $this->getFolderTree($rootLevelFolder, 999);
                        }
-
-                               // Add tree:
-                       $treeArr = array_merge($treeArr, $this->tree);
                }
-               return $this->printTree($treeArr);
        }
 
        /**
         * Fetches the data for the tree
         *
-        * @param       string          Abs file path
-        * @param       integer         Max depth (recursivity limit)
-        * @param       string          HTML-code prefix for recursive calls.
-        * @return      integer         The count of items on the level
+        * @param t3lib_file_Folder $folderObject the folderobject
+        * @param integer $depth Max depth (recursivity limit)
+        * @param string $type HTML-code prefix for recursive calls.
+        * @return integer The count of items on the level
         * @see getBrowsableTree()
         */
-       function getFolderTree($files_path, $depth = 999, $depthData = '', $type = '') {
+       public function getFolderTree(t3lib_file_Folder $folderObject, $depth = 999, $type = '') {
+               $depth = intval($depth);
 
                        // This generates the directory tree
-               $dirs = t3lib_div::get_dirs($files_path);
+               $subFolders = $folderObject->getSubfolders();
+
+               sort($subFolders);
+               $totalSubFolders = count($subFolders);
+
+               $HTML = '';
+               $subFolderCounter = 0;
+
+               foreach ($subFolders as $subFolder) {
+                       $subFolderCounter++;
+                               // Reserve space.
+                       $this->tree[] = array();
+                               // Get the key for this space
+                       end($this->tree);
+                       $treeKey = key($this->tree);
+
+                       $specUID = t3lib_div::md5int($subFolder->getCombinedIdentifier());
+                       $this->specUIDmap[$specUID] = $subFolder->getCombinedIdentifier();
+
+                       $row = array(
+                               'uid'    => $specUID,
+                               'path'   => $subFolder->getCombinedIdentifier(),
+                               'title'  => $subFolder->getName(),
+                               'folder' => $subFolder
+                       );
+
+                               // Make a recursive call to the next level
+                       if ($depth > 1 && $this->expandNext($specUID)) {
+                               $nextCount = $this->getFolderTree(
+                                       $subFolder,
+                                       $depth - 1,
+                                       $type
+                               );
 
-               $c = 0;
-               if (is_array($dirs)) {
-                       $depth = intval($depth);
-                       $HTML = '';
-                       $a = 0;
-                       $c = count($dirs);
-                       sort($dirs);
-
-                       foreach ($dirs as $key => $val) {
-                               $a++;
-                               $this->tree[] = array(); // Reserve space.
-                               end($this->tree);
-                               $treeKey = key($this->tree); // Get the key for this space
-                               $LN = ($a == $c) ? 'blank' : 'line';
-
-                               $val = preg_replace('/^\.\//', '', $val);
-                               $title = $val;
-                               $path = $files_path . $val . '/';
-                               $webpath = t3lib_BEfunc::getPathType_web_nonweb($path);
-
-                               $md5_uid = md5($path);
-                               $specUID = hexdec(substr($md5_uid, 0, 6));
-                               $this->specUIDmap[$specUID] = $path;
-                               $row = array();
-                               $row['path'] = $path;
-                               $row['uid'] = $specUID;
-                               $row['title'] = $title;
-
-                               if ($depth > 1 && $this->expandNext($specUID)) {
-                                       $nextCount = $this->getFolderTree(
-                                               $path,
-                                                       $depth - 1,
-                                               $this->makeHTML ? $depthData . '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $LN . '.gif', 'width="18" height="16"') . ' alt="" />' : '',
-                                               $type
-                                       );
-                                       $exp = 1; // Set "did expand" flag
+                                       // Set "did expand" flag
+                               $isOpen = 1;
+                       } else {
+                               $nextCount = $this->getNumberOfSubfolders($subFolder);
+                                       // Clear "did expand" flag
+                               $isOpen = 0;
+                       }
+
+                               // Set HTML-icons, if any:
+                       if ($this->makeHTML) {
+                               $HTML = $this->PMicon($subFolder, $subFolderCounter, $totalSubFolders, $nextCount, $isOpen);
+                               if ($subFolder->checkActionPermission('write')) {
+                                       $type = '';
+                                       $overlays = array();
                                } else {
-                                       $nextCount = $this->getCount($path);
-                                       $exp = 0; // Clear "did expand" flag
+                                       $type = 'readonly';
+                                       $overlays = array('status-overlay-locked' => array());
                                }
 
-                                       // Set HTML-icons, if any:
-                               if ($this->makeHTML) {
-                                       $HTML = $depthData . $this->PMicon($row, $a, $c, $nextCount, $exp);
+                               if ($isOpen) {
+                                       $icon = 'apps-filetree-folder-opened';
+                               } else {
+                                       $icon = 'apps-filetree-folder-default';
+                               }
 
-                                       $icon = 'gfx/i/_icon_' . $webpath . 'folders' . ($type == 'readonly' ? '_ro' : '') . '.gif';
-                                       if ($val == '_temp_') {
-                                               $icon = 'gfx/i/sysf.gif';
-                                               $row['title'] = $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_mod_file_list.xml:temp', TRUE);
-                                               $row['_title'] = '<strong>' . $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_mod_file_list.xml:temp', TRUE) . '</strong>';
-                                       }
-                                       if ($val == '_recycler_') {
-                                               $icon = 'gfx/i/recycler.gif';
-                                               $row['title'] = $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_mod_file_list.xml:recycler', TRUE);
-                                               $row['_title'] = '<strong>' . $GLOBALS['LANG']->sl('LLL:EXT:lang/locallang_mod_file_list.xml:recycler', TRUE) . '</strong>';
-                                       }
-                                       $HTML .= $this->wrapIcon('<img' . t3lib_iconWorks::skinImg($this->backPath, $icon, 'width="18" height="16"') . ' alt="" />', $row);
+                               if ($subFolder->getIdentifier() == '_temp_') {
+                                       $icon = 'apps-filetree-folder-temp';
+                                       $row['title'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file_list.xml:temp', TRUE);
+                                       $row['_title'] = '<strong>' . $row['title'] . '</strong>';
                                }
 
-                                       // Finally, add the row/HTML content to the ->tree array in the reserved key.
-                               $this->tree[$treeKey] = Array(
-                                       'row' => $row,
-                                       'HTML' => $HTML,
-                                       'bank' => $this->bank
-                               );
+                               if ($subFolder->getIdentifier() == '_recycler_') {
+                                       $icon = 'apps-filetree-folder-recycler';
+                                       $row['title'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file_list.xml:recycler', TRUE);
+                                       $row['_title'] = '<strong>' . $row['title'] . '</strong>';
+                               }
+
+                               $icon = t3lib_iconWorks::getSpriteIcon($icon, array('title' => $subFolder->getIdentifier()), $overlays);
+                               $HTML .= $this->wrapIcon($icon, $subFolder);
                        }
+
+                               // Finally, add the row/HTML content to the ->tree array in the reserved key.
+                       $this->tree[$treeKey] = array(
+                               'row'    => $row,
+                               'HTML'   => $HTML,
+                               'hasSub' => $nextCount && $this->expandNext($specUID),
+                               'isFirst'=> ($subFolderCounter == 1),
+                               'isLast' => FALSE,
+                               'invertedDepth'=> $depth,
+                               'bank'   => $this->bank
+                       );
                }
-               return $c;
+
+               if ($subFolderCounter > 0) {
+                       $this->tree[$treeKey]['isLast'] = TRUE;
+               }
+
+               return $totalSubFolders;
+       }
+
+       /**
+        * Compiles the HTML code for displaying the structure found inside the ->tree array
+        *
+        * @param array|string $treeItems "tree-array" - if blank string, the internal ->tree array is used.
+        * @return string The HTML code for the tree
+        */
+       public function printTree($treeItems = '') {
+               $doExpand = FALSE;
+               $doCollapse = FALSE;
+               $ajaxOutput = '';
+
+               $titleLength = intval($this->BE_USER->uc['titleLen']);
+               if (!is_array($treeItems)) {
+                       $treeItems = $this->tree;
+               }
+
+               $out = '
+                       <!-- TYPO3 folder tree structure. -->
+                       <ul class="tree" id="treeRoot">
+               ';
+
+                       // -- evaluate AJAX request
+               if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
+                       list(, $expandCollapseCommand, $expandedFolderHash,) = $this->evaluateExpandCollapseParameter();
+                       if ($expandCollapseCommand == 1) {
+                                       // We don't know yet. Will be set later.
+                               $invertedDepthOfAjaxRequestedItem = 0;
+                               $doExpand = TRUE;
+                       } else  {
+                               $doCollapse = TRUE;
+                       }
+               }
+
+               // we need to count the opened <ul>'s every time we dig into another level,
+               // so we know how many we have to close when all children are done rendering
+               $closeDepth = array();
+
+               foreach ($treeItems as $treeItem) {
+                       /** @var $folderObject t3lib_file_Folder */
+                       $folderObject = $treeItem['row']['folder'];
+                       $classAttr = $treeItem['row']['_CSSCLASS'];
+                       $folderIdentifier = $folderObject->getCombinedIdentifier();
+                               // this is set if the AJAX request has just opened this folder (via the PM command)
+                       $isExpandedFolderIdentifier = ($expandedFolderHash == t3lib_div::md5int($folderIdentifier));
+                       $idAttr = htmlspecialchars($this->domIdPrefix . $this->getId($folderObject) . '_' . $treeItem['bank']);
+                       $itemHTML  = '';
+
+                       // if this item is the start of a new level,
+                       // then a new level <ul> is needed, but not in ajax mode
+                       if($treeItem['isFirst'] && !($doCollapse) && !($doExpand && $isExpandedFolderIdentifier)) {
+                               $itemHTML = "<ul>\n";
+                       }
+
+                       // add CSS classes to the list item
+                       if ($treeItem['hasSub']) {
+                               $classAttr .= ' expanded';
+                       }
+                       if ($treeItem['isLast']) {
+                               $classAttr .= ' last';
+                       }
+
+                       $itemHTML .='
+                               <li id="' . $idAttr . '" ' . ($classAttr ? ' class="' . trim($classAttr) . '"' : '') . '><div class="treeLinkItem">'.
+                                       $treeItem['HTML'].
+                                       $this->wrapTitle($this->getTitleStr($treeItem['row'], $titleLength), $folderObject, $treeItem['bank']) . '</div>';
+
+                       if (!$treeItem['hasSub']) {
+                               $itemHTML .= "</li>\n";
+                       }
+
+                       // we have to remember if this is the last one
+                       // on level X so the last child on level X+1 closes the <ul>-tag
+                       if ($treeItem['isLast'] && !($doExpand && $isExpandedFolderIdentifier)) {
+                               $closeDepth[$treeItem['invertedDepth']] = 1;
+                       }
+
+                       // if this is the last one and does not have subitems, we need to close
+                       // the tree as long as the upper levels have last items too
+                       if ($treeItem['isLast'] && !$treeItem['hasSub'] && !$doCollapse && !($doExpand && $isExpandedFolderIdentifier)) {
+                               for ($i = $treeItem['invertedDepth']; $closeDepth[$i] == 1; $i++) {
+                                       $closeDepth[$i] = 0;
+                                       $itemHTML .= "</ul></li>\n";
+                               }
+                       }
+
+                               // ajax request: collapse
+                       if ($doCollapse && $isExpandedFolderIdentifier) {
+                               $this->ajaxStatus = TRUE;
+                               return $itemHTML;
+                       }
+
+                               // ajax request: expand
+                       if ($doExpand && $isExpandedFolderIdentifier) {
+                               $ajaxOutput .= $itemHTML;
+                               $invertedDepthOfAjaxRequestedItem = $treeItem['invertedDepth'];
+                       } elseif ($invertedDepthOfAjaxRequestedItem) {
+                               if ($treeItem['invertedDepth'] < $invertedDepthOfAjaxRequestedItem) {
+                                       $ajaxOutput .= $itemHTML;
+                               } else {
+                                       $this->ajaxStatus = TRUE;
+                                       return $ajaxOutput;
+                               }
+                       }
+
+                       $out .= $itemHTML;
+               }
+
+                       // if this is a AJAX request, output directly
+               if ($ajaxOutput) {
+                       $this->ajaxStatus = TRUE;
+                       return $ajaxOutput;
+               }
+
+                       // finally close the first ul
+               $out .= "</ul>\n";
+               return $out;
        }
 
        /**
         * Counts the number of directories in a file path.
         *
-        * @param       string          File path.
-        * @return      integer
+        * @param string $file File path.
+        * @return integer
+        * @deprecated since TYPO3 6.0, as the folder objects do the counting automatically
         */
-       function getCount($files_path) {
+       public function getCount($file) {
+               t3lib_div::logDeprecatedFunction();
                        // This generates the directory tree
-               $dirs = t3lib_div::get_dirs($files_path);
+               $dirs = t3lib_div::get_dirs($file);
                $c = 0;
                if (is_array($dirs)) {
                        $c = count($dirs);
@@ -299,6 +571,17 @@ class t3lib_folderTree extends t3lib_treeView {
        }
 
        /**
+        * Counts the number of directories in a file path.
+        *
+        * @param t3lib_file_Folder $folderObject File path.
+        * @return integer
+        */
+       public function getNumberOfSubfolders(t3lib_file_Folder $folderObject) {
+               $subFolders = $folderObject->getSubfolders();
+               return count($subFolders);
+       }
+
+       /**
         * Get stored tree structure AND updating it if needed according to incoming PM GET var.
         *
         * @return      void
@@ -308,28 +591,125 @@ class t3lib_folderTree extends t3lib_treeView {
                        // Get stored tree structure:
                $this->stored = unserialize($this->BE_USER->uc['browseTrees'][$this->treeName]);
 
-                       // Mapping md5-hash to shorter number:
-               $hashMap = array();
-               foreach ($this->MOUNTS as $key => $val) {
-                       $nkey = hexdec(substr($key, 0, 4));
-                       $hashMap[$nkey] = $key;
-                       $this->MOUNTS[$key]['nkey'] = $nkey;
-               }
+               $this->getShortHashNumberForStorage();
 
                        // PM action:
-                       // (If an plus/minus icon has been clicked, the PM GET var is sent and we must update the stored positions in the tree):
-               $PM = explode('_', t3lib_div::_GP('PM')); // 0: mount key, 1: set/clear boolean, 2: item ID (cannot contain "_"), 3: treeName
-               if (count($PM) == 4 && $PM[3] == $this->treeName) {
-                       if (isset($this->MOUNTS[$hashMap[$PM[0]]])) {
-                               if ($PM[1]) { // set
-                                       $this->stored[$PM[0]][$PM[2]] = 1;
-                                       $this->savePosition($this->treeName);
-                               } else { // clear
-                                       unset($this->stored[$PM[0]][$PM[2]]);
-                                       $this->savePosition($this->treeName);
+                       // (If an plus/minus icon has been clicked, 
+                       // the PM GET var is sent and we must update the stored positions in the tree):
+                       // 0: mount key, 1: set/clear boolean, 2: item ID (cannot contain "_"), 3: treeName
+               list($storageHashNumber, $doExpand, $numericFolderHash, $treeName) = $this->evaluateExpandCollapseParameter();
+               if ($treeName && $treeName == $this->treeName) {
+                       if (in_array($storageHashNumber, $this->storageHashNumbers)) {
+                               if ($doExpand == 1) {
+                                               // set
+                                       $this->stored[$storageHashNumber][$numericFolderHash] = 1;
+                               } else {
+                                               // clear
+                                       unset($this->stored[$storageHashNumber][$numericFolderHash]);
+                               }
+                               $this->savePosition();
+                       }
+               }
+       }
+
+       /**
+        * Helper method to map md5-hash to shorter number
+        *
+        * @param t3lib_file_Storage $storageObject
+        * @param t3lib_file_Folder $startingPointFolder
+        * @return integer
+        */
+       protected function getShortHashNumberForStorage(t3lib_file_Storage $storageObject = NULL, t3lib_file_Folder $startingPointFolder = NULL) {
+               if (!$this->storageHashNumbers) {
+                       $this->storageHashNumbers = array();
+                               // Mapping md5-hash to shorter number:
+                       $hashMap = array();
+                       foreach ($this->storages as $storageUid => $storage) {
+                               $fileMounts = $storage->getFileMounts();
+                               if (count($fileMounts)) {
+                                       foreach ($fileMounts as $fileMount) {
+                                               $nkey = hexdec(substr(t3lib_div::md5int($fileMount['folder']->getCombinedIdentifier()), 0, 4));
+                                               $this->storageHashNumbers[$storageUid . $fileMount['folder']->getCombinedIdentifier()] = $nkey;
+                                       }
+                               } else {
+                                       $folder = $storage->getRootLevelFolder();
+                                       $nkey = hexdec(substr(t3lib_div::md5int($folder->getCombinedIdentifier()), 0, 4));
+                                       $this->storageHashNumbers[$storageUid . $folder->getCombinedIdentifier()] = $nkey;
                                }
                        }
                }
+               if ($storageObject) {
+                       if ($startingPointFolder) {
+                               return $this->storageHashNumbers[$storageObject->getUid() . $startingPointFolder->getCombinedIdentifier()];
+                       } else {
+                               return $this->storageHashNumbers[$storageObject->getUid()];
+                       }
+               } else {
+                       return NULL;
+               }
+       }
+
+       /**
+        * Gets the values from the Expand/Collapse Parameter (&PM)
+        * previously known as "PM" (plus/minus)
+        * PM action:
+        * (If an plus/minus icon has been clicked,
+        * the PM GET var is sent and we must update the stored positions in the tree):
+        * 0: mount key, 1: set/clear boolean, 2: item ID (cannot contain "_"), 3: treeName
+        *
+        * @param string $PM The "plus/minus" command
+        * @return array
+        */
+       protected function evaluateExpandCollapseParameter($PM = NULL) {
+               if ($PM === NULL) {
+                       $PM = t3lib_div::_GP('PM');
+                               // IE takes anchor as parameter
+                       if (($PMpos = strpos($PM, '#')) !== FALSE) {
+                               $PM = substr($PM, 0, $PMpos);
+                       }
+               }
+
+                       // take the first three parameters
+               list($mountKey, $doExpand, $folderIdentifier) = explode('_', $PM, 3);
+
+                       // in case the folder identifier contains "_", we just need to get the fourth/last parameter
+               list($folderIdentifier, $treeName) = t3lib_div::revExplode('_', $folderIdentifier, 2);
+
+               return array(
+                       $mountKey,
+                       $doExpand,
+                       $folderIdentifier,
+                       $treeName
+               );
+       }
+
+       /**
+        * Generates the "PM" string to sent to expand/collapse items
+        *
+        * @param string $mountKey The mount key / storage UID
+        * @param boolean $doExpand Whether to expand/collapse
+        * @param t3lib_file_Folder $folderObject The folder object
+        * @param string $treeName The name of the tree
+        * @return string
+        */
+       protected function generateExpandCollapseParameter($mountKey = NULL, $doExpand = FALSE, t3lib_file_Folder $folderObject = NULL, $treeName = NULL) {
+               $parts = array(
+                       ($mountKey !== NULL ? $mountKey : $this->bank),
+                       ($doExpand == 1 ? 1 : 0),
+                       ($folderObject !== NULL ? t3lib_div::md5int($folderObject->getCombinedIdentifier()) : ''),
+                       ($treeName !== NULL ? $treeName : $this->treeName)
+               );
+
+               return implode('_', $parts);
+       }
+
+       /**
+        * Gets the AJAX status.
+        *
+        * @return boolean
+        */
+       public function getAjaxStatus() {
+               return $this->ajaxStatus;
        }
 }
 
index 87adf62..c40d5b2 100644 (file)
@@ -58,7 +58,6 @@ class t3lib_recordList {
                // Not used in this class - but maybe extension classes...
        var $fixedL = 30; // Max length of strings
        var $script = '';
-       var $thumbScript = 'thumbs.php';
        var $setLMargin = 1; // Set to zero, if you don't want a left-margin with addElement function
 
        var $counter = 0; // Counter increased for each element. Used to index elements for the JavaScript-code that transfers to the clipboard
index fcff03b..495973a 100644 (file)
@@ -355,13 +355,13 @@ class t3lib_refindex {
                                if ($result = $this->getRelations_procFiles($value, $conf, $uid)) {
                                                // Creates an entry for the field with all the files:
                                        $outRow[$field] = array(
-                                               'type' => 'file',
-                                               'newValueFiles' => $result,
+                                               'type' => 'db',
+                                               'itemArray' => $result,
                                        );
                                }
 
                                        // Add DB:
-                               if ($result = $this->getRelations_procDB($value, $conf, $uid, $table)) {
+                               if ($result = $this->getRelations_procDB($value, $conf, $uid, $table, $field)) {
                                                // Create an entry for the field with all DB relations:
                                        $outRow[$field] = array(
                                                'type' => 'db',
@@ -450,7 +450,7 @@ class t3lib_refindex {
                }
 
                        // Add DB:
-               if ($result = $this->getRelations_procDB($dataValue, $dsConf, $uid)) {
+               if ($result = $this->getRelations_procDB($dataValue, $dsConf, $uid, $field)) {
 
                                // Create an entry for the field with all DB relations:
                        $this->temp_flexRelations['db'][$structurePath] = $result;
@@ -487,7 +487,6 @@ class t3lib_refindex {
         * @return      array           If field type is OK it will return an array with the files inside. Else FALSE
         */
        function getRelations_procFiles($value, $conf, $uid) {
-                       // Take care of files...
                if ($conf['type'] == 'group' && ($conf['internal_type'] == 'file' || $conf['internal_type'] == 'file_reference')) {
 
                                // Collect file values in array:
@@ -508,41 +507,39 @@ class t3lib_refindex {
                                // Traverse the files and add them:
                        $uploadFolder = $conf['internal_type'] == 'file' ? $conf['uploadfolder'] : '';
                        $dest = $this->destPathFromUploadFolder($uploadFolder);
-                       $newValue = array();
                        $newValueFiles = array();
 
                        foreach ($theFileValues as $file) {
                                if (trim($file)) {
                                        $realFile = $dest . '/' . trim($file);
-                                       #                                       if (@is_file($realFile))        {               // Now, the refernece index should NOT look if files exist - just faithfully include them if they are in the records!
                                        $newValueFiles[] = array(
                                                'filename' => basename($file),
                                                'ID' => md5($realFile),
                                                'ID_absFile' => $realFile
-                                       ); // the order should be preserved here because.. (?)
-                                       #                                       } else $this->error('Missing file: '.$realFile);
+                                       );
                                }
                        }
 
                        return $newValueFiles;
                }
+               return FALSE;
        }
 
        /**
         * Check field configuration if it is a DB relation field and extract DB relations if any
         *
-        * @param       string          Field value
-        * @param       array           Field configuration array of type "TCA/columns"
-        * @param       integer         Field uid
-        * @param       string          Table name
-        * @return      array           If field type is OK it will return an array with the database relations. Else FALSE
+        * @param string $value Field value
+        * @param array $conf Field configuration array of type "TCA/columns"
+        * @param integer $uid Field uid
+        * @param string $table Table name
+        * @param string $field Field name
+        * @return array If field type is OK it will return an array with the database relations. Else FALSE
         */
-       function getRelations_procDB($value, $conf, $uid, $table = '') {
+       function getRelations_procDB($value, $conf, $uid, $table = '', $field = '') {
 
                        // DB record lists:
                if ($this->isReferenceField($conf)) {
                        $allowedTables = $conf['type'] == 'group' ? $conf['allowed'] : $conf['foreign_table'] . ',' . $conf['neg_foreign_table'];
-                       $prependName = $conf['type'] == 'group' ? $conf['prepend_tname'] : $conf['neg_foreign_table'];
 
                        if ($conf['MM_opposite_field']) {
                                return array();
@@ -552,6 +549,31 @@ class t3lib_refindex {
                        $dbAnalysis->start($value, $allowedTables, $conf['MM'], $uid, $table, $conf);
 
                        return $dbAnalysis->itemArray;
+               } elseif ($conf['type'] == 'inline' && $conf['foreign_table'] == 'sys_file_reference') {
+                       $files = (array)$GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                               'uid_local',
+                               'sys_file_reference',
+                               'tablenames=\'' . $table . '\' AND fieldname=\'' . $field . '\' AND uid_foreign=' . $uid
+                       );
+
+                       $fileArray = array('0' => array());
+                       foreach ($files as $fileUid) {
+                               $fileArray[0][] = array('table' => 'sys_file', 'id' => $fileUid);
+                       }
+
+                       return $fileArray;
+               } elseif ($conf['type'] == 'input' && isset($conf['wizards']['link']) && trim($value)) {
+                       try {
+                               $file = t3lib_file_Factory::getInstance()->retrieveFileOrFolderObject($value);
+                       } catch (Exception $e) {}
+                       if ($file instanceof t3lib_file_FileInterface) {
+                               return array(
+                                       0 => array(
+                                               'table' => 'sys_file',
+                                               'id' => $file->getUid()
+                                       )
+                               );
+                       }
                }
        }
 
@@ -613,7 +635,7 @@ class t3lib_refindex {
                                                                break;
                                                                case 'file_reference':
                                                                case 'file':
-                                                                       $this->setReferenceValue_fileRels($refRec, $dat['newValueFiles'], $newValue, $dataArray);
+                                                                       $error = $this->setReferenceValue_fileRels($refRec, $dat['newValueFiles'], $newValue, $dataArray);
                                                                        if ($error) {
                                                                                return $error;
                                                                        }
@@ -820,7 +842,7 @@ class t3lib_refindex {
         * @return      boolean         TRUE if DB reference field (group/db or select with foreign-table)
         */
        function isReferenceField($conf) {
-               return ($conf['type'] == 'group' && $conf['internal_type'] == 'db') || (($conf['type'] == 'select' || $conf['type'] == 'inline') && $conf['foreign_table']);
+               return ($conf['type'] == 'group' && $conf['internal_type'] == 'db') || (($conf['type'] == 'select' || $conf['type'] == 'inline') && $conf['foreign_table'] && $conf['foreign_table'] !== 'sys_file_reference');
        }
 
        /**
index 32d6dbd..33854a8 100644 (file)
@@ -2142,6 +2142,19 @@ class t3lib_TCEforms {
                                        // Making the array of file items:
                                $itemArray = t3lib_div::trimExplode(',', $PA['itemFormElValue'], TRUE);
 
+                               $fileFactory = t3lib_file_Factory::getInstance();
+
+                                       // correct the filename for the FAL items
+                               foreach ($itemArray as &$fileItem) {
+                                       list($fileUid, $fileLabel) = explode('|', $fileItem);
+                                       if (t3lib_utility_Math::canBeInterpretedAsInteger($fileUid)) {
+                                               $fileObject = $fileFactory->getFileObject($fileUid);
+                                               $fileLabel = $fileObject->getName();
+                                       }
+
+                                       $fileItem = $fileUid . '|' . $fileLabel;
+                               }
+
                                        // Showing thumbnails:
                                $thumbsnail = '';
                                if ($show_thumbs) {
@@ -2150,12 +2163,39 @@ class t3lib_TCEforms {
                                                $imgP = explode('|', $imgRead);
                                                $imgPath = rawurldecode($imgP[0]);
 
-                                               $rowCopy = array();
-                                               $rowCopy[$field] = $imgPath;
+                                                       // FAL icon production
+                                               if (t3lib_utility_Math::canBeInterpretedAsInteger($imgP[0])) {
+                                                       $fileObject = $fileFactory->getFileObject($imgP[0]);
+
+                                                       if (t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
+                                                               $imageUrl = $fileObject->process(t3lib_file_ProcessedFile::CONTEXT_IMAGEPREVIEW, array())->getPublicUrl(TRUE);
+                                                               $imgTag = '<img src="' . $imageUrl . '" alt="' . htmlspecialchars($fileObject->getName()) . '" />';
+                                                       } else {
+                                                                       // Icon
+                                                               $imgTag = t3lib_iconWorks::getSpriteIconForFile(
+                                                                       strtolower($fileObject->getExtension()),
+                                                                       array('title' => $fileObject->getName())
+                                                               );
+                                                       }
+
+                                                       $imgs[] = '<span class="nobr">' . $imgTag . htmlspecialchars($fileObject->getName()) . '</span>';
+                                               } else {
+                                                       $rowCopy = array();
+                                                       $rowCopy[$field] = $imgPath;
+
+                                                       $thumbnailCode = t3lib_BEfunc::thumbCode(
+                                                               $rowCopy,
+                                                               $table,
+                                                               $field,
+                                                               $this->backPath,
+                                                               'thumbs.php',
+                                                               $config['uploadfolder'],
+                                                               0,
+                                                               ' align="middle"'
+                                                       );
+                                                       $imgs[] = '<span class="nobr">' . $thumbnailCode . $imgPath . '</span>';
+                                               }
 
-                                               $imgs[] = '<span class="nobr">' . t3lib_BEfunc::thumbCode($rowCopy, $table, $field, $this->backPath, 'thumbs.php', $config['uploadfolder'], 0, ' align="middle"') .
-                                                                 $imgPath .
-                                                                 '</span>';
                                        }
                                        $thumbsnail = implode('<br />', $imgs);
                                }
@@ -3672,7 +3712,7 @@ class t3lib_TCEforms {
                                        foreach ($itemArray as $item) {
                                                $itemParts = explode('|', $item);
                                                $uidList[] = $pUid = $pTitle = $itemParts[0];
-                                               $title = htmlspecialchars(basename(rawurldecode($itemParts[0])));
+                                               $title = htmlspecialchars(basename(rawurldecode($itemParts[1])));
                                                $opt[] = '<option value="' . htmlspecialchars(rawurldecode($itemParts[0]))
                                                                . '" title="' . $title . '">' . $title . '</option>';
                                        }
@@ -3815,7 +3855,8 @@ class t3lib_TCEforms {
                                        'onFocus' => $onFocus,
                                        'table' => $table,
                                        'field' => $field,
-                                       'uid' => $uid
+                                       'uid' => $uid,
+                                       'config' => $GLOBALS['TCA'][$table]['columns'][$field],
                                );
                                $hookObject->dbFileIcons_postProcess($params, $selector, $thumbnails, $icons, $rightbox, $fName, $uidList, $additionalParams, $this);
                        }
@@ -5443,6 +5484,7 @@ class t3lib_TCEforms {
 
                        $this->loadJavascriptLib('../t3lib/jsfunc.evalfield.js');
                        $this->loadJavascriptLib('jsfunc.tbe_editor.js');
+                       $this->loadJavascriptLib('jsfunc.placeholder.js');
 
                                // needed for tceform manipulation (date picker)
                        $typo3Settings = array(
@@ -6569,6 +6611,8 @@ class t3lib_TCEforms {
                                                        $value = $foreignRecord[$keySegments[1]];
                                                }
                                        }
+                               } elseif (!empty($keySegments[1]) && isset($row[$keySegments[0]][$keySegments[1]])) {
+                                       $value = $row[$keySegments[0]][$keySegments[1]];
                                }
                        }
                }
index 7d0804d..54c050f 100644 (file)
@@ -374,6 +374,7 @@ class t3lib_TCEforms_inline {
                                $overruleTypesArray = isset($config['foreign_types']) ? $config['foreign_types'] : array();
                                $fields = $this->renderMainFields($foreign_table, $rec, $overruleTypesArray);
                                $fields = $this->wrapFormsSection($fields);
+
                                        // Replace returnUrl in Wizard-Code, if this is an AJAX call
                                $ajaxArguments = t3lib_div::_GP('ajax');
                                if (isset($ajaxArguments[2]) && trim($ajaxArguments[2]) != '') {
@@ -512,12 +513,39 @@ class t3lib_TCEforms_inline {
                        $recTitle = t3lib_BEfunc::getRecordTitle($foreign_table, $rec, TRUE);
                }
 
+                       // Renders a thumbnail for the header
+               if (!empty($config['appearance']['headerThumbnail'])) {
+                       $originalRecord = t3lib_BEfunc::getRecord($foreign_table, $rec['uid']);
+
+                       if (is_array($originalRecord)) {
+                               $fileUid = $originalRecord[$config['appearance']['headerThumbnail']];
+                               list($fileUid) = t3lib_div::intExplode(',', $fileUid);
+
+                               if ($fileUid) {
+                                       $fileObject = t3lib_file_Factory::getInstance()->getFileObject($fileUid);
+                                       if ($fileObject) {
+                                               $imageUrl = $fileObject->process(
+                                                       t3lib_file_ProcessedFile::CONTEXT_IMAGEPREVIEW,
+                                                       array('width' => 64, 'height' => 64)
+                                               )->getPublicUrl(TRUE);
+
+                                               $thumbnail = '<span class="nobr"><img src="' . $imageUrl . '" alt="' . htmlspecialchars($recTitle) . '" /></span>';
+                                       }
+                               }
+                       }
+               }
+
                $altText = t3lib_BEfunc::getRecordIconAltText($rec, $foreign_table);
                $iconImg = t3lib_iconWorks::getSpriteIconForRecord($foreign_table, $rec, array('title' => htmlspecialchars($altText), 'id' => $objectId . '_icon'));
                $label = '<span id="' . $objectId . '_label">' . $recTitle . '</span>';
+
                if (!$isVirtualRecord) {
                        $iconImg = $this->wrapWithAnchor($iconImg, '#', array('onclick' => $onClick));
                        $label = $this->wrapWithAnchor($label, '#', array('onclick' => $onClick, 'style' => 'display: block;'));
+
+                       if (!empty($config['appearance']['headerThumbnail'])) {
+                               $thumbnail = $this->wrapWithAnchor($thumbnail, '#', array('onclick' => $onClick, 'style' => 'display: block;'));
+                       }
                }
 
                $ctrl = $this->renderForeignRecordHeaderControl($parentUid, $foreign_table, $rec, $config, $isVirtualRecord);
@@ -527,7 +555,14 @@ class t3lib_TCEforms_inline {
                                '<table cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-right: ' . $this->inlineStyles['margin-right'] . 'px;"' .
                                ($this->fObj->borderStyle[2] ? ' background="' . htmlspecialchars($this->backPath . $this->fObj->borderStyle[2]) . '"' : '') .
                                ($this->fObj->borderStyle[3] ? ' class="' . htmlspecialchars($this->fObj->borderStyle[3]) . '"' : '') . '>' .
-                               '<tr class="class-main12"><td width="18" id="' . $objectId . '_iconcontainer">' . $iconImg . '</td><td align="left"><strong>' . $label . '</strong></td><td align="right">' . $ctrl . '</td></tr></table>';
+                               '<tr class="class-main12">' .
+                                       (!empty($config['appearance']['headerThumbnail']) && !empty($thumbnail)
+                                               ?       '<td width="75" id="' . $objectId . '_thumbnailcontainer">' . $thumbnail . '</td>'
+                                               :       '<td width="18" id="' . $objectId . '_iconcontainer">' . $iconImg . '</td>') .
+                                       '<td align="left"><strong>' . $label . '</strong></td>' .
+                                       '<td align="right">' . $ctrl . '</td>' .
+                               '</tr>' .
+                               '</table>';
 
                return $header;
        }
@@ -840,7 +875,12 @@ class t3lib_TCEforms_inline {
                                // this is neccessary, if the size of the selector is "1" or if
                                // there is only one record item in the select-box, that is selected by default
                                // the selector-box creates a new relation on using a onChange event (see some line above)
-                       $createNewRelationText = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.createNewRelation', 1);
+                       if (!empty($conf['appearance']['createNewRelationLinkTitle'])) {
+                               $createNewRelationText = $GLOBALS['LANG']->sL($conf['appearance']['createNewRelationLinkTitle'], TRUE);
+                       } else {
+                               $createNewRelationText = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.createNewRelation', 1);
+                       }
+
                        $item .=
                                        '<a href="#" onclick="' . htmlspecialchars($onChange) . '" align="abstop">' .
                                        t3lib_iconWorks::getSpriteIcon('actions-document-new', array('title' => $createNewRelationText)) . $createNewRelationText .
@@ -863,17 +903,22 @@ class t3lib_TCEforms_inline {
         */
        function renderPossibleRecordsSelectorTypeGroupDB($conf, &$PA) {
                $foreign_table = $conf['foreign_table'];
-
                $config = $PA['fieldConf']['config'];
                $allowed = $config['allowed'];
                $objectPrefix = $this->inlineNames['object'] . self::Structure_Separator . $foreign_table;
 
-               $createNewRelationText = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.createNewRelation', 1);
-               $onClick = "setFormValueOpenBrowser('db','" . ('|||' . $allowed . '|' . $objectPrefix . '|inline.checkUniqueElement||inline.importElement') . "'); return false;";
-               $item =
-                               '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' .
-                               t3lib_iconWorks::getSpriteIcon('actions-insert-record', array('title' => $createNewRelationText)) . $createNewRelationText .
-                               '</a>';
+               if (!empty($conf['appearance']['createNewRelationLinkTitle'])) {
+                       $createNewRelationText  = $GLOBALS['LANG']->sL($conf['appearance']['createNewRelationLinkTitle'], TRUE);
+               } else {
+                       $createNewRelationText = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:cm.createNewRelation', 1);
+               }
+
+               $browserParams = ('|||' . $allowed . '|' . $objectPrefix . '|inline.checkUniqueElement||inline.importElement');
+
+               $onClick = "setFormValueOpenBrowser('db','" . $browserParams . "'); return false;";
+               $item = '<a href="#" onclick="' . htmlspecialchars($onClick) . '">' .
+                       t3lib_iconWorks::getSpriteIcon('actions-insert-record', array('title' => $createNewRelationText)) . $createNewRelationText .
+                       '</a>';
 
                return $item;
        }
@@ -2271,6 +2316,11 @@ class t3lib_TCEforms_inline {
                if ($field) {
                        $PA = array();
                        $PA['fieldConf'] = $GLOBALS['TCA'][$foreign_table]['columns'][$field];
+
+                       if ($PA['fieldConf'] && $conf['foreign_selector_fieldTcaOverride']) {
+                               $PA['fieldConf'] = t3lib_div::array_merge_recursive_overrule($PA['fieldConf'], $conf['foreign_selector_fieldTcaOverride']);
+                       }
+
                        $PA['fieldConf']['config']['form_type'] = $PA['fieldConf']['config']['form_type'] ? $PA['fieldConf']['config']['form_type'] : $PA['fieldConf']['config']['type']; // Using "form_type" locally in this script
                        $PA['fieldTSConfig'] = $this->fObj->setTSconfig($foreign_table, array(), $field);
                        $config = $PA['fieldConf']['config'];
index 054e895..1b8630c 100644 (file)
@@ -166,6 +166,7 @@ class t3lib_TCEmain {
         * @var t3lib_basicFileFunctions
         */
        var $fileFunc; // For "singleTon" file-manipulation object
+
        var $checkValue_currentRecord = array(); // Set to "currentRecord" during checking of values.
        var $autoVersioningUpdate = FALSE; // A signal flag used to tell file processing that autoversioning has happend and hence certain action should be applied.
 
@@ -1500,12 +1501,20 @@ class t3lib_TCEmain {
 
                                        // Traverse the submitted values:
                                foreach ($valueArray as $key => $theFile) {
-                                               // NEW FILES? If the value contains '/' it indicates, that the file is new and should be added to the uploadsdir (whether its absolute or relative does not matter here)
+                                               // Init:
+                                       $maxSize = intval($tcaFieldConf['max_size']);
+                                       $theDestFile = ''; // Must be cleared. Else a faulty fileref may be inserted if the below code returns an error!
+
+                                               // a FAL file was added, now resolve the file object and get the absolute path
+                                               // @todo in future versions this needs to be modified to handle FAL objects natively
+                                       if (t3lib_utility_Math::canBeInterpretedAsInteger($theFile)) {
+                                               $fileObject = t3lib_file_Factory::getInstance()->getFileObject($theFile);
+                                               $theFile = $fileObject->getForLocalProcessing(FALSE);
+                                       }
+
+                                               // NEW FILES? If the value contains '/' it indicates, that the file
+                                               // is new and should be added to the uploadsdir (whether its absolute or relative does not matter here)
                                        if (strstr(t3lib_div::fixWindowsFilePath($theFile), '/')) {
-                                                       // Init:
-                                               $maxSize = intval($tcaFieldConf['max_size']);
-                                               $cmd = '';
-                                               $theDestFile = ''; // Must be cleared. Else a faulty fileref may be inserted if the below code returns an error!
 
                                                        // Check various things before copying file:
                                                if (@is_dir($dest) && (@is_file($theFile) || @is_uploaded_file($theFile))) { // File and destination must exist
@@ -1561,7 +1570,8 @@ class t3lib_TCEmain {
                                                        $this->log($table, $id, 5, 0, 1, 'The destination (%s) or the source file (%s) does not exist. (%s)', 14, array($dest, $theFile, $recFID), $propArr['event_pid']);
                                                }
 
-                                                       // If the destination file was created, we will set the new filename in the value array, otherwise unset the entry in the value array!
+                                                       // If the destination file was created, we will set the new filename in
+                                                       // the value array, otherwise unset the entry in the value array!
                                                if (@is_file($theDestFile)) {
                                                        $info = t3lib_div::split_fileref($theDestFile);
                                                        $valueArray[$key] = $info['file']; // The value is set to the new filename
@@ -1605,9 +1615,14 @@ class t3lib_TCEmain {
                                        $propArr = $this->getRecordProperties($table, $id); // For logging..
                                        foreach ($valueArray as &$theFile) {
 
-                                                       // if alernative File Path is set for the file, then it was an import
-                                               if ($this->alternativeFilePath[$theFile]) {
+                                                       // FAL handling: it's a UID, thus it is resolved to the absolute path
+                                               if (t3lib_utility_Math::canBeInterpretedAsInteger($theFile)) {
+                                                       $fileObject = t3lib_file_Factory::getInstance()->getFileObject($theFile);
+                                                       $theFile = $fileObject->getForLocalProcessing(FALSE);
+                                               }
 
+                                               if ($this->alternativeFilePath[$theFile]) {
+                                                               // if alernative File Path is set for the file, then it was an import
                                                                // don't import the file if it already exists
                                                        if (@is_file(PATH_site . $this->alternativeFilePath[$theFile])) {
                                                                $theFile = PATH_site . $this->alternativeFilePath[$theFile];
index 7af1d0f..22b28ee 100644 (file)
@@ -1067,6 +1067,10 @@ class t3lib_TStemplate {
                        }
                }
 
+               if (parse_url($file) !== FALSE) {
+                       return $file;
+               }
+
                        // find
                if (strpos($file, '/') !== FALSE) {
                                // if the file is in the media/ folder but it doesn't exist,
index fb145af..1bf82ae 100644 (file)
@@ -87,6 +87,17 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
        var $checkWorkspaceCurrent_cache = NULL; // Cache for checkWorkspaceCurrent()
 
 
+       /**
+        * @var t3lib_file_Storage[]
+        */
+       protected $fileStorages;
+
+       /**
+        * @var array
+        */
+       protected $filePermissions;
+
+
        /************************************
         *
         * Permission checking functions:
@@ -1029,36 +1040,6 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                return (string) ($this->groupData['webmounts']) != '' ? explode(',', $this->groupData['webmounts']) : array();
        }
 
-       /**
-        * Returns an array with the filemounts for the user. Each filemount is represented with an array of a "name", "path" and "type".
-        * If no filemounts an empty array is returned.
-        *
-        * @return      array
-        */
-       function returnFilemounts() {
-               return $this->groupData['filemounts'];
-       }
-
-       /**
-        * Returns an integer bitmask that represents the permissions for file operations.
-        * Permissions of the user and groups the user is a member of were combined by a logical OR.
-        *
-        * Meaning of each bit:
-        *       1 - Files: Upload,Copy,Move,Delete,Rename
-        *       2 - Files: Unzip
-        *       4 - Directory: Move,Delete,Rename,New
-        *       8 - Directory: Copy
-        *       16 - Directory: Delete recursively (rm -Rf)
-        *
-        * @return      integer         File operation permission bitmask
-        */
-       public function getFileoperationPermissions() {
-               if ($this->isAdmin()) {
-                       return 31;
-               } else {
-                       return $this->groupData['fileoper_perms'];
-               }
-       }
 
        /**
         * Returns TRUE or FALSE, depending if an alert popup (a javascript confirmation) should be shown
@@ -1133,22 +1114,6 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                                }
                        }
 
-                               // FILE MOUNTS:
-                               // Admin users has the base fileadmin dir mounted
-                       if ($this->isAdmin() && $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir']) {
-                               $this->addFileMount($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '', PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], 0, '');
-                       }
-
-                               // If userHomePath is set, we attempt to mount it
-                       if ($GLOBALS['TYPO3_CONF_VARS']['BE']['userHomePath']) {
-                                       // First try and mount with [uid]_[username]
-                               $didMount = $this->addFileMount($this->user['username'], '', $GLOBALS['TYPO3_CONF_VARS']['BE']['userHomePath'] . $this->user['uid'] . '_' . $this->user['username'] . $GLOBALS['TYPO3_CONF_VARS']['BE']['userUploadDir'], 0, 'user');
-                               if (!$didMount) {
-                                               // If that failed, try and mount with only [uid]
-                                       $this->addFileMount($this->user['username'], '', $GLOBALS['TYPO3_CONF_VARS']['BE']['userHomePath'] . $this->user['uid'] . $GLOBALS['TYPO3_CONF_VARS']['BE']['userUploadDir'], 0, 'user');
-                               }
-                       }
-
                                // BE_GROUPS:
                                // Get the groups...
                        #                       $grList = t3lib_BEfunc::getSQLselectableList($this->user[$this->usergroup_column],$this->usergroup_table,$this->usergroup_table);
@@ -1194,17 +1159,6 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                                $this->dataLists['webmount_list'] = '0,' . $this->dataLists['webmount_list'];
                        }
 
-                               // Processing filemounts
-                       t3lib_div::loadTCA('sys_filemounts');
-                       $orderBy = $GLOBALS['TCA']['sys_filemounts']['ctrl']['default_sortby'] ? $GLOBALS['TYPO3_DB']->stripOrderBy($GLOBALS['TCA']['sys_filemounts']['ctrl']['default_sortby']) : 'sorting';
-                       $this->dataLists['filemount_list'] = t3lib_div::uniqueList($this->dataLists['filemount_list']);
-                       if ($this->dataLists['filemount_list']) {
-                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_filemounts', 'deleted=0 AND hidden=0 AND pid=0 AND uid IN (' . $this->dataLists['filemount_list'] . ')', '', $orderBy);
-                               while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                                       $this->addFileMount($row['title'], $row['path'], $row['path'], $row['base'] ? 1 : 0, '');
-                               }
-                       }
-
                                // The lists are cleaned for duplicates
                        $this->groupData['webmounts'] = t3lib_div::uniqueList($this->dataLists['webmount_list']);
                        $this->groupData['pagetypes_select'] = t3lib_div::uniqueList($this->dataLists['pagetypes_select']);
@@ -1302,14 +1256,6 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                                        $this->dataLists['filemount_list'] .= ',' . $row['file_mountpoints'];
                                }
 
-                                       // Mount group home-dirs
-                               if (($this->user['options'] & 2) == 2) {
-                                               // If groupHomePath is set, we attempt to mount it
-                                       if ($GLOBALS['TYPO3_CONF_VARS']['BE']['groupHomePath']) {
-                                               $this->addFileMount($row['title'], '', $GLOBALS['TYPO3_CONF_VARS']['BE']['groupHomePath'] . $row['uid'], 0, 'group');
-                                       }
-                               }
-
                                        // The lists are made: groupMods, tables_select, tables_modify, pagetypes_select, non_exclude_fields, explicit_allowdeny, allowed_languages, custom_options
                                if ($row['inc_access_lists'] == 1) {
                                        $this->dataLists['modList'] .= ',' . $row['groupMods'];
@@ -1360,6 +1306,306 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                }
        }
 
+
+
+       /***********************
+        * FILE MOUNT FUNCTIONS
+        **********************/
+
+       /**
+        * Sets up all file storages for a user.
+        * Needs to be called AFTER the groups have been loaded.
+        *
+        * @return void
+        */
+       protected function initializeFileStorages() {
+               $this->fileStorages = array();
+               /** @var $storageRepository t3lib_file_Repository_StorageRepository */
+               $storageRepository = t3lib_div::makeInstance('t3lib_file_Repository_StorageRepository');
+
+                       // Admin users have all file storages visible, without any filters
+               if ($this->isAdmin()) {
+                       $storageObjects = $storageRepository->findAll();
+                       foreach ($storageObjects as $storageObject) {
+                               $this->fileStorages[$storageObject->getUid()] = $storageObject;
+                       }
+               } else {
+                               // If userHomePath is set, we attempt to mount it
+                       if ($GLOBALS['TYPO3_CONF_VARS']['BE']['userHomePath']) {
+                               list($userHomeStorageUid, $userHomeFilter) = explode(':', $GLOBALS['TYPO3_CONF_VARS']['BE']['userHomePath'], 2);
+                               $userHomeStorageUid = intval($userHomeStorageUid);
+                               if ($userHomeStorageUid > 0) {
+                                       $storageObject = $storageRepository->findByUid($userHomeStorageUid);
+                                               // First try and mount with [uid]_[username]
+                                       $userHomeFilterIdentifier = $userHomeFilter . $this->user['uid'] . '_' . $this->user['username'] . $GLOBALS['TYPO3_CONF_VARS']['BE']['userUploadDir'];
+                                       $didMount = $storageObject->injectFileMount($userHomeFilterIdentifier);
+                                               // If that failed, try and mount with only [uid]
+                                       if (!$didMount) {
+                                               $userHomeFilterIdentifier = $userHomeFilter . $this->user['uid'] . '_' . $this->user['username'] . $GLOBALS['TYPO3_CONF_VARS']['BE']['userUploadDir'];
+                                               $storageObject->injectFileMount($userHomeFilterIdentifier);
+                                       }
+                                       $this->fileStorages[$storageObject->getUid()] = $storageObject;
+                               }
+                       }
+
+                               // Mount group home-dirs
+                       if (($this->user['options'] & 2) == 2 && $GLOBALS['TYPO3_CONF_VARS']['BE']['groupHomePath'] != '') {
+                                               // If groupHomePath is set, we attempt to mount it
+                               list($groupHomeStorageUid, $groupHomeFilter) = explode(':', $GLOBALS['TYPO3_CONF_VARS']['BE']['groupHomePath'], 2);
+                               $groupHomeStorageUid = intval($groupHomeStorageUid);
+                               if ($groupHomeStorageUid > 0) {
+                                       $storageObject = $storageRepository->findByUid($groupHomeStorageUid);
+                                       foreach ($this->userGroups as $groupUid => $groupData) {
+                                               $groupHomeFilterIdentifier = $groupHomeFilter . $groupData['uid'];
+                                               $storageObject->injectFileMount($groupHomeFilterIdentifier);
+                                       }
+                                       $this->fileStorages[$storageObject->getUid()] = $storageObject;
+                               }
+                       }
+
+                               // Processing filemounts (both from the user and the groups)
+                       $this->dataLists['filemount_list'] = t3lib_div::uniqueList($this->dataLists['filemount_list']);
+                       if ($this->dataLists['filemount_list']) {
+                               $orderBy = $GLOBALS['TCA']['sys_filemounts']['ctrl']['default_sortby'] ? $GLOBALS['TYPO3_DB']->stripOrderBy($GLOBALS['TCA']['sys_filemounts']['ctrl']['default_sortby']) : 'sorting';
+                               $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+                                       '*',
+                                       'sys_filemounts',
+                                       'deleted=0 AND hidden=0 AND pid=0 AND uid IN (' . $this->dataLists['filemount_list'] . ')',
+                                       '',
+                                       $orderBy
+                               );
+
+                               while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                                       $storageObject = $storageRepository->findByUid($row['base']);
+                                       $storageObject->injectFileMount($row['path'], $row);
+                                       $this->fileStorages[$storageObject->getUid()] = $storageObject;
+                               }
+                               $GLOBALS['TYPO3_DB']->sql_free_result($res);
+                       }
+               }
+
+                       // Injects the users' permissions to each storage
+               foreach ($this->fileStorages as $storageObject) {
+                       $storagePermissions = $this->getFilePermissionsForStorage($storageObject);
+                       $storageObject->injectUserPermissions($storagePermissions);
+               }
+
+                       // more narrowing down through the workspace
+               $this->initializeFileStoragesForWorkspace();
+
+                       // this has to be called always in order to set certain filters
+                       // @todo Should be in BE_USER object then
+               $GLOBALS['BE_USER']->evaluateUserSpecificFileFilterSettings();
+       }
+
+       /**
+        * Returns an array with the filemounts for the user.
+        * Each filemount is represented with an array of a "name", "path" and "type".
+        * If no filemounts an empty array is returned.
+        *
+        * @api
+        * @return t3lib_file_Storage[]
+        */
+       public function getFileStorages() {
+                               // initializing file mounts after the groups are fetched
+               if ($this->fileStorages === NULL) {
+                       $this->initializeFileStorages();
+               }
+
+               return $this->fileStorages;
+       }
+
+       /**
+        * Adds filters based on what the user has set
+        * this should be done in this place, and called whenever needed,
+        * but only when needed
+        *
+        * @return void
+        * @todo Should be in BE_USER object then
+        */
+       public function evaluateUserSpecificFileFilterSettings() {
+                       // add the option for also displaying the non-hidden files
+               if ($this->uc['showHiddenFilesAndFolders']) {
+                       t3lib_file_Utility_FilenameFilters::setShowHiddenFilesAndFolders(TRUE);
+               }
+       }
+
+       /**
+        * Returns the information about file permissions
+        * previously, this was stored in the DB fields (fileoper_perms)
+        * but is now handled via userTSconfig
+        * 
+        * permissions.file.default {
+        *              addFile = 1
+        *              readFile = 1
+        *              editFile = 1
+        *              writeFile = 1
+        *              uploadFile = 1
+        *              copyFile = 1
+        *              moveFile = 1
+        *              renameFile = 1
+        *              unzipFile = 1
+        *              removeFile = 1
+        *
+        *              addFolder = 1
+        *              browseFolder = 1
+        *              moveFolder = 1
+        *              writeFolder = 1
+        *              renameFolder = 1
+        *              removeFolder = 1
+        *              removeSubfolders = 1
+        * }
+        *
+        * # overwrite settings for a specific storageObject
+        * permissions.file.storage.StorageUid {
+        *              readFile = 0
+        *              removeSubfolders = 1
+        * }
+        *
+        * Please note that these permissions only apply, if the storage has the
+        * capabilities (browseable, writable), and if the driver allows for writing etc
+        *
+        * @api
+        * @return array
+        */
+       public function getFilePermissions() {
+               if (!isset($this->filePermissions)) {
+                       $defaultOptions = array(
+                               'addFile'  => TRUE,     // new option
+                               'readFile' => TRUE,     // new option, generic check of the user rights
+                               'editFile' => TRUE,     // new option
+                               'writeFile' => TRUE,    // new option, generic check of the user rights
+                               'uploadFile' => TRUE,
+                               'copyFile' => TRUE,
+                               'moveFile' => TRUE,
+                               'renameFile' => TRUE,
+                               'unzipFile' => TRUE,
+                               'removeFile' => TRUE,
+                               'addFolder' => TRUE,
+                               'browseFolder' => TRUE, // new option,, generic check of the user rights
+                               'moveFolder' => TRUE,
+                               'renameFolder' => TRUE,
+                               'writeFolder' => TRUE,  // new option, generic check of the user rights
+                               'removeFolder' => TRUE,
+                               'removeSubfolders' => TRUE      // was "delete recursively" previously
+                       );
+
+                       if (!$this->isAdmin()) {
+                               $this->filePermissions = $this->getTSConfig('permissions.file.default');
+                               if (!is_array($this->filePermissions)) {
+                                       $oldFileOperationPermissions = $this->getFileoperationPermissions();
+
+                                       // lower permissions if the old file operation permissions are not set
+                                       if ($oldFileOperationPermissions ^ 1) {
+                                               $defaultOptions['addFile'] = FALSE;
+                                               $defaultOptions['uploadFile'] = FALSE;
+                                               $defaultOptions['copyFile'] = FALSE;
+                                               $defaultOptions['moveFile'] = FALSE;
+                                               $defaultOptions['renameFile'] = FALSE;
+                                               $defaultOptions['removeFile'] = FALSE;
+                                       }
+                                       if ($oldFileOperationPermissions ^ 2) {
+                                               $defaultOptions['unzipFile'] = FALSE;
+                                       }
+                                       if ($oldFileOperationPermissions ^ 4) {
+                                               $defaultOptions['addFolder'] = FALSE;
+                                               $defaultOptions['moveFolder'] = FALSE;
+                                               $defaultOptions['renameFolder'] = FALSE;
+                                               $defaultOptions['removeFolder'] = FALSE;
+                                       }
+                                       if ($oldFileOperationPermissions ^ 8) {
+                                               $defaultOptions['copyFolder'] = FALSE;
+                                       }
+                                       if ($oldFileOperationPermissions ^ 16) {
+                                               $defaultOptions['removeSubfolders'] = FALSE;
+                                       }
+                               }
+                       }
+
+                       $this->filePermissions = $defaultOptions;
+               }
+
+               return $this->filePermissions;
+       }
+
+       /**
+        * Gets the file permissions for a storage
+        * by merging any storage-specific permissions for a
+        * storage with the default settings
+        *
+        * @api
+        * @param t3lib_file_Storage $storageObject
+        * @return array
+        */
+       public function getFilePermissionsForStorage(t3lib_file_Storage $storageObject) {
+               $defaultFilePermissions = $this->getFilePermissions();
+               $storageFilePermissions = $this->getTSConfig('permissions.file.storage.' . $storageObject->getUid());
+
+               if (is_array($storageFilePermissions) && count($storageFilePermissions)) {
+                       return array_merge($storageFilePermissions, $defaultFilePermissions);
+               } else {
+                       return $defaultFilePermissions;
+               }
+       }
+
+       /**
+        * Returns a t3lib_file_Folder object that is used for uploading
+        * files by default.
+        * This is used for RTE and its magic images, as well as uploads
+        * in the TCEforms fields, unless otherwise configured (will be added in the future)
+        *
+        * the default upload folder for a user is the defaultFolder on the first
+        * filestorage/filemount that the user can access
+        * however, you can set the users' upload folder like this:
+        *
+        *     options.defaultUploadFolder = 3:myfolder/yourfolder/
+        *
+        * @return t3lib_file_Folder|boolean The default upload folder for this user
+        */
+       public function getDefaultUploadFolder() {
+               $uploadFolder = $this->getTSConfigVal('options.defaultUploadFolder');
+               if ($uploadFolder) {
+                       $uploadFolder = t3lib_file_Factory::getInstance()->getFolderObjectFromCombinedIdentifier($uploadFolder);
+               } else {
+                       $storages = $this->getFileStorages();
+                       if (count($storages) > 0) {
+                               /** @var $firstStorage t3lib_file_Storage */
+                               $firstStorage = reset($storages);
+                               $uploadFolder = $firstStorage->getDefaultFolder();
+                       }
+               }
+
+               if ($uploadFolder instanceof t3lib_file_Folder) {
+                       return $uploadFolder;
+               } else {
+                       return FALSE;
+               }
+       }
+
+       /**
+        * Returns an integer bitmask that represents the permissions for file operations.
+        * Permissions of the user and groups the user is a member of were combined by a logical OR.
+        *
+        * Meaning of each bit:
+        *       1 - Files: Upload,Copy,Move,Delete,Rename
+        *       2 - Files: Unzip
+        *       4 - Directory: Move,Delete,Rename,New
+        *       8 - Directory: Copy
+        *       16 - Directory: Delete recursively (rm -Rf)
+        *
+        * @return integer File operation permission bitmask
+        * @deprecated since TYPO3 6.0, use the TSconfig settings instead
+        */
+       public function getFileoperationPermissions() {
+               t3lib_div::logDeprecatedFunction();
+
+               if ($this->isAdmin()) {
+                       return 31;
+               } else {
+                       return $this->groupData['fileoper_perms'];
+               }
+       }
+
        /**
         * Adds a filemount to the users array of filemounts, $this->groupData['filemounts'][hash_key] = Array ('name'=>$name, 'path'=>$path, 'type'=>$type);
         * Is a part of the authentication proces of the user.
@@ -1372,9 +1618,12 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
         * @param       boolean         If $webspace is set, the $path is relative to 'fileadminDir' in TYPO3_CONF_VARS, otherwise $path is absolute. 'fileadminDir' must be set to allow mounting of relative paths.
         * @param       string          Type of filemount; Can be blank (regular) or "user" / "group" (for user and group filemounts presumably). Probably sets the icon first and foremost.
         * @return      boolean         Returns "1" if the requested filemount was mounted, otherwise no return value.
+        * @deprecated since TYPO3 6.0, will be removed in TYPO3 6.1, all data is stored in $this->fileStorages now, see initializeFileStorages()
         * @access private
         */
        function addFileMount($title, $altTitle, $path, $webspace, $type) {
+               t3lib_div::logDeprecatedFunction();
+
                        // Return FALSE if fileadminDir is not set and we try to mount a relative path
                if ($webspace && !$GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir']) {
                        return FALSE;
@@ -1416,6 +1665,23 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                }
        }
 
+
+       /**
+        * Returns an array with the filemounts for the user. Each filemount is represented with an array of a "name", "path" and "type".
+        * If no filemounts an empty array is returned.
+        *
+        * @return array
+        * @deprecated since TYPO3 6.0, will be removed in TYPO3 6.1 as getFileStorages() should be the one to be used
+        */
+       function returnFilemounts() {
+               t3lib_div::logDeprecatedFunction();
+
+                       // initialize the file storages in order to set some default settings in any time
+               $this->getFileStorages();
+
+               return $this->groupData['filemounts'];
+       }
+
        /**
         * Creates a TypoScript comment with the string text inside.
         *
@@ -1454,6 +1720,20 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                $this->setWorkspace($this->user['workspace_id']);
 
                        // Limiting the DB mountpoints if there any selected in the workspace record
+               $this->initializeDbMountpointsInWorkspace();
+
+               if ($allowed_languages = $this->getTSConfigVal('options.workspaces.allowed_languages.' . $this->workspace)) {
+                       $this->groupData['allowed_languages'] = $allowed_languages;
+                       $this->groupData['allowed_languages'] = t3lib_div::uniqueList($this->groupData['allowed_languages']);
+               }
+       }
+
+       /**
+        * Limiting the DB mountpoints if there any selected in the workspace record
+        *
+        * @return void
+        */
+       protected function initializeDbMountpointsInWorkspace() {
                $dbMountpoints = trim($this->workspaceRec['db_mountpoints']);
                if ($this->workspace > 0 && $dbMountpoints != '') {
                        $filteredDbMountpoints = array();
@@ -1471,48 +1751,52 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                        $filteredDbMountpoints = array_unique($filteredDbMountpoints);
                        $this->groupData['webmounts'] = implode(',', $filteredDbMountpoints);
                }
+       }
 
+       /**
+        * Adds more limitations for users who are no admins
+        * this was previously in workspaceInit but has now been moved to "
+        *
+        * @return void
+        */
+       protected function initializeFileStoragesForWorkspace() {
                        // Filtering the file mountpoints
                        // if there some selected in the workspace record
-               if ($this->workspace !== 0) {
-                       $usersFileMounts = $this->groupData['filemounts'];
-                       $this->groupData['filemounts'] = array();
-               }
-               $fileMountpoints = trim($this->workspaceRec['file_mountpoints']);
                if ($this->workspace > 0) {
+                       $storageFiltersInWorkspace = trim($this->workspaceRec['file_mountpoints']);
 
                                // no custom filemounts that should serve as filter or user is admin
                                // so all user mountpoints are re-applied
-                       if ($this->isAdmin() || $fileMountpoints === '') {
-                               $this->groupData['filemounts'] = $usersFileMounts;
-                       } else {
+                       if (!$this->isAdmin() && $storageFiltersInWorkspace !== '') {
+                                       // empty the fileStorages (will be re-applied later)
+                               $existingFileStoragesOfUser = $this->fileStorages;
+                               $this->fileStorages = array();
+
+                               $storageRepository = t3lib_div::makeInstance('t3lib_file_Repository_StorageRepository');
+
                                        // Fetching all filemounts from the workspace
                                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
                                        '*',
                                        'sys_filemounts',
-                                       'deleted = 0 AND hidden = 0 AND pid = 0 AND uid IN (' . $GLOBALS['TYPO3_DB']->cleanIntList($fileMountpoints) . ')'
+                                       'deleted = 0 AND hidden = 0 AND pid = 0 AND uid IN (' . $GLOBALS['TYPO3_DB']->cleanIntList($storageFiltersInWorkspace) . ')'
                                );
 
+                                       // add every filemount of this workspace record
                                while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
-                                               // add every filemount of this workspace record
-                                       $this->addFileMount($row['title'], $row['path'], $row['path'], ($row['base'] ? 1 : 0), '');
-
                                                // get the added entry, and check if it was in the users' original filemounts
                                                // if not, remove it from the new filemount list again
                                                // see self::addFileMount
-                                       end($this->groupData['filemounts']);
-                                       $md5hash = key($this->groupData['filemounts']);
-                                       if (!array_key_exists($md5hash, $usersFileMounts)) {
-                                               unset($this->groupData['filemounts'][$md5hash]);
+
+                                               // TODO: check if the filter is narrowing down the existing user
+                                       $storageObject = $storageRepository->findByUid($row['base']);
+                                       if (isset($existingFileStoragesOfUser[$storageObject->getUid()])) {
+                                               $storageObject->injectFileMount($row['path']);
+                                               $this->fileStorages[$storageObject->getUid()] = $storageObject;
                                        }
                                }
+                               $GLOBALS['TYPO3_DB']->sql_free_result($res);
                        }
                }
-
-               if ($allowed_languages = $this->getTSConfigVal('options.workspaces.allowed_languages.' . $this->workspace)) {
-                       $this->groupData['allowed_languages'] = $allowed_languages;
-                       $this->groupData['allowed_languages'] = t3lib_div::uniqueList($this->groupData['allowed_languages']);
-               }
        }
 
        /**
@@ -1769,6 +2053,7 @@ abstract class t3lib_userAuthGroup extends t3lib_userAuth {
                        if ($testRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
                                $theTimeBack = $testRow['tstamp'];
                        }
+                       $GLOBALS['TYPO3_DB']->sql_free_result($res);
 
                                // Check for more than $max number of error failures with the last period.
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
index 5206ab6..2fc77b9 100644 (file)
@@ -273,14 +273,22 @@ var inline = {
 
                // foreign_selector: used by element browser (type='group/db')
        importElement: function(objectId, table, uid, type) {
-               window.setTimeout(
-                       function() {
-                               inline.makeAjaxCall('createNewRecord', [inline.getNumberOfRTE(), objectId, uid], true);
-                       },
-                       10
-               );
+               inline.makeAjaxCall('createNewRecord', [inline.getNumberOfRTE(), objectId, uid], true);
        },
 
+       importElementMultiple: function(objectId, table, uidArray, type) {
+               inline.collapseAllRecords();
+               uidArray.each(function(uid) {
+                       inline.delayedImportElement(objectId, table, uid, type);
+               });
+       },
+       delayedImportElement: function(objectId, table, uid, type) {
+               if (inline.lockedAjaxMethod['createNewRecord'] == true) {
+                       window.setTimeout("inline.delayedImportElement('" + objectId + "','" + table + "'," +  uid + ", null );", 300);
+               } else {
+                       inline.importElement(objectId, table, uid, type);
+               }
+       },
                // Check uniqueness for element browser:
        checkUniqueElement: function(objectId, table, uid, type) {
                if (this.checkUniqueUsed(objectId, uid, table)) {
index 132b3c8..8be2935 100644 (file)
  *
  * @author             Kasper Skårhøj        <kasperYYYY@typo3.com>
  */
-
-
-// *******************************
-// Set error reporting
-// *******************************
-error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED);
-
-
-
-// ******************
-// Constants defined
-// ******************
-define('TYPO3_OS', stristr(PHP_OS,'win')&&!stristr(PHP_OS,'darwin')?'WIN':'');
-define('TYPO3_MODE','BE');
-
-if(!defined('PATH_thisScript')) {
-       define('PATH_thisScript', str_replace('//', '/', str_replace('\\', '/',
-               (PHP_SAPI == 'fpm-fcgi' || PHP_SAPI == 'cgi' || PHP_SAPI == 'isapi' || PHP_SAPI == 'cgi-fcgi') &&
-               ($_SERVER['ORIG_PATH_TRANSLATED'] ? $_SERVER['ORIG_PATH_TRANSLATED'] : $_SERVER['PATH_TRANSLATED']) ?
-               ($_SERVER['ORIG_PATH_TRANSLATED'] ? $_SERVER['ORIG_PATH_TRANSLATED'] : $_SERVER['PATH_TRANSLATED']) :
-               ($_SERVER['ORIG_SCRIPT_FILENAME'] ? $_SERVER['ORIG_SCRIPT_FILENAME'] : $_SERVER['SCRIPT_FILENAME']))));
-}
-
-if(!defined('PATH_site'))              define('PATH_site', preg_replace('/[^\/]*.[^\/]*$/','',PATH_thisScript));               // the path to the website folder (see init.php)
-if(!defined('PATH_t3lib'))             define('PATH_t3lib', PATH_site.'t3lib/');
-define('PATH_typo3conf', PATH_site.'typo3conf/');
-define('TYPO3_mainDir', 'typo3/');             // This is the directory of the backend administration for the sites of this TYPO3 installation.
-define('PATH_typo3', PATH_site.TYPO3_mainDir);
-
-
-// ******************
-// Including config
-// ******************
-require_once(PATH_t3lib.'class.t3lib_div.php');
-require_once(PATH_t3lib.'class.t3lib_extmgm.php');
-
-require(PATH_t3lib.'config_default.php');
-if (!defined ('TYPO3_db')) {
-       die ('The configuration file was not included.');
-}
-if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['image_processing']) {
-       die ('ImageProcessing was disabled!');
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 /**
  * Class for generating a thumbnail from the input parameters given to the script
  *
@@ -111,62 +51,115 @@ class SC_t3lib_thumbs {
        var $sizeDefault='64x64';
 
        var $imageList;         // Coming from $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
-       var $input;             // Contains the absolute path to the file for which to make a thumbnail (after init())
+       /**
+        * will hold the file Object
+        * 
+        * @var t3lib_file_File $input
+        */
+       var $image;
 
                // Internal, static: GPvar:
        var $file;              // Holds the input filename (GET: file)
        var $size;              // Holds the input size (GET: size)
-       var $mtime = 0;         // Last modification time of the supplied file
+       var $mTime = 0;         // Last modification time of the supplied file
 
 
        /**
         * Initialize; reading parameters with GPvar and checking file path
-        * Results in internal var, $this->input, being set to the absolute path of the file for which to make the thumbnail.
+        * Results in internal var, $this->file, being set to the file object which should be used to make a thumbnail.
         *
         * @return      void
         */
        function init() {
                        // Setting GPvars:
-               $file = t3lib_div::_GP('file');
-               $size = t3lib_div::_GP('size');
+               $size = t3lib_div::_GP('size'); // Only needed for MD5 sum calculation of backwards-compatibility uploads/ files thumbnails.
+               $filePathOrCombinedFileIdentifier = rawurldecode(t3lib_div::_GP('file'));
                $md5sum = t3lib_div::_GP('md5sum');
 
                        // Image extension list is set:
                $this->imageList = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];                 // valid extensions. OBS: No spaces in the list, all lowercase...
 
-                       // If the filereference $this->file is relative, we correct the path
-               if (substr($file,0,3)=='../') {
-                       $file = PATH_site.substr($file,3);
+                       // Check if we got a combined file identifier of the form storageUid:fileIdentifer.
+               // We need to distinguish it from absolute Windows paths by cbecking for an integer as first part.
+               $parts = t3lib_div::trimExplode(':', $filePathOrCombinedFileIdentifier);
+
+                       // best case: we get a sys_file UID
+               if (t3lib_utility_Math::canBeInterpretedAsInteger($filePathOrCombinedFileIdentifier)) {
+                       /** @var t3lib_file_File $filePathOrCombinedFileIdentifier */
+                       $fileObject = t3lib_file_Factory::getInstance()->getFileObject($filePathOrCombinedFileIdentifier);
+
+               } elseif (count($parts) <= 1 || !t3lib_utility_Math::canBeInterpretedAsInteger($parts[0])) {
+                               // TODO: Historically, the input parameter could also be an absolute path. This should be supported again to stay compatible.
+                       $relativeFilePath = $filePathOrCombinedFileIdentifier; // We assume the FilePath to be a relative file path (as in backwards compatibility mode)
+
+                               // The incoming relative path is relative to the typo3/ directory, but we need it relative to PATH_site. This is corrected here:
+                       if (substr($relativeFilePath, 0, 3)=='../') {
+                               $relativeFilePath = substr($relativeFilePath,3);
+                       } else {
+                               $relativeFilePath = 'typo3/'.$relativeFilePath;
+                       }
+
+                       $relativeFilePath = ltrim($relativeFilePath, '/');
+                       $mTime = 0;
+
+                               // Checking for backpath and double slashes + the thumbnail can be made from files which are in the PATH_site OR the lockRootPath only!
+                       if (t3lib_div::isAllowedAbsPath(PATH_site.$relativeFilePath)) {
+                               $mTime = filemtime(PATH_site.$relativeFilePath);
+                       }
+
+                       if(strstr($relativeFilePath, '../') !== FALSE) {
+                               $this->errorGif('File path', 'must not contain', '"../"'); // Maybe this could be relaxed to not throw an error as long as the path is still within PATH_site
+                       }
+
+                       if ($relativeFilePath && file_exists(PATH_site.$relativeFilePath)) {
+                                       // Check file extension:
+                               $reg = array();
+                               if (preg_match('/(.*)\.([^\.]*$)/', $relativeFilePath, $reg)) {
+                                       $ext=strtolower($reg[2]);
+                                       $ext=($ext=='jpeg') ? 'jpg' : $ext;
+                                       if (!t3lib_div::inList($this->imageList, $ext)) {
+                                               $this->errorGif('Not imagefile!', $ext, basename($relativeFilePath));
+                                       }
+                               } else {
+                                       $this->errorGif('Not imagefile!', 'No ext!', basename($relativeFilePath));
+                               }
+                       } else{
+                               $this->errorGif('Input file not found.', 'not found in thumbs.php', basename($relativeFilePath));
+                       }
+
+                               // Do an MD5 check to prevent viewing of images without permission
+                       $OK = FALSE;
+                       if ($mTime) {
+                                       // Always use the absolute path for this check!
+                               $check = basename($relativeFilePath).':'.$mTime.':'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
+                               $md5_real = t3lib_div::shortMD5($check);
+                               if (!strcmp($md5_real,$md5sum)) {
+                                       $OK = TRUE;
+                               }
+                       }
+
+                       $combinedIdentifier = '0:'.$relativeFilePath;
+               } else {
+                       $combinedIdentifier = $filePathOrCombinedFileIdentifier;
+                       $OK = FALSE;
                }
 
-               $mtime = 0;
-                       // Now the path is absolute.
-                       // Checking for backpath and double slashes + the thumbnail can be made from files which are in the PATH_site OR the lockRootPath only!
-               if (t3lib_div::isAllowedAbsPath($file)) {
-                       $mtime = filemtime($file);
+               if (empty($fileObject)) {
+                       $fileObject = t3lib_file_Factory::getInstance()->getFileObjectFromCombinedIdentifier($combinedIdentifier);
                }
 
-                       // Do an MD5 check to prevent viewing of images without permission
-               $OK = FALSE;
-               if ($mtime) {
-                               // Always use the absolute path for this check!
-                       $check = basename($file).':'.$mtime.':'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
-                       $md5pre47 = t3lib_div::shortMD5($check);
-                       $md5from47 = md5($check);
-                       if (!strcmp($md5pre47, $md5sum) || !strcmp($md5from47, $md5sum)) {
-                               $OK = TRUE;
-                       }
+               if (empty($OK)) {
+                       $OK = $fileObject !== NULL && $fileObject->checkActionPermission('read') && $fileObject->calculateChecksum() == $md5sum;
                }
 
                if ($OK) {
-                       $this->input = $file;
+                       $this->image = $fileObject;
                        $this->size = $size;
-                       $this->mtime = $mtime;
+                       //$this->mtime = $fileObject->getProperty('mtime');
                } else {
                                // hide the path to the document root;
-                       $publicFilename = substr($file, strlen(PATH_site));
                        throw new RuntimeException(
-                               'TYPO3 Fatal Error: Image \'' . $publicFilename . '\' does not exist and/or MD5 checksum did not match. ' .
+                               'TYPO3 Fatal Error: The requested image does not exist and/or MD5 checksum did not match. ' .
                                        'If the target file exists and its file name contains special characters, the setting of ' .
                                        '$TYPO3_CONF_VARS[SYS][systemLocale] might be wrong.'
                                ,
@@ -182,25 +175,18 @@ class SC_t3lib_thumbs {
         * @return      void
         */
        function main() {
-                       // If file exists, we make a thumbsnail of the file.
-               if ($this->input && file_exists($this->input)) {
+                       // If file exists, we make a thumbnail of the file.
+               if (is_object($this->image)) {
 
                                // Check file extension:
-                       $reg = array();
-                       if (preg_match('/(.*)\.([^\.]*$)/', $this->input, $reg)) {
-                               $ext=strtolower($reg[2]);
-                               $ext=($ext=='jpeg') ? 'jpg' : $ext;
-                               if ($ext=='ttf') {
-                                       $this->fontGif($this->input);   // Make font preview... (will not return)
-                               } elseif (!t3lib_div::inList($this->imageList, $ext)) {
-                                       $this->errorGif('Not imagefile!', $ext, basename($this->input));
-                               }
-                       } else {
-                               $this->errorGif('Not imagefile!', 'No ext!', basename($this->input));
+                       if ($this->image->getExtension() == 'ttf') {
+                               $this->fontGif($this->image);   // Make font preview... (will not return)
+                       } elseif(($this->image->getType() != t3lib_file_File::FILETYPE_IMAGE) && !t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $this->image->getExtension())) {
+                               $this->errorGif('Not imagefile!', 'No ext!', $this->image->getName());
                        }
 
                                // ... so we passed the extension test meaning that we are going to make a thumbnail here:
-                       if (!$this->size)       $this->size = $this->sizeDefault;       // default
+                       if (!$this->size) $this->size = $this->sizeDefault;     // default
 
                                // I added extra check, so that the size input option could not be fooled to pass other values. That means the value is exploded, evaluated to an integer and the imploded to [value]x[value]. Furthermore you can specify: size=340 and it'll be translated to 340x340.
                        $sizeParts = explode('x', $this->size . 'x' . $this->size);     // explodes the input size (and if no "x" is found this will add size again so it is the same for both dimensions)
@@ -214,19 +200,19 @@ class SC_t3lib_thumbs {
                                // Should be - ? 'png' : 'gif' - , but doesn't work (ImageMagick prob.?)
                                // René: png work for me
                        $thmMode = t3lib_utility_Math::forceIntegerInRange($GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails_png'], 0);
-                       $outext = ($ext!='jpg' || ($thmMode & 2)) ? ($thmMode & 1 ? 'png' : 'gif') : 'jpg';
+                       $outext = ($this->image->getExtension() != 'jpg' || ($thmMode & 2)) ? ($thmMode & 1 ? 'png' : 'gif') : 'jpg';
 
-                       $outfile = 'tmb_' . substr(md5($this->input . $this->mtime . $this->size), 0, 10) . '.' . $outext;
+                       $outfile = 'tmb_' . substr(md5($this->image->getName() . $this->mtime . $this->size), 0, 10) . '.' . $outext;
                        $this->output = $outpath . $outfile;
 
                        if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im']) {
                                        // If thumbnail does not exist, we generate it
                                if (!file_exists($this->output)) {
-                                       $parameters = '-sample ' . $this->size . ' ' . $this->wrapFileName($this->input) . '[0] ' . $this->wrapFileName($this->output);
+                                       $parameters = '-sample ' . $this->size . ' ' . $this->wrapFileName($this->image->getForLocalProcessing(FALSE)) . '[0] ' . $this->wrapFileName($this->output);
                                        $cmd = t3lib_div::imageMagickCommand('convert', $parameters);
                                        t3lib_utility_Command::exec($cmd);
                                        if (!file_exists($this->output)) {
-                                               $this->errorGif('No thumb','generated!', basename($this->input));
+                                               $this->errorGif('No thumb','generated!', $this->image->getName());
                                        } else {
                                                t3lib_div::fixPermissions($this->output);
                                        }
@@ -246,7 +232,7 @@ class SC_t3lib_thumbs {
                                }
                        } else exit;
                } else {
-                       $this->errorGif('No valid','inputfile!', basename($this->input));
+                       $this->errorGif('No valid', 'inputfile!', basename($this->image));
                }
        }
 
@@ -398,9 +384,6 @@ if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLA
        include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/thumbs.php']);
 }
 
-
-
-
 // Make instance:
 $SOBE = t3lib_div::makeInstance('SC_t3lib_thumbs');
 $SOBE->init();
diff --git a/tests/t3lib/class.t3lib_extfilefuncTest.php b/tests/t3lib/class.t3lib_extfilefuncTest.php
new file mode 100644 (file)
index 0000000..e672616
--- /dev/null
@@ -0,0 +1,591 @@
+<?php
+
+/* * *************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2011 Fabien Udriot <fabien.udriot@ecodev.ch>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project 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.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script 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.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ * ************************************************************* */
+
+/**
+ * Testcase for class t3lib_extFileFunctions
+ *
+ * @author Fabien Udriot <fabien.udriot@ecodev.ch>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_extFileFunctionsTest extends tx_phpunit_testcase {
+
+       /**
+        * @var fileProcessor
+        */
+       protected $fileProcessor;
+
+       /**
+        * @var t3lib_file_Repository_StorageRepository
+        */
+       protected $storageRepository;
+
+       /**
+        * @var string
+        */
+       protected $newFileNameInput = '_unitTestedFile.txt';
+
+       /**
+        * @var string
+        */
+       protected $newFolderNameInput = '_unitTestedFolder';
+
+       /**
+        * @var string
+        */
+       protected $renameFileNameInput = '_unitTestedFileRenamed.txt';
+
+       /**
+        * @var string
+        */
+       protected $renameFolderNameInput = '_unitTestedFolderRenamed';
+
+       /**
+        * @var string
+        */
+       protected $copyFolderNameInput = '_unitTestedFolderCopied';
+
+       /**
+        * @var string
+        */
+       protected $moveFolderNameInput = '_unitTestedFolderMoved';
+
+       /**
+        * @var array
+        */
+       protected $objectsToTearDown = array();
+
+       /**
+        * Sets up this testcase
+        */
+       public function setUp() {
+
+               $this->storageRepository = t3lib_div::makeInstance('t3lib_file_Repository_StorageRepository');
+
+               // Initializing file processor
+               $GLOBALS['BE_USER'] = $this->getMock(
+                       't3lib_beUserAuth', array('getSessionData', 'setAndSaveSessionData')
+               );
+               $GLOBALS['BE_USER']->user['uid'] = 1;
+
+               $GLOBALS['FILEMOUNTS'] = array();
+
+               // Initializing:
+               $this->fileProcessor = t3lib_div::makeInstance('t3lib_extFileFunctions');
+               $this->fileProcessor->init($GLOBALS['FILEMOUNTS'], $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
+               $this->fileProcessor->init_actionPerms($GLOBALS['BE_USER']->getFileoperationPermissions());
+               $this->fileProcessor->dontCheckForUnique = 1;
+       }
+
+       /**
+        * Tears down this testcase
+        */
+       public function tearDown() {
+               foreach ($this->objectsToTearDown as $object) {
+                       if ($object instanceof t3lib_file_File || $object instanceof t3lib_file_Folder) {
+                               $object->delete();
+                       }
+               }
+               $this->objectsToTearDown = array();
+       }
+
+       /**
+        * @return t3lib_file_Storage
+        */
+       protected function getDefaultStorage() {
+
+               // Get the first storage available.
+               // Notice if no storage is found, a storage is created on the fly.
+               $storages = $this->storageRepository->findAll();
+
+               // Makes sure to return a storage having a local driver
+               foreach ($storages as $storage) {
+                       // @todo how to retrieve information about the driver since @driver@ and @storageRecord@ are private
+               }
+
+               //* @var $storage t3lib_file_Storage */
+               return $storages[0];
+       }
+       /**
+        * @return string
+        */
+       protected function getRootFolderIdentifier() {
+               $storage = $this->getDefaultStorage();
+
+               $folderIdentifier = '/'; // the root of the storage
+               $folderCombinedIdentifier = $storage->getUid() . ':' . $folderIdentifier;
+               return $folderCombinedIdentifier;
+       }
+
+       /*********************************
+        * CREATE
+        ********************************/
+       /**
+        * @test
+        */
+       public function createNewFileInLocalStorage() {
+
+               // Defines values
+               $fileValues = array(
+                       'newfile' => array(
+                               array(
+                                       'data' => $this->newFileNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $fileObject = NULL;
+               if (!empty ($results['newfile'][0])) {
+                       $fileObject = $results['newfile'][0];
+               }
+
+               $this->objectsToTearDown[] = $fileObject;
+               $this->assertEquals(TRUE, $fileObject instanceof t3lib_file_File);
+       }
+
+       /**
+        * @test
+        */
+       public function createNewFolderInLocalStorage() {
+
+               // Defines values
+               $fileValues = array(
+                       'newfolder' => array(
+                               array(
+                                       'data' => $this->newFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $folderObject = NULL;
+               if (!empty ($results['newfolder'][0])) {
+                       $folderObject = $results['newfolder'][0];
+               }
+
+               $this->objectsToTearDown[] = $folderObject;
+               $this->assertEquals(TRUE, $folderObject instanceof t3lib_file_Folder);
+       }
+
+       /*********************************
+        * DELETE
+        ********************************/
+       /**
+        * @test
+        */
+       public function deleteFileInLocalStorage() {
+
+               // Computes a $fileIdentifier which looks like 8:/fileName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $fileIdentifier = $storage->getUid() . ':/' . $this->newFileNameInput;
+
+               // Defines values
+               $fileValues = array(
+                       'newfile' => array(
+                               array(
+                                       'data' => $this->newFileNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'delete' => array(
+                               array(
+                                       'data' => $fileIdentifier,
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $this->assertEquals(TRUE, empty ($results['delete'][1]));
+       }
+
+       /**
+        * @test
+        */
+       public function deleteFolderInLocalStorage() {
+
+               // Computes a $fileIdentifier which looks like 8:/fileName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $folderIdentifier = $storage->getUid() . ':/' . $this->newFolderNameInput;
+
+               // Defines values
+               $fileValues = array(
+                       'newfolder' => array(
+                               array(
+                                       'data' => $this->newFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'delete' => array(
+                               array(
+                                       'data' => $folderIdentifier,
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $this->assertEquals(TRUE, empty ($results['delete'][1]));
+       }
+
+       /*********************************
+        * RENAME
+        ********************************/
+       /**
+        * @test
+        */
+       public function renameFileInLocalStorage() {
+
+               // Computes a $fileIdentifier which looks like 8:/fileName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $fileIdentifier = $storage->getUid() . ':/' . $this->newFileNameInput;
+
+               // Defines values
+               $fileValues = array(
+                       'newfile' => array(
+                               array(
+                                       'data' => $this->newFileNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'rename' => array(
+                               array(
+                                       'data' => $fileIdentifier,
+                                       'target' => $this->renameFileNameInput,
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $fileObject = NULL;
+               if (!empty ($results['rename'][0])) {
+                       $fileObject = $results['rename'][0];
+               }
+
+               $this->objectsToTearDown[] = $fileObject;
+               $this->assertEquals(TRUE, $fileObject instanceof t3lib_file_File);
+       }
+
+       /**
+        * @test
+        */
+       public function renameFolderInLocalStorage() {
+
+               // Computes a $fileIdentifier which looks like 8:/fileName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $folderIdentifier = $storage->getUid() . ':/' . $this->newFolderNameInput;
+
+               // Defines values
+               $fileValues = array(
+                       'newfolder' => array(
+                               array(
+                                       'data' => $this->newFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'rename' => array(
+                               array(
+                                       'data' => $folderIdentifier,
+                                       'target' => $this->renameFolderNameInput,
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $folderObject = NULL;
+               if (!empty ($results['rename'][0])) {
+                       $folderObject = $results['rename'][0];
+               }
+
+               $this->objectsToTearDown[] = $folderObject;
+               $this->assertEquals(TRUE, $folderObject instanceof t3lib_file_Folder);
+       }
+
+       /*********************************
+        * MOVE
+        ********************************/
+       /**
+        * @test
+        */
+       public function moveFileInLocalStorage() {
+
+               // Computes a $fileIdentifier which looks like 8:/fileName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $fileIdentifier = $storage->getUid() . ':/' . $this->newFileNameInput;
+               $targetFolder = $this->getRootFolderIdentifier() . $this->newFolderNameInput;
+
+               // Defines values
+               $fileValues = array(
+                       'newfile' => array(
+                               array(
+                                       'data' => $this->newFileNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'newfolder' => array(
+                               array(
+                                       'data' => $this->newFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'move' => array(
+                               array(
+                                       'data' => $fileIdentifier,
+                                       'target' => $targetFolder,
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $fileObject = NULL;
+               if (!empty ($results['move'][0])) {
+                       $fileObject = $results['move'][0];
+               }
+
+               // remove parent folder
+               if (!empty ($results['newfolder'][0])) {
+                       $this->objectsToTearDown[] = $results['newfolder'][0];
+               }
+
+               $this->assertEquals(TRUE, $fileObject instanceof t3lib_file_File);
+       }
+
+       /**
+        * @test
+        */
+       public function moveFolderInLocalStorage() {
+
+               // Computes a $folderIdentifier which looks like 8:/folderName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $folderIdentifier = $storage->getUid() . ':/' . $this->moveFolderNameInput;
+               $targetFolder = $this->getRootFolderIdentifier() . $this->newFolderNameInput;
+
+               // Defines values
+               $fileValues = array(
+                       'newfolder' => array(
+                               array(
+                                       'data' => $this->newFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               ),
+                               array(
+                                       'data' => $this->moveFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'move' => array(
+                               array(
+                                       'data' => $folderIdentifier,
+                                       'target' => $targetFolder,
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $folderObject = NULL;
+               if (!empty ($results['move'][0])) {
+                       $folderObject = $results['move'][0];
+               }
+
+               // remove parent folder
+               if (!empty ($results['newfolder'][0])) {
+                       $this->objectsToTearDown[] = $results['newfolder'][0];
+               }
+
+               $this->assertEquals(TRUE, $folderObject instanceof t3lib_file_File);
+       }
+
+       /*********************************
+        * COPY
+        ********************************/
+       /**
+        * @test
+        */
+       public function copyFileInLocalStorage() {
+
+               // Computes a $fileIdentifier which looks like 8:/fileName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $fileIdentifier = $storage->getUid() . ':/' . $this->newFileNameInput;
+               $targetFolder = $this->getRootFolderIdentifier() . $this->newFolderNameInput;
+
+               // Defines values
+               $fileValues = array(
+                       'newfile' => array(
+                               array(
+                                       'data' => $this->newFileNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'newfolder' => array(
+                               array(
+                                       'data' => $this->newFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'copy' => array(
+                               array(
+                                       'data' => $fileIdentifier,
+                                       'target' => $targetFolder,
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $fileObject = NULL;
+               if (!empty ($results['copy'][0])) {
+                       $fileObject = $results['copy'][0];
+               }
+
+               // remove parent folder
+               if (!empty ($results['newfolder'][0])) {
+                       $this->objectsToTearDown[] = $results['newfolder'][0];
+               }
+               if (!empty ($results['newfile'][0])) {
+                       $this->objectsToTearDown[] = $results['newfile'][0];
+               }
+
+               $this->assertEquals(TRUE, $fileObject instanceof t3lib_file_File);
+       }
+
+       /**
+        * @test
+        */
+       public function copyFolderInLocalStorage() {
+
+               // Computes a $folderIdentifier which looks like 8:/folderName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $folderIdentifier = $storage->getUid() . ':/' . $this->copyFolderNameInput;
+               $targetFolder = $this->getRootFolderIdentifier() . $this->newFolderNameInput;
+
+               // Defines values
+               $fileValues = array(
+                       'newfolder' => array(
+                               array(
+                                       'data' => $this->newFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               ),
+                               array(
+                                       'data' => $this->copyFolderNameInput,
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+                       'copy' => array(
+                               array(
+                                       'data' => $folderIdentifier,
+                                       'target' => $targetFolder,
+                               )
+                       )
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $folderObject = NULL;
+               if (!empty ($results['copy'][0])) {
+                       $folderObject = $results['copy'][0];
+               }
+
+               // remove parent folder
+               if (!empty ($results['newfolder'][0])) {
+                       $this->objectsToTearDown[] = $results['newfolder'][0];
+               }
+               if (!empty ($results['newfolder'][1])) {
+                       $this->objectsToTearDown[] = $results['newfolder'][1];
+               }
+
+               $this->assertEquals(TRUE, $folderObject instanceof t3lib_file_File);
+       }
+
+       /*********************************
+        * UPLOAD
+        ********************************/
+       /**
+        * @test
+        */
+       public function uploadFileInLocalStorage() {
+
+               // Computes a $fileIdentifier which looks like 8:/fileName.txt where 8 is the storage Uid
+               $storage = $this->getDefaultStorage();
+               $fileIdentifier = $storage->getUid() . ':/' . $this->newFileNameInput;
+               $targetFolder = $this->getRootFolderIdentifier() . $this->newFolderNameInput;
+
+               // creates fake file
+               $tmpFile = '/tmp/php5Wx0aJ';
+               touch ($tmpFile);
+
+               $_FILES['upload_phpunit'] = array(
+                       'name' => $this->newFileNameInput,
+                       'type' => 'text/plain',
+                       'tmp_name' => $tmpFile,
+                       'error' => 0,
+                       'size' => 10,
+               );
+
+               // Defines values
+               $fileValues = array(
+                       'upload' => array(
+                               array(
+                                       'data' => 'phpunit',
+                                       'target' => $this->getRootFolderIdentifier(),
+                               )
+                       ),
+               );
+
+               $this->fileProcessor->start($fileValues);
+               $results = $this->fileProcessor->processData();
+
+               $fileObject = NULL;
+               if (!empty ($results['upload'][0])) {
+                       $fileObject = $results['upload'][0];
+               }
+
+               print '<b>Test does not work because of function is_uploaded_file() which is not faked yet @t3lib_file_Storage:820@ </b><br/>';
+
+               $this->objectsToTearDown[] = $fileObject;
+               unlink($tmpFile); // delete
+
+               $this->assertEquals(TRUE, $fileObject instanceof t3lib_file_File);
+       }
+}
+
+?>
\ No newline at end of file
index 436af81..1f4fc87 100644 (file)
@@ -116,7 +116,7 @@ class clickMenu {
                if ($GLOBALS['BE_USER']->uc['condensedMode'] || $this->iParts[2]==2) $this->alwaysContentFrame=1;
                if (strcmp($this->iParts[1],''))        $this->isDBmenu=1;
 
-               $TSkey =($this->isDBmenu?'page':'folder').($this->listFrame?'List':'Tree');
+               $TSkey = ($this->isDBmenu? 'page' : 'folder' ) . ($this->listFrame ? 'List' : 'Tree');
                $this->disabledItems = t3lib_div::trimExplode(',',$GLOBALS['BE_USER']->getTSConfigVal('options.contextMenu.'.$TSkey.'.disableItems'),1);
                $this->leftIcons = $GLOBALS['BE_USER']->getTSConfigVal('options.contextMenu.options.leftIcons');
 
@@ -787,42 +787,77 @@ class clickMenu {
        /**
         * Make 1st level clickmenu:
         *
-        * @param       string          The absolute path
-        * @return      string          HTML content
+        * @param string $combinedIdentifier The combined identifier
+        * @return string HTML content
+        * @see t3lib_file_Factory::retrieveFileOrFolderObject()
         */
-       function printFileClickMenu($path)      {
+       function printFileClickMenu($combinedIdentifier)        {
                $menuItems=array();
-
-               if (file_exists($path) && t3lib_div::isAllowedAbsPath($path))   {
-                       $fI = pathinfo($path);
-                       $size=' ('.t3lib_div::formatSize(filesize($path)).'bytes)';
-                       $icon = t3lib_iconWorks::getSpriteIconForFile(is_dir($path) ? 'folder' : strtolower($fI['extension']),
-                               array('class'=>'absmiddle', 'title' => htmlspecialchars($fI['basename'] . $size)));
-
+               $combinedIdentifier = rawurldecode($combinedIdentifier);
+
+               $fileObject = t3lib_file_Factory::getInstance()->retrieveFileOrFolderObject($combinedIdentifier);
+
+               if ($fileObject) {
+                       $folder = FALSE;
+                       $identifier = $fileObject->getCombinedIdentifier();
+                       if ($fileObject instanceof t3lib_file_Folder) {
+                               $icon = t3lib_iconWorks::getSpriteIconForFile(
+                                       'folder',
+                                       array(
+                                                'class'=>'absmiddle',
+                                                'title' => htmlspecialchars($fileObject->getName())
+                                       )
+                               );
+                               $folder = TRUE;
+                       } else {
+                               $icon = t3lib_iconWorks::getSpriteIconForFile(
+                                       $fileObject->getExtension(),
+                                       array(
+                                                'class'=>'absmiddle',
+                                                'title' => htmlspecialchars(
+                                                        $fileObject->getName() .
+                                                       ' (' . t3lib_div::formatSize($fileObject->getSize()) . ')'
+                                                )
+                                       )
+                               );
+                       }
                                // edit
-                       if (!in_array('edit',$this->disabledItems) && is_file($path) && t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'],$fI['extension'])) $menuItems['edit']=$this->FILE_launch($path,'file_edit.php','edit','edit_file.gif');
+                       if (!in_array('edit', $this->disabledItems) && !$folder
+                                       && t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'], $fileObject->getExtension())) {
+                               $menuItems['edit'] = $this->FILE_launch($identifier, 'file_edit.php', 'edit', 'edit_file.gif');
+                       }
                                // rename
-                       if (!in_array('rename',$this->disabledItems))   $menuItems['rename']=$this->FILE_launch($path,'file_rename.php','rename','rename.gif');
+                       if (!in_array('rename', $this->disabledItems)) {
+                               $menuItems['rename'] = $this->FILE_launch($identifier, 'file_rename.php', 'rename', 'rename.gif');
+                       }
                                // upload
-                       if (!in_array('upload',$this->disabledItems) && is_dir($path)) {
-                               $menuItems['upload'] = $this->FILE_upload($path);
+                       if (!in_array('upload', $this->disabledItems) && $folder) {
+                               $menuItems['upload'] = $this->FILE_upload($identifier);
                        }
 
                                // new
-                       if (!in_array('new',$this->disabledItems) && is_dir($path)) $menuItems['new']=$this->FILE_launch($path,'file_newfolder.php','new','new_file.gif');
+                       if (!in_array('new', $this->disabledItems) && $folder) {
+                               $menuItems['new'] = $this->FILE_launch($identifier, 'file_newfolder.php', 'new', 'new_file.gif');
+                       }
                                // info
-                       if (!in_array('info',$this->disabledItems))     $menuItems['info']=$this->DB_info($path,'');
+                       if (!in_array('info', $this->disabledItems)) {
+                               $menuItems['info'] = $this->DB_info($identifier, '');
+                       }
 
-                       $menuItems[]='spacer';
+                       $menuItems[] = 'spacer';
 
                                // copy:
-                       if (!in_array('copy',$this->disabledItems))     $menuItems['copy']=$this->FILE_copycut($path,'copy');
+                       if (!in_array('copy', $this->disabledItems)) {
+                               $menuItems['copy'] = $this->FILE_copycut($identifier, 'copy');
+                       }
                                // cut:
-                       if (!in_array('cut',$this->disabledItems))      $menuItems['cut']=$this->FILE_copycut($path,'cut');
+                       if (!in_array('cut', $this->disabledItems)) {
+                               $menuItems['cut'] = $this->FILE_copycut($identifier, 'cut');
+                       }
 
                                // Paste:
                        $elFromAllTables = count($this->clipObj->elFromTable('_FILE'));
-                       if (!in_array('paste',$this->disabledItems) && $elFromAllTables && is_dir($path))       {
+                       if (!in_array('paste', $this->disabledItems) && $elFromAllTables && $folder)    {
                                $elArr = $this->clipObj->elFromTable('_FILE');
                                $selItem = reset($elArr);
                                $elInfo=array(
@@ -830,23 +865,25 @@ class clickMenu {
                                        basename($path),
                                        $this->clipObj->currentMode()
                                );
-                               $menuItems['pasteinto']=$this->FILE_paste($path,$selItem,$elInfo);
+                               $menuItems['pasteinto'] = $this->FILE_paste($identifier, $selItem, $elInfo);
                        }
 
                        $menuItems[]='spacer';
 
                                // delete:
-                       if (!in_array('delete',$this->disabledItems))   $menuItems['delete']=$this->FILE_delete($path);
+                       if (!in_array('delete', $this->disabledItems)) {
+                               $menuItems['delete']=$this->FILE_delete($identifier);
+                       }
                }
 
                        // Adding external elements to the menuItems array
-               $menuItems = $this->processingByExtClassArray($menuItems,$path,0);
+               $menuItems = $this->processingByExtClassArray($menuItems, $identifier, 0);
 
                        // Processing by external functions?
                $menuItems = $this->externalProcessingOfFileMenuItems($menuItems);
 
                        // Return the printed elements:
-               return $this->printItems($menuItems,$icon.basename($path));
+               return $this->printItems($menuItems, $icon . $fileObject->getName());
        }
 
 
index d3ce033..14bb7fa 100644 (file)
@@ -50,7 +50,11 @@ class SC_alt_file_navframe {
 
                // Internal, dynamic:
        var $content;           // Content accumulates in this variable.
-       var $foldertree;        // Folder tree object.
+
+       /**
+        * @var filelistFolderTree $foldertree the folder tree object
+        */
+       var $foldertree;
 
        /**
         * document template object
@@ -272,7 +276,7 @@ class SC_alt_file_navframe {
        public function ajaxExpandCollapse($params, $ajaxObj) {
                $this->init();
                $tree = $this->foldertree->getBrowsableTree();
-               if (!$this->foldertree->ajaxStatus)     {
+               if ($this->foldertree->getAjaxStatus() === FALSE) {
                        $ajaxObj->setError($tree);
                } else  {
                        $ajaxObj->addContent('tree', $tree);
index 40e92bc..f48aa39 100644 (file)
@@ -152,6 +152,7 @@ class SC_browse_links {
                        case 'filedrag':
                        case 'folder':
                                        // Setting additional read-only browsing file mounts
+                                       // @todo: add this feature for FAL and TYPO3 6.0
                                $altMountPoints = trim($GLOBALS['BE_USER']->getTSConfigVal('options.folderTree.altElementBrowserMountPoints'));
                                if ($altMountPoints) {
                                        $altMountPoints = t3lib_div::trimExplode(',', $altMountPoints);
index 1d9c408..5e4810a 100644 (file)
@@ -66,6 +66,15 @@ class SC_browser {
                $mode =t3lib_div::_GP('mode');
                $bparams = t3lib_div::_GP('bparams');
 
+               // workaround for FAL: previously, we had file as a mode, now we have sys_file db records
+               // check if we need to "translate" sys_file queries to mode=file queries
+               // @todo: handle this the right way in the TYPO3 core
+               $bParamElements = explode('|', $bparams);
+               if ($mode == 'db' && $bParamElements[3] == 'sys_file') {
+                       $mode = 'file';
+               }
+
+
 
                        // Set doktype:
                $GLOBALS['TBE_TEMPLATE']->docType='xhtml_frames';
index 1019f51..f02f135 100644 (file)
@@ -361,6 +361,7 @@ class TBE_PageTree extends localPageTree {
 /**
  * Base extension class which generates the folder tree.
  * Used directly by the RTE.
+ * also used for the linkpicker on files
  *
  * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
  * @package TYPO3
@@ -383,13 +384,13 @@ class localFolderTree extends t3lib_folderTree {
        /**
         * Wrapping the title in a link, if applicable.
         *
-        * @param       string          Title, ready for output.
-        * @param       array           The "record"
-        * @return      string          Wrapping title string.
+        * @param string $title Title, ready for output.
+        * @param t3lib_file_Folder $folderObject The "record"
+        * @return string Wrapping title string.
         */
-       function wrapTitle($title,$v)   {
-               if ($this->ext_isLinkable($v))  {
-                       $aOnClick = 'return jumpToUrl(\''.$this->thisScript.'?act='.$GLOBALS['SOBE']->browser->act.'&mode='.$GLOBALS['SOBE']->browser->mode.'&expandFolder='.rawurlencode($v['path']).'\');';
+       function wrapTitle($title, t3lib_file_Folder $folderObject) {
+               if ($this->ext_isLinkable($folderObject)) {
+                       $aOnClick = 'return jumpToUrl(\''.$this->thisScript.'?act='.$GLOBALS['SOBE']->browser->act.'&mode='.$GLOBALS['SOBE']->browser->mode.'&expandFolder='.rawurlencode($folderObject->getCombinedIdentifier()).'\');';
                        return '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.$title.'</a>';
                } else {
                        return '<span class="typo3-dimmed">'.$title.'</span>';
@@ -399,15 +400,15 @@ class localFolderTree extends t3lib_folderTree {
        /**
         * Returns TRUE if the input "record" contains a folder which can be linked.
         *
-        * @param       array           Array with information about the folder element. Contains keys like title, uid, path, _title
-        * @return      boolean         TRUE is returned if the path is found in the web-part of the server and is NOT a recycler or temp folder
+        * @param t3lib_file_Folder $folderObject Object with information about the folder element. Contains keys like title, uid, path, _title
+        * @return boolean TRUE is returned if the path is found in the web-part of the server and is NOT a recycler or temp folder
         */
-       function ext_isLinkable($v)     {
-               $webpath=t3lib_BEfunc::getPathType_web_nonweb($v['path']);      // Checking, if the input path is a web-path.
-               if (strstr($v['path'],'_recycler_') || strstr($v['path'],'_temp_') || $webpath!='web')  {
-                       return 0;
+       function ext_isLinkable(t3lib_file_Folder $folderObject) {
+               if (!$folderObject->getStorage()->isPublic() || strstr($folderObject->getIdentifier(), '_recycler_') || strstr($folderObject->getIdentifier(), '_temp_')) {
+                       return FALSE;
+               } else {
+                       return TRUE;
                }
-               return 1;
        }
 
        /**
@@ -427,65 +428,6 @@ class localFolderTree extends t3lib_folderTree {
                $aOnClick = 'return jumpToUrl(\''.$this->thisScript.'?PM='.$cmd.'\',\''.$anchor.'\');';
                return '<a href="#"'.$name.' onclick="'.htmlspecialchars($aOnClick).'">'.$icon.'</a>';
        }
-
-       /**
-        * Create the folder navigation tree in HTML
-        *
-        * @param       mixed           Input tree array. If not array, then $this->tree is used.
-        * @return      string          HTML output of the tree.
-        */
-       function printTree($treeArr='') {
-               $titleLen=intval($GLOBALS['BE_USER']->uc['titleLen']);
-
-               if (!is_array($treeArr))        $treeArr=$this->tree;
-
-               $out='';
-               $c=0;
-
-                       // Preparing the current-path string (if found in the listing we will see a red blinking arrow).
-               if (!$GLOBALS['SOBE']->browser->curUrlInfo['value'])    {
-                       $cmpPath='';
-               } elseif (substr(trim($GLOBALS['SOBE']->browser->curUrlInfo['info']),-1)!='/')  {
-                       $cmpPath=PATH_site.dirname($GLOBALS['SOBE']->browser->curUrlInfo['info']).'/';
-               } else {
-                       $cmpPath=PATH_site.$GLOBALS['SOBE']->browser->curUrlInfo['info'];
-               }
-
-                       // Traverse rows for the tree and print them into table rows:
-               foreach($treeArr as $k => $v)   {
-                       $c++;
-                       $bgColorClass=($c+1)%2 ? 'bgColor' : 'bgColor-10';
-
-                               // Creating blinking arrow, if applicable:
-                       if (($GLOBALS['SOBE']->browser->curUrlInfo['act'] == 'file' || $GLOBALS['SOBE']->browser->curUrlInfo['act'] == 'folder') && $cmpPath == $v['row']['path']) {
-                               $arrCol='<td><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/blinkarrow_right.gif','width="5" height="9"').' class="c-blinkArrowR" alt="" /></td>';
-                               $bgColorClass='bgColor4';
-                       } else {
-                               $arrCol='<td></td>';
-                       }
-                               // Create arrow-bullet for file listing (if folder path is linkable):
-                       $aOnClick = 'return jumpToUrl(\''.$this->thisScript.'?act='.$GLOBALS['SOBE']->browser->act.'&mode='.$GLOBALS['SOBE']->browser->mode.'&expandFolder='.rawurlencode($v['row']['path']).'\');';
-                       $cEbullet = $this->ext_isLinkable($v['row']) ? '<a href="#" onclick="'.htmlspecialchars($aOnClick).'"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/ol/arrowbullet.gif','width="18" height="16"').' alt="" /></a>' : '';
-
-                               // Put table row with folder together:
-                       $out.='
-                               <tr class="'.$bgColorClass.'">
-                                       <td nowrap="nowrap">' . $v['HTML'] . $this->wrapTitle(htmlspecialchars(t3lib_div::fixed_lgd_cs($v['row']['title'], $titleLen)), $v['row']) . '</td>
-                                       '.$arrCol.'
-                                       <td>'.$cEbullet.'</td>
-                               </tr>';
-               }
-
-               $out='
-
-                       <!--
-                               Folder tree:
-                       -->
-                       <table border="0" cellpadding="0" cellspacing="0" id="typo3-tree">
-                               '.$out.'
-                       </table>';
-               return $out;
-       }
 }
 
 
@@ -522,28 +464,30 @@ class TBE_FolderTree extends localFolderTree {
        /**
         * Returns TRUE if the input "record" contains a folder which can be linked.
         *
-        * @param       array           Array with information about the folder element. Contains keys like title, uid, path, _title
-        * @return      boolean         TRUE is returned if the path is NOT a recycler or temp folder AND if ->ext_noTempRecyclerDirs is not set.
+        * @param t3lib_file_Folder $folderObject object with information about the folder element. Contains keys like title, uid, path, _title
+        * @return boolean TRUE is returned if the path is NOT a recycler or temp folder AND if ->ext_noTempRecyclerDirs is not set.
         */
-       function ext_isLinkable($v)     {
-               if ($this->ext_noTempRecyclerDirs && (substr($v['path'],-7)=='_temp_/' || substr($v['path'],-11)=='_recycler_/'))       {
-                       return 0;
-               } return 1;
+       function ext_isLinkable($folderObject) {
+               if ($this->ext_noTempRecyclerDirs && (substr($folderObject->getIdentifier(), -7)=='_temp_/' || substr($folderObject->getIdentifier(),-11)=='_recycler_/'))      {
+                       return FALSE;
+               } else {
+                       return TRUE;
+               }
        }
 
        /**
         * Wrapping the title in a link, if applicable.
         *
-        * @param       string          Title, ready for output.
-        * @param       array           The 'record'
-        * @return      string          Wrapping title string.
+        * @param string $title Title, ready for output.
+        * @param t3lib_file_Folder $folderObject The folderObject 'record'
+        * @return string Wrapping title string.
         */
-       function wrapTitle($title,$v)   {
-               if ($this->ext_isLinkable($v))  {
-                       $aOnClick = 'return jumpToUrl(\''.$this->thisScript.'?act='.$GLOBALS['SOBE']->browser->act.'&mode='.$GLOBALS['SOBE']->browser->mode.'&expandFolder='.rawurlencode($v['path']).'\');';
-                       return '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.$title.'</a>';
+       function wrapTitle($title, $folderObject) {
+               if ($this->ext_isLinkable($folderObject)) {
+                       $aOnClick = 'return jumpToUrl(\'' . $this->thisScript . '?act=' . $GLOBALS['SOBE']->browser->act . '&mode=' . $GLOBALS['SOBE']->browser->mode.'&expandFolder=' . rawurlencode($folderObject->getCombinedIdentifier()) . '\');';
+                       return '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $title . '</a>';
                } else {
-                       return '<span class="typo3-dimmed">'.$title.'</span>';
+                       return '<span class="typo3-dimmed">' . $title . '</span>';
                }
        }
 }
@@ -601,7 +545,11 @@ class browse_links {
         */
        var $expandFolder;
 
-
+       /**
+        * the folder object of a parent folder that was selected
+        * @param t3lib_file_Folder
+        */
+       protected $selectedFolder;
 
        /**
         * TYPO3 Element Browser, wizard mode parameters. There is a heap of parameters there, better debug() them out if you need something... :-)
@@ -671,7 +619,6 @@ class browse_links {
         */
        public $fileProcessor;
 
-
        /**
         * Constructor:
         * Initializes a lot of variables, setting JavaScript functions in header etc.
@@ -699,6 +646,7 @@ class browse_links {
                        // Load the Prototype library and browse_links.js
                $this->doc->getPageRenderer()->loadPrototype();
                $this->doc->loadJavascriptLib('js/browse_links.js');
+               $this->doc->loadJavascriptLib('js/tree.js');
 
                        // init hook objects:
                $this->hookObjects = array();
@@ -735,12 +683,14 @@ class browse_links {
                        } else {
                                $currentValue = '';
                        }
+
                        $currentLinkParts = t3lib_div::unQuoteFilenames($currentValue, TRUE);
+
                        $initialCurUrlArray = array (
-                               'href'   => $currentLinkParts[0],
-                               'target' => $currentLinkParts[1],
-                               'class'  => $currentLinkParts[2],
-                               'title'  => $currentLinkParts[3],
+                               'href'    => $currentLinkParts[0],
+                               'target'  => $currentLinkParts[1],
+                               'class'   => $currentLinkParts[2],
+                               'title'   => $currentLinkParts[3],
                                'params'  => $currentLinkParts[4]
                        );
 
@@ -762,7 +712,13 @@ class browse_links {
 
                        $this->curUrlInfo = $this->parseCurUrl($this->siteURL.'?id='.$this->curUrlArray['href'], $this->siteURL);
                        if ($this->curUrlInfo['pageid'] == 0 && $this->curUrlArray['href']) { // pageid == 0 means that this is not an internal (page) link
-                               if (file_exists(PATH_site.rawurldecode($this->curUrlArray['href'])))    { // check if this is a link to a file
+                                       // check if there is the FAL API
+                               if (t3lib_div::isFirstPartOfStr($this->curUrlArray['href'], 'file:')) {
+                                       $this->curUrlInfo = $this->parseCurUrl($this->curUrlArray['href'], $this->siteURL);
+                                       $currentLinkParts[0] = rawurldecode(substr($this->curUrlArray['href'], 5));     // remove the "file:" prefix
+
+                                       // check if this is a link to a file
+                               } elseif (file_exists(PATH_site.rawurldecode($this->curUrlArray['href'])))      {
                                        if (t3lib_div::isFirstPartOfStr($this->curUrlArray['href'], PATH_site)) {
                                                $currentLinkParts[0] = substr($this->curUrlArray['href'], strlen(PATH_site));
                                        }
@@ -1030,7 +986,16 @@ class browse_links {
                        $JScodeAction = '
                                        if (parent.window.opener) {
                                                parent.window.opener.'.$pArr[7].'("'.addslashes($pArr[4]).'",table,uid,type);
-                                               focusOpenerAndClose(close);
+                                               if (close) { focusOpenerAndClose(close); }
+                                       } else {
+                                               alert("Error - reference to main window is not set properly!");
+                                               if (close) { parent.close(); }
+                                       }
+                       ';
+                       $JScodeActionMultiple = '
+                                               // Call helper function to manage data in the opener window:
+                                       if (parent.window.opener) {
+                                               parent.window.opener.' . $pArr[7] . 'Multiple("' . addslashes($pArr[4]) . '",table,uid,type,"' . addslashes($pArr[0]) . '");
                                        } else {
                                                alert("Error - reference to main window is not set properly!");
                                                parent.close();
@@ -1080,6 +1045,11 @@ class browse_links {
                                }
                                return false;
                        }
+                       function insertMultiple(table, uid) {
+                               var type = "";
+                                               ' . $JScodeActionMultiple . '
+                               return false;
+                       }
                        function addElement(elName,elValue,altElValue,close)    {       //
                                if (parent.window.opener && parent.window.opener.setFormValueFromBrowseWin)     {
                                        parent.window.opener.setFormValueFromBrowseWin("'.$pArr[0].'",altElValue?altElValue:elValue,elName);
@@ -1306,27 +1276,43 @@ class browse_links {
                                $foldertree->thisScript = $this->thisScript;
                                $tree                   = $foldertree->getBrowsableTree();
 
-                               if (!$this->curUrlInfo['value'] || $this->curUrlInfo['act'] != $this->act)      {
+                               if (!$this->curUrlInfo['value'] || $this->curUrlInfo['act'] != $this->act) {
                                        $cmpPath = '';
-                               } elseif (substr(trim($this->curUrlInfo['info']), -1) != '/')   {
-                                       $cmpPath = PATH_site.dirname($this->curUrlInfo['info']).'/';
+                               } else {
+                                       $cmpPath = $this->curUrlInfo['value'];
                                        if (!isset($this->expandFolder)) {
                                                $this->expandFolder = $cmpPath;
                                        }
-                               } else {
-                                       $cmpPath = PATH_site.$this->curUrlInfo['info'];
-                                       if (!isset($this->expandFolder) && $this->curUrlInfo['act'] == 'folder') {
-                                               $this->expandFolder&nb