Fixed bug #14050: CleanUp - CGL format of t3lib files - t3lib_positionmap
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_userauthgroup.php
old mode 100755 (executable)
new mode 100644 (file)
index 955af33..cd89783
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
+*  (c) 1999-2010 Kasper Skårhøj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
  * Contains an extension class specifically for authentication/initialization of backend users in TYPO3
  *
  * $Id$
- * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
+ * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
  *
- * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
  */
 /**
  * [CLASS/FUNCTION INDEX of SCRIPT]
  *
  *
  *
- *  134: class t3lib_userAuthGroup extends t3lib_userAuth
+ *  135: class t3lib_userAuthGroup extends t3lib_userAuth
  *
  *              SECTION: Permission checking functions:
- *  198:     function isAdmin()
- *  210:     function isMemberOfGroup($groupId)
- *  232:     function doesUserHaveAccess($row,$perms)
- *  249:     function isInWebMount($id,$readPerms='',$exitOnError=0)
- *  276:     function modAccess($conf,$exitOnError)
- *  327:     function getPagePermsClause($perms)
- *  366:     function calcPerms($row)
- *  404:     function isRTE()
- *  438:     function check($type,$value)
- *  455:     function checkAuthMode($table,$field,$value,$authMode)
- *  521:     function checkLanguageAccess($langValue)
- *  542:     function recordEditAccessInternals($table,$idOrRow)
- *  607:     function isPSet($lCP,$table,$type='')
- *  624:     function mayMakeShortcut()
- *  638:     function workspaceCannotEditRecord($table,$recData)
- *  677:     function workspaceCannotEditOfflineVersion($table,$recData)
- *  700:     function workspaceAllowLiveRecordsInPID($pid, $table)
- *  721:     function workspaceCreateNewRecord($pid, $table)
- *  740:     function workspaceAllowAutoCreation($table,$id,$recpid)
- *  760:     function workspaceCheckStageForCurrent($stage)
- *  783:     function workspacePublishAccess($wsid)
- *  807:     function workspaceSwapAccess()
- *  819:     function workspaceVersioningTypeAccess($type)
- *  846:     function workspaceVersioningTypeGetClosest($type)
+ *  199:     function isAdmin()
+ *  211:     function isMemberOfGroup($groupId)
+ *  233:     function doesUserHaveAccess($row,$perms)
+ *  250:     function isInWebMount($id,$readPerms='',$exitOnError=0)
+ *  277:     function modAccess($conf,$exitOnError)
+ *  328:     function getPagePermsClause($perms)
+ *  367:     function calcPerms($row)
+ *  405:     function isRTE()
+ *  439:     function check($type,$value)
+ *  456:     function checkAuthMode($table,$field,$value,$authMode)
+ *  522:     function checkLanguageAccess($langValue)
+ *  544:     function recordEditAccessInternals($table,$idOrRow,$newRecord=FALSE)
+ *  619:     function isPSet($lCP,$table,$type='')
+ *  636:     function mayMakeShortcut()
+ *  650:     function workspaceCannotEditRecord($table,$recData)
+ *  689:     function workspaceCannotEditOfflineVersion($table,$recData)
+ *  712:     function workspaceAllowLiveRecordsInPID($pid, $table)
+ *  733:     function workspaceCreateNewRecord($pid, $table)
+ *  752:     function workspaceAllowAutoCreation($table,$id,$recpid)
+ *  772:     function workspaceCheckStageForCurrent($stage)
+ *  795:     function workspacePublishAccess($wsid)
+ *  823:     function workspaceSwapAccess()
+ *  835:     function workspaceVersioningTypeAccess($type)
+ *  866:     function workspaceVersioningTypeGetClosest($type)
  *
  *              SECTION: Miscellaneous functions
- *  887:     function getTSConfig($objectString,$config='')
- *  913:     function getTSConfigVal($objectString)
- *  925:     function getTSConfigProp($objectString)
- *  937:     function inList($in_list,$item)
- *  948:     function returnWebmounts()
- *  958:     function returnFilemounts()
+ *  909:     function getTSConfig($objectString,$config='')
+ *  935:     function getTSConfigVal($objectString)
+ *  947:     function getTSConfigProp($objectString)
+ *  959:     function inList($in_list,$item)
+ *  970:     function returnWebmounts()
+ *  980:     function returnFilemounts()
+ *  997:     function jsConfirmation($bitmask)
  *
  *              SECTION: Authentication methods
- *  989:     function fetchGroupData()
- * 1122:     function fetchGroups($grList,$idList='')
- * 1209:     function setCachedList($cList)
- * 1229:     function addFileMount($title, $altTitle, $path, $webspace, $type)
- * 1276:     function addTScomment($str)
+ * 1035:     function fetchGroupData()
+ * 1168:     function fetchGroups($grList,$idList='')
+ * 1266:     function setCachedList($cList)
+ * 1286:     function addFileMount($title, $altTitle, $path, $webspace, $type)
+ * 1333:     function addTScomment($str)
  *
  *              SECTION: Workspaces
- * 1312:     function workspaceInit()
- * 1355:     function checkWorkspace($wsRec,$fields='uid,title,adminusers,members,reviewers,publish_access,stagechg_notification')
- * 1429:     function checkWorkspaceCurrent()
- * 1442:     function setWorkspace($workspaceId)
- * 1470:     function setWorkspacePreview($previewState)
- * 1480:     function getDefaultWorkspace()
+ * 1369:     function workspaceInit()
+ * 1412:     function checkWorkspace($wsRec,$fields='uid,title,adminusers,members,reviewers,publish_access,stagechg_notification')
+ * 1487:     function checkWorkspaceCurrent()
+ * 1500:     function setWorkspace($workspaceId)
+ * 1528:     function setWorkspacePreview($previewState)
+ * 1538:     function getDefaultWorkspace()
  *
  *              SECTION: Logging
- * 1531:     function writelog($type,$action,$error,$details_nr,$details,$data,$tablename='',$recuid='',$recpid='',$event_pid=-1,$NEWid='',$userId=0)
- * 1563:     function simplelog($message, $extKey='', $error=0)
- * 1584:     function checkLogFailures($email, $secondsBack=3600, $max=3)
+ * 1589:     function writelog($type,$action,$error,$details_nr,$details,$data,$tablename='',$recuid='',$recpid='',$event_pid=-1,$NEWid='',$userId=0)
+ * 1621:     function simplelog($message, $extKey='', $error=0)
+ * 1642:     function checkLogFailures($email, $secondsBack=3600, $max=3)
  *
- * TOTAL FUNCTIONS: 44
+ * TOTAL FUNCTIONS: 45
  * (This index is automatically created/updated by the extension "extdeveval")
  *
  */
 
