git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2471 709f56b5-9817-0410-a4d7...
[Packages/TYPO3.CMS.git] / typo3 / sysext / cms / tslib / class.tslib_fe.php
index baa6a64..eb39175 100755 (executable)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
+*  (c) 1999-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
  *
  *
  *
- *  207: class tslib_fe
- *  375:     function tslib_fe($TYPO3_CONF_VARS, $id, $type, $no_cache='', $cHash='', $jumpurl='',$MP='',$RDCT='')
- *  408:     function connectToMySQL()
- *  418:     function connectToDB()
- *  463:     function sendRedirect()
+ *  213: class tslib_fe
+ *  382:     function tslib_fe($TYPO3_CONF_VARS, $id, $type, $no_cache='', $cHash='', $jumpurl='',$MP='',$RDCT='')
+ *  415:     function connectToMySQL()
+ *  425:     function connectToDB()
+ *  470:     function sendRedirect()
  *
  *              SECTION: Initializing, resolving page id
- *  501:     function initFEuser()
- *  551:     function initUserGroups()
- *  586:     function isUserOrGroupSet()
- *  611:     function checkAlternativeIdMethods()
- *  663:     function clear_preview()
- *  676:     function determineId()
- *  811:     function fetch_the_id()
- *  904:     function getPageAndRootline()
- *  975:     function getPageShortcut($SC,$mode,$thisUid,$itera=20,$pageLog=array())
- * 1025:     function checkRootlineForIncludeSection()
- * 1062:     function checkEnableFields($row,$bypassGroupCheck=FALSE)
- * 1078:     function checkPageGroupAccess($row, $groupList=NULL)
- * 1097:     function checkPagerecordForIncludeSection($row)
- * 1106:     function checkIfLoginAllowedInBranch()
- * 1131:     function getPageAccessFailureReasons()
- * 1163:     function setIDfromArgV()
- * 1179:     function getPageAndRootlineWithDomain($domainStartPage)
- * 1206:     function setSysPageWhereClause()
- * 1218:     function findDomainRecord($recursive=0)
- * 1238:     function pageNotFoundAndExit($reason='', $header='')
- * 1253:     function pageNotFoundHandler($code, $header='', $reason='')
- * 1297:     function checkAndSetAlias()
- * 1312:     function idPartsAnalyze($str)
- * 1337:     function mergingWithGetVars($GET_VARS)
+ *  508:     function initFEuser()
+ *  558:     function initUserGroups()
+ *  593:     function isUserOrGroupSet()
+ *  618:     function checkAlternativeIdMethods()
+ *  670:     function clear_preview()
+ *  683:     function determineId()
+ *  817:     function fetch_the_id()
+ *  911:     function getPageAndRootline()
+ *  994:     function getPageShortcut($SC,$mode,$thisUid,$itera=20,$pageLog=array())
+ * 1044:     function checkRootlineForIncludeSection()
+ * 1081:     function checkEnableFields($row,$bypassGroupCheck=FALSE)
+ * 1097:     function checkPageGroupAccess($row, $groupList=NULL)
+ * 1116:     function checkPagerecordForIncludeSection($row)
+ * 1125:     function checkIfLoginAllowedInBranch()
+ * 1150:     function getPageAccessFailureReasons()
+ * 1182:     function setIDfromArgV()
+ * 1198:     function getPageAndRootlineWithDomain($domainStartPage)
+ * 1225:     function setSysPageWhereClause()
+ * 1237:     function findDomainRecord($recursive=0)
+ * 1257:     function pageNotFoundAndExit($reason='', $header='')
+ * 1272:     function pageNotFoundHandler($code, $header='', $reason='')
+ * 1316:     function checkAndSetAlias()
+ * 1335:     function idPartsAnalyze($str)
+ * 1360:     function mergingWithGetVars($GET_VARS)
+ * 1390:     function ADMCMD_preview()
+ * 1433:     function ADMCMD_preview_postInit($previewConfig)
  *
  *              SECTION: Template and caching related functions.
- * 1386:     function makeCacheHash()
- * 1410:     function reqCHash()
- * 1432:     function cHashParams($addQueryParams)
- * 1441:     function initTemplate()
- * 1453:     function getFromCache()
- * 1498:     function getFromCache_queryRow()
- * 1526:     function headerNoCache()
- * 1555:     function getHash()
- * 1575:     function getConfigArray()
+ * 1465:     function makeCacheHash()
+ * 1489:     function reqCHash()
+ * 1511:     function cHashParams($addQueryParams)
+ * 1520:     function initTemplate()
+ * 1532:     function getFromCache()
+ * 1578:     function getFromCache_queryRow()
+ * 1608:     function headerNoCache()
+ * 1637:     function getHash()
+ * 1657:     function getConfigArray()
  *
  *              SECTION: Further initialization and data processing
- * 1714:     function getCompressedTCarray()
- * 1768:     function includeTCA($TCAloaded=1)
- * 1795:     function settingLanguage()
- * 1885:     function settingLocale()
- * 1910:     function checkDataSubmission()
- * 1935:     function fe_tce()
- * 1949:     function locDataCheck($locationData)
- * 1965:     function sendFormmail()
- * 2016:     function extractRecipientCopy($bodytext)
- * 2031:     function checkJumpUrl()
- * 2113:     function jumpUrl()
- * 2157:     function setUrlIdToken()
+ * 1818:     function getCompressedTCarray()
+ * 1872:     function includeTCA($TCAloaded=1)
+ * 1899:     function settingLanguage()
+ * 1992:     function settingLocale()
+ * 2017:     function checkDataSubmission()
+ * 2050:     function fe_tce()
+ * 2064:     function locDataCheck($locationData)
+ * 2080:     function sendFormmail()
+ * 2131:     function extractRecipientCopy($bodytext)
+ * 2145:     function setExternalJumpUrl()
+ * 2156:     function checkJumpUrlReferer()
+ * 2171:     function jumpUrl()
+ * 2215:     function setUrlIdToken()
  *
  *              SECTION: Page generation; cache handling
- * 2200:     function isGeneratePage()
- * 2210:     function tempPageCacheContent()
- * 2251:     function realPageCacheContent()
- * 2280:     function setPageCacheContent($c,$d,$t)
- * 2304:     function clearPageCacheContent()
- * 2314:     function clearPageCacheContent_pidList($pidList)
- * 2325:     function setSysLastChanged()
+ * 2258:     function isGeneratePage()
+ * 2268:     function tempPageCacheContent()
+ * 2325:     function realPageCacheContent()
+ * 2355:     function setPageCacheContent($content,$data,$tstamp)
+ * 2382:     function clearPageCacheContent()
+ * 2392:     function clearPageCacheContent_pidList($pidList)
+ * 2403:     function pageCachePostProcess(&$row,$type)
+ * 2426:     function setSysLastChanged()
  *
  *              SECTION: Page generation; rendering and inclusion
- * 2361:     function generatePage_preProcessing()
- * 2383:     function generatePage_whichScript()
- * 2395:     function generatePage_postProcessing()
- * 2487:     function INTincScript()
- * 2547:     function INTincScript_loadJSCode()
- * 2588:     function isINTincScript()
- * 2597:     function doXHTML_cleaning()
- * 2606:     function doLocalAnchorFix()
+ * 2462:     function generatePage_preProcessing()
+ * 2484:     function generatePage_whichScript()
+ * 2496:     function generatePage_postProcessing()
+ * 2588:     function INTincScript()
+ * 2648:     function INTincScript_loadJSCode()
+ * 2689:     function isINTincScript()
+ * 2698:     function doXHTML_cleaning()
+ * 2707:     function doLocalAnchorFix()
  *
  *              SECTION: Finished off; outputting, storing session data, statistics...
- * 2637:     function isOutputting()
- * 2660:     function processOutput()
- * 2728:     function sendCacheHeaders()
- * 2796:     function isStaticCacheble()
- * 2809:     function contentStrReplace()
- * 2835:     function isEXTincScript()
- * 2844:     function storeSessionData()
- * 2854:     function setParseTime()
- * 2866:     function statistics()
- * 2974:     function previewInfo()
- * 3002:     function hook_eofe()
- * 3018:     function beLoginLinkIPList()
+ * 2738:     function isOutputting()
+ * 2761:     function processOutput()
+ * 2834:     function sendCacheHeaders()
+ * 2902:     function isStaticCacheble()
+ * 2915:     function contentStrReplace()
+ * 2941:     function isEXTincScript()
+ * 2950:     function storeSessionData()
+ * 2960:     function setParseTime()
+ * 2972:     function statistics()
+ * 3066:     function previewInfo()
+ * 3101:     function hook_eofe()
+ * 3117:     function beLoginLinkIPList()
+ * 3138:     function addTempContentHttpHeaders()
  *
  *              SECTION: Various internal API functions
- * 3073:     function makeSimulFileName($inTitle,$page,$type,$addParams='',$no_cache='')
- * 3120:     function simulateStaticDocuments_pEnc_onlyP_proc($linkVars)
- * 3149:     function getSimulFileName()
- * 3163:     function fileNameASCIIPrefix($inTitle,$titleChars,$mergeChar='.')
- * 3181:     function encryptEmail($string,$back=0)
- * 3207:     function codeString($string, $decode=FALSE)
- * 3233:     function roundTripCryptString($string)
- * 3253:     function checkFileInclude($incFile)
- * 3268:     function newCObj()
- * 3281:     function setAbsRefPrefix()
- * 3295:     function baseUrlWrap($url)
- * 3314:     function printError($label,$header='Error!')
- * 3325:     function updateMD5paramsRecord($hash)
- * 3336:     function tidyHTML($content)
- * 3362:     function prefixLocalAnchorsWithScript()
- * 3373:     function workspacePreviewInit()
- * 3382:     function doWorkspacePreview()
- * 3392:     function whichWorkspace($returnTitle = FALSE)
+ * 3184:     function makeSimulFileName($inTitle,$page,$type,$addParams='',$no_cache='')
+ * 3231:     function simulateStaticDocuments_pEnc_onlyP_proc($linkVars)
+ * 3260:     function getSimulFileName()
+ * 3271:     function setSimulReplacementChar()
+ * 3291:     function fileNameASCIIPrefix($inTitle,$titleChars,$mergeChar='.')
+ * 3314:     function encryptEmail($string,$back=0)
+ * 3340:     function codeString($string, $decode=FALSE)
+ * 3366:     function roundTripCryptString($string)
+ * 3386:     function checkFileInclude($incFile)
+ * 3401:     function newCObj()
+ * 3414:     function setAbsRefPrefix()
+ * 3428:     function baseUrlWrap($url)
+ * 3447:     function printError($label,$header='Error!')
+ * 3458:     function updateMD5paramsRecord($hash)
+ * 3469:     function tidyHTML($content)
+ * 3495:     function prefixLocalAnchorsWithScript()
+ * 3505:     function workspacePreviewInit()
+ * 3521:     function doWorkspacePreview()
+ * 3531:     function whichWorkspace($returnTitle = FALSE)
  *
  *              SECTION: Various external API functions - for use in plugins etc.
