Index: tests/t3lib/matchcondition/t3lib_matchcondition_frontend_testcase.php
===================================================================
--- tests/t3lib/matchcondition/t3lib_matchcondition_frontend_testcase.php	(Revision 0)
+++ tests/t3lib/matchcondition/t3lib_matchcondition_frontend_testcase.php	(Revision 0)
@@ -0,0 +1,596 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Oliver Hader <oliver@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * Testcase for class t3lib_matchCondition_frontend.
+ *
+ * @author	Oliver Hader <oliver@typo3.org>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_matchCondition_frontend_testcase extends tx_phpunit_testcase {
+	/**
+	 * @var	array
+	 */
+	private $backupGlobalVariables;
+
+	/**
+	 * @var	array
+	 */
+	private $rootline;
+
+	/**
+	 * @var	t3lib_matchCondition
+	 */
+	private $matchCondition;
+
+	public function setUp() {
+		$this->backupGlobalVariables = array(
+			'_ENV' => $_ENV,
+			'_GET' => $_GET,
+			'_POST' => $_POST,
+			'_SERVER' => $_SERVER,
+			'TYPO3_CONF_VARS' => $GLOBALS['TYPO3_CONF_VARS'],
+			'T3_VAR' => $GLOBALS['T3_VAR'],
+		);
+
+		$this->testGlobalNamespace = uniqid('TEST');
+		$GLOBALS[$this->testGlobalNamespace] = array();
+
+		$this->setUpTSFE();
+		$this->matchCondition = t3lib_div::makeInstance('t3lib_matchCondition_frontend');
+	}
+
+	public function tearDown() {
+		foreach ($this->backupGlobalVariables as $key => $data) {
+			$GLOBALS[$key] = $data;
+		}
+
+		unset($this->matchCondition);
+		unset($this->backupGlobalVariables);
+		unset($GLOBALS[$this->testGlobalNamespace]);
+	}
+
+	private function setUpTSFE() {
+		$this->rootline = array(
+			2 => array('uid' => 121, 'pid' => 111),
+			1 => array('uid' => 111, 'pid' => 101,),
+			0 => array('uid' => 101, 'pid' => 0,),
+		);
+
+		$GLOBALS['TSFE'] = $this->getMock('tslib_fe', array(), array(), '', FALSE);
+		$GLOBALS['TSFE']->tmpl = $this->getMock('t3lib_TStemplate');
+	}
+
+	/**
+	 * Tests whether a faulty expression fails.
+	 * @test
+	 */
+	public function simulateDisabledMatchAllConditionsFailsOnFaultyExpression() {
+		$this->matchCondition->matchAll = false;
+		$this->assertFalse($this->matchCondition->match('[nullCondition = This expression would return false in general]'));
+	}
+
+	/**
+	 * Tests whether simulating positive matches for all conditions succeeds.
+	 * @test
+	 */
+	public function simulateEnabledMatchAllConditionsSucceeds() {
+		$this->matchCondition->setSimulateMatchResult(true);
+		$this->assertTrue($this->matchCondition->match('[nullCondition = This expression would return false in general]'));
+	}
+
+	/**
+	 * Tests whether simulating positive matches for specific conditions succeeds.
+	 * @test
+	 */
+	public function simulateEnabledMatchSpecificConditionsSucceeds() {
+		$testCondition = '[' . uniqid('test') . ' = Any condition to simulate a positive match]';
+		$this->matchCondition->setSimulateMatchConditions(array($testCondition));
+		$this->assertTrue($this->matchCondition->match($testCondition));
+	}
+
+	/**
+	 * Tests whether a condition matches Internet Explorer 7 on Windows.
+	 *
+	 * @return	void
+	 * @test
+	 */
+	public function conditionMatchesInternetExplorer7Windows() {
+		$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)';
+		$result = $this->matchCondition->match('[browser = msie] && [version = 7] && [system = winNT]');
+		$this->assertTrue($result);
+	}
+
+	/**
+	 * Tests whether a condition does not match Internet Explorer 7 on Windows.
+	 *
+	 * @return	void
+	 * @test
+	 */
+	public function conditionDoesNotMatchInternetExplorer7Windows() {
+		$_SERVER['HTTP_USER_AGENT'] = 'Opera/9.25 (Windows NT 6.0; U; en)';
+		$result = $this->matchCondition->match('[browser = msie] && [version = 7] && [system = winNT]');
+		$this->assertFalse($result);
+	}
+
+	/**
+	 * Tests whether a device type condition matches a crawler.
+	 * @test
+	 */
+	public function deviceConditionMatchesRobot() {
+		$_SERVER['HTTP_USER_AGENT'] = 'Googlebot/2.1 (+http://www.google.com/bot.html)';
+		$result = $this->matchCondition->match('[device = robot]');
+		$this->assertTrue($result);
+	}
+
+	/**
+	 * Tests whether a device type condition does not match a crawler.
+	 * @test
+	 */
+	public function deviceConditionDoesNotMatchRobot() {
+		$_SERVER['HTTP_USER_AGENT'] = md5('Some strange user agent');
+		$result = $this->matchCondition->match('[device = robot]');
+		$this->assertFalse($result);
+	}
+
+	/**
+	 * Tests whether the browserInfo hook is called.
+	 *
+	 * @return	void
+	 * @test
+	 */
+	public function deprecatedBrowserInfoHookIsCalled() {
+		$classRef = uniqid('tx_browserInfoHook');
+		$browserInfoHookMock = $this->getMock($classRef, array('browserInfo'));
+		$browserInfoHookMock->expects($this->atLeastOnce())->method('browserInfo');
+
+		$GLOBALS['T3_VAR']['getUserObj'][$classRef] = $browserInfoHookMock;
+		$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['matchConditionClass'][$classRef] = $classRef;
+
+		$this->matchCondition->__construct();
+		$this->matchCondition->match('[browser = msie] && [version = 7] && [system = winNT]');
+	}
+
+	/**
+	 * Tests whether the whichDevice hook is called.
+	 *
+	 * @return	void
+	 * @test
+	 */
+	public function deprecatedWhichDeviceHookIsCalled() {
+		$classRef = uniqid('tx_whichDeviceHook');
+		$whichDeviceHookMock = $this->getMock($classRef, array('whichDevice'));
+		$whichDeviceHookMock->expects($this->atLeastOnce())->method('whichDevice');
+
+		$GLOBALS['T3_VAR']['getUserObj'][$classRef] = $whichDeviceHookMock;
+		$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['matchConditionClass'][$classRef] = $classRef;
+
+		$this->matchCondition->__construct();
+		$this->matchCondition->match('[device = robot]');
+	}
+
+	/**
+	 * Tests whether the language comparison matches.
+	 * @test
+	 */
+	public function languageConditionMatchesSingleLanguageExpression() {
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
+		$this->assertTrue($this->matchCondition->match('[language = *de*]'));
+		$this->assertTrue($this->matchCondition->match('[language = *de-de*]'));
+	}
+
+	/**
+	 * Tests whether the language comparison matches.
+	 * @test
+	 */
+	public function languageConditionMatchesMultipleLanguagesExpression() {
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
+		$this->assertTrue($this->matchCondition->match('[language = *en*,*de*]'));
+		$this->assertTrue($this->matchCondition->match('[language = *en-us*,*de-de*]'));
+	}
+
+	/**
+	 * Tests whether the language comparison matches.
+	 * @test
+	 */
+	public function languageConditionMatchesCompleteLanguagesExpression() {
+		$this->markTestSkipped('This comparison seems to be incomplete in t3lib_matchCondition.');
+
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
+		$this->assertTrue($this->matchCondition->match('[language = de-de,de;q=0.8]'));
+	}
+
+	/**
+	 * Tests whether usergroup comparison matches.
+	 * @test
+	 */
+	public function usergroupConditionMatchesSingleGroupId() {
+		$GLOBALS['TSFE']->gr_list = '13,14,15';
+		$this->assertTrue($this->matchCondition->match('[usergroup = 13]'));
+	}
+
+	/**
+	 * Tests whether usergroup comparison matches.
+	 * @test
+	 */
+	public function usergroupConditionMatchesMultipleUserGroupId() {
+		$GLOBALS['TSFE']->gr_list = '13,14,15';
+		$this->assertTrue($this->matchCondition->match('[usergroup = 999,15,14,13]'));
+	}
+
+	/**
+	 * Tests whether usergroup comparison matches.
+	 * @test
+	 */
+	public function usergroupConditionDoesNotMatchDefaulUserGroupIds() {
+		$GLOBALS['TSFE']->gr_list = '0,-1';
+		$this->assertFalse($this->matchCondition->match('[usergroup = 0,-1]'));
+	}
+
+	/**
+	 * Tests whether user comparison matches.
+	 * @test
+	 */
+	public function loginUserConditionMatchesAnyLoggedInUser() {
+		$GLOBALS['TSFE']->loginUser = TRUE;
+		$GLOBALS['TSFE']->fe_user->user['uid'] = 13;
+		$this->assertTrue($this->matchCondition->match('[loginUser = *]'));
+	}
+
+	/**
+	 * Tests whether user comparison matches.
+	 * @test
+	 */
+	public function loginUserConditionMatchesSingleLoggedInUser() {
+		$GLOBALS['TSFE']->loginUser = TRUE;
+		$GLOBALS['TSFE']->fe_user->user['uid'] = 13;
+		$this->assertTrue($this->matchCondition->match('[loginUser = 13]'));
+	}
+
+	/**
+	 * Tests whether user comparison matches.
+	 * @test
+	 */
+	public function loginUserConditionMatchesMultipleLoggedInUsers() {
+		$GLOBALS['TSFE']->loginUser = TRUE;
+		$GLOBALS['TSFE']->fe_user->user['uid'] = 13;
+		$this->assertTrue($this->matchCondition->match('[loginUser = 999,13]'));
+	}
+
+	/**
+	 * Tests whether user comparison matches.
+	 * @test
+	 */
+	public function loginUserConditionDoesNotMatchIfNotUserIsLoggedId() {
+		$GLOBALS['TSFE']->loginUser = FALSE;
+		$GLOBALS['TSFE']->fe_user->user['uid'] = 13;
+		$this->assertFalse($this->matchCondition->match('[loginUser = *]'));
+		$this->assertFalse($this->matchCondition->match('[loginUser = 13]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 = 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 = 10.1]'));
+
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 == 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 == 10.1]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnNotEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 != 20]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 != 10.2]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnLowerThanExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 < 20]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 < 10.2]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnLowerThanOrEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 <= 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 <= 20]'));
+
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 <= 10.1]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 <= 10.2]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnGreaterThanExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:20 > 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.2 > 10.1]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnGreaterThanOrEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 >= 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:20 >= 10]'));
+
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 >= 10.1]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.2 >= 10.1]'));
+	}
+
+	/**
+	 * Tests whether string comparison matches.
+	 * @test
+	 */
+	public function globalStringConditionMatchesOnEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3.Test.Condition]'));
+		$this->assertFalse($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3]'));
+	}
+
+	/**
+	 * Tests whether string comparison matches.
+	 * @test
+	 */
+	public function globalStringConditionMatchesWildcardExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3?Test?Condition]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3.T*t.Condition]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3?T*t?Condition]'));
+	}
+
+	/**
+	 * Tests whether string comparison matches.
+	 * @test
+	 */
+	public function globalStringConditionMatchesRegularExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = /^[A-Za-z3.]+$/]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = /^TYPO3\..+Condition$/]'));
+		$this->assertFalse($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = /^FALSE/]'));
+	}
+
+	/**
+	 * Tests whether string comparison matches.
+	 * @test
+	 */
+	public function globalStringConditionMatchesEmptyRegularExpression() {
+		$testKey = uniqid('test');
+		$_SERVER[$testKey] = '';
+		$this->assertTrue($this->matchCondition->match('[globalString = _SERVER|' . $testKey . ' = /^$/]'));
+	}
+
+	/**
+	 * Tests whether treeLevel comparison matches.
+	 * @test
+	 */
+	public function treeLevelConditionMatchesSingleValue() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$this->assertTrue($this->matchCondition->match('[treeLevel = 2]'));
+	}
+
+	/**
+	 * Tests whether treeLevel comparison matches.
+	 * @test
+	 */
+	public function treeLevelConditionMatchesMultipleValues() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$this->assertTrue($this->matchCondition->match('[treeLevel = 999,998,2]'));
+	}
+
+	/**
+	 * Tests whether treeLevel comparison matches.
+	 * @test
+	 */
+	public function treeLevelConditionDoesNotMatchFaultyValue() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$this->assertFalse($this->matchCondition->match('[treeLevel = 999]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionMatchesSinglePageIdInRootline() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$GLOBALS['TSFE']->id = 121;
+		$this->assertTrue($this->matchCondition->match('[PIDupinRootline = 111]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionMatchesMultiplePageIdsInRootline() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$GLOBALS['TSFE']->id = 121;
+		$this->assertTrue($this->matchCondition->match('[PIDupinRootline = 999,111,101]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionDoesNotMatchPageIdNotInRootline() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$GLOBALS['TSFE']->id = 121;
+		$this->assertFalse($this->matchCondition->match('[PIDupinRootline = 999]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionDoesNotMatchLastPageIdInRootline() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$GLOBALS['TSFE']->id = 121;
+		$this->assertFalse($this->matchCondition->match('[PIDupinRootline = 121]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in all rootline entries.
+	 * @test
+	 */
+	public function PIDinRootlineConditionMatchesSinglePageIdInRootline() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$GLOBALS['TSFE']->id = 121;
+		$this->assertTrue($this->matchCondition->match('[PIDinRootline = 111]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in all rootline entries.
+	 * @test
+	 */
+	public function PIDinRootlineConditionMatchesMultiplePageIdsInRootline() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$GLOBALS['TSFE']->id = 121;
+		$this->assertTrue($this->matchCondition->match('[PIDinRootline = 999,111,101]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in all rootline entries.
+	 * @test
+	 */
+	public function PIDinRootlineConditionMatchesLastPageIdInRootline() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$GLOBALS['TSFE']->id = 121;
+		$this->assertTrue($this->matchCondition->match('[PIDinRootline = 121]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in all rootline entries.
+	 * @test
+	 */
+	public function PIDinRootlineConditionDoesNotMatchPageIdNotInRootline() {
+		$GLOBALS['TSFE']->tmpl->rootLine = $this->rootline;
+		$GLOBALS['TSFE']->id = 121;
+		$this->assertFalse($this->matchCondition->match('[PIDinRootline = 999]'));
+	}
+
+	/**
+	 * Tests whether the compatibility version can be evaluated.
+	 * (e.g. 4.9 is compatible to 4.0 but not to 5.0)
+	 * @test
+	 */
+	public function compatVersionConditionMatchesOlderRelease() {
+		$GLOBALS['TYPO3_CONF_VARS']['SYS']['compat_version'] = '4.9';
+		$this->assertTrue($this->matchCondition->match('[compatVersion = 4.0]'));
+	}
+
+	/**
+	 * Tests whether the compatibility version can be evaluated.
+	 * (e.g. 4.9 is compatible to 4.0 but not to 5.0)
+	 * @test
+	 */
+	public function compatVersionConditionMatchesSameRelease() {
+		$GLOBALS['TYPO3_CONF_VARS']['SYS']['compat_version'] = '4.9';
+		$this->assertTrue($this->matchCondition->match('[compatVersion = 4.9]'));
+	}
+
+	/**
+	 * Tests whether the compatibility version can be evaluated.
+	 * (e.g. 4.9 is compatible to 4.0 but not to 5.0)
+	 * @test
+	 */
+	public function compatVersionConditionDoesNotMatchNewerRelease() {
+		$GLOBALS['TYPO3_CONF_VARS']['SYS']['compat_version'] = '4.9';
+		$this->assertFalse($this->matchCondition->match('[compatVersion = 5.0]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with the namespace 'GP'.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithNamespaceGP() {
+		$_GET = array('testGet' => 'getTest');
+		$_POST = array('testPost' => 'postTest');
+
+		$this->assertTrue($this->matchCondition->match('[globalString = GP:testGet = getTest]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = GP:testPost = postTest]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with the namespace 'TSFE'.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithNamespaceTSFE() {
+		$GLOBALS['TSFE']->id = 1234567;
+		$GLOBALS['TSFE']->testSimpleObject = new stdClass();
+		$GLOBALS['TSFE']->testSimpleObject->testSimpleVariable = 'testValue';
+
+		$this->assertTrue($this->matchCondition->match('[globalString = TSFE:id = 1234567]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = TSFE:testSimpleObject|testSimpleVariable = testValue]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with the namespace 'ENV'.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithNamespaceENV() {
+		$testKey = uniqid('test');
+		putenv($testKey .'=testValue');
+
+		$this->assertTrue($this->matchCondition->match('[globalString = ENV:' . $testKey . ' = testValue]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with the namespace 'IENV'.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithNamespaceIENV() {
+		$_SERVER['HTTP_HOST'] = t3lib_div::getIndpEnv('TYPO3_HOST_ONLY') . ':1234567';
+		$this->assertTrue($this->matchCondition->match('[globalString = IENV:TYPO3_PORT = 1234567]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with any global namespace.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithAnyGlobalNamespace() {
+		$GLOBALS[$this->testGlobalNamespace] = array(
+			'first' => 'testFirst',
+			'second' => array('third' => 'testThird'),
+		);
+
+		$this->assertTrue($this->matchCondition->match(
+			'[globalString = ' . $this->testGlobalNamespace . '|first = testFirst]'
+		));
+		$this->assertTrue($this->matchCondition->match(
+			'[globalString = ' . $this->testGlobalNamespace . '|second|third = testThird]'
+		));
+	}
+}
+?>
\ No newline at end of file
Index: tests/t3lib/matchcondition/t3lib_matchcondition_backend_testcase.php
===================================================================
--- tests/t3lib/matchcondition/t3lib_matchcondition_backend_testcase.php	(Revision 0)
+++ tests/t3lib/matchcondition/t3lib_matchcondition_backend_testcase.php	(Revision 0)
@@ -0,0 +1,792 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Oliver Hader <oliver@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+
+/**
+ * Testcase for class t3lib_matchCondition_frontend.
+ *
+ * @author	Oliver Hader <oliver@typo3.org>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_matchCondition_backend_testcase extends tx_phpunit_testcase {
+	/**
+	 * @var	array
+	 */
+	private $backupGlobalVariables;
+
+	/**
+	 * @var	array
+	 */
+	private $rootline;
+
+	/**
+	 * @var	t3lib_matchCondition_backend
+	 */
+	private $matchCondition;
+
+	/**
+	 * @var	string
+	 */
+	private $testTableName;
+
+	public function setUp() {
+		$this->backupGlobalVariables = array(
+			'_ENV' => $_ENV,
+			'_GET' => $_GET,
+			'_POST' => $_POST,
+			'_SERVER' => $_SERVER,
+			'TCA' => $GLOBALS['TCA'],
+			'TYPO3_DB' => $GLOBALS['TYPO3_DB'],
+			'TYPO3_CONF_VARS' => $GLOBALS['TYPO3_CONF_VARS'],
+			'T3_VAR' => $GLOBALS['T3_VAR'],
+			'BE_USER' => $GLOBALS['BE_USER'],
+			'SOBE' => $GLOBALS['SOBE'],
+		);
+
+		$this->testTableName = 't3lib_matchCondition_backend_testTable';
+		$this->testGlobalNamespace = uniqid('TEST');
+
+		$GLOBALS['TCA'][$this->testTableName] = array('ctrl' => array());
+		$GLOBALS[$this->testGlobalNamespace] = array();
+
+		$this->setUpBackend();
+
+		$this->matchCondition = t3lib_div::makeInstance('t3lib_matchCondition_backend');
+	}
+
+	public function tearDown() {
+		foreach ($this->backupGlobalVariables as $key => $data) {
+			$GLOBALS[$key] = $data;
+		}
+
+		unset($this->matchCondition);
+		unset($this->backupGlobalVariables);
+		unset($GLOBALS[$this->testGlobalNamespace]);
+	}
+
+	private function setUpBackend() {
+		$this->rootline = array(
+			2 => array('uid' => 121, 'pid' => 111),
+			1 => array('uid' => 111, 'pid' => 101,),
+			0 => array('uid' => 101, 'pid' => 0,),
+		);
+
+		$GLOBALS['BE_USER'] = $this->getMock('beUserAuth', array(), array(), '', FALSE);
+	}
+
+	private function setUpDatabaseMockForDeterminePageId() {
+		$GLOBALS['TYPO3_DB'] = $this->getMock('t3lib_DB', array('exec_SELECTquery', 'sql_fetch_assoc', 'sql_free_result'));
+		$GLOBALS['TYPO3_DB']->expects($this->any())->method('exec_SELECTquery')->will(
+			$this->returnCallback(array($this, 'determinePageIdByRecordDatabaseExecuteCallback'))
+		);
+		$GLOBALS['TYPO3_DB']->expects($this->any())->method('sql_fetch_assoc')->will(
+			$this->returnCallback(array($this, 'determinePageIdByRecordDatabaseFetchCallback'))
+		);
+	}
+
+	/**
+	 * Tests whether a faulty expression fails.
+	 * @test
+	 */
+	public function simulateDisabledMatchAllConditionsFailsOnFaultyExpression() {
+		$this->matchCondition->matchAll = false;
+		$this->assertFalse($this->matchCondition->match('[nullCondition = This expression would return false in general]'));
+	}
+
+	/**
+	 * Tests whether simulating positive matches for all conditions succeeds.
+	 * @test
+	 */
+	public function simulateEnabledMatchAllConditionsSucceeds() {
+		$this->matchCondition->setSimulateMatchResult(true);
+		$this->assertTrue($this->matchCondition->match('[nullCondition = This expression would return false in general]'));
+	}
+
+	/**
+	 * Tests whether simulating positive matches for specific conditions succeeds.
+	 * @test
+	 */
+	public function simulateEnabledMatchSpecificConditionsSucceeds() {
+		$testCondition = '[' . uniqid('test') . ' = Any condition to simulate a positive match]';
+		$this->matchCondition->setSimulateMatchConditions(array($testCondition));
+		$this->assertTrue($this->matchCondition->match($testCondition));
+	}
+
+	/**
+	 * Tests whether a condition matches Internet Explorer 7 on Windows.
+	 *
+	 * @return	void
+	 * @test
+	 */
+	public function conditionMatchesInternetExplorer7Windows() {
+		$_SERVER['HTTP_USER_AGENT'] = 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)';
+		$result = $this->matchCondition->match('[browser = msie] && [version = 7] && [system = winNT]');
+		$this->assertTrue($result);
+	}
+
+	/**
+	 * Tests whether a condition does not match Internet Explorer 7 on Windows.
+	 *
+	 * @return	void
+	 * @test
+	 */
+	public function conditionDoesNotMatchInternetExplorer7Windows() {
+		$_SERVER['HTTP_USER_AGENT'] = 'Opera/9.25 (Windows NT 6.0; U; en)';
+		$result = $this->matchCondition->match('[browser = msie] && [version = 7] && [system = winNT]');
+		$this->assertFalse($result);
+	}
+
+	/**
+	 * Tests whether a device type condition matches a crawler.
+	 * @test
+	 */
+	public function deviceConditionMatchesRobot() {
+		$_SERVER['HTTP_USER_AGENT'] = 'Googlebot/2.1 (+http://www.google.com/bot.html)';
+		$result = $this->matchCondition->match('[device = robot]');
+		$this->assertTrue($result);
+	}
+
+	/**
+	 * Tests whether a device type condition does not match a crawler.
+	 * @test
+	 */
+	public function deviceConditionDoesNotMatchRobot() {
+		$_SERVER['HTTP_USER_AGENT'] = md5('Some strange user agent');
+		$result = $this->matchCondition->match('[device = robot]');
+		$this->assertFalse($result);
+	}
+
+	/**
+	 * Tests whether the language comparison matches.
+	 * @test
+	 */
+	public function languageConditionMatchesSingleLanguageExpression() {
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
+		$this->assertTrue($this->matchCondition->match('[language = *de*]'));
+		$this->assertTrue($this->matchCondition->match('[language = *de-de*]'));
+	}
+
+	/**
+	 * Tests whether the language comparison matches.
+	 * @test
+	 */
+	public function languageConditionMatchesMultipleLanguagesExpression() {
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
+		$this->assertTrue($this->matchCondition->match('[language = *en*,*de*]'));
+		$this->assertTrue($this->matchCondition->match('[language = *en-us*,*de-de*]'));
+	}
+
+	/**
+	 * Tests whether the language comparison matches.
+	 * @test
+	 */
+	public function languageConditionMatchesCompleteLanguagesExpression() {
+		$this->markTestSkipped('This comparison seems to be incomplete in t3lib_matchCondition.');
+
+		$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'de-de,de;q=0.8,en-us;q=0.5,en;q=0.3';
+		$this->assertTrue($this->matchCondition->match('[language = de-de,de;q=0.8]'));
+	}
+
+	/**
+	 * Tests whether usergroup comparison matches.
+	 * @test
+	 */
+	public function usergroupConditionMatchesSingleGroupId() {
+		$GLOBALS['BE_USER']->groupList = '13,14,15';
+		$this->assertTrue($this->matchCondition->match('[usergroup = 13]'));
+	}
+
+	/**
+	 * Tests whether usergroup comparison matches.
+	 * @test
+	 */
+	public function usergroupConditionMatchesMultipleUserGroupId() {
+		$GLOBALS['BE_USER']->groupList = '13,14,15';
+		$this->assertTrue($this->matchCondition->match('[usergroup = 999,15,14,13]'));
+	}
+
+	/**
+	 * Tests whether user comparison matches.
+	 * @test
+	 */
+	public function loginUserConditionMatchesAnyLoggedInUser() {
+		$GLOBALS['BE_USER']->user['uid'] = 13;
+		$this->assertTrue($this->matchCondition->match('[loginUser = *]'));
+	}
+
+	/**
+	 * Tests whether user comparison matches.
+	 * @test
+	 */
+	public function loginUserConditionMatchesSingleLoggedInUser() {
+		$GLOBALS['BE_USER']->user['uid'] = 13;
+		$this->assertTrue($this->matchCondition->match('[loginUser = 13]'));
+	}
+
+	/**
+	 * Tests whether user comparison matches.
+	 * @test
+	 */
+	public function loginUserConditionDoesNotMatchSingleLoggedInUser() {
+		$GLOBALS['BE_USER']->user['uid'] = 13;
+		$this->assertFalse($this->matchCondition->match('[loginUser = 999]'));
+	}
+
+	/**
+	 * Tests whether user comparison matches.
+	 * @test
+	 */
+	public function loginUserConditionMatchesMultipleLoggedInUsers() {
+		$GLOBALS['BE_USER']->user['uid'] = 13;
+		$this->assertTrue($this->matchCondition->match('[loginUser = 999,13]'));
+	}
+
+	/**
+	 * Tests whether checkinf for an admin user matches
+	 * @test
+	 */
+	public function adminUserConditionMatchesAdminUser() {
+		$GLOBALS['BE_USER']->user['uid'] = 13;
+		$GLOBALS['BE_USER']->user['admin'] = 1;
+		$this->assertTrue($this->matchCondition->match('[adminUser = 1]'));
+	}
+
+	/**
+	 * Tests whether checkinf for an admin user matches
+	 * @test
+	 */
+	public function adminUserConditionMatchesRegularUser() {
+		$GLOBALS['BE_USER']->user['uid'] = 14;
+		$GLOBALS['BE_USER']->user['admin'] = 0;
+		$this->assertTrue($this->matchCondition->match('[adminUser = 0]'));
+	}
+
+	/**
+	 * Tests whether checkinf for an admin user matches
+	 * @test
+	 */
+	public function adminUserConditionDoesNotMatchRegularUser() {
+		$GLOBALS['BE_USER']->user['uid'] = 14;
+		$GLOBALS['BE_USER']->user['admin'] = 0;
+		$this->assertFalse($this->matchCondition->match('[adminUser = 1]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 = 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 = 10.1]'));
+
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 == 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 == 10.1]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnNotEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 != 20]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 != 10.2]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnLowerThanExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 < 20]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 < 10.2]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnLowerThanOrEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 <= 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 <= 20]'));
+
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 <= 10.1]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 <= 10.2]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnGreaterThanExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:20 > 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.2 > 10.1]'));
+	}
+
+	/**
+	 * Tests whether numerical comparison matches.
+	 * @test
+	 */
+	public function globalVarConditionMatchesOnGreaterThanOrEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10 >= 10]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:20 >= 10]'));
+
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.1 >= 10.1]'));
+		$this->assertTrue($this->matchCondition->match('[globalVar = LIT:10.2 >= 10.1]'));
+	}
+
+	/**
+	 * Tests whether string comparison matches.
+	 * @test
+	 */
+	public function globalStringConditionMatchesOnEqualExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3.Test.Condition]'));
+		$this->assertFalse($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3]'));
+	}
+
+	/**
+	 * Tests whether string comparison matches.
+	 * @test
+	 */
+	public function globalStringConditionMatchesWildcardExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3?Test?Condition]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3.T*t.Condition]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = TYPO3?T*t?Condition]'));
+	}
+
+	/**
+	 * Tests whether string comparison matches.
+	 * @test
+	 */
+	public function globalStringConditionMatchesRegularExpression() {
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = /^[A-Za-z3.]+$/]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = /^TYPO3\..+Condition$/]'));
+		$this->assertFalse($this->matchCondition->match('[globalString = LIT:TYPO3.Test.Condition = /^FALSE/]'));
+	}
+
+	/**
+	 * Tests whether string comparison matches.
+	 * @test
+	 */
+	public function globalStringConditionMatchesEmptyRegularExpression() {
+		$testKey = uniqid('test');
+		$_SERVER[$testKey] = '';
+		$this->assertTrue($this->matchCondition->match('[globalString = _SERVER|' . $testKey . ' = /^$/]'));
+	}
+
+	/**
+	 * Tests whether treeLevel comparison matches.
+	 * @test
+	 */
+	public function treeLevelConditionMatchesSingleValue() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->assertTrue($this->matchCondition->match('[treeLevel = 2]'));
+	}
+
+	/**
+	 * Tests whether treeLevel comparison matches.
+	 * @test
+	 */
+	public function treeLevelConditionMatchesMultipleValues() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->assertTrue($this->matchCondition->match('[treeLevel = 999,998,2]'));
+	}
+
+	/**
+	 * Tests whether treeLevel comparison matches.
+	 * @test
+	 */
+	public function treeLevelConditionDoesNotMatchFaultyValue() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->assertFalse($this->matchCondition->match('[treeLevel = 999]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionMatchesSinglePageIdInRootline() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertTrue($this->matchCondition->match('[PIDupinRootline = 111]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionMatchesMultiplePageIdsInRootline() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertTrue($this->matchCondition->match('[PIDupinRootline = 999,111,101]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionDoesNotMatchPageIdNotInRootline() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertFalse($this->matchCondition->match('[PIDupinRootline = 999]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionDoesNotMatchLastPageIdInRootline() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertFalse($this->matchCondition->match('[PIDupinRootline = 121]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionMatchesCurrentPageIdWhileEditingNewPage() {
+		$GLOBALS['SOBE'] = $this->getMock('SC_alt_doc', array());
+		$GLOBALS['SOBE']->elementsData = array(
+			array(
+				'table' => 'pages',
+				'uid' => 'NEW4adc6021e37e7',
+				'pid' => 121,
+				'cmd' => 'new',
+				'deleteAccess' => 0,
+			),
+		);
+		$GLOBALS['SOBE']->data = array();
+
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertTrue($this->matchCondition->match('[PIDupinRootline = 121]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in the previous rootline entries.
+	 * @test
+	 */
+	public function PIDupinRootlineConditionMatchesCurrentPageIdWhileSavingNewPage() {
+		$GLOBALS['SOBE'] = $this->getMock('SC_alt_doc', array());
+		$GLOBALS['SOBE']->elementsData = array(
+			array(
+				'table' => 'pages',
+				/// 999 is the uid of the page that was just created
+				'uid' => 999,
+				'pid' => 121,
+				'cmd' => 'edit',
+				'deleteAccess' => 1,
+			),
+		);
+		$GLOBALS['SOBE']->data = array(
+			'pages' => array(
+				'NEW4adc6021e37e7' => array(
+					'pid' => 121,
+				),
+			),
+		);
+
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertTrue($this->matchCondition->match('[PIDupinRootline = 121]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in all rootline entries.
+	 * @test
+	 */
+	public function PIDinRootlineConditionMatchesSinglePageIdInRootline() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertTrue($this->matchCondition->match('[PIDinRootline = 111]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in all rootline entries.
+	 * @test
+	 */
+	public function PIDinRootlineConditionMatchesMultiplePageIdsInRootline() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertTrue($this->matchCondition->match('[PIDinRootline = 999,111,101]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in all rootline entries.
+	 * @test
+	 */
+	public function PIDinRootlineConditionMatchesLastPageIdInRootline() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertTrue($this->matchCondition->match('[PIDinRootline = 121]'));
+	}
+
+	/**
+	 * Tests whether a page Id is found in all rootline entries.
+	 * @test
+	 */
+	public function PIDinRootlineConditionDoesNotMatchPageIdNotInRootline() {
+		$this->matchCondition->setRootline($this->rootline);
+		$this->matchCondition->setPageId(121);
+		$this->assertFalse($this->matchCondition->match('[PIDinRootline = 999]'));
+	}
+
+	/**
+	 * Tests whether the compatibility version can be evaluated.
+	 * (e.g. 4.9 is compatible to 4.0 but not to 5.0)
+	 * @test
+	 */
+	public function compatVersionConditionMatchesOlderRelease() {
+		$GLOBALS['TYPO3_CONF_VARS']['SYS']['compat_version'] = '4.9';
+		$this->assertTrue($this->matchCondition->match('[compatVersion = 4.0]'));
+	}
+
+	/**
+	 * Tests whether the compatibility version can be evaluated.
+	 * (e.g. 4.9 is compatible to 4.0 but not to 5.0)
+	 * @test
+	 */
+	public function compatVersionConditionMatchesSameRelease() {
+		$GLOBALS['TYPO3_CONF_VARS']['SYS']['compat_version'] = '4.9';
+		$this->assertTrue($this->matchCondition->match('[compatVersion = 4.9]'));
+	}
+
+	/**
+	 * Tests whether the compatibility version can be evaluated.
+	 * (e.g. 4.9 is compatible to 4.0 but not to 5.0)
+	 * @test
+	 */
+	public function compatVersionConditionDoesNotMatchNewerRelease() {
+		$GLOBALS['TYPO3_CONF_VARS']['SYS']['compat_version'] = '4.9';
+		$this->assertFalse($this->matchCondition->match('[compatVersion = 5.0]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with the namespace 'GP'.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithNamespaceGP() {
+		$_GET = array('testGet' => 'getTest');
+		$_POST = array('testPost' => 'postTest');
+
+		$this->assertTrue($this->matchCondition->match('[globalString = GP:testGet = getTest]'));
+		$this->assertTrue($this->matchCondition->match('[globalString = GP:testPost = postTest]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables does not work with the namespace 'TSFE',
+	 * since we are in the backend context here.
+	 * @test
+	 */
+	public function genericGetVariablesFailsWithNamespaceTSFE() {
+		$GLOBALS['TSFE'] = new stdClass();
+		$GLOBALS['TSFE']->id = 1234567;
+
+		$this->assertFalse($this->matchCondition->match('[globalString = TSFE:id = 1234567]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with the namespace 'ENV'.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithNamespaceENV() {
+		$testKey = uniqid('test');
+		putenv($testKey .'=testValue');
+
+		$this->assertTrue($this->matchCondition->match('[globalString = ENV:' . $testKey . ' = testValue]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with the namespace 'IENV'.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithNamespaceIENV() {
+		$_SERVER['HTTP_HOST'] = t3lib_div::getIndpEnv('TYPO3_HOST_ONLY') . ':1234567';
+		$this->assertTrue($this->matchCondition->match('[globalString = IENV:TYPO3_PORT = 1234567]'));
+	}
+
+	/**
+	 * Tests whether the generic fetching of variables works with any global namespace.
+	 * @test
+	 */
+	public function genericGetVariablesSucceedsWithAnyGlobalNamespace() {
+		$GLOBALS[$this->testGlobalNamespace] = array(
+			'first' => 'testFirst',
+			'second' => array('third' => 'testThird'),
+		);
+
+		$this->assertTrue($this->matchCondition->match(
+			'[globalString = ' . $this->testGlobalNamespace . '|first = testFirst]'
+		));
+		$this->assertTrue($this->matchCondition->match(
+			'[globalString = ' . $this->testGlobalNamespace . '|second|third = testThird]'
+		));
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileCallingModuleWithPageTree() {
+		$_GET['id'] = 999;
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileEditingAPageRecord() {
+		$_GET['edit']['pages'][999] = 'edit';
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileEditingARegularRecord() {
+		$this->setUpDatabaseMockForDeterminePageId();
+
+		$_GET['edit'][$this->testTableName][13] = 'edit';
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileCreatingARecord() {
+		$_GET['edit']['pages'][999] = 'new';
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileCreatingARecordAfterAnExistingRecord() {
+		$this->setUpDatabaseMockForDeterminePageId();
+
+		$_GET['edit'][$this->testTableName][-13] = 'new';
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileDeletingAPageRecord() {
+		$_GET['cmd']['pages'][999]['delete'] = 1;
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileCopyingARecordToAnotherPage() {
+		$_GET['cmd']['pages'][121]['copy'] = 999;
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileCopyingARecordAfterAnExistingRecord() {
+		$this->setUpDatabaseMockForDeterminePageId();
+
+		$_GET['cmd'][$this->testTableName][121]['copy'] = -13;
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Tests whether determining a pageId works.
+	 * @test
+	 */
+	public function pageIdCanBeDeterminedWhileMovingARecordToAnotherPage() {
+		$_GET['cmd']['pages'][121]['move'] = 999;
+
+		$this->matchCondition->match('[globalVar = LIT:10 = 10]');
+		$this->assertEquals(999, $this->matchCondition->getPageId());
+	}
+
+	/**
+	 * Callback method for pageIdCanBeDetermined test cases.
+	 * Simulates TYPO3_DB->exec_SELECTquery().
+	 *
+	 * @param	string		$fields
+	 * @param	string		$table
+	 * @param	string		$where
+	 * @return	mixed
+	 */
+	public function determinePageIdByRecordDatabaseExecuteCallback($fields, $table, $where) {
+		if ($table === $this->testTableName) {
+			return array(
+				'scope' => $this->testTableName,
+				'processed' => false,
+				'data' => array(
+					'pid' => 999,
+				),
+			);
+		} else {
+			return FALSE;
+		}
+	}
+
+	/**
+	 * Callback method for pageIdCanBeDetermined test cases.
+	 * Simulates TYPO3_DB->sql_fetch_assoc().
+	 *
+	 * @param	mixed		$resource
+	 * @return	mixed
+	 */
+	public function determinePageIdByRecordDatabaseFetchCallback(&$resource) {
+		if (is_array($resource) && !$resource['processed'] && $resource['scope'] === $this->testTableName) {
+			$resource['processed'] = true;
+			return $resource['data'];
+		} else {
+			return FALSE;
+		}
+	}
+}
+?>
\ No newline at end of file
Index: t3lib/config_default.php
===================================================================
--- t3lib/config_default.php	(Revision 6171)
+++ t3lib/config_default.php	(Arbeitskopie)
@@ -243,6 +243,7 @@
 		'notificationPrefix' => '[TYPO3 Note]',	// String: Used to prefix the subject of mails sent in the taskcenter
 		'accessListRenderMode' => 'singlebox',	// Can be "singlebox", "checkbox" or blank. Refers to the "renderMode" for the selector boxes in be-groups configuration.
 		'explicitADmode' => 'explicitDeny',	// Sets the general allow/deny mode for selector box values. Value can be either "explicitAllow" or "explicitDeny", nothing else!
+		'TSconfigConditions' => 0,			// Boolean. When set it is possible to have TypoScript like conditions in BE Page/User/Group TS-Config
 		'niceFlexFormXMLtags' => TRUE,			// If set, the flexform XML will be stored with meaningful tags which can be validated with DTD schema. If you rely on custom reading of the XML from pre-4.0 versions you should set this to false if you don't like to change your reader code (internally it is insignificant since t3lib_div::xml2array() doesn't care for the tags if the index-attribute value is set)
 		'flexFormXMLincludeDiffBase' => TRUE,	// If set, an additional tag with index "vXX.vDEFbase" is created for translations in flexforms holding the value of the default language when translation was changed. Used to show diff of value. This setting will change whether the system thinks flexform XML looks clean. For example when FALSE XX.vDEFbase fields will be removed in cleaning while accepted if TRUE (of course)
 		'compactFlexFormXML' => 0,				// If set, the flexform XML will not contain indentation spaces making XML more compact
Index: t3lib/class.t3lib_tstemplate.php
===================================================================
--- t3lib/class.t3lib_tstemplate.php	(Revision 6171)
+++ t3lib/class.t3lib_tstemplate.php	(Arbeitskopie)
@@ -293,8 +293,10 @@
 	 */
 	function matching($cc)	{
 		if (is_array($cc['all']))	{
-			$matchObj = t3lib_div::makeInstance('t3lib_matchCondition');
-			$matchObj->altRootLine=$cc['rootLine'];
+			/* @var $matchObj t3lib_matchCondition_frontend */
+			$matchObj = t3lib_div::makeInstance('t3lib_matchCondition_frontend');
+			$matchObj->setRootline((array)$cc['rootLine']);
+			$matchObj->setPageId($GLOBALS['TSFE']->id);
 			foreach ($cc['all'] as $key => $pre) {
 				if ($matchObj->match($pre))	{
 					$sectionsMatch[$key]=$pre;
@@ -809,10 +811,14 @@
 		$constants->breakPointLN=intval($this->ext_constants_BRP);
 		$constants->setup = $this->const;
 		$constants->setup = $this->mergeConstantsFromPageTSconfig($constants->setup);
-		$matchObj = t3lib_div::makeInstance('t3lib_matchCondition');
-		$matchObj->matchAlternative = $this->matchAlternative;
-		$matchObj->matchAll = $this->matchAll;		// Matches ALL conditions in TypoScript
 
+		/* @var $matchObj t3lib_matchCondition_frontend */
+		$matchObj = t3lib_div::makeInstance('t3lib_matchCondition_frontend');
+		$matchObj->setSimulateMatchConditions($this->matchAlternative);
+		if ($this->matchAll) {
+			$matchObj->setSimulateMatchResult(true);
+		}
+
 			// Traverse constants text fields and parse them
 		foreach($this->constants as $str)	{
 			$constants->parse($str,$matchObj);
Index: t3lib/class.t3lib_tsparser_tsconfig.php
===================================================================
--- t3lib/class.t3lib_tsparser_tsconfig.php	(Revision 0)
+++ t3lib/class.t3lib_tsparser_tsconfig.php	(Revision 0)
@@ -0,0 +1,210 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 1999-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
+*  (c) 2007 Kraft Bernhard (kraftb@kraftb.at)
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * A TS-Config parsing class which performs condition evaluation
+ *
+ * $Id$
+ *
+ * @author	Kraft Bernhard <kraftb@kraftb.at>
+ */
+/**
+ * [CLASS/FUNCTION INDEX of SCRIPT]
+ */
+
+class t3lib_TSparser_TSconfig extends t3lib_TSparser {
+	/**
+	 * Parses the passed TS-Config using conditions and caching
+	 *
+	 * @param	integer	The uid of the page being handled
+	 * @param	array	The rootline of the page being handled
+	 * @param	string	The TSConfig being parsed
+	 * @param	string	The type of TSConfig (either "userTS" or "PAGES")
+	 * @return	array	Array containing the parsed TSConfig and a flag wheter the content was retrieved from cache
+	 * @access private
+	 * @see t3lib_TSparser
+	 */
+	public function parseTSconfig($TStext, $id, $rootLine, $type) {
+		$this->type = $type;
+		$this->id = $id;
+		$this->rootLine = $rootLine;
+		$hash = md5($type.':'.$TStext);
+		$cachedContent = $this->getHash($hash, 0);
+
+		if ($cachedContent) {
+			$storedData = unserialize($cachedContent);
+			$storedMD5 = substr($cachedContent, -strlen($hash));
+			$storedData['match'] = array();
+			$storedData = $this->matching($storedData);
+			$checkMD5 = md5(serialize($storedData));
+
+			if ($checkMD5 == $storedMD5) {
+				$res = array(
+					'TSconfig' => $storedData['TSconfig'],
+					'cached' => 1,
+				);
+			} else {
+				$shash = md5($checkMD5.$hash);
+				$cachedSpec = $this->getHash($shash, 0);
+				if ($cachedSpec) {
+					$storedData = unserialize($cachedSpec);
+					$res = array(
+						'TSconfig' => $storedData['TSconfig'],
+						'cached' => 1,
+					);
+				} else {
+					$storeData = $this->parseWithConditions($TStext);
+					$serData = serialize($storeData);
+					$this->storeHash($shash, $serData, $type.'_TSconfig');
+					$res = array(
+						'TSconfig' => $storeData['TSconfig'],
+						'cached' => 0,
+					);
+				}
+			}
+		} else {
+			$storeData = $this->parseWithConditions($TStext);
+			$serData = serialize($storeData);
+			$md5 = md5($serData);
+			$this->storeHash($hash, $serData.$md5, $type.'_TSconfig');
+			$res = array(
+				'TSconfig' => $storeData['TSconfig'],
+				'cached' => 0,
+			);
+		}
+		return $res;
+	}
+
+
+	/**
+	 * Retrieves the string content stored with hash key, $hash, in cache_hash
+	 * Wrapper to the functions by same name found in t3lib_page and t3lib_BEfunc
+	 * Usage: 1
+	 *
+	 * @param	string		Hash key, 32 bytes hex
+	 * @param	integer		$expTime represents the expire time in seconds. For instance a value of 3600 would allow cached content within the last hour, otherwise nothing is returned.
+	 * @return	string
+	 * @see t3lib_page::getHash()
+	 * @see t3lib_befunc::getHash()
+	 */
+	protected function getHash($hash, $expTime) {
+		if (TYPO3_MODE=='BE') {
+			return t3lib_BEfunc::getHash($hash, $expTime);
+		} elseif (TYPO3_MODE=='FE') {
+			if ($GLOBALS['TSFE']->sys_page) {
+					// After initialization of sys_page
+				return $GLOBALS['TSFE']->sys_page->getHash($hash, $expTime);
+			} else {
+					// When BE user is logged in while viewing frontend (FE-Editing) we have to use the t3lib_BEfunc
+					// method before TSFE->sys_page is initialized
+				return t3lib_BEfunc::getHash($hash, $expTime);
+			}
+		}
+	}
+
+
+	/**
+	 * Stores the string value $data in the 'cache_hash' table with the hash key, $hash, and visual/symbolic identification, $ident
+	 * Wrapper to the functions by same name found in t3lib_page and t3lib_BEfunc
+	 * Usage: 1
+	 *
+	 * @param	string		32 bit hash string (eg. a md5 hash of a serialized array identifying the data being stored)
+	 * @param	string		The data string. If you want to store an array, then just serialize it first.
+	 * @param	string		$ident is just a textual identification in order to inform about the content! May be 20 characters long.
+	 * @return	void
+	 * @see t3lib_page::storeHash()
+	 * @see t3lib_befunc::storeHash()
+	 */
+	protected function storeHash($hash, $data, $ident) {
+		if (TYPO3_MODE=='BE') {
+			t3lib_BEfunc::storeHash($hash, $data, $ident);
+		} elseif (TYPO3_MODE=='FE') {
+			if ($GLOBALS['TSFE']->sys_page) {
+					// After initialization of sys_page
+				$GLOBALS['TSFE']->sys_page->storeHash($hash, $data, $ident);
+			} else {
+					// When BE user is logged in while viewing frontend (FE-Editing) we have to use the t3lib_BEfunc
+					// method before TSFE->sys_page is initialized
+				t3lib_BEfunc::storeHash($hash, $data, $ident);
+			}
+		}
+	}
+
+
+	/**
+	 * Does the actual parsing using the parent objects "parse" method. Creates the match-Object
+	 *
+	 * @param	string	The TSConfig being parsed
+	 * @return	array	Array containing the parsed TSConfig, the encountered sectiosn, the matched sections
+	 * @access private
+	 */
+	protected function parseWithConditions($TSconfig) {
+		/* @var $matchObj t3lib_matchCondition_backend */
+		$matchObj = t3lib_div::makeInstance('t3lib_matchCondition_backend');
+		$matchObj->setRootline($this->rootline);
+		$matchObj->setPageId($this->id);
+
+		$this->parse($TSconfig, $matchObj);
+		$storeData = array(
+			'TSconfig' => $this->setup,
+			'sections' => $this->sections,
+			'match' => $this->sectionsMatch,
+		);
+		return $storeData;
+	}
+
+
+	/**
+	 * Is just going through an array of conditions to determine which are matching (for getting correct cache entry)
+	 *
+	 * @param	array	An array containing the sectiosn to match
+	 * @return	array	The input array with matching sections filled into the "match" key
+	 * @access private
+	 */
+	protected function matching($cc) {
+		if (is_array($cc['sections'])) {
+			/* @var $matchObj t3lib_matchCondition_backend */
+			$matchObj = t3lib_div::makeInstance('t3lib_matchCondition_backend');
+			$matchObj->setRootline($this->rootline);
+			$matchObj->setPageId($this->id);
+
+			foreach ($cc['sections'] as $key => $pre) {
+				if ($matchObj->match($pre)) {
+					$cc['match'][$key] = $pre;
+				}
+			}
+		}
+		return $cc;
+	}
+
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tsparser_tsconfig.php']) {
+	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_tsparser_tsconfig.php']);
+}
+?>
\ No newline at end of file
Index: t3lib/class.t3lib_befunc.php
===================================================================
--- t3lib/class.t3lib_befunc.php	(Revision 6171)
+++ t3lib/class.t3lib_befunc.php	(Arbeitskopie)
@@ -1332,18 +1332,26 @@
 			return $TSdataArray;
 		}
 
-			// Parsing the user TS (or getting from cache)
-		$userTS = implode(chr(10) . '[GLOBAL]' . chr(10), $TSdataArray);
-		$hash = md5('pageTS:'.$userTS);
-		$cachedContent = t3lib_BEfunc::getHash($hash);
-		$TSconfig = array();
-		if (isset($cachedContent)) {
-			$TSconfig = unserialize($cachedContent);
+			// Parsing the page TS-Config (or getting from cache)
+		$pageTS = implode(chr(10) . '[GLOBAL]' . chr(10), $TSdataArray);
+		if ($GLOBALS['TYPO3_CONF_VARS']['BE']['TSconfigConditions']) {
+			$parseObj = t3lib_div::makeInstance('t3lib_TSparser_TSconfig');
+			$res = $parseObj->parseTSconfig($pageTS, $id, $rootLine, 'PAGES');
+			if ($res) {
+				$TSconfig = $res['TSconfig'];
+			}
 		} else {
-			$parseObj = t3lib_div::makeInstance('t3lib_TSparser');
-			$parseObj->parse($userTS);
-			$TSconfig = $parseObj->setup;
-			t3lib_BEfunc::storeHash($hash, serialize($TSconfig), 'PAGES_TSconfig');
+			$hash = md5('pageTS:' . $pageTS);
+			$cachedContent = t3lib_BEfunc::getHash($hash);
+			$TSconfig = array();
+			if (isset($cachedContent)) {
+				$TSconfig = unserialize($cachedContent);
+			} else {
+				$parseObj = t3lib_div::makeInstance('t3lib_TSparser');
+				$parseObj->parse($pageTS);
+				$TSconfig = $parseObj->setup;
+				t3lib_BEfunc::storeHash($hash, serialize($TSconfig), 'PAGES_TSconfig');
+			}
 		}
 
 			// get User TSconfig overlay
Index: t3lib/core_autoload.php
===================================================================
--- t3lib/core_autoload.php	(Revision 6171)
+++ t3lib/core_autoload.php	(Arbeitskopie)
@@ -40,6 +40,9 @@
 	't3lib_loadmodules' => PATH_t3lib . 'class.t3lib_loadmodules.php',
 	't3lib_lock' => PATH_t3lib . 'class.t3lib_lock.php',
 	't3lib_matchcondition' => PATH_t3lib . 'class.t3lib_matchcondition.php',
+	't3lib_matchcondition_abstract' => PATH_t3lib . 'matchcondition/class.t3lib_matchcondition_abstract.php',
+	't3lib_matchcondition_backend' => PATH_t3lib . 'matchcondition/class.t3lib_matchcondition_backend.php',
+	't3lib_matchcondition_frontend' => PATH_t3lib . 'matchcondition/class.t3lib_matchcondition_frontend.php',
 	't3lib_modsettings' => PATH_t3lib . 'class.t3lib_modsettings.php',
 	't3lib_pageselect' => PATH_t3lib . 'class.t3lib_page.php',
 	't3lib_pagerenderer' => PATH_t3lib . 'class.t3lib_pagerenderer.php',
@@ -76,6 +79,7 @@
 	't3lib_tsfebeuserauth' => PATH_t3lib . 'class.t3lib_tsfebeuserauth.php',
 	't3lib_tsparser' => PATH_t3lib . 'class.t3lib_tsparser.php',
 	't3lib_tsparser_ext' => PATH_t3lib . 'class.t3lib_tsparser_ext.php',
+	't3lib_tsparser_tsconfig' => PATH_t3lib . 'class.t3lib_tsparser_tsconfig.php',
 	't3lib_tsstyleconfig' => PATH_t3lib . 'class.t3lib_tsstyleconfig.php',
 	't3lib_tstemplate' => PATH_t3lib . 'class.t3lib_tstemplate.php',
 	't3lib_userauth' => PATH_t3lib . 'class.t3lib_userauth.php',
Index: t3lib/matchcondition/class.t3lib_matchcondition_backend.php
===================================================================
--- t3lib/matchcondition/class.t3lib_matchcondition_backend.php	(Revision 0)
+++ t3lib/matchcondition/class.t3lib_matchcondition_backend.php	(Revision 0)
@@ -0,0 +1,315 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Oliver Hader <oliver@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Matching TypoScript conditions for backend disposal.
+ *
+ * Used with the TypoScript parser.
+ * Matches browserinfo, IPnumbers for use with templates
+ *
+ * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_matchCondition_backend extends t3lib_matchCondition_abstract {
+	/**
+	 * Constructor for this class
+	 *
+	 * @return	void
+	 */
+	public function __construct() {
+	}
+
+	/**
+	 * Evaluates a TypoScript condition given as input, eg. "[browser=net][...(other conditions)...]"
+	 *
+	 * @param	string		$string: The condition to match against its criterias.
+	 * @return	boolean		Whether the condition matched
+	 * @see t3lib_tsparser::parse()
+	 */
+	protected function evaluateCondition($string) {
+		list($key, $value) = t3lib_div::trimExplode('=', $string, false, 2);
+
+		$result = parent::evaluateConditionCommon($key, $value);
+
+		if (is_bool($result)) {
+			return $result;
+		} else {
+			switch ($key) {
+				case 'usergroup':
+					$groupList = $this->getGroupList();
+					$values = t3lib_div::trimExplode(',', $value, true);
+					foreach ($values as $test) {
+						if ($test == '*' || t3lib_div::inList($groupList, $test)) {
+							return true;
+						}
+					}
+				break;
+				case 'adminUser':
+					if ($this->isUserLoggedIn()) {
+						$result = !((bool)$value XOR $this->isAdminUser());
+						return $result;
+					}
+					break;
+				case 'treeLevel':
+					// @todo: Behaviour when new page is being created...
+					$values = t3lib_div::trimExplode(',', $value, true);
+					$treeLevel = count($this->rootline) - 1;
+					foreach ($values as $test) {
+						if ($test == $treeLevel) {
+							return true;
+						}
+					}
+				break;
+				case 'PIDupinRootline':
+				case 'PIDinRootline':
+					$values = t3lib_div::trimExplode(',', $value, true);
+					if (($key=='PIDinRootline') || (!in_array($this->pageId, $values)) || $this->isNewPageWithPageId($this->pageId)) {
+						foreach ($values as $test) {
+							foreach ($this->rootline as $rl_dat) {
+								if ($rl_dat['uid'] == $test) {
+									return true;
+								}
+							}
+						}
+					}
+				break;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns GP / ENV vars
+	 *
+	 * @param	string		Identifier
+	 * @return	mixed		The value of the variable pointed to.
+	 * @access private
+	 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=311&cHash=487cbd5cdf
+	 */
+	protected function getVariable($var) {
+		$vars = explode(':', $var, 2);
+
+		$val = parent::getVariableCommon($vars);
+
+		return $val;
+	}
+
+	/**
+	 * Get the usergroup list of the current user.
+	 *
+	 * @return	string		The usergroup list of the current user
+	 */
+	protected function getGroupList() {
+		$groupList = $GLOBALS['BE_USER']->groupList;
+		return $groupList;
+	}
+
+	/**
+	 * Tries to determine the ID of the page currently processed.
+	 * When User/Group TS-Config is parsed when no specific page is handled
+	 * (i.e. in the Extension Manager, etc.) this function will return "0", so that
+	 * the accordant conditions (e.g. PIDinRootline) will return "false"
+	 *
+	 * @return	integer		The determined page id or otherwise 0
+	 */
+	protected function determinePageId() {
+		$pageId = 0;
+		$editStatement = t3lib_div::_GP('edit');
+		$commandStatement = t3lib_div::_GP('cmd');
+
+			// Determine id from module that was called with an id:
+		if ($id = intval(t3lib_div::_GP('id'))) {
+			$pageId = $id;
+			// Determine id from an edit statement:
+		} elseif (is_array($editStatement)) {
+			list($table, $uidAndAction) = each($editStatement);
+			list($uid, $action) = each($uidAndAction);
+
+			if ($action === 'edit') {
+				$pageId = $this->getPageIdByRecord($table, $uid);
+			} elseif ($action === 'new') {
+				$pageId = $this->getPageIdByRecord($table, $uid, true);
+			}
+			// Determine id from a command statement:
+		} elseif (is_array($commandStatement)) {
+			list($table, $uidActionAndTarget) = each($commandStatement);
+			list($uid, $actionAndTarget) = each($uidActionAndTarget);
+			list($action, $target) = each($actionAndTarget);
+
+			if ($action === 'delete') {
+				$pageId = $this->getPageIdByRecord($table, $uid);
+			} elseif (($action === 'copy') || ($action === 'move')) {
+				$pageId = $this->getPageIdByRecord($table, $target, true);
+			}
+		}
+
+		return $pageId;
+	}
+
+	/**
+	 * Gets the page id by a record.
+	 *
+	 * @param	string		$table: Name of the table
+	 * @param	integer		$id: Id of the accordant record
+	 * @param	boolean		$ignoreTable: Whether to ignore the page, if true a positive
+	 *						id value is considered as page id without any further checks
+	 * @return	integer		Id of the page the record is persisted on
+	 */
+	protected function getPageIdByRecord($table, $id, $ignoreTable = false) {
+		$pageId = 0;
+		$id = (int)$id;
+
+		if ($table && $id) {
+			if (($ignoreTable || $table === 'pages') && $id >= 0) {
+				$pageId = $id;
+			} else {
+				$record = t3lib_BEfunc::getRecordWSOL($table, abs($id), '*', '', false);
+				$pageId = $record['pid'];
+			}
+		}
+
+		return $pageId;
+	}
+
+	/**
+	 * Determine if record of table 'pages' with the given $pid is currently created in TCEforms.
+	 * This information is required for conditions in BE for PIDupinRootline.
+	 *
+	 * @param	integer		$pid: The pid the check for as parent page
+	 * @return	boolean		true if the is currently a new page record being edited with $pid as uid of the parent page
+	 */
+	protected function isNewPageWithPageId($pageId) {
+		if (isset($GLOBALS['SOBE']) && $GLOBALS['SOBE'] instanceof SC_alt_doc) {
+			$pageId = intval($pageId);
+			$elementsData = $GLOBALS['SOBE']->elementsData;
+			$data = $GLOBALS['SOBE']->data;
+
+				// If saving a new page record:
+			if (is_array($data) && isset($data['pages']) && is_array($data['pages'])) {
+				foreach ($data['pages'] as $uid => $fields) {
+					if (strpos($uid, 'NEW') === 0 && $fields['pid'] == $pageId) {
+						return true;
+					}
+				}
+			}
+				// If editing a new page record (not saved yet):
+			if (is_array($elementsData)) {
+				foreach ($elementsData as $element) {
+					if ($element['cmd'] == 'new' && $element['table'] == 'pages') {
+						if ($element['pid'] < 0) {
+							$pageRecord = t3lib_BEfunc::getRecord('pages', abs($element['pid']), 'pid');
+							$element['pid'] = $pageRecord['pid'];
+						}
+						if ($element['pid'] == $pageId) {
+							return true;
+						}
+					}
+				}
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Determines the rootline for the current page.
+	 *
+	 * @return	array		The rootline for the current page.
+	 */
+	protected function determineRootline() {
+		$pageId = (isset($this->pageId) ? $this->pageId : $this->determinePageId());
+		$rootline = t3lib_BEfunc::BEgetRootLine($pageId, '', true);
+		return $rootline;
+	}
+
+	/**
+	 * Get prefix for user functions (normally 'user_').
+	 *
+	 * @return	string		The prefix for user functions (normally 'user_').
+	 */
+	protected function getUserFuncClassPrefix() {
+		$userFuncClassPrefix = 'user_';
+		return $userFuncClassPrefix;
+	}
+
+	/**
+	 * Get the id of the current user.
+	 *
+	 * @return	integer		The id of the current user
+	 */
+	protected function getUserId() {
+		$userId = $GLOBALS['BE_USER']->user['uid'];
+		return $userId;
+	}
+
+	/**
+	 * Determines if a user is logged in.
+	 *
+	 * @return	boolean		Determines if a user is logged in
+	 */
+	protected function isUserLoggedIn() {
+		$userLoggedIn = false;
+		if ($GLOBALS['BE_USER']->user['uid']) {
+			$userLoggedIn = true;
+		}
+		return $userLoggedIn;
+	}
+
+	/**
+	 * Determines whether the current user is admin.
+	 *
+	 * @return	boolean		Whether the current user is admin
+	 */
+	protected function isAdminUser() {
+		$isAdminUser = false;
+		if ($GLOBALS['BE_USER']->user['admin']) {
+			$isAdminUser = true;
+		}
+		return $isAdminUser;
+	}
+
+	/**
+	 * Set/write a log message.
+	 *
+	 * @param	string		$message: The log message to set/write
+	 * @return	void
+	 */
+	protected function log($message) {
+		if (is_object($GLOBALS['BE_USER'])) {
+			$GLOBALS['BE_USER']->writelog(3, 0, 1, 0, $message, array());
+		}
+	}
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/matchcondition/class.t3lib_matchcondition_backend.php'])	{
+	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/matchcondition/class.t3lib_matchcondition_backend.php']);
+}
+
+?>
\ No newline at end of file
Index: t3lib/matchcondition/class.t3lib_matchcondition_frontend.php
===================================================================
--- t3lib/matchcondition/class.t3lib_matchcondition_frontend.php	(Revision 0)
+++ t3lib/matchcondition/class.t3lib_matchcondition_frontend.php	(Revision 0)
@@ -0,0 +1,285 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Oliver Hader <oliver@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+
+/**
+ * Matching TypoScript conditions for frontend disposal.
+ *
+ * Used with the TypoScript parser.
+ * Matches browserinfo, IPnumbers for use with templates
+ *
+ * @author	Kasper Skaarhoj <kasperYYYY@typo3.com>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_matchCondition_frontend extends t3lib_matchCondition_abstract {
+	/**
+	 * @var	array
+	 */
+	protected $deprecatedHooks = array();
+
+	/**
+	 * Constructor for this class
+	 *
+	 * @return	void
+	 */
+	public function __construct() {
+		$this->initializeDeprecatedHooks();
+	}
+
+	/**
+	 * Initializes deprectated hooks that existed in t3lib_matchCondition until TYPO3 4.3.
+	 *
+	 * @return	void
+	 */
+	protected function initializeDeprecatedHooks() {
+			// Hook: $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['matchConditionClass']:
+		$matchConditionHooks =& $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['matchConditionClass'];
+		if (is_array($matchConditionHooks)) {
+			t3lib_div::deprecationLog(
+				'The hook $TYPO3_CONF_VARS[SC_OPTIONS][t3lib/class.t3lib_matchcondition.php][matchConditionClass] ' .
+				'is deprecated since TYPO3 4.3. Use the new hooks getBrowserInfo and getDeviceType in ' .
+				't3lib_utility_Client instead.'
+			);
+
+			foreach ($matchConditionHooks as $hookClass) {
+				$this->deprecatedHooks[] = t3lib_div::getUserObj($hookClass, '');
+			}
+		}
+	}
+
+	/**
+	 * Evaluates a TypoScript condition given as input, eg. "[browser=net][...(other conditions)...]"
+	 *
+	 * @param	string		$string: The condition to match against its criterias.
+	 * @return	boolean		Whether the condition matched
+	 * @see t3lib_tsparser::parse()
+	 */
+	protected function evaluateCondition($string) {
+		list($key, $value) = t3lib_div::trimExplode('=', $string, false, 2);
+
+		$result = parent::evaluateConditionCommon($key, $value);
+
+		if (is_bool($result)) {
+			return $result;
+		} else {
+			switch ($key) {
+				case 'usergroup':
+					$groupList = $this->getGroupList();
+					if ($groupList != '0,-1') {		// '0,-1' is the default usergroups when not logged in!
+						$values = t3lib_div::trimExplode(',', $value, true);
+						foreach ($values as $test) {
+							if ($test == '*' || t3lib_div::inList($groupList, $test)) {
+								return true;
+							}
+						}
+					}
+				break;
+				case 'treeLevel':
+					$values = t3lib_div::trimExplode(',', $value, true);
+					$treeLevel = count($this->rootline) - 1;
+					foreach ($values as $test) {
+						if ($test == $treeLevel) {
+							return true;
+						}
+					}
+				break;
+				case 'PIDupinRootline':
+				case 'PIDinRootline':
+					$values = t3lib_div::trimExplode(',', $value, true);
+					if (($key=='PIDinRootline') || (!in_array($this->pageId, $values))) {
+						foreach ($values as $test) {
+							foreach ($this->rootline as $rl_dat) {
+								if ($rl_dat['uid'] == $test) {
+									return true;
+								}
+							}
+						}
+					}
+				break;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Generates an array with abstracted browser information
+	 *
+	 * @param	string		$userAgent: The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
+	 * @return	array		Contains keys "browser", "version", "system"
+	 */
+	protected function getBrowserInfo($userAgent) {
+			// Exceute deprecated hooks:
+			// @deprecated since TYPO3 4.3
+		foreach($this->deprecatedHooks as $hookObj) {
+			if (method_exists($hookObj, 'browserInfo')) {
+				$result = $hookObj->browserInfo($userAgent);
+				if (strlen($result)) {
+					return $result;
+				}
+			}
+		}
+
+		return parent::getBrowserInfo($userAgent);
+	}
+
+	/**
+	 * Gets a code for a browsing device based on the input useragent string.
+	 *
+	 * @param	string		$userAgent: The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
+	 * @return	string		Code for the specific device type
+	 */
+	protected function getDeviceType($userAgent) {
+			// Exceute deprecated hooks:
+			// @deprecated since TYPO3 4.3
+		foreach($this->deprecatedHooks as $hookObj) {
+			if (method_exists($hookObj, 'whichDevice')) {
+				$result = $hookObj->whichDevice($userAgent);
+				if (strlen($result)) {
+					return $result;
+				}
+			}
+		}
+
+		// deprecated, see above
+		if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['devices_class'])) {
+			foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_matchcondition.php']['devices_class'] as $_classRef) {
+				$_procObj = t3lib_div::getUserObj($_classRef);
+				return $_procObj->whichDevice_ext($useragent);
+			}
+		}
+
+		return parent::getDeviceType($userAgent);
+	}
+
+	/**
+	 * Returns GP / ENV / TSFE vars
+	 *
+	 * @param	string		Identifier
+	 * @return	mixed		The value of the variable pointed to.
+	 */
+	protected function getVariable($var) {
+		$vars = explode(':', $var, 2);
+
+		$val = parent::getVariableCommon($vars);
+
+		if (is_null($val)) {
+			$splitAgain=explode('|', $vars[1], 2);
+			$k = trim($splitAgain[0]);
+			if ($k) {
+				switch((string)trim($vars[0])) {
+					case 'TSFE':
+						$val = $this->getGlobal('TSFE|' . $vars[1]);
+					break;
+				}
+			}
+		}
+
+		return $val;
+	}
+
+	/**
+	 * Get the usergroup list of the current user.
+	 *
+	 * @return	string		The usergroup list of the current user
+	 */
+	protected function getGroupList() {
+		$groupList = $GLOBALS['TSFE']->gr_list;
+		return $groupList;
+	}
+
+	/**
+	 * Determines the current page Id.
+	 *
+	 * @return	integer		The current page Id
+	 */
+	protected function determinePageId() {
+		return (int)$GLOBALS['TSFE']->id;
+	}
+
+	/**
+	 * Determines the rootline for the current page.
+	 *
+	 * @return	array		The rootline for the current page.
+	 */
+	protected function determineRootline() {
+		$rootline = (array)$GLOBALS['TSFE']->tmpl->rootLine;
+		return $rootline;
+	}
+
+	/**
+	 * Get prefix for user functions (normally 'user_').
+	 *
+	 * @return	string		The prefix for user functions (normally 'user_').
+	 */
+	protected function getUserFuncClassPrefix() {
+		$userFuncClassPrefix = $GLOBALS['TSFE']->TYPO3_CONF_VARS['FE']['userFuncClassPrefix'];
+		return $userFuncClassPrefix;
+	}
+
+	/**
+	 * Get the id of the current user.
+	 *
+	 * @return	integer		The id of the current user
+	 */
+	protected function getUserId() {
+		$userId = $GLOBALS['TSFE']->fe_user->user['uid'];
+		return $userId;
+	}
+
+	/**
+	 * Determines if a user is logged in.
+	 *
+	 * @return	boolean		Determines if a user is logged in
+	 */
+	protected function isUserLoggedIn() {
+		$userLoggedIn = false;
+		if ($GLOBALS['TSFE']->loginUser) {
+			$userLoggedIn = true;
+		}
+		return $userLoggedIn;
+	}
+
+	/**
+	 * Set/write a log message.
+	 *
+	 * @param	string		$message: The log message to set/write
+	 * @return	void
+	 */
+	protected function log($message) {
+		if (is_object($GLOBALS['TT'])) {
+			$GLOBALS['TT']->setTSlogMessage($message,3);
+		}
+	}
+}
+
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/matchcondition/class.t3lib_matchcondition_frontend.php'])	{
+	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/matchcondition/class.t3lib_matchcondition_frontend.php']);
+}
+
+?>
\ No newline at end of file
Index: t3lib/matchcondition/class.t3lib_matchcondition_abstract.php
===================================================================
--- t3lib/matchcondition/class.t3lib_matchcondition_abstract.php	(Revision 0)
+++ t3lib/matchcondition/class.t3lib_matchcondition_abstract.php	(Revision 0)
@@ -0,0 +1,632 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2009 Oliver Hader <oliver@typo3.org>
+*  All rights reserved
+*
+*  This script is part of the TYPO3 project. The TYPO3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*  A copy is found in the textfile GPL.txt and important notices to the license
+*  from the author is found in LICENSE.txt distributed with these scripts.
+*
+*
+*  This script is distributed in the hope that it will be useful,
+*  but WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * Matching TypoScript conditions
+ *
+ * $Id$
+ *
+ * Used with the TypoScript parser.
+ * Matches browserinfo, IPnumbers for use with templates
+ *
+ * @author	Oliver Hader <oliver@typo3.org>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+abstract class t3lib_matchCondition_abstract {
+	/**
+	 * Id of the current page.
+	 * @var	integer
+	 */
+	protected $pageId;
+	/**
+	 * The rootline for the current page.
+	 * @var	array
+	 */
+	protected $rootline;
+
+	/**
+	 * Whether to simulate the behaviour and match all conditions
+	 * (used in TypoScript object browser).
+	 * @var	boolean
+	 */
+	protected $simulateMatchResult;
+	/**
+	 * Whether to simulat the behaviour and match specific conditions
+	 * (used in TypoScript object browser).
+	 * @var	array
+	 */
+	protected $simulateMatchConditions;
+
+	/**
+	 * Sets the id of the page to evaluate conditions for.
+	 *
+	 * @param	integer		$pageId: Id of the page
+	 * @return	void
+	 */
+	public function setPageId($pageId) {
+		if (is_integer($pageId)) {
+			$this->pageId = $pageId;
+		}
+	}
+
+	/**
+	 * Gets the id of the page to evaluate conditions for.
+	 *
+	 * @return	integer		Id of the page
+	 */
+	public function getPageId() {
+		return $this->pageId;
+	}
+
+	/**
+	 * Sets the rootline.
+	 *
+	 * @param	array		$rootline: The rootline to be used for matching
+	 * @return	void
+	 */
+	public function setRootline(array $rootline) {
+		$this->rootline = $rootline;
+	}
+
+	/**
+	 * Gets the rootline.
+	 *
+	 * @return	array		The rootline to be used for matching
+	 */
+	public function getRootline() {
+		return $this->rootline;
+	}
+
+	/**
+	 * Sets whether to simulate the behaviour and match all conditions.
+	 *
+	 * @param	boolean		$simulateMatchResult: Whether to simulate positive matches
+	 * @return	void
+	 */
+	public function setSimulateMatchResult($simulateMatchResult = NULL) {
+		if (is_bool($simulateMatchResult)) {
+			$this->simulateMatchResult = $simulateMatchResult;
+		} elseif (is_null($simulateMatchResult)) {
+			unset($this->simulateMatchResult);
+		}
+	}
+
+	/**
+	 * Sets whether to simulate the behaviour and match specific conditions.
+	 *
+	 * @param	array		$simulateMatchConditions: Conditions to simulate a match for
+	 * @return	void
+	 */
+	public function setSimulateMatchConditions(array $simulateMatchConditions = NULL) {
+		if (is_array($simulateMatchConditions)) {
+			$this->simulateMatchConditions = $simulateMatchConditions;
+		} elseif (is_null($simulateMatchConditions)) {
+			unset($this->simulateMatchConditions);
+		}
+	}
+
+	/**
+	 * Normalizes an expression and removes the first and last square bracket.
+	 *  + OR normalization: "...]OR[...", "...]||[...", "...][..." --> "...]||[..."
+	 *  + AND normalization: "...]AND[...", "...]&&[..."           --> "...]&&[..."
+	 *
+	 * @param	string		$expression: The expression to be normalized (e.g. "[A] && [B] OR [C]")
+	 * @return	string		The normalized expression (e.g. "[A]&&[B]||[C]")
+	 */
+	protected function normalizeExpression($expression) {
+		$normalizedExpression = preg_replace(
+			array(
+				'/\]\s*(OR|\|\|)?\s*\[/i',
+				'/\]\s*(AND|&&)\s*\[/i',
+			),
+			array(
+				']||[',
+				']&&[',
+			),
+			trim($expression)
+		);
+
+		return $normalizedExpression;
+	}
+
+	/**
+	 * Matches a TypoScript condition expression.
+	 *
+	 * @param	string		$expression: The expression to match
+	 * @return	boolean		Whether the expression matched
+	 */
+	public function match($expression) {
+			// Return directly if result should be simulated:
+		if (isset($this->simulateMatchResult)) {
+			return $this->simulateMatchResult;
+		}
+			// Return directly if matching for specific condition is simulated only:
+		if (isset($this->simulateMatchConditions)) {
+			return in_array($expression, $this->simulateMatchConditions);
+		}
+			// Sets the current pageId if not defined yet:
+		if (!isset($this->pageId)) {
+			$this->setPageId(
+				$this->determinePageId()
+			);
+		}
+			// Sets the rootline if not defined yet:
+		if (!isset($this->rootline)) {
+			$this->setRootline(
+				$this->determineRootline()
+			);
+		}
+
+		$result = false;
+		$normalizedExpression = $this->normalizeExpression($expression);
+
+			// First and last character must be square brackets (e.g. "[A]&&[B]":
+		if (substr($normalizedExpression, 0, 1) === '[' && substr($normalizedExpression, -1) === ']') {
+			$innerExpression = substr($normalizedExpression, 1, -1);
+
+			$orParts = explode(']||[', $innerExpression);
+			foreach ($orParts as $orPart) {
+				$andParts = explode(']&&[', $orPart);
+				foreach ($andParts as $andPart) {
+					$result = $this->evaluateCondition($andPart);
+						// If condition in AND context fails, the whole block is false:
+					if ($result === false) {
+						break;
+					}
+				}
+					// If condition in OR context succeeds, the whole expression is true:
+				if ($result === true) {
+					break;
+				}
+			}
+		}
+
+		return $result;
+	}
+
+	/**
+	 * Evaluates a TypoScript condition given as input, eg. "[browser=net][...(other conditions)...]"
+	 *
+	 * @param	string		The condition to match against its criterias.
+	 * @return	mixed		Returns true or false based on the evaluation
+	 */
+	protected function evaluateConditionCommon($key, $value) {
+		if (t3lib_div::inList('browser,version,system,useragent', strtolower($key))) {
+			$browserInfo = $this->getBrowserInfo(t3lib_div::getIndpEnv('HTTP_USER_AGENT'));
+		}
+
+		switch ($key) {
+			case 'browser':
+				$values = t3lib_div::trimExplode(',', $value, true);
+				foreach ($values as $test) {
+					if (strpos($browserInfo['browser'] . $browserInfo['version'], $test) !== false) {
+						return true;
+					}
+				}
+			break;
+			case 'version':
+				$values = t3lib_div::trimExplode(',', $value, true);
+				foreach ($values as $test) {
+					if (strcspn($test, '=<>') == 0) {
+						switch (substr($test, 0, 1)) {
+							case '=':
+								if (doubleval(substr($test, 1)) == $browserInfo['version']) {
+									return true;
+								}
+							break;
+							case '<':
+								if (doubleval(substr($test, 1)) > $browserInfo['version']) {
+									return true;
+								}
+							break;
+							case '>':
+								if (doubleval(substr($test, 1)) < $browserInfo['version']) {
+									return true;
+								}
+							break;
+						}
+					} else {
+						if (strpos(' ' . $browserInfo['version'], $test) == 1) {
+							return true;
+						}
+					}
+				}
+			break;
+			case 'system':
+				$values = t3lib_div::trimExplode(',', $value, true);
+				foreach ($values as $test) {
+					if (strpos(' ' . $browserInfo['system'], $test) == 1) {
+						return true;
+					}
+				}
+			break;
+			case 'device':
+				if (!isset($this->deviceInfo)) {
+					$this->deviceInfo = $this->getDeviceType(t3lib_div::getIndpEnv('HTTP_USER_AGENT'));
+				}
+				$values = t3lib_div::trimExplode(',', $value, true);
+				foreach ($values as $test) {
+					if ($this->deviceInfo == $test) {
+						return true;
+					}
+				}
+			break;
+			case 'useragent':
+				$test = trim($value);
+				if (strlen($test)) {
+					return $this->searchStringWildcard($browserInfo['useragent'], $test);
+				}
+			break;
+			case 'language':
+				$values = t3lib_div::trimExplode(',', $value, true);
+				foreach ($values as $test) {
+					if (preg_match('/^\*.+\*$/', $test)) {
+						$allLanguages = preg_split('/[,;]/', t3lib_div::getIndpEnv('HTTP_ACCEPT_LANGUAGE'));
+						if (in_array(substr($test, 1, -1), $allLanguages)) {
+							return true;
+						}
+					} else if (t3lib_div::getIndpEnv('HTTP_ACCEPT_LANGUAGE') == $test) {
+						return true;
+					}
+				}
+			break;
+			case 'IP':
+				if (t3lib_div::cmpIP(t3lib_div::getIndpEnv('REMOTE_ADDR'), $value)) {
+					return true;
+				}
+			break;
+			case 'hostname':
+				if (t3lib_div::cmpFQDN(t3lib_div::getIndpEnv('REMOTE_ADDR'), $value)) {
+					return true;
+				}
+			break;
+				// hour, minute, dayofweek, dayofmonth, month, year, julianday
+			case 'hour':
+			case 'minute':
+			case 'month':
+			case 'year':
+			case 'dayofweek':
+			case 'dayofmonth':
+			case 'dayofyear':
+				$theEvalTime = $GLOBALS['SIM_EXEC_TIME'];	// In order to simulate time properly in templates.
+				switch($key) {
+					case 'hour':		$theTestValue = date('H', $theEvalTime);	break;
+					case 'minute':		$theTestValue = date('i', $theEvalTime);	break;
+					case 'month':		$theTestValue = date('m', $theEvalTime);	break;
+					case 'year':		$theTestValue = date('Y', $theEvalTime);	break;
+					case 'dayofweek':	$theTestValue = date('w', $theEvalTime);	break;
+					case 'dayofmonth':	$theTestValue = date('d', $theEvalTime);	break;
+					case 'dayofyear':	$theTestValue = date('z', $theEvalTime);	break;
+				}
+				$theTestValue = intval($theTestValue);
+					// comp
+				$values = t3lib_div::trimExplode(',', $value, true);
+				foreach ($values as $test) {
+					if (t3lib_div::testInt($test)) {
+						$test = '=' . $test;
+					}
+					if ($this->compareNumber($test, $theTestValue)) {
+						return true;
+					}
+				}
+			break;
+			case 'compatVersion':
+				return t3lib_div::compat_version($value);
+			break;
+			case 'loginUser':
+				if ($this->isUserLoggedIn()) {
+					$values = t3lib_div::trimExplode(',', $value, true);
+					foreach ($values as $test) {
+						if ($test == '*' || !strcmp($this->getUserId(), $test)) {
+							return true;
+						}
+					}
+				}
+			break;
+			case 'globalVar':
+				$values = t3lib_div::trimExplode(',', $value, true);
+				foreach ($values as $test) {
+					$point = strcspn($test, '!=<>');
+					$theVarName = substr($test, 0, $point);
+					$nv = $this->getVariable(trim($theVarName));
+					$testValue = substr($test, $point);
+
+					if ($this->compareNumber($testValue, $nv)) {
+						return true;
+					}
+				}
+			break;
+			case 'globalString':
+				$values = t3lib_div::trimExplode(',', $value, true);
+				foreach ($values as $test) {
+					$point = strcspn($test, '=');
+					$theVarName = substr($test, 0, $point);
+					$nv = $this->getVariable(trim($theVarName));
+					$testValue = substr($test, $point+1);
+
+					if ($this->searchStringWildcard($nv, trim($testValue))) {
+						return true;
+					}
+				}
+			break;
+			case 'userFunc':
+				$values = preg_split('/\(|\)/', $value);
+				$funcName = trim($values[0]);
+				$funcValue = t3lib_div::trimExplode(',', $values[1]);
+				$prefix = $this->getUserFuncClassPrefix();
+				if ($prefix &&
+					!t3lib_div::isFirstPartOfStr(trim($funcName), $prefix) &&
+					!t3lib_div::isFirstPartOfStr(trim($funcName),'tx_')
+				)	{
+					$this->log('Match condition: Function "' . $funcName . '" was not prepended with "' . $prefix.'"');
+					return false;
+				}
+				if (function_exists($funcName) && call_user_func($funcName, $funcValue[0]))	{
+					return true;
+				}
+			break;
+		}
+
+		return NULL;
+	}
+
+	protected function getVariableCommon(array $vars) {
+		$value = NULL;
+
+		if (count($vars) == 1) {
+			$value = $this->getGlobal($vars[0]);
+		} else {
+			$splitAgain = explode('|',$vars[1], 2);
+			$k = trim($splitAgain[0]);
+
+			if ($k) {
+				switch((string)trim($vars[0])) {
+					case 'GP':
+						$value = t3lib_div::_GP($k);
+						break;
+					case 'ENV':
+						$value = getenv($k);
+						break;
+					case 'IENV':
+						$value = t3lib_div::getIndpEnv($k);
+						break;
+					// return litteral value:
+					case 'LIT':
+						return trim($vars[1]);
+						break;
+					default:
+						return NULL;
+				}
+					// If array:
+				if (count($splitAgain) > 1) {
+					if (is_array($value) && trim($splitAgain[1])) {
+						$value = $this->getGlobal($splitAgain[1], $value);
+					} else {
+						$value = '';
+					}
+				}
+			}
+		}
+
+		return $value;
+	}
+
+	/**
+	 * Evaluates a $leftValue based on an operator: "<", ">", "<=", ">=", "!=" or "="
+	 *
+	 * @param	string		$test: The value to compare with on the form [operator][number]. Eg. "< 123"
+	 * @param	integer		$leftValue: The value on the left side
+	 * @return	boolean		If $value is "50" and $test is "< 123" then it will return true.
+	 */
+	protected function compareNumber($test, $leftValue) {
+		if (preg_match('/^(!?=+|<=?|>=?)\s*([^\s]*)\s*$/', $test, $matches)) {
+			$operator = $matches[1];
+			$rightValue = $matches[2];
+
+			switch ($operator) {
+				case '>=':
+					return ($leftValue >= doubleval($rightValue));
+					break;
+				case '<=':
+					return ($leftValue <= doubleval($rightValue));
+					break;
+				case '!=':
+					return ($leftValue != doubleval($rightValue));
+					break;
+				case '<':
+					return ($leftValue < doubleval($rightValue));
+					break;
+				case '>':
+					return ($leftValue > doubleval($rightValue));
+					break;
+				default:
+					// nothing valid found except '=', use '='
+					return ($leftValue == trim($rightValue));
+					break;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Matching two strings against each other, supporting a "*" wildcard or (if wrapped in "/") PCRE regular expressions
+	 *
+	 * @param	string		The string in which to find $needle.
+	 * @param	string		The string to find in $haystack
+	 * @return	boolean		Returns true if $needle matches or is found in (according to wildcards) in $haystack. Eg. if $haystack is "Netscape 6.5" and $needle is "Net*" or "Net*ape" then it returns true.
+	 */
+	protected function searchStringWildcard($haystack, $needle) {
+		$result = false;
+
+		if ($needle) {
+			if (preg_match('/^\/.+\/$/', $needle)) {
+				// Regular expression, only "//" is allowed as delimiter
+				$regex = $needle;
+			} else {
+				$needle = str_replace(array('*', '?'), array('###MANY###', '###ONE###'), $needle);
+				$regex = '/^' . preg_quote($needle, '/') . '$/';
+				// Replace the marker with .* to match anything (wildcard)
+				$regex = str_replace(array('###MANY###', '###ONE###'), array('.*' , '.'), $regex);
+			}
+
+			$result = (boolean)preg_match($regex, (string)$haystack);
+		}
+
+		return $result;
+	}
+
+	/**
+	 * Generates an array with abstracted browser information
+	 *
+	 * @param	string		$userAgent: The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
+	 * @return	array		Contains keys "browser", "version", "system"
+	 */
+	protected function getBrowserInfo($userAgent) {
+		return t3lib_utility_Client::getBrowserInfo($userAgent);
+	}
+
+	/**
+	 * Gets a code for a browsing device based on the input useragent string.
+	 *
+	 * @param	string		$userAgent: The useragent string, t3lib_div::getIndpEnv('HTTP_USER_AGENT')
+	 * @return	string		Code for the specific device type
+	 */
+	protected function getDeviceType($userAgent) {
+		return t3lib_utility_Client::getDeviceType($userAgent);
+	}
+
+	/**
+	 * Return global variable where the input string $var defines array keys separated by "|"
+	 * Example: $var = "HTTP_SERVER_VARS | something" will return the value $GLOBALS['HTTP_SERVER_VARS']['something'] value
+	 *
+	 * @param	string		Global var key, eg. "HTTP_GET_VAR" or "HTTP_GET_VARS|id" to get the GET parameter "id" back.
+	 * @param	array		Alternative array than $GLOBAL to get variables from.
+	 * @return	mixed		Whatever value. If none, then blank string.
+	 */
+	protected function getGlobal($var, $source=NULL) {
+		$vars = explode('|', $var);
+		$c = count($vars);
+		$k = trim($vars[0]);
+		$theVar = isset($source) ? $source[$k] : $GLOBALS[$k];
+
+		for ($a=1;$a<$c;$a++)	{
+			if (!isset($theVar))	{ break; }
+
+			$key = trim($vars[$a]);
+			if (is_object($theVar)) {
+				$theVar = $theVar->$key;
+			} elseif (is_array($theVar)) {
+				$theVar = $theVar[$key];
+			} else {
+				return '';
+			}
+		}
+
+		if (!is_array($theVar) && !is_object($theVar))	{
+			return $theVar;
+		} else {
+			return '';
+		}
+	}
+
+	
+	/**
+	 * Evaluates a TypoScript condition given as input, eg. "[browser=net][...(other conditions)...]"
+	 *
+	 * @param	string		$string: The condition to match against its criterias.
+	 * @return	boolean		Whether the condition matched
+	 * @see t3lib_tsparser::parse()
+	 */
+	abstract protected function evaluateCondition($string);
+
+	/**
+	 * Gets the value of a variable.
+	 *
+	 * Examples of names:
+	 * + TSFE:id
+	 * + GP:firstLevel|secondLevel
+	 * + _GET|firstLevel|secondLevel
+	 * + LIT:someLiteralValue
+	 *
+	 * @param	string		$name: The name of the variable to fetch the value from
+	 * @return	mixed		The value of the given variable (string) or NULL if variable did not exist
+	 */
+	abstract protected function getVariable($name);
+
+	/**
+	 * Gets the usergroup list of the current user.
+	 *
+	 * @return	string		The usergroup list of the current user
+	 */
+	abstract protected function getGroupList();
+
+	/**
+	 * Determines the current page Id.
+	 *
+	 * @return	integer		The current page Id
+	 */
+	abstract protected function determinePageId();
+
+	/**
+	 * Determines the rootline for the current page.
+	 *
+	 * @return	array		The rootline for the current page.
+	 */
+	abstract protected function determineRootline();
+
+	/**
+	 * Gets prefix for user functions (normally 'user_').
+	 *
+	 * @return	string		The prefix for user functions (normally 'user_').
+	 */
+	abstract protected function getUserFuncClassPrefix();
+
+	/**
+	 * Hybrid FE/BE: Get the id of the current user.
+	 *
+	 * @return	integer		The id of the current user
+	 */
+	abstract protected function getUserId();
+
+	/**
+	 * Determines if a user is logged in.
+	 *
+	 * @return	boolean		Determines if a user is logged in
+	 */
+	abstract protected function isUserLoggedIn();
+
+	/**
+	 * Sets a log message.
+	 *
+	 * @param	string		$message: The log message to set/write
+	 * @return	void
+	 */
+	abstract protected function log($message);
+}
+
+?>
\ No newline at end of file
Index: t3lib/class.t3lib_userauthgroup.php
===================================================================
--- t3lib/class.t3lib_userauthgroup.php	(Revision 6171)
+++ t3lib/class.t3lib_userauthgroup.php	(Arbeitskopie)
@@ -1160,19 +1160,30 @@
 				// Check include lines.
 			$this->TSdataArray = t3lib_TSparser::checkIncludeLines_array($this->TSdataArray);
 
-				// Parsing the user TSconfig (or getting from cache)
 			$this->userTS_text = implode(chr(10).'[GLOBAL]'.chr(10),$this->TSdataArray);	// Imploding with "[global]" will make sure that non-ended confinements with braces are ignored.
-			$hash = md5('userTS:'.$this->userTS_text);
-			$cachedContent = t3lib_BEfunc::getHash($hash);
-			if (isset($cachedContent) && !$this->userTS_dontGetCached)	{
-				$this->userTS = unserialize($cachedContent);
+
+			if ($GLOBALS['TYPO3_CONF_VARS']['BE']['TSconfigConditions'] && !$this->userTS_dontGetCached) {
+					// Perform TS-Config parsing with condition matching
+				$parseObj = t3lib_div::makeInstance('t3lib_TSparser_TSconfig');
+				$res = $parseObj->parseTSconfig($this->userTS_text, false, false, 'userTS');
+				if ($res) {
+					$this->userTS = $res['TSconfig'];
+					$this->userTSUpdated = ($res['cached'] ? 0 : 1);
+				}
 			} else {
-				$parseObj = t3lib_div::makeInstance('t3lib_TSparser');
-				$parseObj->parse($this->userTS_text);
-				$this->userTS = $parseObj->setup;
-				t3lib_BEfunc::storeHash($hash,serialize($this->userTS),'BE_USER_TSconfig');
-					// Update UC:
-				$this->userTSUpdated=1;
+					// Parsing the user TSconfig (or getting from cache)
+				$hash = md5('userTS:' . $this->userTS_text);
+				$cachedContent = t3lib_BEfunc::getHash($hash);
+				if (isset($cachedContent) && !$this->userTS_dontGetCached) {
+					$this->userTS = unserialize($cachedContent);
+				} else {
+					$parseObj = t3lib_div::makeInstance('t3lib_TSparser');
+					$parseObj->parse($this->userTS_text);
+					$this->userTS = $parseObj->setup;
+					t3lib_BEfunc::storeHash($hash, serialize($this->userTS), 'BE_USER_TSconfig');
+						// Update UC:
+					$this->userTSUpdated=1;
+				}
 			}
 
 				// Processing webmounts
Index: t3lib/class.t3lib_tsparser_ext.php
===================================================================
--- t3lib/class.t3lib_tsparser_ext.php	(Revision 6171)
+++ t3lib/class.t3lib_tsparser_ext.php	(Arbeitskopie)
@@ -292,8 +292,9 @@
 		$constants->setup = $this->const;
 		$constants->setup = $this->mergeConstantsFromPageTSconfig($constants->setup);
 
-		$matchObj = t3lib_div::makeInstance('t3lib_matchCondition');
-		$matchObj->matchAll=1;		// Matches ALL conditions in TypoScript
+		/* @var $matchObj t3lib_matchCondition_frontend */
+		$matchObj = t3lib_div::makeInstance('t3lib_matchCondition_frontend');
+		$matchObj->setSimulateMatchResult(true);	// Matches ALL conditions in TypoScript
 
 		$c=0;
 		$cc=count($this->constants);