-       // Need this for parsing User TSconfig
-require_once (PATH_t3lib.'class.t3lib_tsparser.php');
 
 
 
@@ -127,7 +126,7 @@ require_once (PATH_t3lib.'class.t3lib_tsparser.php');
  * Actually this class is extended again by t3lib_beuserauth which is the actual backend user class that will be instantiated.
  * In fact the two classes t3lib_beuserauth and this class could just as well be one, single class since t3lib_userauthgroup is not - to my knowledge - used separately elsewhere. But for historical reasons they are two separate classes.
  *
- * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @author     Kasper Skårhøj <kasperYYYY@typo3.com>
  * @package TYPO3
  * @subpackage t3lib
  */
@@ -148,6 +147,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        var $dataLists=array(                           // Used internally to accumulate data for the user-group. DONT USE THIS EXTERNALLY! Use $this->groupData instead
                'webmount_list'=>'',
                'filemount_list'=>'',
+               'fileoper_perms' => 0,
                'modList'=>'',
                'tables_select'=>'',
                'tables_modify'=>'',
@@ -249,6 +249,13 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        function isInWebMount($id,$readPerms='',$exitOnError=0) {
                if (!$GLOBALS['TYPO3_CONF_VARS']['BE']['lockBeUserToDBmounts'] || $this->isAdmin())     return 1;
                $id = intval($id);
+
+                       // Check if input id is an offline version page in which case we will map id to the online version:
+               $checkRec = t3lib_beFUnc::getRecord('pages',$id,'pid,t3ver_oid');
+               if ($checkRec['pid']==-1)       {
+                       $id = intval($checkRec['t3ver_oid']);
+               }
+
                if (!$readPerms)        $readPerms = $this->getPagePermsClause(1);
                if ($id>0)      {
                        $wM = $this->returnWebmounts();
@@ -260,9 +267,8 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                                }
                        }
                }
-               if ($exitOnError)       {
-                       t3lib_BEfunc::typo3PrintError ('Access Error','This page is not within your DB-mounts',0);
-                       exit;
+               if ($exitOnError) {
+                       throw new RuntimeException('Access Error: This page is not within your DB-mounts');
                }
        }
 
@@ -275,9 +281,8 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
         */
        function modAccess($conf,$exitOnError)  {
                if (!t3lib_BEfunc::isModuleSetInTBE_MODULES($conf['name']))     {
-                       if ($exitOnError)       {
-                               t3lib_BEfunc::typo3PrintError ('Fatal Error','This module "'.$conf['name'].'" is not enabled in TBE_MODULES',0);
-                               exit;
+                       if ($exitOnError) {
+                               throw new RuntimeException('Fatal Error: This module "'.$conf['name'].'" is not enabled in TBE_MODULES');
                        }
                        return FALSE;
                }
@@ -289,9 +294,8 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                                ($this->workspace>0 && t3lib_div::inList($conf['workspaces'],'custom')))        {
                                        // ok, go on...
                        } else {
-                               if ($exitOnError)       {
-                                       t3lib_BEfunc::typo3PrintError ('Workspace Error','This module "'.$conf['name'].'" is not available under the current workspace',0);
-                                       exit;
+                               if ($exitOnError) {
+                                       throw new RuntimeException('Workspace Error: This module "'.$conf['name'].'" is not available under the current workspace');
                                }
                                return FALSE;
                        }
@@ -305,21 +309,22 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                        $acs = $this->check('modules',$conf['name']);
                }
                if (!$acs && $exitOnError)      {
-                       t3lib_BEfunc::typo3PrintError ('Access Error','You don\'t have access to this module.',0);
-                       exit;
-               } else return $acs;
+                       throw new RuntimeException('Access Error: You don\'t have access to this module.');
+               } else {
+                       return $acs;
+               }
        }
 
        /**
         * Returns a WHERE-clause for the pages-table where user permissions according to input argument, $perms, is validated.
-        * $perms is the 'mask' used to select. Fx. if $perms is 1 then you'll get all pages that a user can actually see!
+        * $perms is the "mask" used to select. Fx. if $perms is 1 then you'll get all pages that a user can actually see!
         *              2^0 = show (1)
         *              2^1 = edit (2)
         *              2^2 = delete (4)
         *              2^3 = new (8)
         * If the user is 'admin' " 1=1" is returned (no effect)
         * If the user is not set at all (->user is not an array), then " 1=0" is returned (will cause no selection results at all)
-        * The 95% use of this function is "->getPagePermsClause(1)" which will return WHERE clauses for *selecting* pages in backend listings - in other words will this check read permissions.
+        * The 95% use of this function is "->getPagePermsClause(1)" which will return WHERE clauses for *selecting* pages in backend listings - in other words this will check read permissions.
         *
         * @param       integer         Permission mask to use, see function description
         * @return      string          Part of where clause. Prefix " AND " to this.
@@ -334,8 +339,10 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                        $perms = intval($perms);        // Make sure it's integer.
                        $str= ' ('.
                                '(pages.perms_everybody & '.$perms.' = '.$perms.')'.    // Everybody
-                               'OR(pages.perms_userid = '.$this->user['uid'].' AND pages.perms_user & '.$perms.' = '.$perms.')';       // User
-                       if ($this->groupList){$str.='OR(pages.perms_groupid in ('.$this->groupList.') AND pages.perms_group & '.$perms.' = '.$perms.')';}       // Group (if any is set)
+                               ' OR (pages.perms_userid = '.$this->user['uid'].' AND pages.perms_user & '.$perms.' = '.$perms.')';     // User
+                       if ($this->groupList)   {
+                               $str.= ' OR (pages.perms_groupid in ('.$this->groupList.') AND pages.perms_group & '.$perms.' = '.$perms.')';   // Group (if any is set)
+                       }
                        $str.=')';
 
                        // ****************
@@ -413,7 +420,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
 
 
                        // Acquire RTE object:
-               $RTE = &t3lib_BEfunc::RTEgetObj();
+               $RTE = t3lib_BEfunc::RTEgetObj();
                if (!is_object($RTE))   {
                        $this->RTE_errors = array_merge($this->RTE_errors, $RTE);
                }
@@ -435,12 +442,13 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
         * @param       string          String to search for in the groupData-list
         * @return      boolean         True if permission is granted (that is, the value was found in the groupData list - or the BE_USER is "admin")
         */