- * 3450:     function getStorageSiterootPids()
- * 3465:     function getPagesTSconfig()
- * 3498:     function setJS($key,$content='')
- * 3536:     function setCSS($key,$content)
- * 3551:     function make_seed()
- * 3564:     function uniqueHash($str='')
- * 3573:     function set_no_cache()
- * 3583:     function set_cache_timeout_default($seconds)
- * 3599:     function plainMailEncoded($email,$subject,$message,$headers='')
+ * 3589:     function getStorageSiterootPids()
+ * 3604:     function getPagesTSconfig()
+ * 3637:     function setJS($key,$content='')
+ * 3677:     function setCSS($key,$content)
+ * 3692:     function make_seed()
+ * 3705:     function uniqueHash($str='')
+ * 3714:     function set_no_cache()
+ * 3724:     function set_cache_timeout_default($seconds)
+ * 3740:     function plainMailEncoded($email,$subject,$message,$headers='')
  *
  *              SECTION: Localization and character set conversion
- * 3640:     function sL($input)
- * 3669:     function readLLfile($fileRef)
- * 3680:     function getLLL($index,$LOCAL_LANG)
- * 3694:     function initLLvars()
- * 3728:     function csConv($str,$from='')
- * 3746:     function convOutputCharset($content,$label='')
- * 3759:     function convPOSTCharset()
+ * 3784:     function sL($input)
+ * 3813:     function readLLfile($fileRef)
+ * 3824:     function getLLL($index,$LOCAL_LANG)
+ * 3838:     function initLLvars()
+ * 3872:     function csConv($str,$from='')
+ * 3890:     function convOutputCharset($content,$label='')
+ * 3903:     function convPOSTCharset()
  *
- * TOTAL FUNCTIONS: 110
+ * TOTAL FUNCTIONS: 116
  * (This index is automatically created/updated by the extension "extdeveval")
  *
  */
        var $rootLine='';                                       // The rootLine (all the way to tree root, not only the current site!) (array)
        var $page='';                                           // The pagerecord (array)
        var $contentPid=0;                                      // This will normally point to the same value as id, but can be changed to point to another page from which content will then be displayed instead.
-       var $sys_page='';                                       // The object with pagefunctions (object)
+
+       /**
+        * sys_page-object, pagefunctions
+        *
+        * @var t3lib_pageSelect
+        */
+       var $sys_page='';
        var $jumpurl='';
        var $pageNotFound=0;                            // Is set to 1 if a pageNotFound handler could have been called.
        var $domainStartPage=0;                         // Domain start page
        var $siteScript='';                                     // Contains the value of the current script path that activated the frontend. Typically "index.php" but by rewrite rules it could be something else! Used for Speaking Urls / Simulate Static Documents.
 
                // USER
-       var $fe_user='';                                        // The user (object)
+
+       /**
+        * The FE user
+        *
+        * @var tslib_feUserAuth
+        */
+       var $fe_user='';
        var $loginUser='';                                      // Global flag indicating that a front-end user is logged in. This is set only if a user really IS logged in. The group-list may show other groups (like added by IP filter or so) even though there is no user.
        var $gr_list='';                                        // (RO=readonly) The group list, sorted numerically. Group '0,-1' is the default group, but other groups may be added by other means than a user being logged in though...
        var $beUserLogin='';                            // Flag that indicates if a Backend user is logged in!
        var $workspacePreview='';                       // Integer, that indicates which workspace is being previewed.
        var $loginAllowedInBranch = TRUE;       // Shows whether logins are allowed in branch
+       var $ADMCMD_preview_BEUSER_uid = 0;     // Integer, set to backend user ID to initialize when keyword-based preview is used.
 
                // PREVIEW
        var $fePreview='';                                      // Flag indication that preview is active. This is based on the login of a backend user and whether the backend user has read access to the current page. A value of 1 means ordinary preview, 2 means preview of a non-live workspace
        var $TCAcachedExtras=array();           // Array of cached information from TCA. This is NOT TCA itself!
 
                // TEMPLATE / CACHE
-       var $tmpl='';                                           // The TypoScript template object. Used to parse the TypoScript template
+
+       /**
+        * The TypoScript template object. Used to parse the TypoScript template
+        *
+        * @var t3lib_TStemplate
+        */
+       var $tmpl='';
        var $cacheTimeOutDefault='';            // Is set to the time-to-live time of cached pages. If false, default is 60*60*24, which is 24 hours.
        var $cacheContentFlag='';                       // Set internally if cached content is fetched from the database
        var $cacheExpires=0;                            // Set to the expire time of cached content
                        JSCode : reserved
                        JSImgCode : reserved
        */
-       var $defaultBodyTag='<body>';           // Default bodytag, if nothing else is set. This can be overridden by applications like TemplaVoila.
        var $additionalHeaderData=array();      // used to accumulate additional HTML-code for the header-section, <head>...</head>. Insert either associative keys (like additionalHeaderData['myStyleSheet'], see reserved keys above) or num-keys (like additionalHeaderData[] = '...')
        var $additionalJavaScript=array();      // used to accumulate additional JavaScript-code. Works like additionalHeaderData. Reserved keys at 'openPic' and 'mouseOver'
        var $additionalCSS=array();                     // used to accumulate additional Style code. Works like additionalHeaderData.
        var $JSeventFuncCalls = array(          // you can add JavaScript functions to each entry in these arrays. Please see how this is done in the GMENU_LAYERS script. The point is that many applications on a page can set handlers for onload, onmouseover and onmouseup
                'onmousemove' => array(),
                'onmouseup' => array(),
+               'onmousemove' => array(),
+               'onkeydown' => array(),
+               'onkeyup' => array(),
+               'onkeypress' => array(),
                'onload' => array(),
+               'onunload' => array(),
        );
-       var $JSCode='';                                         // Depreciated, use additionalJavaScript instead.
+       var $JSCode='';                                         // Deprecated, use additionalJavaScript instead.
        var $JSImgCode='';                                      // Used to accumulate JavaScript loaded images (by menus)
        var $divSection='';                                     // Used to accumulate DHTML-layers.
+       var $defaultBodyTag='<body>';           // Default bodytag, if nothing else is set. This can be overridden by applications like TemplaVoila.
 
                // RENDERING configuration, settings from TypoScript is loaded into these vars. See pagegen.php
        var $debug='';                                          // Debug flag, may output special debug html-code.
        var $excludeCHashVars='';                       // A string set with a comma list of additional GET vars which should NOT be included in the cHash calculation. These vars should otherwise be detected and involved in caching, eg. through a condition in TypoScript.
        var $displayEditIcons='';                       // If set, edit icons are rendered aside content records. Must be set only if the ->beUserLogin flag is set and set_no_cache() must be called as well.
        var $displayFieldEditIcons='';          // If set, edit icons are rendered aside individual fields of content. Must be set only if the ->beUserLogin flag is set and set_no_cache() must be called as well.
-       var $sys_language_uid=0;                        // Site language, 0 (zero) is default, int+ is uid pointing to a sys_language record. Should reflect which language it DOES actually display!
-       var $sys_language_mode='';                      // Site language mode
-       var $sys_language_content=0;            // Site content selection uid
+       var $sys_language_uid=0;                        // Site language, 0 (zero) is default, int+ is uid pointing to a sys_language record. Should reflect which language menus, templates etc is displayed in (master language) - but not necessarily the content which could be falling back to default (see sys_language_content)
+       var $sys_language_mode='';                      // Site language mode for content fall back.
+       var $sys_language_content=0;            // Site content selection uid (can be different from sys_language_uid if content is to be selected from a fall-back language. Depends on sys_language_mode)
        var $sys_language_contentOL=0;          // Site content overlay flag; If set - and sys_language_content is > 0 - , records selected will try to look for a translation pointing to their uid. (If configured in [ctrl][languageField] / [ctrl][transOrigP...]
        var $sys_language_isocode = '';         // Is set to the iso code of the sys_language_content if that is properly defined by the sys_language record representing the sys_language_uid. (Requires the extension "static_info_tables")
 
        var $indexedDocTitle='';                        // This value will be used as the title for the page in the indexer (if indexing happens)
        var $altPageTitle='';                           // Alternative page title (normally the title of the page record). Can be set from applications you make.
        var $pEncAllowedParamNames=array();     // An array that holds parameter names (keys) of GET parameters which MAY be MD5/base64 encoded with simulate_static_documents method.
-       var $baseUrl='';                                        // The Base url set for the page header.
+       var $baseUrl='';                                        // The base URL set for the page header.
        var $anchorPrefix='';                           // The proper anchor prefix needed when using speaking urls. (only set if baseUrl is set)
 
-               // Page content render object
-       var $cObj ='';                                          // is instantiated object of tslib_cObj
+       /**
+        * Page content render object
+        *
+        * @var tslib_cObj
+        */
+       var $cObj ='';
 
                // CONTENT accumulation
        var $content='';                                        // All page content is accumulated in this variable. See pagegen.php
        var $TCAloaded = 0;                                     // Set ONLY if the full TCA is loaded
 
                // Character set (charset) conversion object:
