#!/usr/bin/perl
#use strict;
#
# WTG Zebra (C) XXI, White Tiger Group
# http://www.wtg.ru/
# http://www.wtg.ru/zebra/
# -----------------------------------
# E-mail:  zebra@wtg.ru
#          support@wtg.ru
#
#
# Zebra Site
# Головной модуль Zebra Site
# V.0.14 (0143, 12/01/2004)

# ВВЕДЕНИЕ
# ========================================================================
#      Данный модуль Zebra служит для вывода страниц, зарегистрированных в
# базе страниц сайта, в соответствии с некоторыми дополнительными условиями.
# Он может учитывать списки избранных ресурсов, группы страниц, закрытых
# паролем от несанкционированного доступа, а также некоторые другие моменты.
# Модуль выбирает страницу, запрошенную пользователем, интерполирует ее
# согласно установленным условиям и ключам, меняет соответственно некоторые
# параметры, увеличивает счетчики и регистрирует прочие данные.
#      Поскольку данный модуль наиболее показательно использует предоставляемые
# ядром Zebra возможности, он является также примером, на основе которого
# возможно сделать любой другой модуль к Zebra для решения специфических
# задач. В целях осмысленного использования процедур модуль ZS подробно
# откомментирован.

# 1. ОРГАНИЗАЦИЯ МОДУЛЕЙ РАСШИРЕНИЯ
# ========================================================================
#      Модули расширения Zebra рекомендуется организовывать следующим образом.
# В качестве базового модуля выбирается скрипт, выполняющий основную нагрузку
# расширения. В нашем случае это 'zs.cgi'. Вспомогательные модули -
# административный и оверлейный. Административный модуль реализует все
# административные и управленческие функции администратора, при этом модуль
# должен обеспечивать разделение прав доступа к секциям для разных
# администраторов. Zebra предоставляет вполне исчерпывающий инструментарий
# для организации такого подхода. Административным модулем для расширения
# ZS является скрипт 'zse.cgi'.
#      В оверлейный модуль целесообразно вынести подпрограммы и функции
# данного расширения, либо используемые равно базовым и административным
# модулями, либо не требуемыми к использованию при каждом запуске базового
# модуля. В идеале все необходимые для постоянного использования процедуры
# должны находиться в базовом модуле, чтобы наименее загружать сервер.
#      Оверлейный модуль расширения ZS называется 'zsx0.cgi' и содержит
# все подпрограммы, которые используют модули ZS и ZSE.

# 2. СЕКЦИЯ АДМИНИСТРАТИВНОГО ДОСТУПА
# ========================================================================
#      В начале базового модуля расширения рекомендуется указать фрагмент,
# подлежащий обработке основным административным скриптом ZE в режиме
# "Инсталляции". Это позволит легко подключать и отключать ваш модуль,
# а также выполнять некоторые дополнительные условия.
#      Административная секция допускает следующие ключи:
#      - admin.setup.begin - начало секции
#      - require - минимально необходимая версия Zebra для функционирования
# данного модуля
#      - name - наименование модуля расширения
#      - module - буква (буквы), идентифицирующая модуль в Zebra
#      - exec - название базового модуля расширения
#      - edit - название административного модуля расширения
#      - admin.setup.end - конец секции. При обнаружении такой строки
# обработка секции административного доступа прекращается.
#      Ниже реализована секция административного доступа для модуля ZS.

# admin.setup.begin
# require=0142
# name=Zebra Site 0.14
# module=s
# exec=zs.cgi
# include=zebra_s.inc
# admin.setup.end


# 3. ИНИЦИАЛИЗАЦИЯ
# ========================================================================


#      Рассмотрим инициализацию непосредственно в модуле более подробно.

#      Во избежание многократных предупреждений о неинициализированных
# переменных рекомендуется перечислить их с использованием прагмы use vars.
#use strict;
use vars qw/%ENV %int %zpp %inx @a $cur $r $lpp $c $part $err $ip $curtime %su $zebracookie @s $l $p $id $dc $zebracharset $sep $wrongpasswordtext @private $auth_mode $text @list @recent $cgi $page $module $pathcgi $auam $pathcgi $ace $usercharset $v @zebracookie/;

