<?php
/**
* @version	$Id: main_processor.php 13336 2010-04-06 08:07:25Z alex $
* @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 {

	function Init($prefix, $special, $event_params = null)
	{
		parent::Init($prefix, $special, $event_params);

		$actions =& $this->Application->recallObject('kActions');
		$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)) {
			$force_admin = array_key_exists('force_admin', $params) && $params['force_admin'];
			$module = array_key_exists('module', $params) ? $params['module'] : 'core';

			if ($this->Application->isAdmin || $force_admin) {
				if ($module == 'in-portal') {
					$module = 'kernel';
				}

				$path = $force_admin ? '/core/admin_templates' : THEMES_PATH;
				$path = preg_replace('/\/(.*?)\/(.*)/', $module.'/\\2', $path); // remove leading slash + substitute module
			}
			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
	 *
	 * @return string
	 * @access public
	 */
	function Base_Ref($params)
	{
		return '<base href="'.$this->TemplatesBase($params).'/" />';
	}

	/**
	 * 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);
	}

	function Env($params)
	{
		$t = $params['template'];
		unset($params['template']);
		return $this->Application->BuildEnv($t, $params, 'm', null, false);
	}

	function FormAction($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 = htmlspecialchars($ret);
		}

		if (getArrayValue($params, 'urlencode')) {
			$ret = urlencode($ret);
		}

		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);
	}

	/**
	 * 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)
	{
		$ret = $this->Application->GetVar($this->SelectParam($params, 'name,var,param'), '');
		return getArrayValue($params, 'htmlchars') ? htmlspecialchars($ret) : $ret;
	}

	/**
	 * 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( getArrayValue($params, 'escape') ) $ret = addslashes($ret);
		return $ret;
	}

	function ConfigEquals($params)
	{
		$option = $this->SelectParam($params, 'name,option,var');
		return $this->Application->ConfigValue($option) == getArrayValue($params, 'value');
	}

	/**
	 * Creates all hidden fields
	 * needed for kernel_form
	 *
	 * @param Array $params
	 * @return string
	 * @access public
	 */
	function DumpSystemInfo($params)
	{
		$actions =& $this->Application->recallObject('kActions');
		$actions->Set('t', $this->Application->GetVar('t') );

		$params = $actions->GetParams();
		$o='';
		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
	 * @author Alex
	 */
	function GetFormHiddens($params)
	{
		$t = $this->SelectParam($params, 'template,t');
		unset($params['template']);

		$form_fields = Array ();
		if ($this->Application->RewriteURLs()) {
			$session =& $this->Application->recallObject('Session');
			if ($session->NeedQueryString()) {
				$form_fields['sid'] = $this->Application->GetSID();
			}
		}
		else {
			$form_fields['env'] = $this->Application->BuildEnv($t, $params, 'm', null, 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');
		$no_editing = array_key_exists('no_editing', $params) && $params['no_editing'];
		$translation = $this->Application->Phrase($phrase_name, !$no_editing);

		if (isset($params['escape']) && $params['escape']) {
			$translation = htmlspecialchars($translation, ENT_QUOTES);
			$translation = addslashes($translation);
		}
		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'];
		}

		if ( preg_match("/^".str_replace('/', '\/', $test_templ)."/i", $this->Application->GetVar('t'))) {
			return $if_true;
		}
		else {
			return $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 public
	 */
	function GetEquals($params)
	{
		$name = $this->SelectParam($params, 'var,name,param');

		$value = $params['value'];
		if ($this->Application->GetVar($name) == $value) {
			return 1;
		}
	}

	function ModuleInclude($params)
	{
		$ret = '';
		$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');

		$included = Array ();

		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_prefix = $module_data['Path']; // was $module_key . '/';
			}
			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');
		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');
		if ($next_t = getArrayValue($params, 'next_template')) {
			$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) {
			$conn =& $this->Application->GetADODBConnection();
			$group_id = $conn->GetOne('SELECT GroupId FROM '.TABLE_PREFIX.'PortalGroup WHERE Name = '.$conn->qstr($group));
			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 (array_key_exists('pass_category', $params)) {
				$redirect_params['pass_category'] = $params['pass_category'];
			}

			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' => urlencode('external:' . $_SERVER['REQUEST_URI']),
				);
			}
			else {
				$redirect_params['next_template'] = $t;
			}

			if ( $this->Application->LoggedIn() && !$group_access) {
				$this->Application->Redirect($params['no_group_perm_template'], $redirect_params);
			}

			$this->Application->Redirect($params['login_template'], $redirect_params);
		}
	}

	function IsMember($params)
	{
		$group = getArrayValue($params, 'group');
		$conn =& $this->Application->DB;
		$group_id = $conn->GetOne('SELECT GroupId FROM '.TABLE_PREFIX.'PortalGroup WHERE Name = '.$conn->qstr($group));
		if ($group_id) {
			$groups = explode(',', $this->Application->RecallVar('UserGroups'));
			$group_access = in_array($group_id, $groups);
		}
		return $group_access;
	}

	/**
	 * 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 unknown_type $params
	 */
	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 = $this->Application->ConfigValue('SSL_URL');
		}

		if (!$ssl) return; //SSL URL is not set - no way to require SSL

		$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;
				}
			}
		}

		$http_query =& $this->Application->recallObject('HTTPQuery');
		$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;
			}
			$this->Application->Redirect('', array_merge_recursive2($pass, Array('__SSL__' => 1)));
		}
		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);
				$this->Application->Redirect('', array_merge_recursive2($pass, Array('__SSL__' => 0))); // $pass_more
			}
		}
	}

	function ConstOn($params)
	{
		$name = $this->SelectParam($params,'name,const');
		return 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)
	{
		safeDefine('DBG_SKIP_REPORTING', 1);

		if (isset($params['cache']) && $params['cache']) {
			$nextyear = intval(date('Y') + 1);

			$format = "D, d M Y H:i:s";
			$expiration = gmdate($format, mktime() + $params['cache']).' GMT';
			$last_modified = mktime();

			header ('Cache-Control: public, cache, max-age='.$params['cache']);
			header ("Expires: $expiration");
			header ('Pragma: public');

			// Getting headers sent by the client.
			$headers = request_headers();

			// 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
		set_time_limit(0);
		ini_set('memory_limit', -1);

		return $this->Application->XMLHeader(getArrayValue($params, 'xml_version'));
	}

	function Header($params)
	{
		header($params['data']);
	}

	function NoDebug($params)
	{
		if (!$this->Application->GetVar('debug')) {
			define('DBG_SKIP_REPORTING', 1);
		}
	}

	function RootCategoryName($params)
	{
		$phrase_name = $this->Application->ConfigValue('Root_Name');
		$no_editing = array_key_exists('no_editing', $params) && $params['no_editing'];

		return $this->Application->Phrase($phrase_name, !$no_editing);
	}

	/**
	 * Allows to attach file directly from email event template
	 *
	 * @param Array $params
	 */
	function AttachFile($params)
	{
		$esender =& $application->recallObject('EmailSender'.(isset($params['special']) ? '.'.$params['special'] : ''));
		/* @var $esender kEmailSendingHelper */

		$path = FULL_PATH.'/'.$params['path'];
		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) {
			$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')) {
			$db =& $this->Application->GetADODBConnection();

			// get current counte
			$sql = 'SELECT VariableValue
					FROM '.TABLE_PREFIX.'ConfigurationValues
					WHERE VariableName = "PageHitCounter"';
			$page_counter = (int)$db->GetOne($sql);

			$sql = 'UPDATE LOW_PRIORITY '.TABLE_PREFIX.'ConfigurationValues
					SET VariableValue = '.($page_counter + 1).'
					WHERE VariableName = "PageHitCounter"';
			$db->Query($sql);
		}
	}

	function Timestamp($params)
	{
		$format = isset($params['format']) ? $params['format'] : 'd.m.Y H:i:s';
		return adodb_date($format);
	}
}