-       var $csConvObj;                                         // An instance of the "t3lib_cs" class. May be used by any application.
+
+       /**
+        * charset conversion class. May be used by any application.
+        *
+        * @var t3lib_cs
+        */
+       var $csConvObj;
        var $defaultCharSet = 'iso-8859-1';     // The default charset used in the frontend if nothing else is set.
        var $renderCharset='';                          // Internal charset of the frontend during rendering: Defaults to "forceCharset" and if that is not set, to ->defaultCharSet
        var $metaCharset='';                            // Output charset of the websites content. This is the charset found in the header, meta tag etc. If different from $renderCharset a conversion happens before output to browser. Defaults to ->renderCharset if not set.
                                        // Redirects to the Install Tool:
                                echo '<script type="text/javascript">
                                                /*<![CDATA[*/
-                                       document.location = "'.TYPO3_mainDir.'install/index.php?mode=123&step=1&password=joh316";
+                                       window.location.href = "'.TYPO3_mainDir.'install/index.php?mode=123&step=1&password=joh316";
                                                /*]]>*/
                                        </script>';
                                exit;
                        } elseif (!$GLOBALS['TYPO3_DB']->sql_select_db(TYPO3_db))       {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
                                $this->printError('Cannot connect to the current database, "'.TYPO3_db.'"','Database Error');
                                exit;
                        }
                                        // Redirects to the Install Tool:
                                echo '<script type="text/javascript">
                                                /*<![CDATA[*/
-                                       document.location = "'.TYPO3_mainDir.'install/index.php?mode=123&step=1&password=joh316";
+                                       window.location.href = "'.TYPO3_mainDir.'install/index.php?mode=123&step=1&password=joh316";
                                                /*]]>*/
                                        </script>';
                                exit;
                        }
+                       header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
                        $this->printError('The current username, password or host was not accepted when the connection to the database was attempted to be established!','Database Error');
                        exit;
                }
                                                // Initialize the page-select functions to check rootline:
                                        $temp_sys_page = t3lib_div::makeInstance('t3lib_pageSelect');
                                        $temp_sys_page->init($this->showHiddenPage);
-
                                                // If root line contained NO records and ->error_getRootLine_failPid tells us that it was because of a pid=-1 (indicating a "version" record)...:
                                        if (!count($temp_sys_page->getRootLine($this->id,$this->MP)) && $temp_sys_page->error_getRootLine_failPid==-1)  {
 
                                if ($theFirstPage)      {
                                        $this->id = $theFirstPage['uid'];
                                } else {
+                                       header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                                       t3lib_div::sysLog('No pages are found on the rootlevel!', 'cms', 3);
                                        $this->printError('No pages are found on the rootlevel!');
                                        exit;
                                }
                                1 => 'ID was not an accessible page',
                                2 => 'Subsection was found and not accessible',
                                3 => 'ID was outside the domain',
+                               4 => 'The requested page alias does not exist'
                        );
                        $this->pageNotFoundAndExit($pNotFoundMsg[$this->pageNotFound]);
                }
                                        $c--;
                                        $this->id = $this->rootLine[$c]['uid'];
                                        $this->page = $this->sys_page->getPage($this->id);
-                                       if (count($this->page)){ break; }
+                                       if (count($this->page)) { break; }
                                }
                        }
                                // If still no page...
                                if ($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling'])      {
                                        $this->pageNotFoundAndExit('The requested page does not exist!');
                                } else {
+                                       header( 'HTTP/1.0 404 Page Not Found' );
+                                       t3lib_div::sysLog('The requested page does not exist!', 'cms', 3);
                                        $this->printError('The requested page does not exist!');
                                        exit;
                                }
                        }
                }
+
+                       // Spacer is not accessible in frontend
+               if ($this->page['doktype'] == 199)      {
+                       if ($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling'])      {
+                               $this->pageNotFoundAndExit('The requested page does not exist!');
+                       } else {
+                               header( 'HTTP/1.0 404 Page Not Found' );
+                               t3lib_div::sysLog('The requested page does not exist!', 'cms', 3);
+                               $this->printError('The requested page does not exist!');
+                               exit;
+                       }
+               }
+
                        // Is the ID a link to another page??
                if ($this->page['doktype']==4)  {
                        $this->MP = '';         // We need to clear MP if the page is a shortcut. Reason is if the short cut goes to another page, then we LEAVE the rootline which the MP expects.
                        $this->page = $this->getPageShortcut($this->page['shortcut'],$this->page['shortcut_mode'],$this->page['uid']);
                        $this->id = $this->page['uid'];
                }
+
                        // Gets the rootLine
                $this->rootLine = $this->sys_page->getRootLine($this->id,$this->MP);
 
                        // If not rootline we're off...
                if (!count($this->rootLine))    {
-                       $this->printError('The requested page didn\'t have a proper connection to the tree-root! <br /><br />('.$this->sys_page->error_getRootLine.')');
-                       exit;
+                       $ws = $this->whichWorkspace();
+                       if ($this->sys_page->error_getRootLine_failPid==-1 && $ws) {
+                               $this->sys_page->versioningPreview = TRUE;
+                               $this->versioningWorkspaceId = $ws;
+                               $this->rootLine = $this->sys_page->getRootLine($this->id,$this->MP);
+                       }
+                       if (!count($this->rootLine))    {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                               t3lib_div::sysLog('The requested page didn\'t have a proper connection to the tree-root! ('.$this->sys_page->error_getRootLine.')', 'cms', 3);
+                               $this->printError('The requested page didn\'t have a proper connection to the tree-root! <br /><br />('.$this->sys_page->error_getRootLine.')');
+                               exit;
+                       }
+                       $this->fePreview = 1;
                }
 
                        // Checking for include section regarding the hidden/starttime/endtime/fe_user (that is access control of a whole subbranch!)
                if ($this->checkRootlineForIncludeSection())    {
                        if (!count($this->rootLine))    {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                               t3lib_div::sysLog('The requested page was not accessible!', 'cms', 3);
                                $this->printError('The requested page was not accessible!');
                                exit;
                        } else {
                                $page = $this->getPageShortcut($page['shortcut'],$page['shortcut_mode'],$page['uid'],$itera-1,$pageLog);
                        } else {
                                $pageLog[] = $page['uid'];
+                               header( 'HTTP/1.0 500 Internal Server Error' );
+                               t3lib_div::sysLog('Page shortcuts were looping in uids '.implode(',',$pageLog).'...!', 'cms', 3);
                                $this->printError('Page shortcuts were looping in uids '.implode(',',$pageLog).'...!');
                                exit;
                        }
                if (!$this->id) {
                        list($theAlias) = explode('&',t3lib_div::getIndpEnv('QUERY_STRING'));
                        $theAlias = trim($theAlias);
-                       $this->id = $theAlias ? $theAlias : 0;
+                       $this->id = ($theAlias != '' && strpos($theAlias, '=') === false) ? $theAlias : 0;
                }
        }
 
         * Page not found handler.
         * Exits.
         *
-        * @param       mixed           Which type of handling; If a true PHP-boolean and TRUE then a ->printError message is outputted. If integer an error message with that number is shown. Otherwise the $code value is expected to be a "Location:" header value.
+        * @param       mixed           Which type of handling; If a true PHP-boolean or TRUE then a ->printError message is outputted. If integer an error message with that number is shown. Otherwise the $code value is expected to be a "Location:" header value.
         * @param       string          If set, this is passed directly to the PHP function, header()
         * @param       string          If set, error messages will also mention this as the reason for the page-not-found.