#      В переменной $pathcgi определяется путь к выполняемому скрипту. Это
# может оказаться необходимым на некоторых серверах, а также при выполнении
# некоторых процедур посредством запуска через системный CRON.

unless($pathcgi)
{	$pathcgi=($ENV{'SCRIPT_FILENAME'}||$0);
	$pathcgi=~s/\w+\.\w+$//;$pathcgi=~s/[\\\/]+$/\//
}

#      В переменной $int{current} нужно определить наименование текущего
# скрипта, и в дальнейшем в шаблонах вместо явного указания скрипта
# рекомендуется использовать ключ $current, а в непосредственных указаниях -
# $int{current}. В частности, если вы используете процедуры авторизации и
# регистрации, предоставляемые Zebra API, это определение необходимо.

$int{current}||='zs.cgi';
$int{site}='Zebra Site';

#      В оверлейном модуле 'zx0.cgi' содержатся основные процедуры,
# используемые всеми модулями Zebra. Отсутствие этого модуля фатально для
# работы. Поэтому проверка его наличия не помешает.
#      Подробное описание функций, реализованных в модулях ZX0 и ZX1 приведено
# в документации по API (http://www.wtg.ru/zebra/api).

unless(-e"${pathcgi}zx0.cgi"){print "Content-type: text/html\n\n<html><title>Fatal error</title><h3>Fatal error: cannot find main overlay 'zx0.cgi'. Run Zebra Install.";exit}
require "${pathcgi}zx0.cgi";

#      Далее подключается оверлейный модуль расширения ZS. Все специфические
# процедуры расширения, вызываемые из модулей 'zs.cgi' и 'zse.cgi' определены
# в нем.

unless(-e"${pathcgi}zsx0.cgi"){print "Content-type: text/html\n\n<html><title>Fatal error</title><h3>Fatal error: cannot find Zebra Site overlay 'zsx0.cgi'. Run Zebra Install.";exit}
require "${pathcgi}zsx0.cgi";


#      Основной блок работы модуля рекомендуется реализовать в подпрограмме.
# Это позволит при необходимости довольно просто модифицировать программу
# для выполнения с ускорителями серверных приложений типа FastCGI или mod_perl
# (хотя в силу некоторых причин выполнение Zebra под управлением mod_perl,
# скорее всего, невозможно).

&main_zs;