-       function check($type,$value)    {
-               if (isset($this->groupData[$type]))     {
-                       if ($this->isAdmin() || $this->inList($this->groupData[$type],$value)) {
-                               return 1;
+       function check($type, $value) {
+               if (isset($this->groupData[$type])) {
+                       if ($this->isAdmin() || $this->inList($this->groupData[$type], $value)) {
+                               return TRUE;
                        }
                }
+               return FALSE;
        }
 
        /**
@@ -462,7 +470,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                if (!strcmp($value,'')) return TRUE;
 
                        // Certain characters are not allowed in the value
-               if (ereg('[:|,]',$value))       {
+               if (preg_match('/[:|,]/',$value))       {
                        return FALSE;
                }
 
@@ -519,7 +527,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
         * @return      boolean         Returns true if the language value is allowed, otherwise false.
         */
        function checkLanguageAccess($langValue)        {
-               if (strcmp($this->groupData['allowed_languages'],''))   {       // The users language list must be non-blank - otherwise all languages are allowed.
+               if (strcmp(trim($this->groupData['allowed_languages']),''))     {       // The users language list must be non-blank - otherwise all languages are allowed.
                        $langValue = intval($langValue);
                        if ($langValue != -1 && !$this->check('allowed_languages',$langValue))  {       // Language must either be explicitly allowed OR the lang Value be "-1" (all languages)
                                return FALSE;
@@ -529,6 +537,56 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        }
 
        /**
+        * Check if user has access to all existing localizations for a certain record
+        *
+        * @param string        the table
+        * @param array         the current record
+        * @return boolean
+        */
+       function checkFullLanguagesAccess($table, $record) {
+               $recordLocalizationAccess = $this->checkLanguageAccess(0);
+               if ($recordLocalizationAccess
+                                && (
+                                       t3lib_BEfunc::isTableLocalizable($table)
+                                       || isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable'])
+                               )
+               ) {
+
+                       if (isset($GLOBALS['TCA'][$table]['ctrl']['transForeignTable'])) {
+                               $l10nTable = $GLOBALS['TCA'][$table]['ctrl']['transForeignTable'];
+                               $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField'];
+                               $pointerValue = $record['uid'];
+                       } else {
+                               $l10nTable = $table;
+                               $pointerField = $GLOBALS['TCA'][$l10nTable]['ctrl']['transOrigPointerField'];
+                               $pointerValue = $record[$pointerField] > 0 ? $record[$pointerField] : $record['uid'];
+                       }
+
+                       $recordLocalizations = t3lib_BEfunc::getRecordsByField(
+                               $l10nTable,
+                               $pointerField,
+                               $pointerValue,
+                               '',
+                               '',
+                               '',
+                               '1'
+                       );
+
+                       if (is_array($recordLocalizations)) {
+                               foreach($recordLocalizations as $localization) {
+                                       $recordLocalizationAccess = $recordLocalizationAccess
+                                               && $this->checkLanguageAccess($localization[$GLOBALS['TCA'][$l10nTable]['ctrl']['languageField']]);
+                                       if (!$recordLocalizationAccess) {
+                                               break;
+                                       }
+                               }
+                       }
+
+               }
+               return $recordLocalizationAccess;
+       }
+
+       /**
         * Checking if a user has editing access to a record from a $TCA table.
         * The checks does not take page permissions and other "environmental" things into account. It only deal with record internals; If any values in the record fields disallows it.
         * For instance languages settings, authMode selector boxes are evaluated (and maybe more in the future).
@@ -537,9 +595,12 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
         *
         * @param       string          Table name
         * @param       mixed           If integer, then this is the ID of the record. If Array this just represents fields in the record.
+        * @param       boolean         Set, if testing a new (non-existing) record array. Will disable certain checks that doesn't make much sense in that context.
+        * @param       boolean         Set, if testing a deleted record array.
+        * @param       boolean         Set, whenever access to all translations of the record is required
         * @return      boolean         True if OK, otherwise false
         */
-       function recordEditAccessInternals($table,$idOrRow)     {
+       function recordEditAccessInternals($table, $idOrRow, $newRecord = FALSE, $deletedRecord = FALSE, $checkFullLanguageAccess = FALSE) {
                global $TCA;
 
                if (isset($TCA[$table]))        {
@@ -550,7 +611,11 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
 
                                // Fetching the record if the $idOrRow variable was not an array on input:
                        if (!is_array($idOrRow))        {
-                               $idOrRow = t3lib_BEfunc::getRecord($table, $idOrRow);
+                               if ($deletedRecord) {
+                                       $idOrRow = t3lib_BEfunc::getRecord($table, $idOrRow, '*', '', FALSE);
+                               } else {
+                                       $idOrRow = t3lib_BEfunc::getRecord($table, $idOrRow);
+                               }
                                if (!is_array($idOrRow))        {
                                        $this->errorMsg = 'ERROR: Record could not be fetched.';
                                        return FALSE;
@@ -563,17 +628,25 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                                        if (!$this->checkLanguageAccess($idOrRow[$TCA[$table]['ctrl']['languageField']]))       {
                                                $this->errorMsg = 'ERROR: Language was not allowed.';
                                                return FALSE;
+                                       } elseif ($checkFullLanguageAccess && $idOrRow[$TCA[$table]['ctrl']['languageField']]==0 && !$this->checkFullLanguagesAccess($table, $idOrRow)) {
+                                               $this->errorMsg = 'ERROR: Related/affected language was not allowed.';
+                                               return FALSE;
                                        }
+                               } else {
+                                       $this->errorMsg = 'ERROR: The "languageField" field named "'.$TCA[$table]['ctrl']['languageField'].'" was not found in testing record!';
+                                       return FALSE;
                                }
+                       } elseif (isset($TCA[$table]['ctrl']['transForeignTable']) && $checkFullLanguageAccess && !$this->checkFullLanguagesAccess($table, $idOrRow)) {
+                               return FALSE;
                        }
 
                                // Checking authMode fields:
                        if (is_array($TCA[$table]['columns']))  {
-                               foreach($TCA[$table]['columns'] as $fN => $fV)  {
-                                       if (isset($idOrRow[$fN]))       {       //
-                                               if ($fV['config']['type']=='select' && $fV['config']['authMode'] && !strcmp($fV['config']['authMode_enforce'],'strict')) {
-                                                       if (!$this->checkAuthMode($table,$fN,$idOrRow[$fN],$fV['config']['authMode']))  {
-                                                               $this->errorMsg = 'ERROR: authMode "'.$fV['config']['authMode'].'" failed for field "'.$fN.'" with value "'.$idOrRow[$fN].'" evaluated';
+                               foreach ($TCA[$table]['columns'] as $fieldName => $fieldValue) {
+                                       if (isset($idOrRow[$fieldName])) {
+                                               if ($fieldValue['config']['type'] == 'select' && $fieldValue['config']['authMode'] && !strcmp($fieldValue['config']['authMode_enforce'], 'strict')) {
+                                                       if (!$this->checkAuthMode($table, $fieldName, $idOrRow[$fieldName], $fieldValue['config']['authMode'])) {
+                                                               $this->errorMsg = 'ERROR: authMode "' . $fieldValue['config']['authMode'] . '" failed for field "' . $fieldName . '" with value "' . $idOrRow[$fieldName] . '" evaluated';
                                                                return FALSE;
                                                        }
                                                }
@@ -581,39 +654,76 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                                }
                        }
 
-                               // Checking "editlock" feature
-                       if ($TCA[$table]['ctrl']['editlock'] && $idOrRow[$TCA[$table]['ctrl']['editlock']])     {
-                               $this->errorMsg = 'ERROR: Record was locked for editing. Only admin users can change this state.';
-                               return FALSE;
+                               // Checking "editlock" feature (doesn't apply to new records)
+                       if (!$newRecord && $TCA[$table]['ctrl']['editlock'])    {
+                               if (isset($idOrRow[$TCA[$table]['ctrl']['editlock']]))  {
+                                       if ($idOrRow[$TCA[$table]['ctrl']['editlock']]) {
+                                               $this->errorMsg = 'ERROR: Record was locked for editing. Only admin users can change this state.';
+                                               return FALSE;
+                                       }
+                               } else {
+                                       $this->errorMsg = 'ERROR: The "editLock" field named "'.$TCA[$table]['ctrl']['editlock'].'" was not found in testing record!';
+                                       return FALSE;
+                               }
                        }
 
                                // Checking record permissions
                        // THIS is where we can include a check for "perms_" fields for other records than pages...
 
+                               // Process any hooks
+                       if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['recordEditAccessInternals']))    {
+                               foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['recordEditAccessInternals'] as $funcRef)     {
+                                       $params = array(
+                                               'table' => $table,
+                                               'idOrRow' => $idOrRow,
+                                               'newRecord' => $newRecord
+                                       );
+                                       if (!t3lib_div::callUserFunction($funcRef, $params, $this)) {
+                                               return FALSE;
+                                       }
+                               }
+                       }
+
                                // Finally, return true if all is well.
                        return TRUE;
                }
        }
 
        /**
-        * Will check a type of permission against the compiled permission integer, $lCP, and in relation to table, $table
+        * Checks a type of permission against the compiled permission integer, $compiledPermissions, and in relation to table, $tableName
         *
-        * @param       integer         $lCP could typically be the "compiled permissions" integer returned by ->calcPerms
-        * @param       string          $table is the tablename to check: If "pages" table then edit,new,delete and editcontent permissions can be checked. Other tables will be checked for "editcontent" only (and $type will be ignored)
-        * @param       string          For $table='pages' this can be 'edit' (2), 'new' (8 or 16), 'delete' (4), 'editcontent' (16). For all other tables this is ignored. (16 is used)
+        * @param       integer         $compiledPermissions could typically be the "compiled permissions" integer returned by ->calcPerms
+        * @param       string          $tableName is the tablename to check: If "pages" table then edit,new,delete and editcontent permissions can be checked. Other tables will be checked for "editcontent" only (and $type will be ignored)
+        * @param       string          For $tableName='pages' this can be 'edit' (2), 'new' (8 or 16), 'delete' (4), 'editcontent' (16). For all other tables this is ignored. (16 is used)
         * @return      boolean
-        * @access private
+        * @access public (used by typo3/alt_clickmenu.php)
         */
-       function isPSet($lCP,$table,$type='')   {
-               if ($this->isAdmin())   return true;
-               if ($table=='pages')    {
-                       if ($type=='edit')      return $lCP & 2;
-                       if ($type=='new')       return ($lCP & 8) || ($lCP & 16);       // Create new page OR pagecontent
-                       if ($type=='delete')    return $lCP & 4;
-                       if ($type=='editcontent')       return $lCP & 16;
+       public function isPSet($compiledPermissions, $tableName, $actionType = '') {
+               if ($this->isAdmin()) {
+                       $result = TRUE;
+               }
+               elseif ($tableName == 'pages') {
+                       switch($actionType) {
+                               case 'edit':
+                                       $result = ($compiledPermissions & 2) !== 0;
+                                       break;
+                               case 'new':
+                                       // Create new page OR page content
+                                       $result = ($compiledPermissions & (8 + 16)) !== 0;
+                                       break;
+                               case 'delete':
+                                       $result = ($compiledPermissions & 4) !== 0;
+                                       break;
+                               case 'editcontent':
+                                       $result = ($compiledPermissions & 16) !== 0;
+                                       break;
+                               default:
+                                       $result = FALSE;
+                       }
                } else {
-                       return $lCP & 16;
+                       $result = ($compiledPermissions & 16) !== 0;
                }
+               return $result;
        }
 
        /**
@@ -622,7 +732,12 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
         * @return      boolean
         */
        function mayMakeShortcut()      {
-               return $this->getTSConfigVal('options.shortcutFrame') && !$this->getTSConfigVal('options.mayNotCreateEditShortcuts');
+                       // "Shortcuts" have been renamed to "Bookmarks"
+                       // @deprecated remove shortcuts code in TYPO3 4.7
+               return  ($this->getTSConfigVal('options.enableShortcuts')
+                               || $this->getTSConfigVal('options.enableBookmarks'))
+                               &&      (!$this->getTSConfigVal('options.mayNotCreateEditShortcuts')
+                               && !$this->getTSConfigVal('options.mayNotCreateEditBookmarks'));
        }
 
        /**
@@ -700,7 +815,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        function workspaceAllowLiveRecordsInPID($pid, $table)   {
 
                        // Always for Live workspace AND if live-edit is enabled and tables are completely without versioning it is ok as well.
-               if ($this->workspace===0 || ($this->workspaceRec['live_edit'] && !$GLOBALS['TCA'][$table]['ctrl']['versioningWS']))     {
+               if ($this->workspace===0 || ($this->workspaceRec['live_edit'] && !$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) || $GLOBALS['TCA'][$table]['ctrl']['versioningWS_alwaysAllowLiveEdit'])      {
                        return 2;       // OK to create for this table.
                } elseif (t3lib_BEfunc::isPidInVersionizedBranch($pid, $table)) {       // Check if records from $table can be created with this PID: Either if inside "branch" versioning type or a "versioning_followPages" table on a "page" versioning type.
                                // Now, check what the stage of that "page" or "branch" version type is:
@@ -753,6 +868,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
         * Checks if an element stage allows access for the user in the current workspace
         * In workspaces 0 (Live) and -1 (Default draft) access is always granted for any stage.
         * Admins are always allowed.
+        * An option for custom workspaces allows members to also edit when the stage is "Review"
         *
         * @param       integer         Stage id from an element: -1,0 = editing, 1 = reviewer, >1 = owner
         * @return      boolean         TRUE if user is allowed access
@@ -762,10 +878,35 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
 
                if ($this->workspace>0) {
                        $stat = $this->checkWorkspaceCurrent();
-                       if (($stage<=0 && $stat['_ACCESS']==='member') ||
-                               ($stage<=1 && $stat['_ACCESS']==='reviewer') ||
-                               ($stat['_ACCESS']==='owner')) {
-                                       return TRUE;    // OK for these criteria
+
+                               // Check if custom staging is activated
+                       $workspaceRec = t3lib_BEfunc::getRecord('sys_workspace', $stat['uid']);
+                       if ($workspaceRec['custom_stages'] > 0  && $stage !== '0' && $stage !== '-10') {
+
+                                       // Get custom stage record
+                               $workspaceStageRec = t3lib_BEfunc::getRecord('sys_workspace_stage', $stage);
+                                       // Check if the user is responsible for the current stage
+                               if ((t3lib_div::inList($workspaceStageRec['responsible_persons'], 'be_users_' . $this->user['uid'])
+                                               && $stat['_ACCESS'] === 'member')
+                                       || $stat['_ACCESS'] === 'owner') {
+                                       return TRUE; // OK for these criteria
+                               }
+
+                                       // Check if the user is in a group which is responsible for the current stage
+                               foreach ($this->userGroupsUID as $groupUid) {
+                                       if ((t3lib_div::inList($workspaceStageRec['responsible_persons'], 'be_groups_' . $groupUid)
+                                                       && $stat['_ACCESS'] === 'member')
+                                               || $stat['_ACCESS'] === 'owner') {
+                                               return TRUE; // OK for these criteria
+                                       }
+                               }
+                       } else {
+                               $memberStageLimit = $this->workspaceRec['review_stage_edit'] ? 1 : 0;
+                               if (($stage <= $memberStageLimit && $stat['_ACCESS'] === 'member')
+                                               || ($stage <= 1 && $stat['_ACCESS'] === 'reviewer')
+                                               || $stat['_ACCESS'] === 'owner') {
+                                               return TRUE;    // OK for these criteria
+                               }
                        }
                } else return TRUE;     // Always OK for live and draft workspaces.
        }
@@ -783,20 +924,24 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        function workspacePublishAccess($wsid)  {
                if ($this->isAdmin())   return TRUE;
 
+                       // If no access to workspace, of course you cannot publish!
+               $retVal = FALSE;
+
                $wsAccess = $this->checkWorkspace($wsid);
                if ($wsAccess)  {
                        switch($wsAccess['uid'])        {
                                case 0:         // Live workspace
-                                       return TRUE;    // If access to Live workspace, no problem.
+                                       $retVal =  TRUE;        // If access to Live workspace, no problem.
                                break;
                                case -1:        // Default draft workspace
-                                       return $this->checkWorkspace(0) ? TRUE : FALSE; // If access to Live workspace, no problem.
+                                       $retVal =  $this->checkWorkspace(0) ? TRUE : FALSE;     // If access to Live workspace, no problem.
                                break;
                                default:        // Custom workspace
-                                       return $wsAccess['_ACCESS'] === 'owner' || ($this->checkWorkspace(0) && !($wsAccess['publish_access']&2));      // Either be an adminuser OR have access to online workspace which is OK as well as long as publishing access is not limited by workspace option.
+                                       $retVal =  $wsAccess['_ACCESS'] === 'owner' || ($this->checkWorkspace(0) && !($wsAccess['publish_access']&2));  // Either be an adminuser OR have access to online workspace which is OK as well as long as publishing access is not limited by workspace option.
                                break;
                        }
-               } else return FALSE;    // If no access to workspace, of course you cannot publish!
+               }
+               return $retVal;
        }
 
        /**
@@ -811,53 +956,71 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        }
 
        /**
-        * Workspace Versioning type access?
+        * Workspace Versioning type access. Check wether the requsted type of versioning (element/page/branch) is allowd in current workspace
+        *   (element/pages/branches type of versioning can/could be set on custom workspaces on filed "vtype")
         *
+        * @todo workspacecleanup: this seems mostly obsolete and should be removed
         * @param       integer         Versioning type to evaluation: -1, 0, >1
+        *                                              0 = page (deprecated)
+        *                                              -1 = element
+        *                                              >1 = branch (deprecated), indicating the "nesting" level
         * @return      boolean         TRUE if OK
         */
        function workspaceVersioningTypeAccess($type)   {
+               $retVal = FALSE;
+
+               $type = t3lib_div::intInRange($type,-1);
+
+                       // Check if only element versioning is allowed:
+               if ($GLOBALS['TYPO3_CONF_VARS']['BE']['elementVersioningOnly'] && $type!=-1)    {
+                       return FALSE;
+               }
+
                if ($this->workspace>0 && !$this->isAdmin())    {
                        $stat = $this->checkWorkspaceCurrent();
                        if ($stat['_ACCESS']!=='owner') {
 
-                               $type = t3lib_div::intInRange($type,-1);
                                switch((int)$type)      {
                                        case -1:
-                                               return $this->workspaceRec['vtypes']&1 ? FALSE : TRUE;
+                                               $retVal = $this->workspaceRec['vtypes']&1 ? FALSE : TRUE;
                                        break;
                                        case 0:
-                                               return $this->workspaceRec['vtypes']&2 ? FALSE : TRUE;
+                                               $retVal = $this->workspaceRec['vtypes']&2 ? FALSE : TRUE;
                                        break;
                                        default:
-                                               return $this->workspaceRec['vtypes']&4 ? FALSE : TRUE;
+                                               $retVal = $this->workspaceRec['vtypes']&4 ? FALSE : TRUE;
                                        break;
                                }
-                       } else return TRUE;
-               } else return TRUE;
+                       } else $retVal = TRUE;
+               } else $retVal = TRUE;
+
+               return $retVal;
        }
 
        /**
         * Finding "closest" versioning type, used for creation of new records.
         *
+        * @see workspaceVersioningTypeAccess() for hints on $type
         * @param       integer         Versioning type to evaluation: -1, 0, >1
         * @return      integer         Returning versioning type
         */
        function workspaceVersioningTypeGetClosest($type)       {
+               $type = t3lib_div::intInRange($type,-1);
+
                if ($this->workspace>0) {
-                       $type = t3lib_div::intInRange($type,-1);
                        switch((int)$type)      {
                                case -1:
-                                       return -1;
+                                       $type = -1;
                                break;
                                case 0:
-                                       return $this->workspaceVersioningTypeAccess($type) ? $type : -1;
+                                       $type = $this->workspaceVersioningTypeAccess($type) ? $type : -1;
                                break;
                                default:
-                                       return $this->workspaceVersioningTypeAccess($type) ? $type : ($this->workspaceVersioningTypeAccess(0) ? 0 : -1);
+                                       $type = $this->workspaceVersioningTypeAccess($type) ? $type : ($this->workspaceVersioningTypeAccess(0) ? 0 : -1);
                                break;
                        }
-               } else return $type;
+               }
+               return $type;
        }
 
 
@@ -960,25 +1123,46 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        }
 
        /**
+        * 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
         * call like $GLOBALS['BE_USER']->jsConfirmation($BITMASK)
         *
-        * @param $bitmask int   Bitmask
         *    1 - typeChange
         *    2 - copy/move/paste
         *    4 - delete
         *    8 - frontend editing
         *    128 - other (not used yet)
-        * @return boolean true if the confirmation should be shown
-        **/
+        *
+        * @param       integer   Bitmask
+        * @return      boolean         true if the confirmation should be shown
+        */
         function jsConfirmation($bitmask)      {
                 $alertPopup = $GLOBALS['BE_USER']->getTSConfig('options.alertPopups');
-                $alertPopup = (int)$alertPopup['value'];
-
-                if(!$alertPopup)       {
+                if (empty($alertPopup['value']))       {
                         $alertPopup = 255;     // default: show all warnings
+                } else {
+                        $alertPopup = (int)$alertPopup['value'];
                 }
-
                 if(($alertPopup&$bitmask) == $bitmask) { // show confirmation
                         return 1;
                 } else { // don't show confirmation
@@ -1019,6 +1203,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                        $this->dataLists['workspace_perms'] = $this->user['workspace_perms'];                                   // Set user value for workspace permissions.
                        $this->dataLists['webmount_list'] = $this->user['db_mountpoints'];              // Database mountpoints
                        $this->dataLists['filemount_list'] = $this->user['file_mountpoints'];   // File mountpoints
+                       $this->dataLists['fileoper_perms'] = (int)$this->user['fileoper_perms'];        // Fileoperation permissions
 
                                // Setting default User TSconfig:
                        $this->TSdataArray[]=$this->addTScomment('From $GLOBALS["TYPO3_CONF_VARS"]["BE"]["defaultUserTSconfig"]:').
@@ -1028,7 +1213,6 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                        if ($this->isAdmin())   {
                                $this->TSdataArray[]=$this->addTScomment('"admin" user presets:').'
                                        admPanel.enable.all = 1
-                                       options.shortcutFrame = 1
                                ';
                                if (t3lib_extMgm::isLoaded('sys_note')) {
                                        $this->TSdataArray[]='
@@ -1069,19 +1253,30 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                                // Check include lines.
                        $this->TSdataArray = t3lib_TSparser::checkIncludeLines_array($this->TSdataArray);
 
-                               // Parsing the user TSconfig (or getting from cache)
-                       $this->userTS_text = implode(chr(10).'[GLOBAL]'.chr(10),$this->TSdataArray);    // Imploding with "[global]" will make sure that non-ended confinements with braces are ignored.
-                       $hash = md5('userTS:'.$this->userTS_text);
-                       $cachedContent = t3lib_BEfunc::getHash($hash,0);
-                       if (isset($cachedContent) && !$this->userTS_dontGetCached)      {
-                               $this->userTS = unserialize($cachedContent);
+                       $this->userTS_text = implode(LF.'[GLOBAL]'.LF,$this->TSdataArray);      // Imploding with "[global]" will make sure that non-ended confinements with braces are ignored.
+
+                       if ($GLOBALS['TYPO3_CONF_VARS']['BE']['TSconfigConditions'] && !$this->userTS_dontGetCached) {
+                                       // Perform TS-Config parsing with condition matching
+                               $parseObj = t3lib_div::makeInstance('t3lib_TSparser_TSconfig');
+                               $res = $parseObj->parseTSconfig($this->userTS_text, 'userTS');
+                               if ($res) {
+                                       $this->userTS = $res['TSconfig'];
+                                       $this->userTSUpdated = ($res['cached'] ? 0 : 1);
+                               }
                        } else {
-                               $parseObj = t3lib_div::makeInstance('t3lib_TSparser');
-                               $parseObj->parse($this->userTS_text);
-                               $this->userTS = $parseObj->setup;
-                               t3lib_BEfunc::storeHash($hash,serialize($this->userTS),'BE_USER_TSconfig');
-                                       // Update UC:
-                               $this->userTSUpdated=1;
+                                       // Parsing the user TSconfig (or getting from cache)
+                               $hash = md5('userTS:' . $this->userTS_text);
+                               $cachedContent = t3lib_BEfunc::getHash($hash);
+                               if (isset($cachedContent) && !$this->userTS_dontGetCached) {
+                                       $this->userTS = unserialize($cachedContent);
+                               } else {
+                                       $parseObj = t3lib_div::makeInstance('t3lib_TSparser');
+                                       $parseObj->parse($this->userTS_text);
+                                       $this->userTS = $parseObj->setup;
+                                       t3lib_BEfunc::storeHash($hash, serialize($this->userTS), 'BE_USER_TSconfig');
+                                               // Update UC:
+                                       $this->userTSUpdated=1;
+                               }
                        }
 
                                // Processing webmounts
@@ -1090,9 +1285,11 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                        }
 
                                // 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'].')');
+                               $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, '');
                                }
@@ -1108,6 +1305,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                        $this->groupData['allowed_languages'] = t3lib_div::uniqueList($this->dataLists['allowed_languages']);
                        $this->groupData['custom_options'] = t3lib_div::uniqueList($this->dataLists['custom_options']);
                        $this->groupData['modules'] = t3lib_div::uniqueList($this->dataLists['modList']);
+                       $this->groupData['fileoper_perms'] = $this->dataLists['fileoper_perms'];
                        $this->groupData['workspace_perms'] = $this->dataLists['workspace_perms'];
 
                                // populating the $this->userGroupsUID -array with the groups in the order in which they were LAST included.!!
@@ -1144,19 +1342,20 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
         * @access private
         */
        function fetchGroups($grList,$idList='')        {
+               global $TYPO3_CONF_VARS;
 
                        // Fetching records of the groups in $grList (which are not blocked by lockedToDomain either):
-               $lockToDomain_SQL = ' AND (lockToDomain=\'\' OR lockToDomain=\''.t3lib_div::getIndpEnv('HTTP_HOST').'\')';
+               $lockToDomain_SQL = ' AND (lockToDomain=\'\' OR lockToDomain IS NULL OR lockToDomain=\''.t3lib_div::getIndpEnv('HTTP_HOST').'\')';
                $whereSQL = 'deleted=0 AND hidden=0 AND pid=0 AND uid IN ('.$grList.')'.$lockToDomain_SQL;
 
                        // Hook for manipulation of the WHERE sql sentence which controls which BE-groups are included
                if (is_array ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroupQuery'])) {
-                   foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroupQuery'] as $classRef) {
-                       $hookObj = &t3lib_div::getUserObj($classRef);
+                       foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroupQuery'] as $classRef) {
+                       $hookObj = t3lib_div::getUserObj($classRef);
                        if(method_exists($hookObj,'fetchGroupQuery_processQuery')){
-                           $whereSQL = $hookObj->fetchGroupQuery_processQuery($this, $grList, $idList, $whereSQL);
+                               $whereSQL = $hookObj->fetchGroupQuery_processQuery($this, $grList, $idList, $whereSQL);
+                       }
                        }
-                   }
                }
 
                $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $this->usergroup_table, $whereSQL);
@@ -1168,8 +1367,8 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
 
                        // Traversing records in the correct order
                $include_staticArr = t3lib_div::intExplode(',',$grList);
-               reset($include_staticArr);
-               while(list(,$uid)=each($include_staticArr))     {       // traversing list
+                       // traversing list
+               foreach ($include_staticArr as $key => $uid) {
 
                                // Get row:
                        $row=$this->userGroups[$uid];
@@ -1211,6 +1410,9 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                                        $this->dataLists['custom_options'].= ','.$row['custom_options'];
                                }
 
+                               // Setting fileoperation permissions
+                               $this->dataLists['fileoper_perms'] |= (int)$row['fileoper_perms'];
+
                                        // Setting workspace permissions:
                                $this->dataLists['workspace_perms'] |= $row['workspace_perms'];
 
@@ -1220,6 +1422,16 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                                }
                        }
                }
+
+               // ****************
+               // HOOK: fetchGroups_postProcessing
+               // ****************
+               if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroups_postProcessing'])) {
+                       foreach($TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_userauthgroup.php']['fetchGroups_postProcessing'] as $_funcRef) {
+                               $_params = array();
+                               t3lib_div::callUserFunction($_funcRef, $_params, $this);
+                       }
+               }
        }
 
        /**
@@ -1261,10 +1473,9 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                }
                        // If the path is true and validates as a valid path string:
                if ($path && t3lib_div::validPathStr($path))    {
-                               // these lines remove all slashes and dots before and after the path
-                       $path=ereg_replace('^[\/\. ]*','',$path);
-                       $path=trim(ereg_replace('[\/\. ]*$','',$path));
-
+                               // normalize path: remove leading '/' and './', and trailing '/' and '/.'
+                       $path=trim($path);
+                       $path=preg_replace('#^\.?/|/\.?$#','',$path);
 
                        if ($path)      {       // there must be some chars in the path
                                $fdir=PATH_site.$GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'];      // fileadmin dir, absolute
@@ -1300,12 +1511,12 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        function addTScomment($str)     {
                $delimiter = '# ***********************************************';
 
-               $out = $delimiter.chr(10);
-               $lines = t3lib_div::trimExplode(chr(10),$str);
+               $out = $delimiter.LF;
+               $lines = t3lib_div::trimExplode(LF,$str);
                foreach($lines as $v)   {
-                       $out.= '# '.$v.chr(10);
+                       $out.= '# '.$v.LF;
                }
-               $out.= $delimiter.chr(10);
+               $out.= $delimiter.LF;
                return $out;
        }
 
@@ -1338,35 +1549,66 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                        // Initializing workspace by evaluating and setting the workspace, possibly updating it in the user record!
                $this->setWorkspace($this->user['workspace_id']);
 
-                       // Setting up the db mount points of the (custom) workspace, if any:
-               if ($this->workspace>0 && $this->workspaceRec['db_mountpoints']!=='')   {
-
-                               // Initialize:
-                       $newMounts = array();
+                       // Limiting the DB mountpoints if there any selected in the workspace record
+               $dbMountpoints = trim($this->workspaceRec['db_mountpoints']);
+               if ($this->workspace > 0 && $dbMountpoints != '') {
+                       $filteredDbMountpoints = array();
                        $readPerms = '1=1'; // Notice: We cannot call $this->getPagePermsClause(1); as usual because the group-list is not available at this point. But bypassing is fine because all we want here is check if the workspace mounts are inside the current webmounts rootline. The actual permission checking on page level is done elsewhere as usual anyway before the page tree is rendered.
 
                                // Traverse mount points of the
-                       $mountPoints = t3lib_div::intExplode(',',$this->workspaceRec['db_mountpoints']);
-                       foreach($mountPoints as $mpId)  {
-                               if ($this->isInWebMount($mpId,$readPerms))      {
-                                       $newMounts[] = $mpId;
+                       $dbMountpoints = t3lib_div::intExplode(',', $dbMountpoints);
+                       foreach ($dbMountpoints as $mpId) {
+                               if ($this->isInWebMount($mpId, $readPerms)) {
+                                       $filteredDbMountpoints[] = $mpId;
                                }
                        }
 
                                // Re-insert webmounts:
-                       $this->groupData['webmounts'] = implode(',',array_unique($newMounts));
+                       $filteredDbMountpoints = array_unique($filteredDbMountpoints);
+                       $this->groupData['webmounts'] = implode(',', $filteredDbMountpoints);
                }
 
-                       // Setting up the file mount points of the (custom) workspace, if any:
-               if ($this->workspace!==0)       $this->groupData['filemounts'] = array();
-               if ($this->workspace>0 && $this->workspaceRec['file_mountpoints']!=='') {
+                       // 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) {
 
-                               // Processing filemounts
-                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_filemounts', 'deleted=0 AND hidden=0 AND pid=0 AND uid IN ('.$GLOBALS['TYPO3_DB']->cleanIntList($this->workspaceRec['file_mountpoints']).')');
-                       while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))      {
-                               $this->addFileMount($row['title'], $row['path'], $row['path'], $row['base']?1:0, '');
+                               // no custom filemounts that should serve as filter
+                               // so all user mountpoints are re-applied
+                       if ($fileMountpoints === '') {
+                               $this->groupData['filemounts'] = $usersFileMounts;
+                       } else {
+                                       // 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) . ')'
+                               );
+
+                               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]);
+                                       }
+                               }
                        }
                }
+
+               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']);
+               }
        }
 
        /**
@@ -1377,6 +1619,23 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
         * @return      array           TRUE if access. Output will also show how access was granted. Admin users will have a true output regardless of input.
         */
        function checkWorkspace($wsRec,$fields='uid,title,adminusers,members,reviewers,publish_access,stagechg_notification')   {
+               $retVal = FALSE;
+
+                       // Show draft workspace only if it's enabled in version extension
+               if (t3lib_extMgm::isLoaded('version')) {
+                       $versionExtConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['version']);
+                       if (!$versionExtConf['showDraftWorkspace']) {
+                               if (!is_array($wsRec)) {
+                                       if ((string) $wsRec === '-1') {
+                                               return FALSE;
+                                       }
+                               } else {
+                                       if ((string) $wsRec['uid'] === '-1') {
+                                               return FALSE;
+                                       }
+                               }
+                       }
+               }
 
                        // If not array, look up workspace record:
                if (!is_array($wsRec))  {
@@ -1406,16 +1665,22 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
 
                                switch((string)$wsRec['uid'])   {
                                        case '0':
-                                               return ($this->groupData['workspace_perms']&1) ? array_merge($wsRec,array('_ACCESS' => 'online')) : FALSE;
+                                               $retVal = ($this->groupData['workspace_perms']&1) ? array_merge($wsRec,array('_ACCESS' => 'online')) : FALSE;
                                        break;
                                        case '-1':
-                                               return ($this->groupData['workspace_perms']&2) ? array_merge($wsRec,array('_ACCESS' => 'offline')) : FALSE;
+                                               $retVal = ($this->groupData['workspace_perms']&2) ? array_merge($wsRec,array('_ACCESS' => 'offline')) : FALSE;
                                        break;
                                        default:
                                                        // Checking if the guy is admin:
-                                               if (t3lib_div::inList($wsRec['adminusers'],$this->user['uid'])) {
+                                               if (t3lib_div::inList($wsRec['adminusers'], 'be_users_' . $this->user['uid'])) {
                                                        return array_merge($wsRec, array('_ACCESS' => 'owner'));
                                                }
+                                                       // Checking if he is owner through a user group of his:
+                                               foreach ($this->userGroupsUID as $groupUid) {
+                                                       if (t3lib_div::inList($wsRec['adminusers'], 'be_groups_' . $groupUid)) {
+                                                               return array_merge($wsRec, array('_ACCESS' => 'owner'));
+                                                       }
+                                               }
                                                        // Checking if he is reviewer user:
                                                if (t3lib_div::inList($wsRec['reviewers'],'be_users_'.$this->user['uid']))      {
                                                        return array_merge($wsRec, array('_ACCESS' => 'reviewer'));
@@ -1441,7 +1706,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                        }
                }
 
-               return FALSE;
+               return $retVal;
        }
 
        /**
@@ -1488,7 +1753,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
        /**
         * Setting workspace preview state for user:
         *
-        * @param       boolean         State
+        * @param       boolean         State of user preview.
         * @return      void
         */
        function setWorkspacePreview($previewState)     {
@@ -1610,7 +1875,7 @@ class t3lib_userAuthGroup extends t3lib_userAuth {
                if ($email)     {
 
                                // get last flag set in the log for sending
-                       $theTimeBack = time()-$secondsBack;
+                       $theTimeBack = $GLOBALS['EXEC_TIME'] - $secondsBack;
                        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
                                                        'tstamp',
                                                        'sys_log',
@@ -1643,13 +1908,13 @@ This is a dump of the failures:
 ';
                                while($testRows = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))  {
                                        $theData = unserialize($testRows['log_data']);
-                                       $email_body.=date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'].' H:i',$testRows['tstamp']).':  '.@sprintf($testRows['details'],''.$theData[0],''.$theData[1],''.$theData[2]);
-                                       $email_body.=chr(10);
+                                       $email_body.= date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'].' '.$GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'],$testRows['tstamp']).':  '.@sprintf($testRows['details'],''.$theData[0],''.$theData[1],''.$theData[2]);
+                                       $email_body.= LF;
                                }
-                               mail(   $email,
-                                               $subject,
-                                               $email_body,
-                                               'From: TYPO3 Login WARNING<>'
+                               t3lib_utility_Mail::mail($email,
+                                       $subject,
+                                       $email_body,
+                                       'From: TYPO3 Login WARNING<>'
                                );
                                $this->writelog(255,4,0,3,'Failure warning (%s failures within %s seconds) sent by email to %s',Array($GLOBALS['TYPO3_DB']->sql_num_rows($res),$secondsBack,$email));   // Logout written to log
                        }
@@ -1662,4 +1927,5 @@ This is a dump of the failures:
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_userauthgroup.php'])    {
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_userauthgroup.php']);
 }
+
 ?>