-        * @return      void            (The function exists!)
+        * @return      void            (The function exits!)
         */
        function pageNotFoundHandler($code, $header='', $reason='')     {
+
                        // Issue header in any case:
-               if ($header)    {header($header);}
+               if ($header)    {
+                       $headerArr = preg_split('/\r|\n/',$header,-1,PREG_SPLIT_NO_EMPTY);
+                       foreach ($headerArr as $header) {
+                               header ($header);
+                       }
+               }
 
                        // Create response:
                if (gettype($code)=='boolean' || !strcmp($code,1))      {       // Simply boolean; Just shows TYPO3 error page with reason:
                        $this->printError('The page did not exist or was inaccessible.'.($reason ? ' Reason: '.htmlspecialchars($reason) : ''));
-                       exit;
                } elseif (t3lib_div::isFirstPartOfStr($code,'USER_FUNCTION:')) {
                        $funcRef = trim(substr($code,14));
                        $params = array(
                                'pageAccessFailureReasons' => $this->getPageAccessFailureReasons()
                        );
                        echo t3lib_div::callUserFunction($funcRef,$params,$this);
-                       exit;
                } elseif (t3lib_div::isFirstPartOfStr($code,'READFILE:')) {
                        $readFile = t3lib_div::getFileAbsFileName(trim(substr($code,9)));
                        if (@is_file($readFile))        {
                        } else {
                                $this->printError('Configuration Error: 404 page "'.$readFile.'" could not be found.');
                        }
+               } elseif (t3lib_div::isFirstPartOfStr($code,'REDIRECT:')) {
+                       header('Location: '.t3lib_div::locationHeaderUrl(substr($code,9)));
                        exit;
-               } elseif (strlen($code)) {
-                       header('Location: '.t3lib_div::locationHeaderUrl($code));
-                       exit;
+               } elseif (strlen($code))        {
+                               // Check if URL is relative
+                       $url_parts = parse_url($code);
+                       if ($url_parts['host'] == '')   {
+                               $url_parts['host'] = t3lib_div::getIndpEnv('HTTP_HOST');
+                               $code = t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST') . $code;
+                               $checkBaseTag = false;
+                       } else {
+                               $checkBaseTag = true;
+                       }
+
+                               // Check recursion
+                       if ($code == t3lib_div::getIndpEnv('TYPO3_REQUEST_URL')) {
+                               if ($reason == '') {
+                                       $reason = 'Page cannot be found.';
+                               }
+                               $reason.= chr(10) . chr(10) . 'Additionally, ' . $code . ' was not found while trying to retrieve the error document.';
+                               $this->printError('Reason: '.nl2br(htmlspecialchars($reason)));
+                               exit();
+                       }
+
+                               // Prepare headers
+                       $headerArr = array(
+                               'User-agent: ' . t3lib_div::getIndpEnv('HTTP_USER_AGENT'),
+                               'Referer: ' . t3lib_div::getIndpEnv('TYPO3_REQUEST_URL')
+                       );
+                       $res = t3lib_div::getURL($code, 1, $headerArr);
+
+                               // Header and content are separated by an empty line
+                       list($header,$content) = split("\r\n\r\n", $res, 2);
+                       $content.= "\r\n";
+
+                       if (false === $content) {
+                                       // Last chance -- redirect
+                               header('Location: '.t3lib_div::locationHeaderUrl($code));
+                       } else {
+
+                               $forwardHeaders = array(        // Forward these response headers to the client
+                                       'Content-Type:',
+                               );
+                               $headerArr = preg_split('/\r|\n/',$header,-1,PREG_SPLIT_NO_EMPTY);
+                               foreach ($headerArr as $header) {
+                                       foreach ($forwardHeaders as $h) {
+                                               if (preg_match('/^'.$h.'/', $header))   {
+                                                       header ($header);
+                                               }
+                                       }
+                               }
+                                       // Put <base> if necesary
+                               if ($checkBaseTag)      {
+
+                                               // If content already has <base> tag, we do not need to do anything
+                                       if (false === stristr($content, '<base '))      {
+
+                                                       // Generate href for base tag
+                                               $base = $url_parts['scheme'] . '://';
+                                               if ($url_parts['user'] != '')   {
+                                                       $base.= $url_parts['user'];
+                                                       if ($url_parts['pass'] != '')   {
+                                                               $base.= ':' . $url_parts['pass'];
+                                                       }
+                                                       $base.= '@';
+                                               }
+                                               $base.= $url_parts['host'];
+
+                                                       // Add path portion skipping possible file name
+                                               $base.= preg_replace('/(.*\/)[^\/]*/', '${1}', $url_parts['path']);
+
+                                                       // Put it into content (generate also <head> if necessary)
+                                               $replacement = chr(10) . '<base href="' . htmlentities($base) . '" />' . chr(10);
+                                               if (stristr($content, '<head>'))        {
+                                                       $content = preg_replace('/(<head>)/i', '\1' . $replacement, $content);
+                                               } else {
+                                                       $content = preg_replace('/(<html[^>]*>)/i', '\1<head>' . $replacement . '</head>', $content);
+                                               }
+                                       }
+                               }
+                               echo $content;  // Output the content
+                       }
                } else {
-                       $this->printError('Error.'.($reason ? ' Reason: '.htmlspecialchars($reason) : ''));
-                       exit;
+                       $this->printError($reason ? 'Reason: '.htmlspecialchars($reason) : 'Page cannot be found.');
                }
+               exit();
        }
 
        /**
        function checkAndSetAlias()     {
                if ($this->id && !t3lib_div::testInt($this->id))        {
                        $aid = $this->sys_page->getPageIdFromAlias($this->id);
-                       if ($aid)       {$this->id = $aid;}
+                       if ($aid)       {
+                               $this->id = $aid;
+                       } else {
+                               $this->pageNotFound = 4;
+                       }
                }
        }
 
                }
        }
 
+       /**
+        * Looking for a ADMCMD_prev code, looks it up if found and returns configuration data.
+        * Background: From the backend a request to the frontend to show a page, possibly with workspace preview can be "recorded" and associated with a keyword. When the frontend is requested with this keyword the associated request parameters are restored from the database AND the backend user is loaded - only for that request.
+        * The main point is that a special URL valid for a limited time, eg. http://localhost/typo3site/index.php?ADMCMD_prev=035d9bf938bd23cb657735f68a8cedbf will open up for a preview that doesn't require login. Thus its useful for sending an email.
+        * This can also be used to generate previews of hidden pages, start/endtimes, usergroups and those other settings from the Admin Panel - just not implemented yet.
+        *
+        * @return      array           Preview configuration array from sys_preview record.
+        * @see t3lib_BEfunc::compilePreviewKeyword()
+        */
+       function ADMCMD_preview(){
+               $inputCode = t3lib_div::_GP('ADMCMD_prev');
+               $cookieTTL = 60*60;
+
+                       // If cookie is set, see what to do:
+               if ($_COOKIE['ADMCMD_prev'])    {
+                       
+                               // If no input code is given by GET method, lets look it up in a cookie (for workspace previews not only tied to the page) and update the cookie time:
+                       if (!$inputCode)        {
+                               $inputCode = $_COOKIE['ADMCMD_prev'];
+                               SetCookie('ADMCMD_prev', $inputCode, time()+$cookieTTL);
+                       } else {        // Otherwise "log out":
+                               SetCookie('ADMCMD_prev', '', 0);
+                               die("You logged out from Workspace preview mode. Reload the browser to log in again.");
+                       }
+               }
+
+                       // If inputcode now, look up the settings:
+               if ($inputCode) {
 
+                               // Look for keyword configuration record:
+                       list($previewData) = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                               '*',
+                               'sys_preview',
+                               'keyword='.$GLOBALS['TYPO3_DB']->fullQuoteStr($inputCode, 'sys_preview').
+                                       ' AND endtime>'.time()
+                       );
 
+                               // Get: Backend login status, Frontend login status
+                               // - Make sure to remove fe/be cookies (temporarily); BE already done in ADMCMD_preview_postInit()
+                       if (is_array($previewData))     {
+                               if (!count(t3lib_div::_POST())) {
+                                               // Unserialize configuration:
+                                       $previewConfig = unserialize($previewData['config']);
+
+                                       if ($previewConfig['fullWorkspace']) {  // For full workspace preview we only ADD a get variable to set the preview of the workspace - so all other Get vars are accepted. Hope this is not a security problem. Still posting is not allowed and even if a backend user get initialized it shouldn't lead to situations where users can use those credentials.
+                                       
+                                                       // Set the workspace preview value:
+                                               t3lib_div::_GETset($previewConfig['fullWorkspace'],'ADMCMD_previewWS');
+                                               
+                                                       // If ADMCMD_prev is set the $inputCode value cannot come from a cookie and we set that cookie here. Next time it will be found from the cookie if ADMCMD_prev is not set again...
+                                               if (t3lib_div::_GP('ADMCMD_prev'))      {
+                                                       SetCookie('ADMCMD_prev', t3lib_div::_GP('ADMCMD_prev'), time()+$cookieTTL);     // Lifetime is 1 hour, does it matter much? Requires the user to click the link from their email again if it expires.
+                                               }
+                                               return $previewConfig;
+                                       } elseif (t3lib_div::getIndpEnv('TYPO3_SITE_URL').'index.php?ADMCMD_prev='.$inputCode === t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'))   {
+
+                                                       // Set GET variables:
+                                               $GET_VARS = '';
+                                               parse_str($previewConfig['getVars'], $GET_VARS);
+                                               t3lib_div::_GETset($GET_VARS);
+
+                                                       // Return preview keyword configuration:
+                                               return $previewConfig;
+                                       } else die(htmlspecialchars('Request URL did not match "'.t3lib_div::getIndpEnv('TYPO3_SITE_URL').'index.php?ADMCMD_prev='.$inputCode.'"'));    // This check is to prevent people from setting additional GET vars via realurl or other URL path based ways of passing parameters.
+                               } else die('POST requests are incompatible with keyword preview.');
+                       } else die('ADMCMD command could not be executed! (No keyword configuration found)');
+               }
+       }
 
+       /**
+        * Configuration after initialization of TSFE object.
+        * Basically this unsets the BE cookie if any and forces the BE user set according to the preview configuration.
+        *
+        * @param       array           Preview configuration, see ADMCMD_preview()
+        * @return      void
+        * @see ADMCMD_preview(), index_ts.php
+        */
+       function ADMCMD_preview_postInit($previewConfig){
+               if (is_array($previewConfig))   {
 
+                               // Clear cookies:
+                       unset($_COOKIE['be_typo_user']);
+                       $this->ADMCMD_preview_BEUSER_uid = $previewConfig['BEUSER_uid'];
 
+               } else die('Error in preview configuration.');
+       }
 
 
 
         * @return      void
         */
        function getFromCache() {
-               $this->tmpl->getCurrentPageData();
-               $cc = Array();
-               if (is_array($this->tmpl->currentPageData))     {
-                               // BE CAREFULL to change the content of the cc-array. This array is serialized and an md5-hash based on this is used for caching the page.
-                               // If this hash is not the same in here in this section and after page-generation the page will not be properly cached!
-
-                       $cc['all'] = $this->tmpl->currentPageData['all'];
-                       $cc['rowSum'] = $this->tmpl->currentPageData['rowSum'];
-                       $cc['rootLine'] = $this->tmpl->currentPageData['rootLine'];             // This rootline is used with templates only (matching()-function)
-                       $this->all = $this->tmpl->matching($cc);        // This array is an identification of the template. If $this->all is empty it's because the template-data is not cached, which it must be.
-                       ksort($this->all);
+               if (!$this->no_cache)   {
+                       $this->tmpl->getCurrentPageData();
+
+                       $cc = Array();
+                       if (is_array($this->tmpl->currentPageData))     {
+                                       // BE CAREFULL to change the content of the cc-array. This array is serialized and an md5-hash based on this is used for caching the page.
+                                       // If this hash is not the same in here in this section and after page-generation the page will not be properly cached!
+
+                               $cc['all'] = $this->tmpl->currentPageData['all'];
+                               $cc['rowSum'] = $this->tmpl->currentPageData['rowSum'];
+                               $cc['rootLine'] = $this->tmpl->currentPageData['rootLine'];             // This rootline is used with templates only (matching()-function)
+                               $this->all = $this->tmpl->matching($cc);        // This array is an identification of the template. If $this->all is empty it's because the template-data is not cached, which it must be.
+                               ksort($this->all);
+                       }
                }
 
                $this->content='';      // clearing the content-variable, which will hold the pagecontent
 
                                        $this->config = (array)unserialize($row['cache_data']);         // Fetches the lowlevel config stored with the cached data
                                        $this->content = $row['HTML'];  // Getting the content
+                                       $this->tempContent = $row['temp_content'];      // Flag for temp content
                                        $this->cacheContentFlag = 1;    // Setting flag, so we know, that some cached content is gotten.
                                        $this->cacheExpires = $row['expires'];
 
                                        if ($this->TYPO3_CONF_VARS['FE']['debug'] || $this->config['config']['debug'])  {
-                                               $this->content.=chr(10).'<!-- Cached page generated '.Date('d/m Y H:i', $row['tstamp']).'. Expires '.Date('d/m Y H:i', $row['expires']).' -->';
+                                               $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
+                                               $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
+
+                                               $this->content.=chr(10).'<!-- Cached page generated '.date($dateFormat.' '.$timeFormat, $row['tstamp']).'. Expires '.Date($dateFormat.' '.$timeFormat, $row['expires']).' -->';
                                        }
 
                                }
        }
 
        /**
-        * Returning the cached version of page with hash ->newHash
+        * Returning the cached version of page with hash newHash
         *
         * @return      array           Cached row, if any. Otherwise void.
         */
                        );
                $GLOBALS['TT']->pull();
 
