Index: branches/2.8.x/CHANGELOG
===================================================================
--- branches/2.8.x/CHANGELOG	(revision 1519)
+++ branches/2.8.x/CHANGELOG	(revision 1520)
@@ -12,6 +12,12 @@
 
 =============================== FEATURES FREEZE ================================
 ----------------------------------- Fixes 2.8.2 --------------------------------
+09 Nov-2011 Build 1519 Werner v.d.Decken(DarkViper)
+! /modules/output_filter completely recoded
++ new filter for relative-URL added
++ some small fixes
+! /admin/admintools/tool.php completely recoded
+! /wb/index.php output_filter request changed to adopt new output_filter
 26 Okt-2011 Build 1518 Dietmar Woellbrink (Luisehahne)
 # see http://www.websitebaker2.org/forum/index.php/topic,22649.msg152666.html#msg152666
 24 Okt-2011 Build 1517 Dietmar Woellbrink (Luisehahne)
Index: branches/2.8.x/wb/admin/interface/version.php
===================================================================
--- branches/2.8.x/wb/admin/interface/version.php	(revision 1519)
+++ branches/2.8.x/wb/admin/interface/version.php	(revision 1520)
@@ -52,4 +52,4 @@
 
 // check if defined to avoid errors during installation (redirect to admin panel fails if PHP error/warnings are enabled)
 if(!defined('VERSION')) define('VERSION', '2.8.2');
-if(!defined('REVISION')) define('REVISION', '1518');
+if(!defined('REVISION')) define('REVISION', '1519');
Index: branches/2.8.x/wb/admin/admintools/tool.php
===================================================================
--- branches/2.8.x/wb/admin/admintools/tool.php	(revision 1519)
+++ branches/2.8.x/wb/admin/admintools/tool.php	(revision 1520)
@@ -3,12 +3,11 @@
  *
  * @category        admin
  * @package         admintools
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
+ * @author          WB-Project, Werner v.d. Decken
+ * @copyright       2011, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.8.x
+ * @platform        WebsiteBaker 2.8.2
  * @requirements    PHP 5.2.2 and higher
  * @version         $Id$
  * @filesource		$HeadURL$
@@ -15,46 +14,39 @@
  * @lastmodified    $Date$
  *
  */
-
 require('../../config.php');
 require_once(WB_PATH.'/framework/class.admin.php');
 require_once(WB_PATH.'/framework/functions.php');
 
-if(!isset($_GET['tool'])) {
-	header("Location: index.php");
-	exit(0);
-} else {
-	$array = array();
-	preg_match("/[a-z,_,a-z]+/i",$_GET['tool'],$array);
-	$tool = $array[0];
-}
-
-$ModulesUsingFTAN = '';
-$admin_header =  true;
-if(isset($_POST['save_settings'])) {
-	$ModulesUsingFTAN = WB_PATH.'/modules/'.$tool.'/FTAN_SUPPORTED';
-}
-
-$admin_header = (file_exists($ModulesUsingFTAN) && is_file($ModulesUsingFTAN)) == false;
-$admin = new admin('admintools', 'admintools', $admin_header );
-
-// Check if tool is installed
-$result = $database->query("SELECT * FROM ".TABLE_PREFIX."addons WHERE type = 'module' AND function = 'tool' AND directory = '".preg_replace('/[^a-z0-9_-]/i', "", $tool)."'");
-if($result->numRows() == 0) {
-	header("Location: index.php");
-	exit(0);
-}
-$tools = $result->fetchRow();
-if(!isset($_POST['save_settings'])) {
-
-?>
-<h4>
-	<a href="<?php echo ADMIN_URL; ?>/admintools/index.php"><?php echo $HEADING['ADMINISTRATION_TOOLS']; ?></a>
-	&raquo;
-	<?php echo $tools['name']; ?>
-</h4>
-<?php
-}
-require(WB_PATH.'/modules/'.$tools['directory'].'/tool.php');
-
-$admin->print_footer();
+	$toolDir = (isset($_GET['tool']) && (trim($_GET['tool']) != '') ? trim($_GET['tool']) : '');
+	$doSave = (isset($_POST['save_settings']) || (isset($_POST['action']) && strtolower($_POST['action']) == 'save'));
+// test for valid tool name
+	if(preg_match('/^[a-z][a-z_\-0-9]{2,}$/i', $toolDir)) {
+	// Check if tool is installed
+		$sql = 'SELECT `name` FROM `'.TABLE_PREFIX.'addons` '.
+		       'WHERE `type`=\'module\' AND `function`=\'tool\' '.
+		              'AND `directory`=\''.$toolDir.'\'';
+		if(($toolName = $database->get_one($sql))) {
+		// create admin-object and print header if FTAN is NOT supported AND function 'save' is requested
+			$admin_header = !(is_file(WB_PATH.'/modules/'.$toolDir.'/FTAN_SUPPORTED') && $doSave);
+			$admin = new admin('admintools', 'admintools', $admin_header );
+			if(!$doSave) {
+			// show title if not function 'save' is requested
+				print '<h4><a href="'.ADMIN_URL.'/admintools/index.php" '.
+				      'title="'.$HEADING['ADMINISTRATION_TOOLS'].'">'.
+				      $HEADING['ADMINISTRATION_TOOLS'].'</a>'.
+					  '&raquo'.$toolName.'</h4>'."\n";
+			}
+			// include modules tool.php
+			require(WB_PATH.'/modules/'.$toolDir.'/tool.php');
+			$admin->print_footer();
+		}else {
+		// no installed module found, jump to index.php of admintools
+			header('location: '.ADMIN_URL.'/admintools/index.php');
+			exit(0);
+		}
+	}else {
+	// invalid module name requested, jump to index.php of admintools
+		header('location: '.ADMIN_URL.'/admintools/index.php');
+		exit(0);
+	}
Index: branches/2.8.x/wb/admin/admintools/index.php
===================================================================
--- branches/2.8.x/wb/admin/admintools/index.php	(revision 1519)
+++ branches/2.8.x/wb/admin/admintools/index.php	(revision 1520)
@@ -3,9 +3,8 @@
  *
  * @category        admin
  * @package         admintools
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
+ * @author          WB-Project, Werner v.d. Decken
+ * @copyright       2011, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
  * @platform        WebsiteBaker 2.8.x
