Index: branches/5.2.x/core/kernel/processors/main_processor.php
===================================================================
--- branches/5.2.x/core/kernel/processors/main_processor.php	(revision 16272)
+++ branches/5.2.x/core/kernel/processors/main_processor.php	(revision 16273)
@@ -1,1290 +1,1301 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license      GNU/GPL
 * In-Portal is Open Source software.
 * This means that this software may have been modified pursuant
 * the GNU General Public License, and as distributed it includes
 * or is derivative of works licensed under the GNU General Public License
 * or other free or open source software licenses.
 * See http://www.in-portal.org/license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class kMainTagProcessor extends kTagProcessor {
 
 	public function __construct()
 	{
 		parent::__construct();
 
 		$actions = $this->Application->recallObject('kActions');
 		/* @var $actions Params */
 
 		$actions->Set('t', $this->Application->GetVar('t'));
 		$actions->Set('sid', $this->Application->GetSID());
 		$actions->Set('m_opener', $this->Application->GetVar('m_opener') );
 	}
 
 	/**
 	 * Base folder for all template includes
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function TemplatesBase($params)
 	{
 		static $cached = Array ();
 
 		$cache_key = crc32( serialize($params) );
 
 		if (!array_key_exists($cache_key, $cached)) {
 			$module = array_key_exists('module', $params) ? $params['module'] : 'core';
 
 			if ($this->Application->isAdmin) {
 				if ($module == 'in-portal') {
 					$module = 'kernel';
 				}
 
 				// remove leading slash + substitute module
 				$module_path = $this->Application->findModule('Name', $module, 'Path');
 
 				if ($module_path !== false) {
 					$path = $module_path . 'admin_templates';
 				}
 				else {
 					// remove leading slash + substitute module
 					$path = preg_replace('/\/(.*?)\/(.*)/', $module . '/\\2', THEMES_PATH);
 				}
 			}
 			else {
 				$path = mb_substr(THEMES_PATH, 1);
 
 				if (mb_strtolower($module) == 'in-portal') {
 					$module_folder = 'platform';
 				}
 				else {
 					$module_folder = $this->Application->findModule('Name', $module, 'TemplatePath');
 				}
 
 				$path .= rtrim('/' . trim($module_folder, '/'), '/') . '/';
 			}
 
 			$cached[$cache_key] = $this->Application->BaseURL() . $path;
 		}
 
 		return $cached[$cache_key];
 	}
 
 	/**
 	 * Creates <base href ..> HTML tag for all templates
 	 * affects future css, js files and href params of links
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 * @see kMainTagProcessor::TemplatesBase
 	 */
 	protected function Base_Ref($params)
 	{
 		// tag TemplatesBase adds trailing "/" but only on Front-End
 		$base_href = rtrim($this->TemplatesBase($params), '/');
 
 		return '<base href="' . $base_href . '/" />';
 	}
 
 	/**
 	 * Returns base url for web-site
 	 *
 	 * @return string
 	 * @access public
 	 */
 	function BaseURL()
 	{
 		return $this->Application->BaseURL();
 	}
 
 	//for compatability with K3 tags
 	function Base($params)
 	{
 		return $this->TemplatesBase($params).'/';
 	}
 
 	function ProjectBase($params)
 	{
 		return $this->Application->BaseURL();
 	}
 
 	/*function Base($params)
 	{
 		return $this->Application->BaseURL().$params['add'];
 	}*/
 
 	/**
 	 * Used to create link to any template.
 	 * use "pass" paramter if "t" tag to specify
 	 * prefix & special of object to be represented
 	 * in resulting url
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function T($params)
 	{
 		// by default link to current template
 		$template = $this->SelectParam($params, 't,template');
 		$prefix = array_key_exists('prefix', $params) ? $params['prefix'] : '';
 
 		unset($params['t'], $params['template'], $params['prefix']);
 
 		return $this->Application->HREF($template, $prefix, $params);
 	}
 
 	function Link($params)
 	{
 		// pass "m" prefix, instead of "all", that is by default on Front-End
 		if (!array_key_exists('pass', $params)) {
 			$params['pass'] = 'm';
 		}
 
 		return $this->T($params);
 	}
 
 	/**
 	 * Performs redirect to provided template/url
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function Redirect($params)
 	{
-		$this->Application->Redirect('external:' . $this->Link($params));
+		// By default link to current template.
+		$template = $this->SelectParam($params, 't,template');
+		$prefix = array_key_exists('prefix', $params) ? $params['prefix'] : '';
+
+		unset($params['t'], $params['template'], $params['prefix']);
+
+		// Pass "m" prefix, instead of "all", that is by default on Front-End.
+		if ( !array_key_exists('pass', $params) ) {
+			$params['pass'] = 'm';
+		}
+
+		$this->Application->Redirect($template, $params, $prefix);
 
 		return '';
 	}
 
 	/*function Env($params)
 	{
 		$t = $params['template'];
 		unset($params['template']);
 		return $this->Application->BuildEnv($t, $params, 'm', false, false);
 	}*/
 
 	function FormAction($params)
 	{
 		if (!array_key_exists('pass', $params)) {
 			$params['pass'] = 'all,m';
 		}
 
 		$params['pass_category'] = 1;
 
 		return $this->Application->HREF('', '', $params);
 	}
 
 	/*// NEEDS TEST
 	function Config($params)
 	{
 		return $this->Application->ConfigOption($params['var']);
 	}
 
 	function Object($params)
 	{
 		$name = $params['name'];
 		$method = $params['method'];
 
 		$tmp = $this->Application->recallObject($name);
 		if ($tmp != null) {
 			if (method_exists($tmp, $method))
 				return $tmp->$method($params);
 			else
 				echo "Method $method does not exist in object ".get_class($tmp)." named $name<br>";
 		}
 		else
 			echo "Object $name does not exist in the appliaction<br>";
 	}*/
 
 	/**
 	 * Tag, that always returns true.
 	 * For parser testing purposes
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function True($params)
 	{
 		return true;
 	}
 
 	/**
 	 * Tag, that always returns false.
 	 * For parser testing purposes
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function False($params)
 	{
 		return false;
 	}
 
 	/**
 	 * Returns block parameter by name (used only as "check" parameter value for "m_if" tag!)
 	 *
 	 * @param Array $params
 	 * @return stirng
 	 * @access public
 	 */
 	function Param($params)
 	{
 		$name = $params['name'];
 
 		if (array_key_exists($name, $this->Application->Parser->Captures)) {
 			$capture_params = $params;
 			$capture_params['name'] = '__capture_' . $name;
 
 			$this->Application->Parser->SetParam($name, $this->Application->ParseBlock($capture_params));
 		}
 
 		$res = $this->Application->Parser->GetParam($name);
 
 		if ($res === false) {
 			$res = '';
 		}
 
 		if (array_key_exists('plus', $params)) {
 			$res += $params['plus'];
 		}
 
 		return $res;
 	}
 
 	/**
 	 * Compares block parameter with value specified
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function ParamEquals($params)
 	{
 		$name = $this->SelectParam($params, 'name,var,param');
 		$value = $params['value'];
 
 		return ($this->Application->Parser->GetParam($name) == $value);
 	}
 
 	/*function PHP_Self($params)
 	{
 		return $HTTP_SERVER_VARS['PHP_SELF'];
 	}
 	*/
 
 	/**
 	 * Returns session variable value by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Recall($params)
 	{
 		$var_name = $this->SelectParam($params,'name,var,param');
 
 		if (isset($params['persistent']) && $params['persistent']) {
 			$ret = $this->Application->RecallPersistentVar($var_name);
 		}
 		else {
 			 $ret = $this->Application->RecallVar($var_name);
 		}
 
 		$ret = ($ret === false && isset($params['no_null'])) ? '' : $ret;
 		if (getArrayValue($params, 'special') || getArrayValue($params, 'htmlchars')) {
 			$ret = kUtil::escape($ret, kUtil::ESCAPE_HTML);
 		}
 
 		if (getArrayValue($params, 'urlencode')) {
 			$ret = kUtil::escape($ret, kUtil::ESCAPE_URL);
 		}
 
 		return $ret;
 	}
 
 	function RemoveVar($params)
 	{
 		$this->Application->RemoveVar( $this->SelectParam($params,'name,var,param') );
 	}
 
 	// bad style to store something from template to session !!! (by Alex)
 	// Used here only to test how session works, nothing more
 	function Store($params)
 	{
 		//echo"Store $params[name]<br>";
 		$name = $params['name'];
 		$value = $params['value'];
 		$this->Application->StoreVar($name,$value);
 	}
 
 	/**
 	 * Links variable from request with variable from session
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function LinkVar($params)
 	{
 		$var_name = $params['name'];
 		$session_var_name = isset($params['session_name']) ? $params['session_name'] : $var_name;
 		$default_value = isset($params['default']) ? $params['default'] : '';
 
 		$this->Application->LinkVar($var_name, $session_var_name, $default_value);
 
 		return '';
 	}
 
 	/**
 	 * Links variable from request with variable from session and returns it's value
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function GetLinkedVar($params)
 	{
 		$this->LinkVar($params);
 
 		return $this->Application->GetVar( $params['name'] );
 	}
 
 	/**
 	 * Sets application variable value(-s)
 	 *
 	 * @param Array $params
 	 * @access public
 	 */
 	function Set($params)
 	{
 		foreach ($params as $param => $value) {
 			$this->Application->SetVar($param, $value);
 		}
 	}
 
 	/**
 	 * Increment application variable
 	 * specified by number specified
 	 *
 	 * @param Array $params
 	 * @access public
 	 */
 	function Inc($params)
 	{
 		$this->Application->SetVar($params['param'], $this->Application->GetVar($params['param']) + $params['by']);
 	}
 
 	/**
 	 * Retrieves application variable
 	 * value by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Get($params)
 	{
 		$name = $this->SelectParam($params, 'name,var,param');
 
 		if ( strpos($name, '[') !== false ) {
 			preg_match('/([^\[\]]+)\[(.*)\]/', $name, $regs);
 
 			$function_params = explode('][', $regs[2]);
 			$ret = $this->Application->GetVar($regs[1], array());
 			kUtil::array_unshift_ref($function_params, $ret);
 
 			$ret = call_user_func_array('getArrayValue', $function_params);
 		}
 		else {
 			$ret = $this->Application->GetVar($name, '');
 		}
 
 		if ( array_key_exists('no_html_escape', $params) && $params['no_html_escape'] ) {
 			return $this->Application->isAdmin ? $ret : kUtil::unescape($ret, kUtil::ESCAPE_HTML);
 		}
 
 		return kUtil::escape($ret, kUtil::ESCAPE_HTML);
 	}
 
 	/**
 	 * Retrieves application constant
 	 * value by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function GetConst($params)
 	{
 		$constant_name = $this->SelectParam($params, 'name,const');
 
 		return defined($constant_name) ? constant($constant_name) : '';
 	}
 
 	/**
 	 * Retrieves configuration variable value by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function GetConfig($params)
 	{
 		$config_name = $this->SelectParam($params, 'name,var');
 		$ret = $this->Application->ConfigValue($config_name);
 
 		if ( isset($params['formatted']) && $params['formatted'] ) {
 			$sql = 'SELECT ValueList
 					FROM ' . TABLE_PREFIX . 'SystemSettings
 					WHERE VariableName = ' . $this->Conn->qstr($config_name) . ' AND ElementType IN ("select", "radio")';
 			$value_list = $this->Conn->GetOne($sql);
 
 			if ( $value_list ) {
 				$helper = $this->Application->recallObject('InpCustomFieldsHelper');
 				/* @var $helper InpCustomFieldsHelper */
 
 				$options = $helper->GetValuesHash($value_list);
 				$ret = isset($options[$ret]) ? $options[$ret] : $ret;
 			}
 		}
 
 		if ( isset($params['as_label']) && $params['as_label'] ) {
 			$ret = $this->Application->Phrase($ret);
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Compares configuration variable to a given value
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @deprecated
 	 * @access protected
 	 */
 	protected function ConfigEquals($params)
 	{
 		$option = $this->SelectParam($params, 'name,option,var');
 
 		return $this->Application->ConfigValue($option) == $params['value'];
 	}
 
 	/**
 	 * Creates all hidden fields
 	 * needed for kernel_form
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function DumpSystemInfo($params)
 	{
 		$actions = $this->Application->recallObject('kActions');
 		/* @var $actions Params */
 
 		$actions->Set('t', $this->Application->GetVar('t'));
 
 		$o = '';
 		$params = $actions->GetParams();
 
 		foreach ($params AS $name => $val) {
 			$o .= "<input type='hidden' name='$name' id='$name' value='$val'>\n";
 		}
 
 		return $o;
 	}
 
 	/**
 	 * Used for search sidebox on front-end only
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function GetFormHiddens($params)
 	{
 		$t = $this->SelectParam($params, 'template,t');
 		unset($params['template']);
 
 		$form_fields = Array ();
 		if ( $this->Application->RewriteURLs() ) {
 			$session = $this->Application->recallObject('Session');
 			/* @var $session Session */
 
 			if ( $session->NeedQueryString() ) {
 				$form_fields['sid'] = $this->Application->GetSID();
 			}
 		}
 		else {
 			$form_fields['env'] = $this->Application->BuildEnv($t, $params, 'm', false, false);
 		}
 
 		if ( $this->Application->GetVar('admin') == 1 ) {
 			$form_fields['admin'] = 1;
 		}
 
 		$ret = '';
 		$field_tpl = '<input type="hidden" name="%1$s" id="%1$s" value="%2$s"/>' . "\n";
 		foreach ($form_fields as $form_field => $field_value) {
 			$ret .= sprintf($field_tpl, $form_field, $field_value);
 		}
 
 		return $ret;
 	}
 
 	function Odd_Even($params)
 	{
 		$odd = $params['odd'];
 		$even = $params['even'];
 		if (!isset($params['var'])) {
 			$var = 'odd_even';
 		}
 		else {
 			$var = $params['var'];
 		}
 
 		if ($this->Application->GetVar($var) == 'even') {
 			if (!isset($params['readonly']) || !$params['readonly']) {
 				$this->Application->SetVar($var, 'odd');
 			}
 			return $even;
 		}
 		else {
 			if (!isset($params['readonly']) || !$params['readonly']) {
 				$this->Application->SetVar($var, 'even');
 			}
 			return $odd;
 		}
 	}
 
 	/**
 	 * Returns phrase translation by name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Phrase($params)
 	{
 		$phrase_name = $this->SelectParam($params, 'label,name,title');
 		$default_translation = $this->SelectParam($params, 'default');
 
 		$no_editing = isset($params['no_editing']) && $params['no_editing'];
 		$translation = $this->Application->Phrase($phrase_name, !$no_editing);
 
 		$phrase_key = mb_strtoupper($phrase_name);
 
 		if ( $default_translation && strpos($translation, '!' . $phrase_key . '!') !== false ) {
 			$phrase = $this->Application->recallObject('phrases.autocreate', null, Array ('skip_autoload' => true));
 			/* @var $phrase kDBItem */
 
 			if ( !$phrase->Load($phrase_key, 'PhraseKey') ) {
 				$phrase->SetDBField('Phrase', $phrase_name);
 
 				$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
 				/* @var $ml_helper kMultiLanguageHelper */
 
 				$languages = $ml_helper->getLanguages();
 
 				foreach ($languages AS $language_id) {
 					$phrase->SetDBField('l' . $language_id . '_Translation', $default_translation);
 				}
 
 				if ( $phrase->Create() ) {
 					$translation = $default_translation;
 				}
 			}
 		}
 
 		if ( isset($params['escape']) && $params['escape'] ) {
 			// html escaping here is redundant
 			$translation = kUtil::escape($translation, kUtil::ESCAPE_JS);
 		}
 
 		return $translation;
 	}
 
 	// for tabs
 	function is_active($params)
 	{
 		$test_templ = $this->SelectParam($params, 'templ,template,t');
 		if ( !getArrayValue($params, 'allow_empty') ) {
 			$if_true = getArrayValue($params, 'true') ? $params['true'] : 1;
 			$if_false = getArrayValue($params, 'false') ? $params['false'] : 0;
 		}
 		else {
 			$if_true = $params['true'];
 			$if_false = $params['false'];
 		}
 
 		$physical_template = $this->Application->getPhysicalTemplate($this->Application->GetVar('t'));
 
 		return preg_match('/^' . str_replace('/', '\/', $test_templ) . '/i', $physical_template) ? $if_true : $if_false;
 	}
 
 	function IsNotActive($params)
 	{
 		return !$this->is_active($params);
 	}
 
 	function IsActive($params)
 	{
 		return $this->is_active($params);
 	}
 
 	function is_t_active($params)
 	{
 		return $this->is_active($params);
 	}
 
 	function CurrentTemplate($params)
 	{
 		return $this->is_active($params);
 	}
 
 	/**
 	 * Checks if session variable
 	 * specified by name value match
 	 * value passed as parameter
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function RecallEquals($params)
 	{
 		$name = $this->SelectParam($params, 'name,var');
 		$value = $params['value'];
 
 		if (isset($params['persistent']) && $params['persistent']) {
 			return $this->Application->RecallPersistentVar($name) == $value;
 		}
 
 		return ($this->Application->RecallVar($name) == $value);
 	}
 
 	/**
 	 * Checks if application variable specified by name value match value passed as parameter
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access protected
 	 * @deprecated
 	 */
 	protected function GetEquals($params)
 	{
 		$name = $this->SelectParam($params, 'var,name,param');
 
 		return $this->Application->GetVar($name) == $params['value'];
 	}
 
 	function ModuleInclude($params)
 	{
 		$ret = '';
 		$included = Array ();
 		$block_params = array_merge($params, Array ('is_silent' => 2)); // don't make fatal errors in case if template is missing
 		$current_template = $this->Application->GetVar('t');
 
 		$replace_main = isset($params['replace_m']) && $params['replace_m'];
 		$skip_prefixes = isset($params['skip_prefixes']) ? explode(',', $params['skip_prefixes']) : Array ();
 		$cms_mode = $this->Application->GetVar('admin');
 
 		foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
 			$module_key = mb_strtolower($module_name);
 
 			if ( $module_name == 'In-Portal' ) {
 				if ( !$cms_mode && $this->Application->isAdmin ) {
 					// don't process In-Portal templates in admin
 					continue;
 				}
 
 				// Front-End still relies on In-Portal module
 				$module_prefix = $module_data['TemplatePath'];
 			}
 			elseif ( $this->Application->isAdmin && $module_data['Path'] != 'core/' ) {
 				$module_prefix = $module_key . '/'; // was $module_data['Path'];
 			}
 			else {
 				$module_prefix = $module_data['TemplatePath']; // always have trailing "/"
 			}
 
 			if ( in_array($module_prefix, $included) ) {
 				// template by this path was already included by other module (e.g. in-portal used core's template)
 				continue;
 			}
 
 			$block_params['t'] = $module_prefix . $this->SelectParam($params, $module_key . '_template,' . $module_key . '_t,template,t');
 
 			$check_prefix = $module_data['Var'];
 
 			if ( $check_prefix == 'adm' && $replace_main ) {
 				$check_prefix = 'c';
 			}
 
 			if ( $block_params['t'] == $current_template || in_array($check_prefix, $skip_prefixes) ) {
 				continue;
 			}
 
 			$no_data = $this->SelectParam($params, $module_key . '_block_no_data,block_no_data');
 			if ( $no_data ) {
 				$block_params['block_no_data'] = $module_prefix . '/' . $no_data;
 			}
 
 			$ret .= $this->Application->IncludeTemplate($block_params);
 			$included[] = $module_prefix;
 		}
 
 		return $ret;
 	}
 
 	function ModuleEnabled($params)
 	{
 		return $this->Application->isModuleEnabled( $params['module'] );
 	}
 
 	/**
 	 * Checks if debug mode is on
 	 *
 	 * @param Array $params
 	 * @return bool
 	 * @access public
 	 */
 	function IsDebugMode($params)
 	{
 		return defined('DEBUG_MODE') && $this->Application->isDebugMode();
 	}
 
 	/*function MassParse($params)
 	{
 		$qty = $params['qty'];
 		$block = $params['block'];
 		$mode = $params['mode'];
 
 		$o = '';
 		if ($mode == 'func') {
 			$func = create_function('$params', '
 					$o = \'<tr>\';
 					$o.= \'<td>a\'.$params[\'param1\'].\'</td>\';
 					$o.= \'<td>a\'.$params[\'param2\'].\'</td>\';
 					$o.= \'<td>a\'.$params[\'param3\'].\'</td>\';
 					$o.= \'<td>a\'.$params[\'param4\'].\'</td>\';
 					$o.= \'</tr>\';
 					return $o;
 				');
 			for ($i=1; $i<$qty; $i++) {
 				$block_params['param1'] = rand(1, 10000);
 				$block_params['param2'] = rand(1, 10000);
 				$block_params['param3'] = rand(1, 10000);
 				$block_params['param4'] = rand(1, 10000);
 				$o .= $func($block_params);
 			}
 			return $o;
 		}
 
 		$block_params['name'] = $block;
 
 		for ($i=0; $i<$qty; $i++) {
 			$block_params['param1'] = rand(1, 10000);
 			$block_params['param2'] = rand(1, 10000);
 			$block_params['param3'] = rand(1, 10000);
 			$block_params['param4'] = rand(1, 10000);
 			$block_params['passed'] = $params['passed'];
 			$block_params['prefix'] = 'm';
 
 			$o.= $this->Application->ParseBlock($block_params);
 		}
 		return $o;
 	}*/
 
 	function LoggedIn($params)
 	{
 		return $this->Application->LoggedIn();
 	}
 
 	/**
 	 * Allows to check if permission exists directly in template and perform additional actions if required
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function CheckPermission($params)
 	{
 		$perm_helper = $this->Application->recallObject('PermissionsHelper');
 		/* @var $perm_helper kPermissionsHelper */
 
 		return $perm_helper->TagPermissionCheck($params);
 	}
 
 	/**
 	 * Checks if user is logged in and if not redirects it to template passed
 	 *
 	 * @param Array $params
 	 */
 	function RequireLogin($params)
 	{
 		$t = $this->Application->GetVar('t');
 		$next_t = getArrayValue($params, 'next_template');
 
 		if ( $next_t ) {
 			$t = $next_t;
 		}
 
 		// check by permissions: begin
 		if ((isset($params['perm_event']) && $params['perm_event']) ||
 			(isset($params['perm_prefix']) && $params['perm_prefix']) ||
 			(isset($params['permissions']) && $params['permissions'])) {
 
 			$perm_helper = $this->Application->recallObject('PermissionsHelper');
 			/* @var $perm_helper kPermissionsHelper */
 
 			$perm_status = $perm_helper->TagPermissionCheck($params);
 			if (!$perm_status) {
 				list($redirect_template, $redirect_params) = $perm_helper->getPermissionTemplate($params);
 				$this->Application->Redirect($redirect_template, $redirect_params);
 			}
 			else {
 				return ;
 			}
 		}
 		// check by permissions: end
 
 		// check by configuration value: begin
 		$condition = getArrayValue($params, 'condition');
 		if (!$condition) {
 			$condition = true;
 		}
 		else {
 			if (substr($condition, 0, 1) == '!') {
 				$condition = !$this->Application->ConfigValue(substr($condition, 1));
 			}
 			else {
 				$condition = $this->Application->ConfigValue($condition);
 			}
 		}
 		// check by configuration value: end
 
 		// check by belonging to group: begin
 		$group = $this->SelectParam($params, 'group');
 		$group_access = true;
 		if ($group) {
 			$sql = 'SELECT GroupId
 					FROM '.TABLE_PREFIX.'UserGroups
 					WHERE Name = '.$this->Conn->qstr($group);
 			$group_id = $this->Conn->GetOne($sql);
 
 			if ($group_id) {
 				$groups = explode(',', $this->Application->RecallVar('UserGroups'));
 				$group_access = in_array($group_id, $groups);
 			}
 		}
 		// check by belonging to group: end
 
 		if ((!$this->Application->LoggedIn() || !$group_access) && $condition) {
 			$redirect_params = $this->Application->HttpQuery->getRedirectParams(true);
 
 			if (MOD_REWRITE) {
 				// TODO: $next_t variable is ignored !!! (is anyone using m_RequireLogin tag with "next_template" parameter?)
 				$redirect_params = Array (
 					'm_cat_id' => 0,
 					'next_template' => kUtil::escape('external:' . $_SERVER['REQUEST_URI'], kUtil::ESCAPE_URL),
 				);
 			}
 			else {
 				$redirect_params['next_template'] = $t;
 			}
 
 			if (array_key_exists('pass_category', $params)) {
 				$redirect_params['pass_category'] = $params['pass_category'];
 			}
 
 			if (array_key_exists('use_section', $params)) {
 				$redirect_params['use_section'] = $params['use_section'];
 			}
 
 			if ( $this->Application->LoggedIn() && !$group_access) {
 				$this->Application->Redirect($params['no_group_perm_template'], $redirect_params);
 			}
 
 			$this->Application->Redirect($params['login_template'], $redirect_params);
 		}
 	}
 
 	/**
 	 * Checks, that user belongs to a group with a given name
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	protected function IsMember($params)
 	{
 		$sql = 'SELECT GroupId
 				FROM ' . TABLE_PREFIX . 'UserGroups
 				WHERE Name = ' . $this->Conn->qstr($params['group']);
 		$group_id = $this->Conn->GetOne($sql);
 
 		if ( $group_id ) {
 			$groups = explode(',', $this->Application->RecallVar('UserGroups'));
 
 			return in_array($group_id, $groups);
 		}
 
 		return false;
 	}
 
 	/**
 	 * Checks if SSL is on and redirects to SSL URL if needed
 	 * If SSL_URL is not defined in config - the tag does not do anything
 	 * If for_logged_in_only="1" exits if user is not logged in.
 	 * If called without params forces https right away. If called with by_config="1" checks the
 	 * Require SSL setting from General Config and if it is ON forces https
 	 *
 	 * @param Array $params
 	 */
 	protected function CheckSSL($params)
 	{
 		$ssl = $this->Application->isAdmin ? $this->Application->ConfigValue('AdminSSL_URL') : false;
 
 		if ( !$ssl ) {
 			// not in admin or admin ssl url is empty
 			$ssl_url = $this->Application->siteDomainField('SSLUrl');
 			$ssl = $ssl_url !== false ? $ssl_url : $this->Application->ConfigValue('SSL_URL');
 		}
 
 		if ( !$ssl || ($this->Application->TemplatesCache->forceThemeName !== false) ) {
 			// SSL URL is not set - no way to require SSL
 			// internal parsing (e.g. "TemplateParser::_parseTemplate") -> don't redirect
 			return;
 		}
 
 		$require = false;
 
 		if ( isset($params['mode']) && $params['mode'] == 'required' ) {
 			$require = true;
 			if ( isset($params['for_logged_in_only']) && $params['for_logged_in_only'] && !$this->Application->LoggedIn() ) {
 				$require = false;
 			}
 
 			if ( isset($params['condition']) ) {
 				if ( !$this->Application->ConfigValue($params['condition']) ) {
 					$require = false;
 				}
 			}
 		}
 
 		if ( EDITING_MODE ) {
 			// match SSL mode on front-end to one in administrative console, when browse modes are used
 			$require = $this->Application->ConfigValue('Require_AdminSSL');
 		}
 
 		$http_query = $this->Application->recallObject('HTTPQuery');
 		/* @var $http_query kHTTPQuery */
 
 		$pass = $http_query->getRedirectParams();
 		$pass['pass_events'] = 1; // to make sure all events are passed when redirect happens
 
 		if ( $require ) {
 			if ( PROTOCOL == 'https://' ) {
 				$this->Application->SetVar('__KEEP_SSL__', 1);
 				return;
 			}
 
 			$pass['__SSL__'] = 1;
 			$this->Application->Redirect('', $pass);
 		}
 		else {
 			if ( PROTOCOL == 'https://' && $this->Application->ConfigValue('Force_HTTP_When_SSL_Not_Required') ) {
 				if ( $this->Application->GetVar('__KEEP_SSL__') ) {
 					return;
 				}
 
 				// $pass_more = Array ('pass' => 'm', 'm_cat_id' => 0, '__SSL__' => 0);
 				$pass['__SSL__'] = 0;
 				$this->Application->Redirect('', $pass); // $pass_more
 			}
 		}
 	}
 
 	function ConstOn($params)
 	{
 		$name = $this->SelectParam($params,'name,const');
 		return kUtil::constOn($name);
 	}
 
 	function SetDefaultCategory($params)
 	{
 		$category_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
 		$this->Application->SetVar('m_cat_id', $category_id);
 	}
 
 	function XMLTemplate($params)
 	{
 		$this->NoDebug($params);
 
 		if ( isset($params['cache']) && $params['cache'] ) {
 			$nextyear = intval(date('Y') + 1);
 
 			$format = "D, d M Y H:i:s";
 			$expiration = gmdate($format, time() + $params['cache']) . ' GMT';
 			$last_modified = time();
 
 			header('Cache-Control: public, cache, max-age=' . $params['cache']);
 			header("Expires: $expiration");
 			header('Pragma: public');
 
 			// Getting headers sent by the client.
 			$headers = $this->_requestHeaders();
 
 			// Checking if the client is validating his cache and if it is current.
 			if ( isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) > $last_modified - $params['cache']) ) {
 				// Client's cache IS current, so we just respond '304 Not Modified'.
 				header('Last-Modified: ' . date($format, strtotime($headers['If-Modified-Since'])) . ' GMT', true, 304);
 				exit;
 			}
 			else {
 				// Image not cached or cache outdated, we respond '200 OK' and output the image.
 				header('Last-Modified: ' . gmdate($format, $last_modified) . ' GMT', true, 200);
 			}
 		}
 
 		// xml documents are usually long
 		kUtil::setResourceLimit();
 
 		if ( !$this->Application->GetVar('debug') ) {
 			return $this->Application->XMLHeader(getArrayValue($params, 'xml_version'));
 		}
 
 		return '';
 	}
 
 	protected function _requestHeaders()
 	{
 		if ( function_exists('apache_request_headers') ) {
 			// If apache_request_headers() exists...
 			$headers = apache_request_headers();
 
 			if ($headers) {
 				return $headers; // And works... Use it
 			}
 		}
 
 		$headers = Array ();
 
 		foreach (array_keys($_SERVER) as $skey) {
 			if (substr($skey, 0, 5) == 'HTTP_') {
 				$headername = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($skey, 0, 5)))));
 				$headers[$headername] = $_SERVER[$skey];
 			}
 		}
 
 		return $headers;
 	}
 
 	function Header($params)
 	{
 		header($params['data']);
 	}
 
 	function NoDebug($params)
 	{
 		if ( !$this->Application->GetVar('debug') ) {
 			kUtil::safeDefine('DBG_SKIP_REPORTING', 1);
 		}
 	}
 
 	/**
 	 * Returns Home category name
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @deprecated
 	 */
 	function RootCategoryName($params)
 	{
 		$no_editing = array_key_exists('no_editing', $params) && $params['no_editing'];
 
 		return $this->Application->Phrase('la_rootcategory_name', !$no_editing);
 	}
 
 	/**
 	 * Allows to attach file directly from email event template
 	 *
 	 * @param Array $params
 	 */
 	function AttachFile($params)
 	{
 		$path = FULL_PATH . '/' . $params['path'];
 		$pseudo = isset($params['special']) ? 'EmailSender.' . $params['special'] : 'EmailSender';
 
 		$esender = $this->Application->recallObject($pseudo);
 		/* @var $esender kEmailSendingHelper */
 
 		if ( file_exists($path) ) {
 			$esender->AddAttachment($path);
 		}
 	}
 
 	function CaptchaImage($params)
 	{
 		$this->NoDebug($params);
 		$this->Application->SetVar('skip_last_template', 1);
 
 		$captcha_helper = $this->Application->recallObject('CaptchaHelper');
 		/* @var $captcha_helper kCaptchaHelper */
 
 		// generate captcha code
 		$code = $captcha_helper->prepareCode( $this->Application->GetVar('var') );
 
 		$captcha_helper->GenerateCaptchaImage($code, $this->Application->GetVar('w'), $this->Application->GetVar('h'), true);
 	}
 
 	function SID($params)
 	{
 		return $this->Application->GetSID();
 	}
 
 	function ModuleInfo($params)
 	{
 		return $this->Application->findModule($params['key'], $params['value'], $params['return']);
 	}
 
 	function Random($params)
 	{
 		return rand(1, 100000000);
 	}
 
 	/**
 	 * Prints parser params, available at current deep level
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function PrintCurrentParams($params)
 	{
 		$current_params = $this->Application->Parser->Params;
 
 		foreach ($current_params as $param_name => $param_value) {
 			if ( is_object($param_value) && !method_exists($param_value, '__toString') ) {
 				$param_value = 'ClassName: ' . get_class($param_value);
 			}
 
 			$current_params[$param_name] = $param_name . ' = "' . $param_value . '"';
 		}
 
 		return '<pre>' . implode("\n", $current_params) . '</pre>';
 	}
 
 	/**
 	 * Gets previously defined counter result
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function GetCounter($params)
 	{
 		return $this->Application->getCounter($params['name'], $params);
 	}
 
 	/**
 	 * Increments PageHit counter
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function RegisterPageHit($params)
 	{
 		if ($this->Application->ConfigValue('UsePageHitCounter')) {
 			// get current counte
 			$sql = 'SELECT VariableValue
 					FROM '.TABLE_PREFIX.'SystemSettings
 					WHERE VariableName = "PageHitCounter"';
 			$page_counter = (int)$this->Conn->GetOne($sql);
 
 			$sql = 'UPDATE LOW_PRIORITY '.TABLE_PREFIX.'SystemSettings
 					SET VariableValue = '.($page_counter + 1).'
 					WHERE VariableName = "PageHitCounter"';
 			$this->Conn->Query($sql);
 		}
 	}
 
 	function Timestamp($params)
 	{
 		$format = isset($params['format']) ? $params['format'] : 'd.m.Y H:i:s';
 		return adodb_date($format);
 	}
 
 	function GetUrlHiddenFileds($params)
 	{
 		$vars = Array ('page', 'per_page', 'sort_by');
 		$ret = '<input type="hidden" name="main_list" value="1"/>';
 
 		if (array_key_exists('skip', $params)) {
 			$vars = array_diff($vars, $params['skip']);
 		}
 
 		foreach ($vars as $var_name) {
 			$var_value = $this->Application->GetVar($var_name);
 
 			if ($var_value) {
 				$ret .= '<input type="hidden" name="' . $var_name . '" value="' . $var_value . '"/>';
 			}
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Returns current Page URL (without re-assembling it).
 	 * "skip_query" param is optional and will remove the ?QUERY part from the result.
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function CurrentPageLink($params)
 	{
 		if ( isset($params['skip_query']) && $params['skip_query'] ) {
 			return preg_replace('/\?' . preg_quote($_SERVER['QUERY_STRING'], '/') . '$/', '', $_SERVER['REQUEST_URI']);
 		}
 
 		return $_SERVER['REQUEST_URI'];
 	}
 
 	/**
 	 * Returns current maintenance mode state
 	 *
 	 * @param Array $params
 	 * @return int
 	 * @access protected
 	 */
 	protected function MaintenanceMode($params)
 	{
 		$check_ips = isset($params['check_ips']) ? $params['check_ips'] : true;
 
 		return $this->Application->getMaintenanceMode($check_ips);
 	}
 
 	/**
 	 * Checks if element with given name is defined
 	 *
 	 * @param Array $params
 	 * @return int
 	 * @access protected
 	 */
 	protected function ElementDefined($params)
 	{
 		return $this->Application->Parser->blockFound($params['name']);
 	}
 }