-               $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
+               if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+                       $this->pageCachePostProcess($row,'get');
+               }
                $GLOBALS['TYPO3_DB']->sql_free_result($res);
                return $row;
        }
                                $this->pSetup = $this->tmpl->setup[$this->sPre.'.'];
 
                                if (!is_array($this->pSetup))   {
+                                       header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                                       t3lib_div::sysLog('The page is not configured! [type= '.$this->type.']['.$this->sPre.']', 'cms', 3);
                                        $this->printError('The page is not configured! [type= '.$this->type.']['.$this->sPre.']');
                                        exit;
                                } else {
                                        }
                                                // if .simulateStaticDocuments was not present, the default value will rule.
                                        if (!isset($this->config['config']['simulateStaticDocuments'])) {
-                                               $this->config['config']['simulateStaticDocuments'] = $this->TYPO3_CONF_VARS['FE']['simulateStaticDocuments'];
+                                               $this->config['config']['simulateStaticDocuments'] = trim($this->TYPO3_CONF_VARS['FE']['simulateStaticDocuments']);
+                                       }
+                                       if ($this->config['config']['simulateStaticDocuments']) {
+                                                       // Set replacement char only if it is needed
+                                               $this->setSimulReplacementChar();
+                                       }
+
+                                               // Set default values for removeDefaultJS and inlineStyle2TempFile so CSS and JS are externalized if compatversion is higher than 4.0
+                                       if (!isset($this->config['config']['removeDefaultJS']) && t3lib_div::compat_version('4.0'))     {
+                                               $this->config['config']['removeDefaultJS'] = 'external';
+                                       }
+                                       if (!isset($this->config['config']['inlineStyle2TempFile']) && t3lib_div::compat_version('4.0'))        {
+                                               $this->config['config']['inlineStyle2TempFile'] = 1;
                                        }
 
                                                        // Processing for the config_array:
                                        $this->config['mainScript'] = trim($this->config['config']['mainScript']) ? trim($this->config['config']['mainScript']) : 'index.php';
 
                                                // STAT:
-                                       $theLogFile = $this->TYPO3_CONF_VARS['FE']['logfile_dir'].$this->config['config']['stat_apache_logfile'];
+                                       $theLogFile = $this->TYPO3_CONF_VARS['FE']['logfile_dir'].strftime($this->config['config']['stat_apache_logfile']);
                                                // Add PATH_site left to $theLogFile if the path is not absolute yet
                                        if (!t3lib_div::isAbsPath($theLogFile)) $theLogFile = PATH_site.$theLogFile;
 
                                }
                                $GLOBALS['TT']->pull();
                        } else {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                               t3lib_div::sysLog('No template found!', 'cms', 3);
                                $this->printError('No template found!');
                                exit;
                        }
                        // Initialize charset settings etc.
                $this->initLLvars();
 
-                       // We want nice names, so we need to know the charset
+                       // We want nice names, so we need to handle the charset
                if ($setStatPageName)   {
-                       if ($this->config['config']['stat_apache_niceTitle'])   {
+                               // Make life easier and accept variants for utf-8
+                       if (preg_match('/utf-?8/i', $this->config['config']['stat_apache_niceTitle']))  {
+                               $this->config['config']['stat_apache_niceTitle'] = 'utf-8';
+                       }
+                       if ($this->config['config']['stat_apache_niceTitle'] == 'utf-8')        {
+                               $shortTitle = $this->csConvObj->utf8_encode($this->page['title'],$this->renderCharset);
+                       } elseif ($this->config['config']['stat_apache_niceTitle'])     {
                                $shortTitle = $this->csConvObj->specCharsToASCII($this->renderCharset,$this->page['title']);
                        } else {
                                $shortTitle = $this->page['title'];
                        }
-                       $shortTitle = substr(preg_replace('/[^.[:alnum:]_-]/','_',$shortTitle),0,30);
+                       $len = t3lib_div::intInRange($this->config['config']['stat_apache_pageLen'],1,100,30);
+                       if ($this->config['config']['stat_apache_niceTitle'] == 'utf-8')        {
+                               $shortTitle = rawurlencode($this->csConvObj->substr('utf-8',$shortTitle,0,$len));
+                       } else {
+                               $shortTitle = substr(preg_replace('/[^.[:alnum:]_-]/','_',$shortTitle),0,$len);
+                       }
                        $pageName = $this->config['config']['stat_apache_pagenames'] ? $this->config['config']['stat_apache_pagenames'] : '[path][title]--[uid].html';
                        $pageName = str_replace('[title]', $shortTitle ,$pageName);
                        $pageName = str_replace('[uid]',$this->page['uid'],$pageName);
                                array_shift($temp);
                        }
                        $len = t3lib_div::intInRange($this->config['config']['stat_titleLen'],1,100,20);
-                       if ($this->config['config']['stat_apache_niceTitle'])   {
+                       if ($this->config['config']['stat_apache_niceTitle'] == 'utf-8')        {
+                               $path = '';
+                               $c = count($temp);
+                               for ($i=0; $i<$c; $i++) {
+                                       if ($temp[$i]['uid'])   {
+                                               $p = $this->csConvObj->crop('utf-8',$this->csConvObj->utf8_encode($temp[$i]['title'],$this->renderCharset),$len,"\xE2\x80\xA6");        // U+2026; HORIZONTAL ELLIPSIS
+                                               $path .= '/' . rawurlencode($p);
+                                       }
+                               }
+                       } elseif ($this->config['config']['stat_apache_niceTitle'])     {
                                $path = $this->csConvObj->specCharsToASCII($this->renderCharset,$this->sys_page->getPathFromRootline($temp,$len));
                        } else {
                                $path = $this->sys_page->getPathFromRootline($temp,$len);
                        }
-                       $this->config['stat_vars']['pageName'] = str_replace('[path]', preg_replace('/[^.[:alnum:]\/_-]/','_',$path.'/'), $pageName);
+                       if ($this->config['config']['stat_apache_niceTitle'] == 'utf-8')        {
+                               $this->config['stat_vars']['pageName'] = str_replace('[path]', $path.'/', $pageName);
+                       } else {
+                               $this->config['stat_vars']['pageName'] = str_replace('[path]', preg_replace('/[^.[:alnum:]\/_-]/','_',$path.'/'), $pageName);
+                       }
                }
 
                        // No cache
                if ($this->absRefPrefix_force && strcmp($this->config['config']['simulateStaticDocuments'],'PATH_INFO'))        {
                        $redirectUrl = t3lib_div::getIndpEnv('TYPO3_REQUEST_DIR').'index.php?id='.$this->id.'&type='.$this->type;
                        if ($this->config['config']['simulateStaticDocuments_dontRedirectPathInfoError'])       {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                               t3lib_div::sysLog('PATH_INFO was not configured for this website, and the URL tries to find the page by PATH_INFO!', 'cms', 3);
                                $this->printError('PATH_INFO was not configured for this website, and the URL tries to find the page by PATH_INFO!<br /><br /><a href="'.htmlspecialchars($redirectUrl).'">Click here to get to the right page.</a>','Error: PATH_INFO not configured');
                        } else {
                                header('Location: '.t3lib_div::locationHeaderUrl($redirectUrl));
                                                                        }
                                                                }
                                                        break;
+                                                       case 'ignore':
+                                                               $this->sys_language_content = $this->sys_language_uid;
+                                                       break;
                                                        default:
                                                                        // Default is that everything defaults to the default language...
                                                                $this->sys_language_uid = $this->sys_language_content = 0;
                        list($tN,$fN) = explode(':',$TF);
                        $this->TCAcachedExtras[$tN]['l10n_mode'][$fN] = 'mergeIfNotBlank';
                }