Index: branches/2.8.x/wb/index.php
===================================================================
--- branches/2.8.x/wb/index.php	(revision 1519)
+++ branches/2.8.x/wb/index.php	(revision 1520)
@@ -4,8 +4,7 @@
  * @category        frontend
  * @package         page
  * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
+ * @copyright       2009-, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
  * @platform        WebsiteBaker 2.8.x
@@ -130,27 +129,26 @@
    $wb->preprocess($output);
 }
 // Load Droplet engine and process
-if(file_exists(WB_PATH .'/modules/droplets/droplets.php'))
-{
-    include_once(WB_PATH .'/modules/droplets/droplets.php');
-    if(function_exists('evalDroplets'))
-    {
-		$output = evalDroplets($output);
-    }
-}
+	if(file_exists(WB_PATH .'/modules/droplets/droplets.php')) {
+		include_once(WB_PATH .'/modules/droplets/droplets.php');
+		if(function_exists('evalDroplets')) {
+			$output = evalDroplets($output);
+		}
+	}
 // Load backwards compatible frontend filter support and process
-if(file_exists(WB_PATH .'/modules/output_filter/filter-routines.php'))
-{
-    include_once(WB_PATH .'/modules/output_filter/filter-routines.php');
-    if(function_exists('filter_frontend_output'))
-    {
-        $output = filter_frontend_output($output);
-    }
-}
+	if(file_exists(WB_PATH .'/modules/output_filter/filter-routines.php')) {
+		include_once(WB_PATH .'/modules/output_filter/filter-routines.php');
+		if(function_exists('executeFrontendOutputFilter')) {
+			$output = executeFrontendOutputFilter($output);
+		}elseif(function_exists('filter_frontend_output')) {
+			$output = filter_frontend_output($output);
+		}
+
+	}
 // move css definitions into head section
-if(function_exists('moveCssToHead')) {
-	$output = moveCssToHead($output);
-}
+	if(function_exists('moveCssToHead')) {
+		$output = moveCssToHead($output);
+	}
 // now send complete page to the browser
 echo $output;
 // end of wb-script
Index: branches/2.8.x/wb/modules/output_filter/uninstall.php
===================================================================
--- branches/2.8.x/wb/modules/output_filter/uninstall.php	(revision 1519)
+++ branches/2.8.x/wb/modules/output_filter/uninstall.php	(revision 1520)
@@ -3,12 +3,11 @@
  *
  * @category        modules
  * @package         output_filter
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
+ * @author          Christian Sommer, WB-Project, Werner v.d. Decken
+ * @copyright       2009-, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.8.x
+ * @platform        WebsiteBaker 2.8.2
  * @requirements    PHP 5.2.2 and higher
  * @version         $Id$
  * @filesource		$HeadURL$
@@ -15,9 +14,11 @@
  * @lastmodified    $Date$
  *
  */
+/* -------------------------------------------------------- */
+// Must include code to stop this file being accessed directly
+require_once( dirname(dirname(dirname(__FILE__))).'/framework/globalExceptionHandler.php');
+if(!defined('WB_PATH')) { throw new IllegalFileException(); }
+/* -------------------------------------------------------- */
 
-// Must include code to stop this file being access directly
-if(defined('WB_PATH') == false) { die("Cannot access this file directly"); }
-
 $table = TABLE_PREFIX .'mod_output_filter';
 $database->query("DROP TABLE IF EXISTS `$table`");
Index: branches/2.8.x/wb/modules/output_filter/filter-routines.php
===================================================================
--- branches/2.8.x/wb/modules/output_filter/filter-routines.php	(revision 1519)
+++ branches/2.8.x/wb/modules/output_filter/filter-routines.php	(revision 1520)
@@ -3,12 +3,11 @@
  *
  * @category        modules
  * @package         output_filter
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
+ * @author          Christian Sommer, WB-Project, Werner v.d. Decken
+ * @copyright       2011, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.8.x
+ * @platform        WebsiteBaker 2.8.2
  * @requirements    PHP 5.2.2 and higher
  * @version         $Id$
  * @filesource		$HeadURL$
@@ -15,231 +14,221 @@
  * @lastmodified    $Date$
  *
  */
+/* -------------------------------------------------------- */
+// Must include code to stop this file being accessed directly
+require_once( dirname(dirname(dirname(__FILE__))).'/framework/globalExceptionHandler.php');
+if(!defined('WB_PATH')) { throw new IllegalFileException(); }
+/* -------------------------------------------------------- */
 