sub main_zs
{
local$module='s'; #local($page);
if(&zs_initialize<0){goto END}
my$toprint;


#use ZebUser;
#my$a=new ZebUser('airatscmaksturu');
#print "\n\n";
#for(keys%{$a->{props}})
#{print "<br>$_=$a->{props}->{$_}"}

#exit;



for(@ARGV)
{	if(s/p(age)?=(.*)/$2/){$page||=$_}
	if(s/list=(.*)/$1/){$list||=$_}
	if(s/part=(.*)/$1/){$part||=$_}
}
$page||=(($cgi->param('p'))||($cgi->param('page')));
$list||=$cgi->param('list');

unless($list)
{	$page||=$ENV{'QUERY_STRING'};if($page=~/\bp(?:age)?=(.*?)(?:&|\Z)/i){$page=$1}else{$page=~s/(^|&).*?=.*?(&|$)/$1/g;$page=~s/&//g}
	$page||='index';
}

if($page){$page=~s|\\|/|g;$page=~s|^/+||}
$int{tag}="p=$page&";
$int{page}=$page;
unless($list){$cgi->param('page',$page)}


# если ресурс не найден, проверяем индекс для списка
unless(%zpp=zs_getpagehdr($page))
{	my$a=$list.'/index';
	if(%zpp=zs_getpagehdr($a)){$page=$a;undef$list}
# если индекс не найден, устанавливаем режим отображения списка
	elsif(!$list){$list=$page}
}

$list=~s/\\/\//g;$int{list}=$list;
unless($int{list}){$int{list}=$page;$int{list}=~s|/(\w+)$||}


# здесь идет поиск по ключевым словам
if($int{search}=$cgi->param('search'))
{
	zs_site_search();
	$toprint=zs_substpage(zs_getinis('siteindexpage',$int{list}));
#	zs_printz($cgi->header(),zs_substpage(zs_getinis('siteindexpage')));
	goto END;
}

#savevalue('__substit_zs_userform',join(chr(0),'zx1','zs_userform'));
#savevalue('__substit_zs_form_pd4',join(chr(0),'zx2','zs_form_pd4'));
if($int{registration}||$int{action}){require"${pathcgi}zx1.cgi";zs_authentication();goto END}



## возврат запрошенного списка
if($list)
{	$int{page}=$list;
	@a=zs_groupprops($list);
	if(!@a || !$a[6])
	{
		$page='notfound';
		$toprint=zs_systempage('notfound');
#		zs_printz($cgi->header(-type=>"text/html; charset=$zebracharset"),zs_systempage('notfound'));
		goto END;
	}

	$int{grouptitle}=$int{title}=$int{header}=($a[2]||(split(/\//,$list))[-1]);

	if($a[3])
	{
		require "${pathcgi}zx1.cgi";
		unless(&zs_authentication){goto END}

		
		if($a[3]==1){$v=1}
		elsif($a[3]==2){for(@{$a[8]}){if($_ eq $su{zgr}){$v=1;last}}}
		else
		{#	unless(&zs_authentication){goto END}
		}

		unless($v)
		{
			$wrongpasswordtext||=zs_getinis('wrongpassword');

			$int{notaccess}=1;$page='wrongpassword';
			$int{login}=Zebra::translate($int{login},1);
			$toprint=zs_substpage($wrongpasswordtext);
#			zs_printz($cgi->header(-type=>"text/html; charset=$zebracharset"),zs_substpage($wrongpasswordtext));
			goto END;
		}
		
	}

	my$recentpage=($a[9]||zs_getinil('recentpage'));
	$int{tag}="list=$list&";

# несортируемый список подгрупп
	my$hlist=$list;if($hlist){$hlist.='/'}
	if($a[7]!=1)
	{
		my$i;
		if($recentpage=~/MULTIPLEgroup/)
		{

			for(@{$a[0]})
			{	my@b;
				my@a=zs_groupprops("$hlist$_");
				unless($a[6]){next}
				++$i;
				$int{"number\$listgroup_$i"}=$i;
				$int{"grouptitle\$listgroup_$i"}=$a[2];
				$int{"groupname\$listgroup_$i"}="$hlist$_";
				$int{"groupgroups\$listgroup_$i"}=@{$a[0]};
				$int{"grouplist\$listgroup_$i"}=@{$a[1]};
			}
			$int{groups}=$int{group}=$int{listgroup}=$i;
		}
# сортируемый список подгрупп
		if($recentpage=~s/%tablegroup\{(.*?)\}tablegroup%/\$tablegroup/gs)
		{
			my%aln;
			$int{tablegroup}=$1;
			my$sort=($cgi->param('sortgroup'))*1;
			if($sort)
			{	$int{tag}.="sortgroup=$sort&";
				$int{reversegroup}=1;
			}
			my@b=split(',',$int{tablegroup});
			for(@b)
			{
				if(s/^(#.)//){$aln{$_}=$1}
			}
			my@c=();
			for(@{$a[0]})
			{
				my@a=zs_groupprops("$hlist$_");

				for$i(@b)
				{	if($i eq 'groupname'){push@c,$aln{groupname}."$hlist$_"}
#					elsif($i eq 'grouphref'){push@c,$aln{grouphref}.qq|<a href="$int{dircgi}/$int{current}list=$hlist$_&l=$int{lang}&f=$int{prof}">$a[2]</a>|}
					elsif($i eq 'grouphref'){push@c,$aln{grouphref}.qq|<a href="$int{dircgi}/$int{current}list=$hlist$_">$a[2]</a>|}
					elsif($i eq 'grouptitle'){push@c,$aln{grouptitle}.$a[2]}
					elsif($i eq 'groupgroups'){my$b=@{$a[0]};push@c,$aln{groupgroups}.$b}
					elsif($i eq 'grouplist'){my$b=@{$a[1]};push@c,$aln{grouplist}.$b}
				}
			}
			if($b[$sort-1]=~/^grouplist|groupgroups$/){$sort="#$sort"}

			if($cgi->param('reversegroup'))
			{	delete$int{'reversegroup'};
				$sort="-$sort";
				$int{tag}.='reversegroup=1&'
			}
			else
			{
			}
			require "${pathcgi}zx1.cgi";
			if(@c){$int{groups}=$int{group}=1}
			require "${pathcgi}zex0.cgi";
			$int{tablegroup}=zs_stattable($#b+1,1,$sort,@c);
		}
	}
# список страниц
	if($a[7]!=2)
	{

# несортируемый список ресурсов
		if($recentpage=~/MULTIPLElistpage/)
		{
			my$i;for(@{$a[1]})
			{
				%zpp=zs_getpagehdr("$hlist$_");
				if($zpp{znam})
				{	++$i;
					$int{"title\$listpage_$i"}=$zpp{znam};
					$int{"number\$listpage_$i"}=$i;
					$int{"name\$listpage_$i"}="$hlist$_";
					$int{"counter\$listpage_$i"}=$zpp{zcnt}*1;
					$int{"size\$listpage_$i"}=$zpp{zsiz}*1;
					$int{"createdate\$listpage_$i"}=zs_stringdate(Zebra::unpacktime($zpp{zdcr},\@days,\@months));
					$int{"modifydate\$listpage_$i"}=zs_stringdate(Zebra::unpacktime($zpp{zdch},\@days,\@months));
					$int{"accessdate\$listpage_$i"}=zs_stringdate(Zebra::unpacktime($zpp{zdrd},\@days,\@months));
					$int{"limitdate\$listpage_$i"}=zs_stringdate(Zebra::unpacktime($zpp{zdlm},\@days,\@months));
				}
				else{next}
			}
			$int{pages}=$int{listpage}=$i;
		}
# сортируемый список ресурсов
		if($recentpage=~s/%tablepage\{(.*?)\}tablepage%/\$tablepage/gs)
		{
			my%aln;
			$int{tablepage}=$1;
			my$sort=($cgi->param('sort'))*1;
			if($sort)
			{
				$int{tag}.="sort=$sort&";
				$int{'reverse'}=1;
			}
			my@b=split(',',$int{tablepage});
			for(@b)
			{
				if(s/^(#.)//){$aln{$_}=$1}
			}

			my@c=();
			for(@{$a[1]})
			{
				%zpp=zs_getpagehdr("$hlist$_");

				for$i(@b)
				{	if($i eq 'name'){push@c,$aln{name}."$hlist$_"}
#					elsif($i eq 'href'){push@c,$aln{href}.qq|<a href="$int{dircgi}/$int{current}p=$hlist$_">$zpp{znam}</a>|}
					elsif($i eq 'href'){push@c,$aln{href}.zs_substit(qq|<a href="\%$hlist$_\%">$zpp{znam}</a>|)}
					elsif($i eq 'title'){push@c,$aln{title}.$zpp{znam}}
					elsif($i eq 'counter'){push@c,$aln{counter}.$zpp{zcnt}}
					elsif($i eq 'size'){push@c,$aln{size}.$zpp{zsiz}}
					elsif($i eq 'createdate'){push@c,$aln{createdate}.zs_stringdate(Zebra::unpacktime($zpp{zdcr},\@days,\@months))}
					elsif($i eq 'modifydate'){push@c,$aln{modifydate}.zs_stringdate(Zebra::unpacktime($zpp{zdch},\@days,\@months))}
					elsif($i eq 'accessdate'){push@c,$aln{accessdate}.zs_stringdate(Zebra::unpacktime($zpp{zdrd},\@days,\@months))}
					elsif($i eq 'limitdate'){push@c,$aln{limitdate}.zs_stringdate(Zebra::unpacktime($zpp{zdlm},\@days,\@months))}
				}
			}
			if($b[$sort-1]=~/^size|counter$/){$sort="#$sort"}
			elsif($b[$sort-1]=~/^.*date$/){$sort="&$sort"}

			if($cgi->param('reverse'))
			{	delete$int{'reverse'};
				$sort="-$sort";
				$int{tag}.='reverse=1&'
			}
			require "${pathcgi}zx1.cgi";
			if(@c){$int{pages}=1}
			$int{tablepage}=zs_stattable($#b+1,1,$sort,@c);
		}
	}

	$text=$recentpage;
	goto PAGE;

}

## возврат запрошенной страницы
#%zpp=zs_getpagehdr($page);
$text=zs_getpage($page);
$zpp{zdrd}=$curtime;

# отключение изменений, если ресурс бинарный
if($zpp{ztyp}>2)
{	undef$inx{'$__zebra_benchstatistic'};
	undef$inx{'$__printoptimize'};
	undef$usercharset;
}

## ключи в теле страницы
# редирект
if($text=~s/^(?:location:\s*)(.*)/$1/i || $text=~s/^((?:http:\/\/|ftp:\/\/)(?:.*))/$1/i)
{	$text=zs_substit($text);
	print $cgi->redirect(($inx{'$__zebra_headerexpires'}? (-expires=>'+'.$inx{'$__zebra_headerexpires'}.'s'):@q),($inx{'$__zebra_headernocache'}?(-pragma=>'no-cache'):@q),(@zebracookie?(-cookie=>\@zebracookie):@q),-uri=>$text);
	if($inx{"\$__counter_enabled"})
	{	++$zpp{zcnt};delete@zpp{'zloc','zpro'};
		zs_savepagehdr("a$zpp{zid}",\%zpp);
	}
	&zs_deinitialize;
	exit;
}


unless($zpp{zid})
{	$page='notfound';
	$toprint=zs_systempage('notfound');
#	zs_printz($cgi->header(-type=>"text/html; charset=$zebracharset"),zs_systempage('notfound'));
	goto END
}

if($zpp{zpvt})
{
# данная страница требует авторизации сама по себе
	require "${pathcgi}zx1.cgi";

	$int{noregistration}=1;
	unless(&zs_authentication){goto END}

	if(!$wrongpasswordtext){$page='wrongpassword';$wrongpasswordtext=zs_getinis('wrongpassword')}

	$int{notaccess}=1;$page='wrongpassword';
	$int{login}=Zebra::translate($int{login},1);
	$toprint=zs_substpage($wrongpasswordtext);
#	zs_printz($cgi->header(-type=>"text/html; charset=$zebracharset"),zs_substpage($wrongpasswordtext));

	goto END;
}
else
{
# страница включена в группу с ограниченным доступом
	my@a=split(/[\/\\]/,$page);
	my$list=$int{list}=join('/',@a[0..($#a-1)]);
	@a=zs_groupprops($list);
	if($a[3])
	{
		require "${pathcgi}zx1.cgi";
#		$int{noregistration}=1;
		unless(&zs_authentication){goto END}

# доступ по регистрации
		if($a[3]==1){$v=1}
# конфиденциальный доступ
		elsif($a[3]==2)
		{	for(@{$a[8]}){if($_ eq $su{zgr}){$v=1;last}}
		}

		unless($v)
		{
			$wrongpasswordtext||=zs_getinis('wrongpassword');

			$int{notaccess}=1;$page='wrongpassword';
			$int{login}=Zebra::translate($int{login},1);
			$toprint=zs_substpage($wrongpasswordtext);
#			zs_printz($cgi->header(-type=>"text/html; charset=$zebracharset"),zs_substpage($wrongpasswordtext));
			goto END;
		}
		
	}

}


PAGE:


if(!$list&&$inx{"\$__counter_enabled"})
{	++$zpp{zcnt};
	$zpp{zrip}=$ENV{REMOTE_ADDR};
	delete@zpp{'zloc','zpro'};

	savevalue("a$zpp{zid}",join(chr(0),%zpp),'shdr');
}

unless($int{title}){@int{title}=$text=~/<title>((?!\$title\b).*?)<\/title>/i}
unless($int{title})
{	if($zpp{znam}){$int{title}=$zpp{znam}}
	else{$int{title}=$page}
}
$int{header}=$int{title};
$int{shortpage}=$int{page}=$page;
$int{"page_$page"}=1;
$int{shortpage}=~s#.*/##;
unless($int{list}){$int{list}=$int{page};$int{list}=~s|\w+$||;$int{list}=~s|/+$||}


$text=zs_substpage($text);


my$a=zs_getinil('pagemaxlength');
if($a&&(length$text>$a)&&(my$b=zs_getinil('pagesplitpages'))&&!$nosplit)
{	
	$part||=($cgi->param('part'))*1;
	if($part<=1){$part=1}

	$c=$text;
	$int{'split'}=int((length$c)/$a)+1;


	if($text=~s/<!\-\-beginpaged\-\->((?:.|\r|\n)+)<!\-\-endpaged\-\->/#%%#/mi){$c=$1}
	elsif($b==2)
	{	my($a1,$a2);if($part>1){$a1=zs_substpage($int{begbody})}if($part<$int{'split'}){$a2=zs_substpage($int{endbody})}
		$text=qq|<p><center><table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td><!--linkpaged--></td></tr></table></center><p>$a1 #%%# $a2<p><center><table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td><!--linkpaged--></td></tr></table></center><p>|;
	}

	my@a;
# разбиение страницы на части
	for(1..$int{'split'})
	{
#		$r=$c=~s/^((?:.|\r|\n){$a}.*?)(\r|\n|$)/$2/m;

		my$d=substr($c,0,$a,'');
		$r=$c=~s/^(.*?)(<p|<br|<tr|\r|\n|$)/$2/moi;

		$int{"part\$split_$_"}=$_;
		$int{"tag\$split_$_"}=$int{tag}."part=$_&";
		if(($part*1)==$_)
		{
			$int{"active\$split_$_"}=1;
			if($r){$cur=$d.$1}else{$cur=$d}
		}
	}


	if($part<$int{'split'})
	{	$int{'next'}=$part+1;
		$int{tagnext}=$int{tag}."part=$int{next}&";
	}
	if($part>1)
	{	$int{prev}=$part-1;
		$int{tagprev}=$int{tag}."part=$int{prev}&"
	}

	if($list){$int{page}="&list=$list"}

	$int{first}=1;
	$int{tagfirst}=$int{tag}."part=$int{first}&";
	$int{'last'}=$int{'split'};
	$int{taglast}=$int{tag}."part=$int{last}&";
#	$c=~s/((?:.|\r|\n){$a})(?:.|\r|\n)*/$1/;

	my$lp=zs_substpage(zs_getinil('splitpage'));

	$text=~s/#%%#/$cur/;
	my$d=$part+1;
	$text=~s/<!\-\-linkpaged\-\->/$lp/g;

}

unless($text=~/<title/i){$text="<title>$int{title}</title>$text"}
$toprint=$text;

END:


if($toprint)
{	unless($inx{'$__perlis'})
	{
		zs_printz($cgi->header(-type=>"text/html; charset=$zebracharset",($inx{'$__zebra_headerexpires'}? (-expires=>'+'.$inx{'$__zebra_headerexpires'}.'s'):@q),($inx{'$__zebra_headernocache'}?(-pragma=>'no-cache'):@q),(@zebracookie?(-cookie=>\@zebracookie):@q)),"\n\n",$toprint)
	}
	else{zs_printz($cgi->header(-type=>"text/html; charset=$zebracharset",($inx{'$__zebra_headerexpires'}? (-expires=>'+'.$inx{'$__zebra_headerexpires'}.'s'):@q),($inx{'$__zebra_headernocache'}?(-pragma=>'no-cache'):@q),(@zebracookie?(-cookie=>\@zebracookie):@q)),"\n\n",$toprint)}
}


if($inx{'$__zebra_benchstatistic'}&&($cgi->param('statistic') ne 'off')){zs_printz(&zs_statistic)}

# выполнение класса autoend
my@a=split(/\x00/,getvalue('__adminautoend'));for(@a){zs_runfunc($_)}

# запуск регулярных процедур, обозначенных для запуска Зеброй
if($ace==1){require "${pathcgi}zx1.cgi";zs_runregular(1,1)}

# деинициализация Zebra
&zs_deinitialize;

}
1;