+
+                       // Setting softExclude:
+               $table_fields = t3lib_div::trimExplode(',', $this->config['config']['sys_language_softExclude'],1);
+               foreach($table_fields as $TF)   {
+                       list($tN,$fN) = explode(':',$TF);
+                       $this->TCAcachedExtras[$tN]['l10n_mode'][$fN] = 'exclude';
+               }
        }
 
        /**
        /**
         * Checks if any email-submissions or submission via the fe_tce
         *
-        * @return      string          'email' if a formmail has been send, 'fe_tce' if front-end data submission (like forums, guestbooks) is send. '' if none.
+        * @return      string          "email" if a formmail has been sent, "fe_tce" if front-end data submission (like forums, guestbooks) is sent. "" if none.
         */
        function checkDataSubmission()  {
-               if ($_POST['formtype_db'] || $_POST['formtype_mail'])   {
+               $ret = '';
+               $formtype_db = isset($_POST['formtype_db']) || isset($_POST['formtype_db_x']);
+               $formtype_mail = isset($_POST['formtype_mail']) || isset($_POST['formtype_mail_x']);
+               if ($formtype_db || $formtype_mail)     {
                        $refInfo = parse_url(t3lib_div::getIndpEnv('HTTP_REFERER'));
                        if (t3lib_div::getIndpEnv('TYPO3_HOST_ONLY')==$refInfo['host'] || $this->TYPO3_CONF_VARS['SYS']['doNotCheckReferer'])   {
                                if ($this->locDataCheck($_POST['locationData']))        {
-                                       $ret = '';
-                                       if ($_POST['formtype_mail'])    {
+                                       if ($formtype_mail)     {
                                                $ret = 'email';
-                                       } elseif ($_POST['formtype_db'] && is_array($_POST['data']))    {
+                                       } elseif ($formtype_db && is_array($_POST['data']))     {
                                                $ret = 'fe_tce';
                                        }
                                        $GLOBALS['TT']->setTSlogMessage('"Check Data Submission": Return value: '.$ret,0);
                                }
                        } else $GLOBALS['TT']->setTSlogMessage('"Check Data Submission": HTTP_HOST and REFERER HOST did not match when processing submitted formdata!',3);
                }
+
+                       // Hook for processing data submission to extensions:
+               if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkDataSubmission']))  {
+                       foreach($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkDataSubmission'] as $_classRef)  {
+                               $_procObj = &t3lib_div::getUserObj($_classRef);
+                               $_procObj->checkDataSubmission($this);
+                       }
+               }
+               return $ret;
        }
 
        /**
                $EMAIL_VARS = t3lib_div::_POST();
                $locationData = $EMAIL_VARS['locationData'];
                unset($EMAIL_VARS['locationData']);
-               unset($EMAIL_VARS['formtype_mail']);
+               unset($EMAIL_VARS['formtype_mail'], $EMAIL_VARS['formtype_mail_x'], $EMAIL_VARS['formtype_mail_y']);
 
                $integrityCheck = $this->TYPO3_CONF_VARS['FE']['strictFormmail'];
 
-               if(!$this->TYPO3_CONF_VARS['FE']['secureFormmail']) {
+               if (!$this->TYPO3_CONF_VARS['FE']['secureFormmail'])    {
                                // Check recipient field:
                        $encodedFields = explode(',','recipient,recipient_copy');       // These two fields are the ones which contain recipient addresses that can be misused to send mail from foreign servers.
-                       foreach($encodedFields as $fieldKey)    {
+                       foreach ($encodedFields as $fieldKey)   {
                                if (strlen($EMAIL_VARS[$fieldKey]))     {
                                        if ($res = $this->codeString($EMAIL_VARS[$fieldKey], TRUE))     {       // Decode...
                                                $EMAIL_VARS[$fieldKey] = $res;  // Set value if OK
        }
 
        /**
-        * Checks if jumpurl is set.
-        * This function also takes care of jumpurl utilized by the Direct Mail module (ext: direct_mail) which may set an integer value for jumpurl which refers to a link in a certain mail-record, mid
+        * Sets the jumpurl for page type "External URL"
         *
         * @return      void
         */
-       function checkJumpUrl() {
-               global $TCA;
-
-               $mid = t3lib_div::_GP('mid');           // mail id, if direct mail link
-               $rid = t3lib_div::_GP('rid');           // recipient id, if direct mail link
-               if ((strcmp($this->jumpurl,'') && ((t3lib_div::getIndpEnv('HTTP_REFERER') || $this->TYPO3_CONF_VARS['SYS']['doNotCheckReferer']) || $mid)) || ($this->jumpurl = $this->sys_page->getExtURL($this->page,$this->config['config']['disablePageExternalUrl'])))     {
-                       if ($mid && is_array($TCA['sys_dmail']))        {       // Yes, it's OK if the link comes from a direct mail. AND sys_dmail module has installed the table, sys_dmail (and therefore we expect sys_dmail_maillog as well!)
-                               $temp_recip=explode('_',$rid);
-                               $url_id=0;
-                               if (t3lib_div::testInt($this->jumpurl)) {
-                                       $temp_res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('mailContent', 'sys_dmail', 'uid='.intval($mid));
-                                       if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($temp_res))    {
-                                               $temp_unpackedMail = unserialize($row['mailContent']);
-                                               $url_id=$this->jumpurl;
-                                               if ($this->jumpurl>=0)  {
-                                                       $responseType=1;        // Link (number)
-                                                       $this->jumpurl = $temp_unpackedMail['html']['hrefs'][$url_id]['absRef'];
-                                               } else {
-                                                       $responseType=2;        // Link (number, plaintext)
-                                                       $this->jumpurl = $temp_unpackedMail['plain']['link_ids'][abs($url_id)];
-                                               }
-                                               switch($temp_recip[0])  {
-                                                       case 't':
-                                                               $theTable = 'tt_address';
-                                                       break;
-                                                       case 'f':
-                                                               $theTable = 'fe_users';
-                                                       break;
-                                                       default:
-                                                               $theTable='';
-                                                       break;
-                                               }
-                                               if ($theTable)  {
-                                                       $recipRow = $this->sys_page->getRawRecord($theTable,$temp_recip[1]);
-                                                       if (is_array($recipRow))        {
-//                                                             debug($recipRow);
-                                                               $authCode = t3lib_div::stdAuthCode($recipRow['uid']);
-                                                               $rowFieldsArray = explode(',', 'uid,name,title,email,phone,www,address,company,city,zip,country,fax,firstname');
-                                                               reset($rowFieldsArray);
-                                                               while(list(,$substField)=each($rowFieldsArray)) {
-                                                                       $this->jumpurl = str_replace('###USER_'.$substField.'###', $recipRow[$substField], $this->jumpurl);
-                                                               }
-                                                               $this->jumpurl = str_replace('###SYS_TABLE_NAME###', $tableNameChar, $this->jumpurl);   // Put in the tablename of the userinformation
-                                                               $this->jumpurl = str_replace('###SYS_MAIL_ID###', $mid, $this->jumpurl);        // Put in the uid of the mail-record
-                                                               $this->jumpurl = str_replace('###SYS_AUTHCODE###', $authCode, $this->jumpurl);
-
-                                               //              debug($this->jumpurl);
-                                                       }
-                                               }
-                                       }
-
-                                       $GLOBALS['TYPO3_DB']->sql_free_result($temp_res);
-
-                                       if (!$this->jumpurl)    die('Error: No further link. Please report error to the mail sender.');
-                               } else {
-                                       $responseType=-1;       // received (url, dmailerping)
-                               }
-                               if ($responseType!=0)   {
-                                       $insertFields = array(
-                                               'mid' => intval($mid),
-                                               'rtbl' => $temp_recip[0],
-                                               'rid' => intval($temp_recip[1]),
-                                               'tstamp' => time(),
-                                               'url' => $this->jumpurl,
-                                               'response_type' => intval($responseType),
-                                               'url_id' => intval($url_id)
-                                       );
+       function setExternalJumpUrl()   {
+               if ($extUrl = $this->sys_page->getExtURL($this->page, $this->config['config']['disablePageExternalUrl']))       {
+                       $this->jumpurl = $extUrl;
+               }
+       }
 
-                                       $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_dmail_maillog', $insertFields);
-                               }
-                       }
-               } else {
-                       unset($this->jumpurl);
+       /**
+        * Checks the jumpurl referer if required
+        *
+        * @return      void
+        */
+       function checkJumpUrlReferer()  {
+               if (strcmp($this->jumpurl,'') && !$this->TYPO3_CONF_VARS['SYS']['doNotCheckReferer']) {
+                       $referer = parse_url(t3lib_div::getIndpEnv('HTTP_REFERER'));
+                       if (isset($referer['host']) && !($referer['host'] == t3lib_div::getIndpEnv('TYPO3_HOST_ONLY'))) {
+                               unset($this->jumpurl);
+                       }
                }
        }
 
                                                if (@is_file($this->jumpurl))   {
                                                        $mimeType = t3lib_div::_GP('mimeType');
                                                        $mimeType = $mimeType ? $mimeType : 'application/octet-stream';
-                                                       Header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
-                                                       Header('Content-Type: '.$mimeType);
-                                                       Header('Content-Disposition: attachment; filename='.basename($this->jumpurl));
+                                                       header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+                                                       header('Content-Type: '.$mimeType);
+                                                       header('Content-Disposition: attachment; filename='.basename($this->jumpurl));
                                                        readfile($this->jumpurl);
                                                        exit;
                                                } else die('jumpurl Secure: "'.$this->jumpurl.'" was not a valid file!');
                                if ($TSConf['TSFE.']['jumpUrl_transferSession'])        {
                                        $uParts = parse_url($this->jumpurl);
                                        $params = '&FE_SESSION_KEY='.rawurlencode($this->fe_user->id.'-'.md5($this->fe_user->id.'/'.$this->TYPO3_CONF_VARS['SYS']['encryptionKey']));
-                                       $this->jumpurl.=($uParts['query']?'':'?').$params;      // Add the session parameter ...
+                                       $this->jumpurl.= ($uParts['query']?'':'?').$params;     // Add the session parameter ...
                                }
-                               Header('Location: '.$this->jumpurl);
+                               header('Location: '.$this->jumpurl);
                                exit;
                        }
                }
 <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
                <title>'.$title.'</title>
-               <meta name="robots" content="noarchive" />
-               <script type="text/javascript">
-                       window.setTimeout("location.reload()", 3000);
-               </script>
+               <meta http-equiv="refresh" content="10" />
        </head>
        <body style="background-color:white; font-family:Verdana,Arial,Helvetica,sans-serif; color:#cccccc; text-align:center;">'.
                $message.'
        </body>
 </html>';
 
+                               // Fix 'nice errors' feature in modern browsers
+                       $padSuffix = '<!--pad-->';      // prevent any trims
+                       $padSize = 768 - strlen($padSuffix) - strlen($temp_content);
+                       if ($padSize > 0) {
+                               $temp_content = str_pad($temp_content, $padSize, "\n") . $padSuffix;
+                       }
+
                        if (!$this->headerNoCache() && $cachedRow = $this->getFromCache_queryRow())     {
                                        // We are here because between checking for cached content earlier and now some other HTTP-process managed to store something in cache AND it was not due to a shift-reload by-pass.
                                        // This is either the "Page is being generated" screen or it can be the final result.
                                        // Actually $cachedRow contains content that we could show instead of rendering. Maybe we should do that to gain more performance but then we should set all the stuff done in $this->getFromCache()... For now we stick to this...
                                $this->set_no_cache();
                        } else {
-                               $this->setPageCacheContent($temp_content, $this->config, $GLOBALS['EXEC_TIME']+$seconds);
                                $this->tempContent = TRUE;              // This flag shows that temporary content is put in the cache
+                               $this->setPageCacheContent($temp_content, $this->config, $GLOBALS['EXEC_TIME']+$seconds);
                        }
                }
        }
         * @return      void
         */
        function realPageCacheContent() {
-               $cache_timeout = $this->page['cache_timeout'] ? $this->page['cache_timeout'] : ($this->cacheTimeOutDefault ? $this->cacheTimeOutDefault : 60*60*24);            // seconds until a cached page is too old
+               $cache_timeout = $this->get_cache_timeout();            // seconds until a cached page is too old
                $timeOutTime = $GLOBALS['EXEC_TIME']+$cache_timeout;
                if ($this->config['config']['cache_clearAtMidnight'])   {
                        $midnightTime = mktime (0,0,0,date('m',$timeOutTime),date('d',$timeOutTime),date('Y',$timeOutTime));
                                $timeOutTime = $midnightTime;
                        }
                }