-// Must include code to stop this file being access directly
-if(defined('WB_PATH') == false) { die("Cannot access this file directly"); }
-
-// function to read the current filter settings
-if (!function_exists('get_output_filter_settings')) {
-	function get_output_filter_settings() {
+/* ************************************************************************** */
+/**
+ * execute the frontend output filter to modify email addresses
+ * @param string actual content
+ * @return string modified content
+ */
+	function executeFrontendOutputFilter($content) {
+		// get output filter settings from database
+		$filter_settings = getOutputFilterSettings();
+		$output_filter_mode = 0;
+		$output_filter_mode |= ($filter_settings['email_filter'] * pow(2, 0));  // n | 2^0
+		$output_filter_mode |= ($filter_settings['mailto_filter'] * pow(2, 1)); // n | 2^1
+		define('OUTPUT_FILTER_AT_REPLACEMENT', $filter_settings['at_replacement']);
+		define('OUTPUT_FILTER_DOT_REPLACEMENT', $filter_settings['dot_replacement']);
+/* ### filter type: full qualified URLs ##################################### */
+        if($filter_settings['sys_rel'] == 1){
+			$content = _doFilterRelUrl($content);
+		}
+/* ### filter type: protect email addresses ################################# */
+		if( ($output_filter_mode & pow(2, 0)) || ($output_filter_mode & pow(2, 1)) ) {
+			$content = _doFilterEmail($content, $output_filter_mode);
+		}
+/* ### end of filters ####################################################### */
+		return $content;
+	}
+/* ************************************************************************** */
+/**
+ * function to read the current filter settings
+ * @global object $database
+ * @global object $admin
+ * @param void
+ * @return array contains all settings
+ */
+	function getOutputFilterSettings() {
 		global $database, $admin;
-	// be sure field is in table (suppresses strict warning)
-		$table_name = TABLE_PREFIX .'mod_output_filter';
-		$field_name = 'sys_rel';
-		$description = 'VARCHAR(1) NOT NULL DEFAULT \'0\'';
-		$msg_flag = ($database->field_add($table_name,$field_name,$description ));
-		// connect to database and read out filter settings
-		$result = $database->query("SELECT * FROM " .TABLE_PREFIX ."mod_output_filter");
-		if($result && $result->numRows() > 0) {
-			// get all data
-			$data = $result->fetchRow();
-			$filter_settings['sys_rel'] = $admin->strip_slashes($data['sys_rel']);
-			$filter_settings['email_filter'] = $admin->strip_slashes($data['email_filter']);
-			$filter_settings['mailto_filter'] = $admin->strip_slashes($data['mailto_filter']);
-			$filter_settings['at_replacement'] = $admin->strip_slashes($data['at_replacement']);
-			$filter_settings['dot_replacement'] = $admin->strip_slashes($data['dot_replacement']);
-		} else {
-			// something went wrong, use default values
-			$filter_settings['sys_rel'] = '0';
-			$filter_settings['email_filter'] = '0';
-			$filter_settings['mailto_filter'] = '0';
-			$filter_settings['at_replacement'] = '(at)';
-			$filter_settings['dot_replacement'] = '(dot)';
+	// set default values
+		$settings = array(
+			'sys_rel'         => 0,
+			'email_filter'    => 0,
+			'mailto_filter'   => 0,
+			'at_replacement'  => '(at)',
+			'dot_replacement' => '(dot)'
+		);
+	// be sure field 'sys_rel' is in table
+		$database->field_add( TABLE_PREFIX.'mod_output_filter', 'sys_rel', 'INT NOT NULL DEFAULT \'0\' FIRST');
+	// request settings from database
+		$sql = 'SELECT * FROM `'.TABLE_PREFIX.'mod_output_filter';
+		if(($res = $database->query($sql))) {
+			if(($rec = $res->fetchRow())) {
+				$settings = $rec;
+				$settings['at_replacement']  = $admin->strip_slashes($settings['at_replacement']);
+				$settings['dot_replacement'] = $admin->strip_slashes($settings['dot_replacement']);
+			}
 		}
-		
-		// return array with filter settings
-		return $filter_settings;
+	// return array with filter settings
+		return $settings;
 	}
-}
-
-// function to filter the output before displaying it on the frontend
-if (!function_exists('filter_frontend_output')) {
-	function filter_frontend_output($content) {
-		// get output filter settings from database
-		$filter_settings = get_output_filter_settings();
-		$location = '';
-		if($filter_settings['sys_rel'] == '1'){
-			if( !isset($_SERVER['HTTPS']) || strtolower($_SERVER['HTTPS']) == 'off' ) {
-				define('SYS_HTTPS', false);
-				define('SYS_PORT', (($_SERVER['SERVER_PORT'] != '80') ? ':'.$_SERVER['SERVER_PORT'] : '') );
-				define('SYS_PROTOCOL', 'http');
-			} else {
-				define('SYS_HTTPS', true);
-				define('SYS_PORT', (($_SERVER['SERVER_PORT'] != '443') ? ':'.$_SERVER['SERVER_PORT'] : '') );
-				define('SYS_PROTOCOL', 'https');
+/* ************************************************************************** */
+/**
+ * Convert full qualified, local URLs into relative URLs
+ * @param string $content
+ * @return string
+ */
+	function _doFilterRelUrl($content) {
+		$content = preg_replace_callback(
+				'/((?:href|src)\s*=\s*")([^\"]*?)(")/iU',
+				create_function('$matches',
+				    '$retval = $matches[0]; '.
+		            '$h = parse_url($matches[2], PHP_URL_HOST); '.
+		            'if(stripos(WB_URL, $h) !== false) { '.
+		            '$a = parse_url($matches[2]); '.
+		            '$p = (isset($a[\'path\']) ? $a[\'path\'] : \'\'); '.
+		            '$q = (isset($a[\'query\']) ? \'?\'.$a[\'query\'] : \'\'); '.
+		            '$f = (isset($a[\'fragment\']) ? \'#\'.$a[\'fragment\'] : \'\'); '.
+		            '$p .= ($q.$f); '.
+		            '$retval = $matches[1]."/".(isset($p) ? ltrim(str_replace("//", "/", $p), "/") : "").$matches[3]; '.
+		            '} '.
+		            'return $retval;'),
+		        $content);
+		return $content;
+	}
+/* ************************************************************************** */
+/**
+ * protect email addresses (replace '@' and '.' and obfuscate address
+ * @param string $content
+ * @return string
+ */
+	function _doFilterEmail($content, $output_filter_mode) {
+	// test if js-decryption is installed
+		if( preg_match('/<head.*<.*src=\".*\/mdcr.js.*>.*<\/head/siU', $content) ) {
+			$output_filter_mode |= pow(2, 2); // n | 2^2
+		}else {
+		// try to insert js-decrypt into <head> if available
+			$script = str_replace('\\', '/', dirname(__FILE__)).'/js/mdcr.js';
+			if(is_readable($script)) {
+				$scriptLink = '<script src="'.$script.'" type="text/javascript"></script>';
+				$regex = '/(.*)(<\s*?\/\s*?head\s*>.*)/isU';
+				$replace = '$1<script src="'.$scriptLink.'" type="text/javascript"></script>$2';
+				$content = preg_replace ($regex, $replace, $content);
+				$output_filter_mode |= pow(2, 2); // n | 2^2
 			}
-			$tmp = '';
-			if( isset($_SERVER['HTTP_HOST']) ) {
-				$tmp = $_SERVER['HTTP_HOST'];
-			} elseif( isset($_SERVER['SERVER_NAME']) ) {
-				$tmp = $_SERVER['SERVER_NAME'];
-			}
-
-			define('WB_HOST', preg_replace('/:[0-9]*$/', '', $tmp));
-			$location = SYS_PROTOCOL.'://'.WB_HOST.SYS_PORT;
-			$searchfor = '/(<.*?=\s*?\")(?:'.preg_quote($location, '/').'\/?)(.*?\".*?>)/i';
-			$content = preg_replace($searchfor, '$1/$2', $content);
-			$content = preg_replace('/(<.*?(?:href|src)\s*=\s*?\")(\".*?>)/i', '$1/$2', $content);
-
 		}
-
+	// define some constants so we do not call the database in the callback functions again
+		define('OUTPUT_FILTER_MODE', (int)$output_filter_mode);
+/* *** obfuscate mailto addresses by js:mdcr *** */
 		// work out the defined output filter mode: possible output filter modes: [0], 1, 2, 3, 6, 7
 		// 2^0 * (0.. disable, 1.. enable) filtering of mail addresses in text
 		// 2^1 * (0.. disable, 1.. enable) filtering of mail addresses in mailto links
 		// 2^2 * (0.. disable, 1.. enable) Javascript mailto encryption (only if mailto filtering enabled)
 
-		// only filter output if we are supposed to
-		if($filter_settings['email_filter'] != '1' && $filter_settings['mailto_filter'] != '1'){
-			// do nothing more
-			return $content;
-		}
-
-		// check if non mailto mail addresses needs to be filtered
-		$output_filter_mode = ($filter_settings['email_filter'] == '1') ? 1 : 0;		// 0|1
-
-		// check if mailto mail addresses needs to be filtered
-		if($filter_settings['mailto_filter'] == '1') {
-			$output_filter_mode = $output_filter_mode + 2;								// 0|2
-
-			// check if Javascript mailto encryption is enabled (call register_frontend_functions in the template)
-           $search_pattern = '/<.*src=\".*\/mdcr.js.*>/iU';
-           if(preg_match($search_pattern, $content))
-           {
-            $output_filter_mode = $output_filter_mode + 4;       // 0|4
-           }
-/*
-			$search = '<script src="' .WB_URL .'/modules/output_filter/js/mdcr.js" type="text/javascript"></script>';
-			$search_droplet = '<script src="' .WB_URL .'/modules/droplets/js/mdcr.js" type="text/javascript"></script>';
-			if(strpos($content, $search) !== false || strpos($content, $search_droplet) !== false) {
-				$output_filter_mode = $output_filter_mode + 4;							// 0|4
-			}
-*/
-		}
-		
-		// define some constants so we do not call the database in the callback function again
-		define('OUTPUT_FILTER_MODE', (int) $output_filter_mode);
-		define('OUTPUT_FILTER_AT_REPLACEMENT', $filter_settings['at_replacement']);
-		define('OUTPUT_FILTER_DOT_REPLACEMENT', $filter_settings['dot_replacement']);
-		
 		// first search part to find all mailto email addresses
 		$pattern = '#(<a[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})([^"]*?)"([^>]*>)(.*?)</a>';
 		// second part to find all non mailto email addresses
 		$pattern .= '|(value\s*=\s*"|\')??\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b#i';
-		/*
-		Sub 1:\b(<a.[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)			-->	"<a id="yyy" class="xxx" href = " mailto :" ignoring white spaces
-		Sub 2:([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})			-->	the email address in the mailto: part of the mail link
-		Sub 3:([^"]*?)"												--> possible ?Subject&cc... stuff attached to the mail address
-		Sub 4:([^>]*>)												--> all class or id statements after the mailto but before closing ..>
-		Sub 5:(.*?)</a>\b											--> the mailto text; all characters between >xxxxx</a>
-		Sub 6:|\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b		--> email addresses which may appear in the text (require word boundaries)
-		*/
-			
+/*
+	Sub 1:\b(<a.[^<]*href\s*?=\s*?"\s*?mailto\s*?:\s*?)			-->	"<a id="yyy" class="xxx" href = " mailto :" ignoring white spaces
+	Sub 2:([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})			-->	the email address in the mailto: part of the mail link
+	Sub 3:([^"]*?)"												--> possible ?Subject&cc... stuff attached to the mail address
+	Sub 4:([^>]*>)												--> all class or id statements after the mailto but before closing ..>
+	Sub 5:(.*?)</a>\b											--> the mailto text; all characters between >xxxxx</a>
+	Sub 6:|\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b		--> email addresses which may appear in the text (require word boundaries)
+*/
 		// find all email addresses embedded in the content and filter them using a callback function
-		$content = preg_replace_callback($pattern, 'filter_mail_addresses', $content);
-		// href can't be empty
-		$searchfor = '/(<.*?=\s*?\")(?:'.preg_quote($location, '/').')(.*?\".*?>)/i';
-		$content = preg_replace($searchfor, '$1$2', $content);
+		$content = preg_replace_callback($pattern, '_cbDoExecuteFilter', $content);
 		return $content;
 	}
-}		
-
-
-// function to filter mail addresses embedded in text or mailto links before outputing them on the frontend
-if (!function_exists('filter_mail_addresses')) {
-	function filter_mail_addresses($match) { 
-		
-		// check if required output filter mode is defined
-		if(!(defined('OUTPUT_FILTER_MODE') && defined('OUTPUT_FILTER_MODE') && defined('OUTPUT_FILTER_MODE'))) {
+/* ************************************************************************** */
+/**
+ * callback-function for function _doFilterEmail() to proceed search results
+ * @param array results from preg_replace
+ * @return string proceeded replacement string
+ */
+	function _cbDoExecuteFilter($match) {
+		// check if required arguments are defined
+		if(!( defined('OUTPUT_FILTER_MODE')
+		      && defined('OUTPUT_FILTER_AT_REPLACEMENT')
+		      && defined('OUTPUT_FILTER_MODE')
+    	    ) ) {
 			return $match[0];
 		}
-		
 		$search = array('@', '.');
 		$replace = array(OUTPUT_FILTER_AT_REPLACEMENT ,OUTPUT_FILTER_DOT_REPLACEMENT);
-		
 		// check if the match contains the expected number of subpatterns (6|8)
-		if(count($match) == 8) {
-			/**
-				OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN TEXT
-			**/
-			
+		switch (count($match)) {
+			case 8:
+			/** OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN TEXT **/
 			// 1.. text mails only, 3.. text mails + mailto (no JS), 7 text mails + mailto (JS)
-			if(!in_array(OUTPUT_FILTER_MODE, array(1,3,7))) return $match[0];
-
-			// do not filter mail addresses included in input tags (<input ... value = "test@mail)
-			if (strpos($match[6], 'value') !== false) return $match[0];
-			
-			// filtering of non mailto email addresses enabled
-			return str_replace($search, $replace, $match[0]);
-				
-		} elseif(count($match) == 6) {
-			/**
-				OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN MAILTO LINKS
-			**/
-
+				if(!in_array(OUTPUT_FILTER_MODE, array(1,3,7))) return $match[0];
+				// do not filter mail addresses included in input tags (<input ... value = "test@mail)
+				if (strpos($match[6], 'value') !== false) return $match[0];
+				// filtering of non mailto email addresses enabled
+				return str_replace($search, $replace, $match[0]);
+			break;
+			case 6:
+			/** OUTPUT FILTER FOR EMAIL ADDRESSES EMBEDDED IN MAILTO LINKS **/
 			// 2.. mailto only (no JS), 3.. text mails + mailto (no JS), 6.. mailto only (JS), 7.. all filters active
-			if(!in_array(OUTPUT_FILTER_MODE, array(2,3,6,7))) return $match[0];
-			
-			// check if last part of the a href link: >xxxx</a> contains a email address we need to filter
-			$pattern = '#[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}#i';
-			if(preg_match_all($pattern, $match[5], $matches)) {
-				foreach($matches as $submatch) {
-					foreach($submatch as $value) {
+				if(!in_array(OUTPUT_FILTER_MODE, array(2,3,6,7))) return $match[0];
+				// check if last part of the a href link: >xxxx</a> contains a email address we need to filter
+				$pattern = '#[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}#i';
+				if(preg_match_all($pattern, $match[5], $matches)) {
+					foreach($matches as $submatch) {
+						foreach($submatch as $value) {
 						// replace all . and all @ in email address parts by (dot) and (at) strings
-						$match[5] = str_replace($value, str_replace($search, $replace, $value), $match[5]);
+							$match[5] = str_replace($value, str_replace($search, $replace, $value), $match[5]);
+						}
 					}
 				}
-			}
-
-			// check if Javascript encryption routine is enabled
-			if(in_array(OUTPUT_FILTER_MODE, array(6,7))) {
+				// check if Javascript encryption routine is enabled
+				if(in_array(OUTPUT_FILTER_MODE, array(6,7))) {
 				/** USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
-				
 				// extract possible class and id attribute from ahref link
-				preg_match('/class\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $class_attr);
-				$class_attr = empty($class_attr) ? '' : 'class="' . $class_attr[2] . '" ';
-				preg_match('/id\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $id_attr);
-				$id_attr = empty($id_attr) ? '' : 'id="' . $id_attr[2] . '" ';
-				
+					preg_match('/class\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $class_attr);
+					$class_attr = empty($class_attr) ? '' : 'class="' . $class_attr[2] . '" ';
+					preg_match('/id\s*?=\s*?("|\')(.*?)\1/ix', $match[0], $id_attr);
+					$id_attr = empty($id_attr) ? '' : 'id="' . $id_attr[2] . '" ';
 				// preprocess mailto link parts for further usage
-				$search = array('@', '.', '_', '-'); $replace = array('F', 'Z', 'X', 'K');
-				$email_address = str_replace($search, $replace, strtolower($match[2]));
-				$email_subject = rawurlencode(html_entity_decode($match[3]));
-				
+					$search = array('@', '.', '_', '-'); $replace = array('F', 'Z', 'X', 'K');
+					$email_address = str_replace($search, $replace, strtolower($match[2]));
+					$email_subject = rawurlencode(html_entity_decode($match[3]));
 				// create a random encryption key for the Caesar cipher
-				mt_srand((double)microtime()*1000000);	// (PHP < 4.2.0)
-				$shift = mt_rand(1, 25);
-				
+					mt_srand((double)microtime()*1000000);	// (PHP < 4.2.0)
+					$shift = mt_rand(1, 25);
 				// encrypt the email using an adapted Caesar cipher
-		  		$encrypted_email = "";
-				for($i = strlen($email_address) -1; $i > -1; $i--) {
-					if(preg_match('#[FZXK0-9]#', $email_address[$i], $characters)) {
-						$encrypted_email .= $email_address[$i];
-					} else {	
-						$encrypted_email .= chr((ord($email_address[$i]) -97 + $shift) % 26 + 97);
+					$encrypted_email = "";
+					for($i = strlen($email_address) -1; $i > -1; $i--) {
+						if(preg_match('#[FZXK0-9]#', $email_address[$i], $characters)) {
+							$encrypted_email .= $email_address[$i];
+						} else {
+							$encrypted_email .= chr((ord($email_address[$i]) -97 + $shift) % 26 + 97);
+						}
 					}
-				}
-				$encrypted_email .= chr($shift + 97);
-
+					$encrypted_email .= chr($shift + 97);
 				// build the encrypted Javascript mailto link
-				$mailto_link  = "<a {$class_attr}{$id_attr}href=\"javascript:mdcr('$encrypted_email','$email_subject')\">" .$match[5] ."</a>";
-				
-				return $mailto_link;	
-
-			} else {
+					$mailto_link  = "<a {$class_attr}{$id_attr}href=\"javascript:mdcr('$encrypted_email','$email_subject')\">" .$match[5] ."</a>";
+					return $mailto_link;
+				} else {
 				/** DO NOT USE JAVASCRIPT ENCRYPTION FOR MAILTO LINKS **/
-
-				// as minimum protection, replace replace @ in the mailto part by (at)
+				// as minimum protection, replace @ in the mailto part by (at)
 				// dots are not transformed as this would transform my.name@domain.com into: my(dot)name(at)domain(dot)com
-				
 				// rebuild the mailto link from the subpatterns (at the missing characters " and </a>")
-				return $match[1] .str_replace('@', OUTPUT_FILTER_AT_REPLACEMENT, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
+					return $match[1] .str_replace('@', OUTPUT_FILTER_AT_REPLACEMENT, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
 				// if you want to protect both, @ and dots, comment out the line above and remove the comment from the line below
 				// return $match[1] .str_replace($search, $replace, $match[2]) .$match[3] .'"' .$match[4] .$match[5] .'</a>';
-			}
-		
+				}
+			break;
+			default:
+		// number of subpatterns do not match the requirements ... do nothing
+				return $match[0];
+			break;
 		}
-		
-		// number of subpatterns do not match the requirements ... do nothing
-		return $match[0];
-	}		
-}
+	}
+/* ************************************************************************** */
Index: branches/2.8.x/wb/modules/output_filter/info.php
===================================================================
--- branches/2.8.x/wb/modules/output_filter/info.php	(revision 1519)
+++ branches/2.8.x/wb/modules/output_filter/info.php	(revision 1520)
@@ -4,11 +4,10 @@
  * @category        modules
  * @package         output_filter
  * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
+ * @copyright       2011, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.8.x
+ * @platform        WebsiteBaker 2.8.2
  * @requirements    PHP 5.2.2 and higher
  * @version         $Id$
  * @filesource		$HeadURL$
@@ -19,8 +18,8 @@
 $module_directory = 'output_filter';
 $module_name = 'Frontend Output Filter';
 $module_function = 'tool';
-$module_version	= '0.2';
-$module_platform = '2.7 | 2.8.x';
-$module_author = 'Christian Sommer (doc)';
+$module_version	= '0.3';
+$module_platform = '2.8.2';
+$module_author = 'Christian Sommer(doc), WB-Project, Werner v.d. Decken(DarkViper)';
 $module_license = 'GNU General Public License';
 $module_description = 'This module allows to filter the output before displaying it on the frontend. Support for filtering mailto links and mail addresses in strings.';
Index: branches/2.8.x/wb/modules/output_filter/tool.php
===================================================================
--- branches/2.8.x/wb/modules/output_filter/tool.php	(revision 1519)
+++ branches/2.8.x/wb/modules/output_filter/tool.php	(revision 1520)
@@ -3,12 +3,11 @@
  *
  * @category        modules
  * @package         output_filter
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
+ * @author          Christian Sommer, WB-Project, Werner v.d. Decken
+ * @copyright       2011-, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.8.x
+ * @platform        WebsiteBaker 2.8.2
  * @requirements    PHP 5.2.2 and higher
  * @version         $Id$
  * @filesource		$HeadURL$
@@ -15,67 +14,69 @@
  * @lastmodified    $Date$
  *
  */
+/* -------------------------------------------------------- */
+// Must include code to stop this file being accessed directly
+require_once( dirname(dirname(dirname(__FILE__))).'/framework/globalExceptionHandler.php');
+if(!defined('WB_PATH')) { throw new IllegalFileException(); }
+/* -------------------------------------------------------- */
 
-// Must include code to stop this file being access directly
-if(defined('WB_PATH') == false) { die("Cannot access this file directly"); }
-
-// check if module language file exists for the language set by the user (e.g. DE, EN)
-$MOD_MAIL_FILTER['WARNING']	= '<p style="color: red; line-height:1.5em;"><strong>Warning: </strong>This function is now available as a Droplet. The next major release of website baker will not include this filter anymore. Please concider using the <a href="?tool=droplets">Droplet</a> [[EmailFilter]]</p>';
-if(!file_exists(WB_PATH .'/modules/output_filter/languages/'.LANGUAGE .'.php')) {
-	// no module language file exists for the language set by the user, include default module language file EN.php
-	require_once(WB_PATH .'/modules/output_filter/languages/EN.php');
-} else {
-	// a module language file exists for the language defined by the user, load it
-	require_once(WB_PATH .'/modules/output_filter/languages/'.LANGUAGE .'.php');
-}
+	$modPath = str_replace('\\', '/', dirname(__FILE__)).'/';
+	$msgTxt = '';
+	$msgCls = 'msg-box';
+// include the modules language definitions
+	if(!is_readable($modPath.'languages/'.LANGUAGE .'.php')) {
+		require_once($modPath.'languages/EN.php');
+	} else {
+		require_once($modPath.'languages/'.LANGUAGE .'.php');
+	}
 // check if data was submitted
-if(isset($_POST['save_settings'])) {
-	
-	if (!$admin->checkFTAN())
-	{
-		if(!$admin_header) { $admin->print_header(); }
-		$admin->print_error($MESSAGE['GENERIC_SECURITY_ACCESS'],$_SERVER['REQUEST_URI'],false);
+	if($doSave) {
+	// take over post - arguments
+		$data = array();
+		$data['sys_rel']       = (int)(intval(isset($_POST['sys_rel']) ? $_POST['sys_rel'] : 0) != 0);
+		$data['email_filter']  = (int)(intval(isset($_POST['email_filter']) ? $_POST['email_filter'] : 0) != 0);
+		$data['mailto_filter'] = (int)(intval(isset($_POST['mailto_filter']) ? $_POST['mailto_filter'] : 0) != 0);
+		$data['at_replacement']  = isset($_POST['at_replacement']) ? trim(strip_tags($_POST['at_replacement'])) : '';
+		$data['dot_replacement'] = isset($_POST['dot_replacement']) ? trim(strip_tags($_POST['dot_replacement'])) : '';
+		if ($admin->checkFTAN()) {
+		// update database settings
+			$sql = 'UPDATE `'.TABLE_PREFIX.'mod_output_filter` SET '.
+					  '`email_filter`='.$data['email_filter'].', '.
+					  '`sys_rel`='.$data['sys_rel'].', '.
+					  '`mailto_filter`='.$data['mailto_filter'].', '.
+					  '`at_replacement`=\''.mysql_real_escape_string($data['at_replacement']).'\', '.
+					  '`dot_replacement`=\''.mysql_real_escape_string($data['dot_replacement']).'\'';
+			if($database->query($sql)) {
+			//anything ok
+				$msgTxt = $MESSAGE['RECORD_MODIFIED_SAVED'];
+				$msgCls = 'msg-box';
+			}else {
+			// database error
+				$msgTxt = $MESSAGE['RECORD_MODIFIED_FAILED'];
+				$msgCls = 'error-box';
+			}
+		}else {
+		// FTAN error
+			$msgTxt = $MESSAGE['GENERIC_SECURITY_ACCESS'];
+			$msgCls = 'error-box';
+		}
+	}else {
+	// read settings from the database to show
+		require_once($modPath.'filter-routines.php');
+		$data = getOutputFilterSettings();
 	}
-	// get overall output filter settings
-	$sys_rel = (isset($_POST['sys_rel']) && $_POST['sys_rel'] == '1') ? '1' : '0';
-	$email_filter = (isset($_POST['email_filter']) && $_POST['email_filter'] == '1') ? '1' : '0';
-	$mailto_filter = (isset($_POST['mailto_filter']) && $_POST['mailto_filter'] == '1') ? '1' : '0';
-	
-	// get email replacement settings
-	$at_replacement = isset($_POST['at_replacement']) ?strip_tags($_POST['at_replacement']) : '';
-	$at_replacement = (strlen(trim($at_replacement)) > 0) ? $admin->add_slashes($at_replacement) : '(at)';
-	$dot_replacement = isset($_POST['dot_replacement']) ?strip_tags($_POST['dot_replacement']) : '';
-	$dot_replacement = (strlen(trim($dot_replacement)) > 0) ? $admin->add_slashes($dot_replacement) : '(dot)';
-	
-	// update database settings
-	$database->query("UPDATE " .TABLE_PREFIX ."mod_output_filter SET email_filter = '$email_filter',
-		sys_rel = '$sys_rel', mailto_filter = '$mailto_filter', at_replacement = '$at_replacement', dot_replacement = '$dot_replacement'");
-
-	// check if there is a database error, otherwise say successful
+	// write out header if needed
 	if(!$admin_header) { $admin->print_header(); }
-	if($database->is_error()) {
-		$admin->print_error($database->get_error(), $js_back);
-	} else {
-		$admin->print_success($MESSAGE['PAGES']['SAVED'], ADMIN_URL.'/admintools/tool.php?tool=output_filter');
+	if( $msgTxt != '') {
+	// write message box if needed
+		echo '<div class="'.$msgCls.'">'.$msgTxt.'</div>';
 	}
-
-} else {
-}
-	// write out heading
-	echo '<h2>' .$MOD_MAIL_FILTER['HEADING'] .'</h2>';
-
-	// include filter functions
-	require_once(WB_PATH .'/modules/output_filter/filter-routines.php');
-	
-	// read the mail filter settings from the database
-	$data = get_output_filter_settings();
-	
-	// output the form with values from the database
-	echo '<p>' .$MOD_MAIL_FILTER['HOWTO'] .'</p>';
-	echo $MOD_MAIL_FILTER['WARNING'];
 ?>
+<h2><?php echo $MOD_MAIL_FILTER['HEADING']; ?></h2>
+<p><?php echo $MOD_MAIL_FILTER['HOWTO']; ?></p>
 <form name="store_settings" action="<?php echo $_SERVER['REQUEST_URI'];?>" method="post">
-<?php echo $admin->getFTAN(); ?>
+	<?php echo $admin->getFTAN(); ?>
+	<input type="hidden" name="action" value="save" />
 	<table width="98%" cellspacing="0" cellpadding="5px" class="row_a">
 	<tr><td colspan="2"><strong><?php echo $MOD_MAIL_FILTER['BASIC_CONF'];?>:</strong></td></tr>
 	<tr>
@@ -117,5 +118,5 @@
 			name="dot_replacement"/></td>
 	</tr>
 	</table>
-	<input type="submit" name="save_settings" style="margin-top:10px; width:140px;" value="<?php echo $TEXT['SAVE']; ?>" />
-</form>
+	<input type="submit" style="margin-top:10px; width:140px;" value="<?php echo $TEXT['SAVE']; ?>" />
+</form>
\ No newline at end of file
Index: branches/2.8.x/wb/modules/output_filter/install.php
===================================================================
--- branches/2.8.x/wb/modules/output_filter/install.php	(revision 1519)
+++ branches/2.8.x/wb/modules/output_filter/install.php	(revision 1520)
@@ -3,12 +3,11 @@
  *
  * @category        modules
  * @package         output_filter
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
- * @copyright       2009-2011, Website Baker Org. e.V.
+ * @author          Christian Sommer, WB-Project, Werner v.d. Decken
+ * @copyright       2011-, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.8.x
+ * @platform        WebsiteBaker 2.8.2
  * @requirements    PHP 5.2.2 and higher
  * @version         $Id$
  * @filesource		$HeadURL$
@@ -15,15 +14,17 @@
  * @lastmodified    $Date$
  *
  */
+/* -------------------------------------------------------- */
+// Must include code to stop this file being accessed directly
+require_once( dirname(dirname(dirname(__FILE__))).'/framework/globalExceptionHandler.php');
+if(!defined('WB_PATH')) { throw new IllegalFileException(); }
+/* -------------------------------------------------------- */
 
-// Must include code to stop this file being access directly
-if(defined('WB_PATH') == false) { die("Cannot access this file directly"); }
-
 $table = TABLE_PREFIX .'mod_output_filter';
 $database->query("DROP TABLE IF EXISTS `$table`");
 
 $database->query("CREATE TABLE `$table` (
-	`sys_rel` VARCHAR(1) NOT NULL DEFAULT '0',
+	`sys_rel` INT NOT NULL DEFAULT '0',
 	`email_filter` VARCHAR(1) NOT NULL DEFAULT '0',
 	`mailto_filter` VARCHAR(1) NOT NULL DEFAULT '0',
 	`at_replacement` VARCHAR(255) NOT NULL DEFAULT '(at)',
Index: branches/2.8.x/wb/modules/output_filter/index.php
===================================================================
--- branches/2.8.x/wb/modules/output_filter/index.php	(revision 1519)
+++ branches/2.8.x/wb/modules/output_filter/index.php	(revision 1520)
@@ -3,12 +3,11 @@
  *
  * @category        modules
  * @package         output_filter
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
+ * @author          Christian Sommer, WB-Project, Werner v.d. Decken
  * @copyright       2009-2011, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.8.x
+ * @platform        WebsiteBaker 2.8.2
  * @requirements    PHP 5.2.2 and higher
  * @version         $Id$
  * @filesource		$HeadURL$
Index: branches/2.8.x/wb/modules/output_filter/upgrade.php
===================================================================
--- branches/2.8.x/wb/modules/output_filter/upgrade.php	(revision 1519)
+++ branches/2.8.x/wb/modules/output_filter/upgrade.php	(revision 1520)
@@ -3,12 +3,11 @@
  *
  * @category        modules
  * @package         output_filter
- * @author          WebsiteBaker Project
- * @copyright       2004-2009, Ryan Djurovich
+ * @author          Christian Sommer, WB-Project, Werner v.d. Decken
  * @copyright       2009-2011, Website Baker Org. e.V.
  * @link			http://www.websitebaker2.org/
  * @license         http://www.gnu.org/licenses/gpl.html
- * @platform        WebsiteBaker 2.8.x
+ * @platform        WebsiteBaker 2.8.2
  * @requirements    PHP 5.2.2 and higher
  * @version         $Id$
  * @filesource		$HeadURL$
@@ -15,9 +14,11 @@
  * @lastmodified    $Date$
  *
  */
-
-// Must include code to stop this file being access directly
-if(defined('WB_PATH') == false) { die("Cannot access this file directly"); }
+/* -------------------------------------------------------- */
+// Must include code to stop this file being accessed directly
+require_once( dirname(dirname(dirname(__FILE__))).'/framework/globalExceptionHandler.php');
+if(!defined('WB_PATH')) { throw new IllegalFileException(); }
+/* -------------------------------------------------------- */
 global $i;
 $table_name = TABLE_PREFIX .'mod_output_filter';
 $field_name = 'sys_rel';
@@ -30,7 +31,7 @@
 if ( ($database->field_exists($table_name,$field_name) )) {
 		print "<br /><strong>'Output Filter already updated'</strong> $OK<br />\n";
 } else {
-	$description = 'VARCHAR(1) NOT NULL DEFAULT \'0\'';
+	$description = 'INT NOT NULL DEFAULT \'0\' FIRST';
 	if( ($database->field_add($table_name,$field_name,$description )) ) {
 		print "<br /><strong>Updating Output Filter</strong> $OK<br />\n";
 	} else {
