Index: t3lib/class.t3lib_iconworks.php
===================================================================
--- t3lib/class.t3lib_iconworks.php	(Revision 3468)
+++ t3lib/class.t3lib_iconworks.php	(Arbeitskopie)
@@ -183,7 +183,7 @@
 
 			// Icon state based on "enableFields":
 		if (is_array($TCA[$table]['ctrl']['enablecolumns'])) {
-			$enCols = $TCA[$table]['ctrl']['enablecolumns'];
+			$enCols =& $TCA[$table]['ctrl']['enablecolumns'];
 				// If "hidden" is enabled:
 			if ($enCols['disabled'])	{ if ($row[$enCols['disabled']]) { $hidden = TRUE; }}
 				// If a "starttime" is set and higher than current time:
@@ -203,6 +203,10 @@
 				$user = $row[$enCols['fe_group']];
 				if ($user && $doNotRenderUserGroupNumber)	$user = 100;	// Limit for user number rendering!
 			}
+				// If a frone-end rules field is set:
+			if ($enCols['fe_rules'])	{
+				$fe_rules = $row[$enCols['fe_rules']];
+			}
 		}
 
 			// If "deleted" flag is set (only when listing records which are also deleted!)
@@ -215,7 +219,7 @@
 		}
 
 			// If ANY of the booleans are set it means we have to alter the icon:
-		if ($hidden || $timing || $futuretiming || $user || $deleted || $shaded || $noIconFound) {
+		if ($hidden || $timing || $futuretiming || $user || $fe_rules || $deleted || $shaded || $noIconFound) {
 			$flags = '';
 			$string = '';
 			if ($deleted) {
@@ -236,6 +240,7 @@
 					($timing ? 't' : '').
 					($futuretiming ? 'f' : '').
 					($user ? 'u' : '').
+					($fe_rules ? 'r' : '').
 					($protectSection ? 'p' : '').
 					($shaded ? 's' : '');
 			}
Index: t3lib/class.t3lib_matchcondition.php
===================================================================
--- t3lib/class.t3lib_matchcondition.php	(Revision 3468)
+++ t3lib/class.t3lib_matchcondition.php	(Arbeitskopie)
@@ -416,9 +416,8 @@
 			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,'/').'$/';
-				$regex = str_replace(array('###MANY###','###ONE###'), array('.*','.'), $regex);	// Replace the marker with .* to match anything (wildcard)
+					// Replace '?' with '.' and '*' with '.*' for disposal in preg_match():
+				$regex = t3lib_div::wildcard2regexp($needle);
 			}
 
 			if (preg_match($regex, $haystack)) return true;
Index: t3lib/class.t3lib_page.php
===================================================================
--- t3lib/class.t3lib_page.php	(Revision 3468)
+++ t3lib/class.t3lib_page.php	(Arbeitskopie)
@@ -110,6 +110,7 @@
 	var $urltypes = Array('','http://','ftp://','mailto:','https://');
 	var $where_hid_del = ' AND pages.deleted=0';	// This is not the final clauses. There will normally be conditions for the hidden,starttime and endtime fields as well. You MUST initialize the object by the init() function
 	var $where_groupAccess = '';	// Clause for fe_group access
+	var $where_rulesActive = '';	// Clause for fe_rules that are active
 	var $sys_language_uid = 0;
 
 		// Versioning preview related:
@@ -137,6 +138,7 @@
 	 */
 	function init($show_hidden)	{
 		$this->where_groupAccess = '';
+		$this->where_rulesActive = '';
 		$this->where_hid_del = ' AND pages.deleted=0 ';
 		if (!$show_hidden)	{
 			$this->where_hid_del.= 'AND pages.hidden=0 ';
@@ -1030,8 +1032,12 @@
 					}
 					if ($ctrl['enablecolumns']['fe_group'] && !$ignore_array['fe_group']) {
 						$field = $table.'.'.$ctrl['enablecolumns']['fe_group'];
-						$query.= $this->getMultipleGroupsWhereClause($field, $table);
+						$query.= $this->getMultipleGroupsWhereClause($field, $table, $GLOBALS['TSFE']->gr_list);
 					}
+					if ($ctrl['enablecolumns']['fe_rules'] && !$ignore_array['fe_rules']) {
+						$field = $table.'.'.$ctrl['enablecolumns']['fe_rules'];
+						$query.= $this->getMultipleGroupsWhereClause($field, $table, $GLOBALS['TSFE']->rulesActive);
+					}
 
 					// Call hook functions for additional enableColumns
 					// It is used by the extension ingmar_accessctrl which enables assigning more than one usergroup to content and page records
@@ -1060,17 +1066,23 @@
 	 *
 	 * @param	string		Field with group list
 	 * @param	string		Table name
+	 * @param	array		The groups to be processed
 	 * @return	string		AND sql-clause
 	 * @see enableFields()
 	 */
-	function getMultipleGroupsWhereClause($field, $table)	{
-		$memberGroups = t3lib_div::intExplode(',',$GLOBALS['TSFE']->gr_list);
+	function getMultipleGroupsWhereClause($field, $table, $groups=null)	{
+		if (!isset($groups)) {
+			$groups = $GLOBALS['TSFE']->gr_list;
+		}
+		if (!is_array($groups)) {
+			$groups = t3lib_div::intExplode(',', $groups);
+		}
 		$orChecks=array();
 		$orChecks[]=$field.'=\'\'';	// If the field is empty, then OK
 		$orChecks[]=$field.' IS NULL';	// If the field is NULL, then OK
 		$orChecks[]=$field.'=\'0\'';	// If the field contsains zero, then OK
 
-		foreach($memberGroups as $value)	{
+		foreach($groups as $value)	{
 			$orChecks[] = $GLOBALS['TYPO3_DB']->listQuery($field, $value, $table);
 		}
 
Index: t3lib/class.t3lib_div.php
===================================================================
--- t3lib/class.t3lib_div.php	(Revision 3468)
+++ t3lib/class.t3lib_div.php	(Arbeitskopie)
@@ -1457,6 +1457,19 @@
 		return strtr((string)$str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
 	}
 
+	/**
+	 * Convert a string with wildcards '*,?' to a regular expression,
+	 * e.g. '*something?' get converted to '.*something.'.
+	 *
+	 * @param	string		$string: The wildcard string to be converted to a regular expression
+	 * @return	string		The regular expression string
+	 */
+	function wildcard2regexp($string) {
+		$string = str_replace(array('*','?'), array('###MANY###','###ONE###'), $string);
+		$string = '/^'.preg_quote($string,'/').'$/';
+		$string = str_replace(array('###MANY###','###ONE###'), array('.*','.'), $string);	// Replace the marker with .* to match anything (wildcard)
+		return $string;
+	}
 
 
 
@@ -1468,6 +1481,7 @@
 
 
 
+
 	/*************************
 	 *
 	 * ARRAY FUNCTIONS
Index: typo3/sysext/lang/locallang_general.xml
===================================================================
--- typo3/sysext/lang/locallang_general.xml	(Revision 3468)
+++ typo3/sysext/lang/locallang_general.xml	(Arbeitskopie)
@@ -14,6 +14,7 @@
 			<label index="LGL.hidden">Hide:</label>
 			<label index="LGL.starttime">Start:</label>
 			<label index="LGL.fe_group">Access:</label>
+			<label index="LGL.fe_rules">Rules:</label>
 			<label index="LGL.hide_at_login">Hide at login</label>
 			<label index="LGL.any_login">Show at any login</label>
 			<label index="LGL.usergroups">__Usergroups:__</label>
Index: typo3/sysext/cms/ext_tables.php
===================================================================
--- typo3/sysext/cms/ext_tables.php	(Revision 3468)
+++ typo3/sysext/cms/ext_tables.php	(Arbeitskopie)
@@ -645,6 +645,7 @@
 			'starttime' => 'starttime',
 			'endtime' => 'endtime',
 			'fe_group' => 'fe_group',
+			'fe_rules' => 'fe_rules',
 		),
 		'typeicon_column' => 'CType',
 		'typeicons' => array (
@@ -666,7 +667,7 @@
 			'div' => 'tt_content_div.gif',
 			'html' => 'tt_content_html.gif'
 		),
-		'mainpalette' => '15',
+		'mainpalette' => '15,16',
 		'thumbnail' => 'image',
 		'requestUpdate' => 'list_type,rte_enabled',
 		'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tbl_tt_content.php',
@@ -722,6 +723,25 @@
 );
 
 // ******************************************************************
+// fe_rules
+// ******************************************************************
+$TCA['fe_rules'] = Array (
+	'ctrl' => Array (
+		'label' => 'title',
+		'tstamp' => 'tstamp',
+		'delete' => 'deleted',
+		'type' => 'type',
+		'prependAtCopy' => 'LLL:EXT:lang/locallang_general.php:LGL.prependAtCopy',
+		'enablecolumns' => Array (
+			'disabled' => 'hidden'
+		),
+		'title' => 'LLL:EXT:cms/locallang_tca.php:fe_rules',
+		'dynamicConfigFile' => t3lib_extMgm::extPath($_EXTKEY).'tbl_cms.php',
+		'requestUpdate' => 'type',
+	)
+);
+
+// ******************************************************************
 // sys_domain
 // ******************************************************************
 $TCA['sys_domain'] = array (
Index: typo3/sysext/cms/locallang_tca.xml
===================================================================
--- typo3/sysext/cms/locallang_tca.xml	(Revision 3468)
+++ typo3/sysext/cms/locallang_tca.xml	(Arbeitskopie)
@@ -91,6 +91,12 @@
 			<label index="fe_groups.subgroup">Subgroups:</label>
 			<label index="fe_groups.tabs.options">Options</label>
 			<label index="fe_groups.tabs.extended">Extended</label>
+ 			<label index="fe_rules">Website rule</label>
+ 			<label index="fe_rules.type">Type:</label>
+ 			<label index="fe_rules.title">Rule title:</label>
+ 			<label index="fe_rules.allow">Allow/Deny expression:</label>
+ 			<label index="fe_rules.expression">Expression:</label>
+ 			<label index="fe_rules.subrules">Sub rules:</label>
 			<label index="sys_domain">Domain</label>
 			<label index="sys_domain.domainName">Domain:</label>
 			<label index="sys_domain.redirectTo">Redirect to:</label>
Index: typo3/sysext/cms/ext_tables.sql
===================================================================
--- typo3/sysext/cms/ext_tables.sql	(Revision 3468)
+++ typo3/sysext/cms/ext_tables.sql	(Arbeitskopie)
@@ -94,6 +94,25 @@
 
 
 #
+# Table structure for table 'fe_rules'
+#
+CREATE TABLE fe_rules (
+  uid int(11) unsigned NOT NULL auto_increment,
+  pid int(11) unsigned DEFAULT '0' NOT NULL,
+  tstamp int(11) unsigned DEFAULT '0' NOT NULL,
+  type varchar(16) DEFAULT '' NOT NULL,
+  title varchar(50) DEFAULT '' NOT NULL,
+  hidden tinyint(3) unsigned DEFAULT '0' NOT NULL,
+  deleted tinyint(3) unsigned DEFAULT '0' NOT NULL,
+  description text NOT NULL,
+  allow tinyint(1) unsigned DEFAULT '0' NOT NULL,
+  expression varchar(128) DEFAULT '' NOT NULL,
+  subrules tinyblob NOT NULL,
+  PRIMARY KEY (uid),
+  KEY parent (pid)
+);
+
+#
 # Table structure for table 'fe_session_data'
 #
 CREATE TABLE fe_session_data (
@@ -331,6 +350,7 @@
   spaceBefore tinyint(4) unsigned DEFAULT '0' NOT NULL,
   spaceAfter tinyint(4) unsigned DEFAULT '0' NOT NULL,
   fe_group varchar(100) DEFAULT '0' NOT NULL,
+  fe_rules varchar(100) DEFAULT '0' NOT NULL,
   header_link varchar(255) DEFAULT '' NOT NULL,
   imagecaption_position varchar(6) DEFAULT '' NOT NULL,
   image_link varchar(255) DEFAULT '' NOT NULL,
Index: typo3/sysext/cms/tbl_tt_content.php
===================================================================
--- typo3/sysext/cms/tbl_tt_content.php	(Revision 3468)
+++ typo3/sysext/cms/tbl_tt_content.php	(Arbeitskopie)
@@ -39,7 +39,7 @@
 	'ctrl' => $TCA['tt_content']['ctrl'],
 	'interface' => Array (
 		'always_description' => 0,
-		'showRecordFieldList' => 'CType,header,header_link,bodytext,image,imagewidth,imageorient,media,records,colPos,starttime,endtime,fe_group'
+		'showRecordFieldList' => 'CType,header,header_link,bodytext,image,imagewidth,imageorient,media,records,colPos,starttime,endtime,fe_group,fe_rules'
 	),
 	'columns' => Array (
 		'CType' => Array (
@@ -127,6 +127,18 @@
 				'foreign_table' => 'fe_groups'
 			)
 		),
+		'fe_rules' => Array (
+			'exclude' => 1,
+			'label' => 'LLL:EXT:lang/locallang_general.php:LGL.fe_rules',
+			'config' => Array (
+				'type' => 'select',
+				'size' => 5,
+				'maxitems' => 20,
+				'items' => Array (
+				),
+				'foreign_table' => 'fe_rules'
+			)
+		),
 		'sys_language_uid' => Array (
 			'exclude' => 1,
 			'label' => 'LLL:EXT:lang/locallang_general.php:LGL.language',
@@ -1109,6 +1121,7 @@
 		'13' => Array('showitem' => 'imagewidth, imageheight','canNotCollapse' => 1),
 		'14' => Array('showitem' => 'sys_language_uid, l18n_parent, colPos'),
 		'15' => Array('showitem' => 'fe_group'),
+		'16' => Array('showitem' => 'fe_rules'),
 	)
 );
 
Index: typo3/sysext/cms/tbl_cms.php
===================================================================
--- typo3/sysext/cms/tbl_cms.php	(Revision 3468)
+++ typo3/sysext/cms/tbl_cms.php	(Arbeitskopie)
@@ -382,6 +382,95 @@
 
 
 // ******************************************************************
+// fe_rules
+//
+// FrontEnd rules - determines visibility of elements
+// ******************************************************************
+$TCA['fe_rules'] = Array (
+	'ctrl' => $TCA['fe_rules']['ctrl'],
+	'interface' => Array (
+		'showRecordFieldList' => 'title,hidden,type,subrules,description,allow'
+	),
+	'columns' => Array (
+		'hidden' => Array (
+			'label' => 'LLL:EXT:lang/locallang_general.php:LGL.disable',
+			'exclude' => 1,
+			'config' => Array (
+				'type' => 'check',
+				'default' => '0'
+			)
+		),
+		'type' => array(
+			'label' => 'LLL:EXT:cms/locallang_tca.php:fe_rules.type',
+			'config' => array(
+				'type' => 'select',
+				'items' => Array (
+					Array('Domain', 'domain'),
+					Array('Group of rules', 'group'),
+				),
+				'default' => 'domain',
+			),
+		),
+		'title' => Array (
+			'label' => 'LLL:EXT:cms/locallang_tca.php:fe_rules.title',
+			'config' => Array (
+				'type' => 'input',
+				'size' => '20',
+				'max' => '50',
+				'eval' => 'trim,required'
+			)
+		),
+		'subrules' => Array (
+			'exclude' => 1,
+			'label' => 'LLL:EXT:cms/locallang_tca.php:fe_rules.subrules',
+			'config' => Array (
+				'type' => 'select',
+				'foreign_table' => 'fe_rules',
+				'foreign_table_where' => 'AND NOT(fe_rules.uid = ###THIS_UID###) AND fe_rules.hidden=0 ORDER BY fe_rules.title',
+				'size' => 4,
+				'autoSizeMax' => 10,
+				'minitems' => 0,
+				'maxitems' => 20
+			)
+		),
+		'allow' => array(
+			'label' => 'LLL:EXT:cms/locallang_tca.php:fe_rules.allow',
+			'config' => array(
+				'type' => 'select',
+				'items' => Array (
+					Array('Deny', '0'),
+					Array('Allow', '1'),
+				),
+				'default' => '1'
+			),
+		),
+		'expression' => array(
+			'label' => 'LLL:EXT:cms/locallang_tca.php:fe_rules.expression',
+			'config' => array(
+				'type' => 'input',
+				'size' => '20',
+				'max' => '50',
+				'eval' => 'trim,required'
+			),
+		),
+		'description' => Array (
+			'label' => 'LLL:EXT:lang/locallang_general.php:LGL.description',
+			'config' => Array (
+				'type' => 'text',
+				'rows' => 5,
+				'cols' => 48
+			)
+		),
+	),
+	'types' => Array (
+		'0' => Array('showitem' => 'hidden;;;;1-1-1,type, title;;;;2-2-2,description;;;;3-3-3, --div--, allow, expression'),
+		'domain' => Array('showitem' => 'hidden;;;;1-1-1,type, title;;;;2-2-2,description;;;;3-3-3, --div--, allow, expression'),
+		'group' => Array('showitem' => 'hidden;;;;1-1-1,type, title;;;;2-2-2,description;;;;3-3-3, --div--, allow, subrules'),
+	)
+);
+
+
+// ******************************************************************
 // sys_domain
 // ******************************************************************
 $TCA['sys_domain'] = Array (
Index: typo3/sysext/cms/tslib/class.tslib_fe.php
===================================================================
--- typo3/sysext/cms/tslib/class.tslib_fe.php	(Revision 3468)
+++ typo3/sysext/cms/tslib/class.tslib_fe.php	(Arbeitskopie)
@@ -238,6 +238,11 @@
 	var $page_cache_reg1=0;				// This can be set from applications as a way to tag cached versions of a page and later perform some external cache management, like clearing only a part of the cache of a page...
 	var $siteScript='';					// Contains the value of the current script path that activated the frontend. Typically "index.php" but by rewrite rules it could be something else! Used for Speaking Urls / Simulate Static Documents.
 
+		// RULES
+
+	var $rulesActive=array();			// FE rules that have positively passed the checks and thus are active
+	var $rulesProcessed=array();		// FE rules that were processed
+
 		// USER
 
 	/**
@@ -567,6 +572,88 @@
 
 
 	/**
+	 * Initialize the front-end rules.
+	 * 
+	 * @return	void
+	 */
+	function initFErules() {
+		$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
+			'*',
+			'fe_rules',
+			'hidden=0 AND deleted=0'
+		);
+		while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
+			$this->evaluateFErule($row);
+		}
+		$GLOBALS['TYPO3_DB']->sql_free_result($res);
+			// Make array unique and sort it:
+		$this->rulesActive = array_unique($this->rulesActive);
+		sort($this->rulesActive);
+	}
+
+	/**
+	 * Evaluate a singe front-end rule and put the processed rules to $this->rulesProcessed.
+	 * The rules that were tested positive are stored in $this->rulesActive.
+	 *
+	 * @param	array		$row: A record row of table fe_rules
+	 * @return	boolean		Returns true if the rule matches the current sitation, otherwise false
+	 */
+	function evaluateFErule($row) {
+		$result = null;
+		$allow = (boolean)$row['allow'];
+		switch($row['type']) {
+				// Domain: Evaluate the expression against HTTP_HOST:
+			case 'domain':
+				$expression = trim($row['expression']);
+				if ($expression) {
+					$result = (boolean)preg_match(t3lib_div::wildcard2regexp($expression), t3lib_div::getIndpEnv('HTTP_HOST'));
+				}
+				break;
+				// Group: Evaluate sub rules that appear in an AND context (e.g. <result> = <rule_1> && <rule_2> && <rule_3>):
+			case 'group':
+				$subRules = t3lib_div::trimExplode(',', $row['subrules']);
+				foreach ($subRules as $rule) {
+						// Get result of sub rule if this was processed before (cached):
+					if (isset($this->rulesProcessed[$rule])) {
+						$subResult = $this->rulesProcessed[$rule];
+						// Get result of sub rule if this wasn't processed before:
+					} else {
+						$subRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('*', 'fe_rules', 'deleted=0 AND hidden=0 AND uid='.intval($rule));
+						$subResult = (count($subRows) ? $this->evaluateFErule($subRows[0]) : null);
+					}
+						// If a sub rule could be evaluated (is true or false):
+						// ($allow!=$subResult) means:
+						// * if $allow=true and $subResult=false -> stop processing next rules because first false was found
+						// * if $allow=false and $subResult=true -> stop processing next rules because first true was found
+					if (isset($subResult) && $allow!=$subResult) {
+						$result = (!$allow && $subResult);
+						break;
+					}
+				}
+					// If result wasn't set before, all sub result values were of the same type:
+				if (!isset($result)) {
+					$result = $allow;
+				}
+				break;
+		}
+		if (isset($result)) {
+				// Invert result if this is a deny expresion:
+			if (!$allow) {
+				$result = ($result xor true);
+			}
+				// Cache the result of the current rule:
+			if (!isset($this->rulesProcessed[$row['uid']])) {
+				$this->rulesProcessed[$row['uid']] = $result;
+					// If the result is positive, add it to $this->rulesActive array:
+				if ($result) {
+					$this->rulesActive[] = $row['uid'];
+				}
+			}
+		}
+		return $result;
+	}
+
+	/**
 	 * Initializes the front-end login user.
 	 *
 	 * @return	void
@@ -1326,7 +1413,8 @@
 	 */
 	function setSysPageWhereClause()	{
 		$this->sys_page->where_hid_del.=' AND pages.doktype<200';
-		$this->sys_page->where_groupAccess = $this->sys_page->getMultipleGroupsWhereClause('pages.fe_group', 'pages');
+		$this->sys_page->where_groupAccess = $this->sys_page->getMultipleGroupsWhereClause('pages.fe_group', 'pages', $this->gr_list);
+		$this->sys_page->where_rulesActive = $this->sys_page->getMultipleGroupsWhereClause('pages.fe_group', 'pages', $this->rulesActive);
 	}
 
 	/**
@@ -1945,6 +2033,7 @@
 				'id' => intval($this->id),
 				'type' => intval($this->type),
 				'gr_list' => (string)$this->gr_list,
+				'rulesActive' => implode(',', $this->rulesActive),
 				'MP' => (string)$this->MP,
 				'cHash' => $this->cHash_array
 			)
Index: typo3/sysext/cms/tslib/index_ts.php
===================================================================
--- typo3/sysext/cms/tslib/index_ts.php	(Revision 3468)
+++ typo3/sysext/cms/tslib/index_ts.php	(Arbeitskopie)
@@ -202,6 +202,13 @@
 }
 
 // *********
+// FE_RULES
+// *********
+$TT->push('Front End rules initialized','');
+	$TSFE->initFErules();
+$TT->pull();
+
+// *********
 // FE_USER
 // *********
 $TT->push('Front End user initialized','');