+               $this->tempContent = false;
                $this->setPageCacheContent($this->content, $this->config, $timeOutTime);
 
                        // Hook for cache post processing (eg. writing static files!)
                        'hash' => $this->newHash,
                        'page_id' => $this->id,
                        'HTML' => $content,
+                       'temp_content' => $this->tempContent,
                        'cache_data' => serialize($data),
                        'expires' => $tstamp,
                        'tstamp' => $GLOBALS['EXEC_TIME']
                if ($this->page_cache_reg1)     {
                        $insertFields['reg1'] = intval($this->page_cache_reg1);
                }
+               $this->pageCachePostProcess($insertFields,'set');
+
                $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_pages', $insertFields);
        }
 
        }
 
        /**
+        * Post processing page cache rows for both get and set.
+        *
+        * @param       array           Input "cache_pages" row, passed by reference!
+        * @param       string          Type of operation, either "get" or "set"
+        * @return      void
+        */
+       function pageCachePostProcess(&$row,$type)      {
+
+               if ($this->TYPO3_CONF_VARS['FE']['pageCacheToExternalFiles'])   {
+                       $cacheFileName = PATH_site.'typo3temp/cache_pages/'.$row['hash']{0}.$row['hash']{1}.'/'.$row['hash'].'.html';
+                       switch((string)$type)   {
+                               case 'get':
+                                       $row['HTML'] = @is_file($cacheFileName) ? t3lib_div::getUrl($cacheFileName) : '<!-- CACHING ERROR, sorry -->';
+                               break;
+                               case 'set':
+                                       t3lib_div::writeFileToTypo3tempDir($cacheFileName,$row['HTML']);
+                                       $row['HTML'] = '';
+                               break;
+                       }
+               }
+       }
+
+       /**
         * Sets sys last changed
         * Setting the SYS_LASTCHANGED value in the pagerecord: This value will thus be set to the highest tstamp of records rendered on the page. This includes all records with no regard to hidden records, userprotection and so on.
         *
                        $this->realPageCacheContent();
                } elseif ($this->tempContent)   {               // If there happens to be temporary content in the cache and the cache was not cleared due to new content put in it... ($this->no_cache=0)
                        $this->clearPageCacheContent();
+                       $this->tempContent = false;
                }
 
                        // Sets sys-last-change:
                $GLOBALS['TT']->setTSlogMessage('Parts: '.count($INTiS_splitC));
                $GLOBALS['TT']->pull();
 
-                       // Depreciated stuff:
+                       // Deprecated stuff:
                $this->additionalHeaderData = is_array($this->config['INTincScript_ext']['additionalHeaderData']) ? $this->config['INTincScript_ext']['additionalHeaderData'] : array();
                $this->additionalJavaScript = $this->config['INTincScript_ext']['additionalJavaScript'];
                $this->additionalCSS = $this->config['INTincScript_ext']['additionalCSS'];
                $INTiS_config = $GLOBALS['TSFE']->config['INTincScript'];
                foreach($INTiS_splitC as $INTiS_c => $INTiS_cPart)      {
                        if (substr($INTiS_cPart,32,3)=='-->')   {       // If the split had a comment-end after 32 characters it's probably a split-string
-                               $GLOBALS['TT']->push('Include '.$INTiS_config[$INTiS_key]['file'],'');
                                $INTiS_key = 'INT_SCRIPT.'.substr($INTiS_cPart,0,32);
+                               $GLOBALS['TT']->push('Include '.$INTiS_config[$INTiS_key]['file'],'');
                                $incContent='';
                                if (is_array($INTiS_config[$INTiS_key]))        {
                                        $INTiS_cObj = unserialize($INTiS_config[$INTiS_key]['cObj']);
@@ -2700,6 +2989,11 @@ if (version == "n3") {
                        }
                }
 
+                       // Send appropriate status code in case of temporary content
+               if ($this->tempContent) {
+                       $this->addTempContentHttpHeaders();
+               }
+
                        // Make substitution of eg. username/uid in content only if cache-headers for client/proxy caching is NOT sent!
                if (!$this->isClientCachable)   {
                        $this->contentStrReplace();
@@ -2990,13 +3284,20 @@ if (version == "n3") {
                                $stdMsg = '
                                <br />
                                <div align="center">
-                                       <table border="3" bordercolor="black" cellpadding="2" bgcolor="red">
+                                       <table border="3" bordercolor="black" cellpadding="2" bgcolor="red" summary="">
                                                <tr>
                                                        <td>&nbsp;&nbsp;<font face="Verdana" size="1"><b>'.htmlspecialchars($text).'</b></font>&nbsp;&nbsp;</td>
                                                </tr>
                                        </table>
                                </div>';
-                               $temp_content = $this->config['config']['message_preview'] ? $this->config['config']['message_preview'] : $stdMsg;
+
+                               if ($this->fePreview==2)        {
+                                       $temp_content = $this->config['config']['message_preview_workspace'] ?
+                                               @sprintf($this->config['config']['message_preview_workspace'], $this->whichWorkspace(TRUE),$this->whichWorkspace()) :
+                                               $stdMsg;
+                               } else {
+                                       $temp_content = $this->config['config']['message_preview'] ? $this->config['config']['message_preview'] : $stdMsg;
+                               }
                                echo $temp_content;
                }
        }
@@ -3028,9 +3329,9 @@ if (version == "n3") {
                                $label = !$this->beUserLogin ? $this->config['config']['beLoginLinkIPList_login'] : $this->config['config']['beLoginLinkIPList_logout'];
                                if ($label)     {
                                        if (!$this->beUserLogin)        {
-                                               $link = '<a href="'.htmlspecialchars(TYPO3_mainDir.'index.php?redirect_url='.rawurlencode(t3lib_div::getIndpEnv("REQUEST_URI"))).'">'.$label.'</a>';
+                                               $link = '<a href="'.htmlspecialchars(TYPO3_mainDir.'index.php?redirect_url='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'">'.$label.'</a>';
                                        } else {
-                                               $link = '<a href="'.htmlspecialchars(TYPO3_mainDir.'index.php?L=OUT&redirect_url='.rawurlencode(t3lib_div::getIndpEnv("REQUEST_URI"))).'">'.$label.'</a>';
+                                               $link = '<a href="'.htmlspecialchars(TYPO3_mainDir.'index.php?L=OUT&redirect_url='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'">'.$label.'</a>';
                                        }
                                        return $link;
                                }
@@ -3038,6 +3339,18 @@ if (version == "n3") {
                }
        }
 
+       /**
+        * Sends HTTP headers for temporary content. These headers prevent search engines from caching temporary content and asks them to revisit this page again.
+        *
+        * @return      void
+        */
+       function addTempContentHttpHeaders() {
+               header('HTTP/1.0 503 Service unavailable');
+               header('Retry-after: 3600');
+               header('Pragma: no-cache');
+               header('Cache-control: no-cache');
+               header('Expire: 0');
+       }
 
 
 
@@ -3077,7 +3390,7 @@ if (version == "n3") {
         * @return      string          The body of the filename.
         * @see getSimulFileName(), t3lib_tstemplate::linkData(), tslib_frameset::frameParams()
         */
-       function makeSimulFileName($inTitle,$page,$type,$addParams='',$no_cache='')     {
+       function makeSimulFileName($inTitle,$page,$type,$addParams='',$no_cache=false)  {
                $titleChars = intval($this->config['config']['simulateStaticDocuments_addTitle']);
                        // Default value is 30 but values > 1 will be override this
                if($titleChars==1)      { $titleChars = 30; }
@@ -3154,12 +3467,29 @@ if (version == "n3") {
         * @see makeSimulFileName(), publish.php
         */
        function getSimulFileName()     {
-               $url='';
-               $url.=$this->makeSimulFileName($this->page['title'], $this->page['alias']?$this->page['alias']:$this->id, $this->type).'.html';
+               $url = '';
+               $url.= $this->makeSimulFileName($this->page['title'], $this->page['alias']?$this->page['alias']:$this->id, $this->type).'.html';
                return $url;
        }
 
        /**
+        * Checks and sets replacement character for simulateStaticDocuments. Default is underscore.
+        *
+        * @return      void
+        */
+       function setSimulReplacementChar() {
+               $replacement = $defChar = t3lib_div::compat_version('4.0') ? '-' : '_';
+               if (isset($this->config['config']['simulateStaticDocuments_replacementChar'])) {
+                       $replacement = trim($this->config['config']['simulateStaticDocuments_replacementChar']);
+                       if (urlencode($replacement) != $replacement) {
+                                       // Invalid character
+                               $replacement = $defChar;
+                       }
+               }
+               $this->config['config']['simulateStaticDocuments_replacementChar'] = $replacement;
+       }
+
+       /**
         * Converts input string to an ASCII based file name prefix
         *
         * @param       string          String to base output on
@@ -3169,16 +3499,41 @@ if (version == "n3") {
         */
        function fileNameASCIIPrefix($inTitle,$titleChars,$mergeChar='.')       {
                $out = $this->csConvObj->specCharsToASCII($this->renderCharset, $inTitle);
-               $out = ereg_replace('[^[:alnum:]_-]','_',trim(substr($out,0,$titleChars)));
-               $out = ereg_replace('[_-]*$','',$out);
-               $out = ereg_replace('^[_-]*','',$out);
-               $out = ereg_replace('([_-])[_-]*','\1',$out);
-               if (strlen($out))       $out.=$mergeChar;
+                       // Get replacement character
+               $replacementChar = $this->config['config']['simulateStaticDocuments_replacementChar'];
+               $replacementChars = '_\-' . ($replacementChar != '_' && $replacementChar != '-' ? $replacementChar : '');
+               $out = preg_replace('/[^A-Za-z0-9_-]/', $replacementChar, trim(substr($out, 0, $titleChars)));
+               $out = preg_replace('/([' . $replacementChars . ']){2,}/', '\1', $out);
+               $out = preg_replace('/[' . $replacementChars . ']?$/', '', $out);
+               $out = preg_replace('/^[' . $replacementChars . ']?/', '', $out);
+               if (strlen($out)) {
+                       $out.= $mergeChar;
+               }
 
                return $out;
        }
 
        /**
+        * Encryption (or decryption) of a single character.
+        * Within the given range the character is shifted with the supplied offset.
+        *
+        * @param       int             Ordinal of input character
+        * @param       int             Start of range
+        * @param       int             End of range
+        * @param       int             Offset
+        * @return      string          encoded/decoded version of character
+        */
+       function encryptCharcode($n,$start,$end,$offset)        {
+               $n = $n + $offset;
+               if ($offset > 0 && $n > $end)   {
+                       $n = $start + ($n - $end - 1);
+               } else if ($offset < 0 && $n < $start)  {
+                       $n = $end - ($start - $n - 1);
+               }
+               return chr($n);
+       }
+
+       /**
         * Encryption of email addresses for <A>-tags See the spam protection setup in TS 'config.'
         *
         * @param       string          Input string to en/decode: "mailto:blabla@bla.com"
@@ -3193,10 +3548,20 @@ if (version == "n3") {
                                $out .= '&#'.ord(substr($string, $a, 1)).';';
                        }
                } else  {
-                       for ($a=0; $a<strlen($string); $a++)    {
-                               $charValue = ord(substr($string,$a,1));
-                               $charValue+= intval($this->spamProtectEmailAddresses)*($back?-1:1);
-                               $out.= chr($charValue);
+                               // like str_rot13() but with a variable offset and a wider character range
+                       $len = strlen($string);
+                       $offset = intval($this->spamProtectEmailAddresses)*($back?-1:1);
+                       for ($i=0; $i<$len; $i++)       {
+                               $charValue = ord($string{$i});
+                               if ($charValue >= 0x2B && $charValue <= 0x3A)   {       // 0-9 . , - + / :
+                                       $out .= $this->encryptCharcode($charValue,0x2B,0x3A,$offset);
+                               } elseif ($charValue >= 0x40 && $charValue <= 0x5A)     {       // A-Z @
+                                       $out .= $this->encryptCharcode($charValue,0x40,0x5A,$offset);
+                               } else if ($charValue >= 0x61 && $charValue <= 0x7A)    {       // a-z
+                                       $out .= $this->encryptCharcode($charValue,0x61,0x7A,$offset);
+                               } else {
+                                       $out .= $string{$i};
+                               }
                        }
                }
                return $out;
@@ -3213,7 +3578,7 @@ if (version == "n3") {
         */
        function codeString($string, $decode=FALSE)     {
 
-               if ($decode) {
+               if ($decode)    {
                        list($md5Hash, $str) = explode(':',$string,2);
                        $newHash = substr(md5($this->TYPO3_CONF_VARS['SYS']['encryptionKey'].':'.$str),0,10);
                        if (!strcmp($md5Hash, $newHash))        {
@@ -3278,7 +3643,7 @@ if (version == "n3") {
        }
 
        /**
-        * Substitute the path's to files in the media/ folder like icons used in static_template of TypoScript
+        * Substitute the path's to files in the fileadmin/ and media/ folder like icons used in static_template of TypoScript
         * Works on $this->content
         *
         * @return      void
@@ -3287,14 +3652,14 @@ if (version == "n3") {
         */
        function setAbsRefPrefix()      {
                if ($this->absRefPrefix)        {
-                       $this->content = str_replace('"media/', '"'.$this->absRefPrefix.'media/', $this->content);
+                       $this->content = str_replace('"media/', '"'.t3lib_extMgm::siteRelPath('cms').'tslib/media/', $this->content);
                        $this->content = str_replace('"fileadmin/', '"'.$this->absRefPrefix.'fileadmin/', $this->content);
                }
        }
 
        /**
         * Prefixing the input URL with ->baseUrl If ->baseUrl is set and the input url is not absolute in some way.
-        * Designed as a wrapper functions for use with all frontend links that are processed by JavaScript (for "realurl" compatibility!). So each time a URL goes into window.open, document.location or otherwise, wrap it with this function!
+        * Designed as a wrapper functions for use with all frontend links that are processed by JavaScript (for "realurl" compatibility!). So each time a URL goes into window.open, window.location.href or otherwise, wrap it with this function!
         *
         * @param       string          Input URL, relative or absolute
         * @return      string          Processed input value.
@@ -3368,18 +3733,22 @@ if (version == "n3") {
         */
        function prefixLocalAnchorsWithScript() {
                $scriptPath = substr(t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'),strlen(t3lib_div::getIndpEnv('TYPO3_SITE_URL')));
-               $this->content = preg_replace('/(<(a|area).*?href=")(#[^"]*")/i','$1' . htmlspecialchars($scriptPath) . '$3',$this->content);
+               $this->content = preg_replace('/(<(a|area).*?href=")(#[^"]*")/i','${1}' . htmlspecialchars($scriptPath) . '${3}',$this->content);
        }
 
        /**
         * Initialize workspace preview
-        * STILL VERY TEMPORARY - MUST INCLUDE SECURITY of some sort.
         *
         * @return      void
         */
        function workspacePreviewInit() {
-               if ($this->beUserLogin && is_object($GLOBALS['BE_USER']) && t3lib_div::testInt(t3lib_div::_GP('ADMCMD_previewWS')))     {
-                       $this->workspacePreview = intval(t3lib_div::_GP('ADMCMD_previewWS'));
+               $previewWS = t3lib_div::_GP('ADMCMD_previewWS');
+               if ($this->beUserLogin && is_object($GLOBALS['BE_USER']) && t3lib_div::testInt($previewWS))     {
+                       if ($previewWS>=-1 && ($previewWS==0 || $GLOBALS['BE_USER']->checkWorkspace($previewWS)))       {       // Check Access to workspace. Live (0) is OK to preview for all.
+                               $this->workspacePreview = intval($previewWS);
+                       } else {
+                               $this->workspacePreview = -99;  // No preview, will default to "Live" at the moment
+                       }
                }
        }
 
@@ -3512,13 +3881,13 @@ if (version == "n3") {
 '              // JS function for mouse-over
        function over(name,imgObj)      {       //
                if (version == "n3" && document[name]) {document[name].src = eval(name+"_h.src");}
-               else if (typeof(document.getElementById)=="function" && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_h.src");}
+               else if (document.getElementById && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_h.src");}
                else if (imgObj)        {imgObj.src = eval(name+"_h.src");}
        }
                // JS function for mouse-out
        function out(name,imgObj)       {       //
                if (version == "n3" && document[name]) {document[name].src = eval(name+"_n.src");}
-               else if (typeof(document.getElementById)=="function" && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_n.src");}
+               else if (document.getElementById && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_n.src");}
                else if (imgObj)        {imgObj.src = eval(name+"_n.src");}
        }';
                                break;
@@ -3596,6 +3965,25 @@ if (version == "n3") {
        }
 
        /**
+        * Get the cache timeout for the current page.
+        *
+        * @return      integer         The cache timeout for the current page.
+        */
+       function get_cache_timeout() {
+                       // Cache period was set for the page:
+               if ($this->page['cache_timeout']) {
+                       $cacheTimeout = $this->page['cache_timeout'];
+                       // Cache period was set for the whole site:
+               } elseif ($this->cacheTimeOutDefault) {
+                       $cacheTimeout = $this->cacheTimeOutDefault;
+                       // No cache period set at all, so we take one day (60*60*24 seconds = 86400 seconds):
+               } else {
+                       $cacheTimeout = 86400;
+               }
+               return $cacheTimeout;
+       }
+
+       /**
         * Substitute function for the PHP mail() function.
         * It will encode the email with the setting of TS 'config.notification_email_encoding' (base64 or none)
         * It will also find all links to http:// in the text and substitute with a shorter link using the redirect feature which stores the long link in the database. Depends on configuration in TS 'config.notification_email_urlmode'
@@ -3608,10 +3996,32 @@ if (version == "n3") {
         * @see t3lib_div::plainMailEncoded()
         */
        function plainMailEncoded($email,$subject,$message,$headers='') {
-               $urlmode=$this->config['config']['notification_email_urlmode']; // '76', 'all', ''
+               $urlmode = $this->config['config']['notification_email_urlmode'];       // '76', 'all', ''
 
                if ($urlmode)   {
-                       $message=t3lib_div::substUrlsInPlainText($message,$urlmode);
+                       $message = t3lib_div::substUrlsInPlainText($message,$urlmode);
+               }
+
+               $encoding = $this->config['config']['notification_email_encoding'] ? $this->config['config']['notification_email_encoding'] : '';
+               $charset = $this->renderCharset;
+
+               $convCharset = FALSE;   // do we need to convert mail data?
+               if ($this->config['config']['notification_email_charset'])      {       // Respect config.notification_email_charset if it was set
+                       $charset = $this->csConvObj->parse_charset($this->config['config']['notification_email_charset']);
+                       if ($charset != $this->renderCharset)   {
+                               $convCharset = TRUE;
+                       }
+
+               } elseif ($this->metaCharset != $this->renderCharset)   {       // Use metaCharset for mail if different from renderCharset
+                       $charset = $this->metaCharset;
+                       $convCharset = TRUE;
+               }
+
+               if ($convCharset)       {
+                       $email = $this->csConvObj->conv($email,$this->renderCharset,$charset);
+                       $subject = $this->csConvObj->conv($subject,$this->renderCharset,$charset);
+                       $message = $this->csConvObj->conv($message,$this->renderCharset,$charset);
+                       $headers = $this->csConvObj->conv($headers,$this->renderCharset,$charset);
                }
 
                t3lib_div::plainMailEncoded(
@@ -3619,8 +4029,8 @@ if (version == "n3") {
                        $subject,
                        $message,
                        $headers,
-                       $this->config['config']['notification_email_encoding'],
-                       $this->config['config']['notification_email_charset'] ? $this->config['config']['notification_email_charset'] : 'ISO-8859-1'
+                       $encoding,
+                       $charset
                );
        }