4 # viewer is generated from viewer.1.pl.
9 # Copyright (C) 2016-2017, 2019-2020, 2023 Balthasar SzczepaĆski
11 # This program is free software: you can redistribute it and/or modify
12 # it under the terms of the GNU Affero General Public License as
13 # published by the Free Software Foundation, either version 3 of the
14 # License, or (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU Affero General Public License for more details.
21 # You should have received a copy of the GNU Affero General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
27 use bsta_lib qw(failpage gethttpheader getcgi entityencode readdatafile writedatafile printdatafileht urlencode bb2ht bb2bb linehtml);
80 delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
83 if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
87 exit failpage("Status: 405 Method Not Allowed\nAllow: GET, POST, HEAD\n","405 Method Not Allowed","The interface does not support the $ENV{'REQUEST_METHOD'} method.",$method);
90 %http = gethttpheader (\%ENV);
91 %cgi = getcgi($ENV{'QUERY_STRING'});
93 if ($method eq 'POST') {
94 if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
95 my %cgipost=getcgi( <STDIN> );
96 foreach my $ind (keys %cgipost) {
97 $cgi{$ind}=$cgipost{$ind};
100 # multipart not supported
102 exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}.");
106 if ($ENV{'HTTP_X_FORWARDED_FOR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) {
109 elsif ($ENV{'REMOTE_ADDR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) {
116 if ($cgi{'f'} =~ /^(.+)$/) {
119 elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) {
126 if ($cgi{'p'} =~ /^(.+)$/) {
132 # print "Content-type: text/plain\n\n";
134 %settings=readdatafile(SETTINGS_PATH);
135 %default=readdatafile(DEFAULT_PATH);
136 %framedata=readdatafile(DATA_PATH.$frame);
137 if($password eq $settings{'password'}){
144 if (open ($statefile,"+<",STATE_PATH)){
145 if (flock($statefile,2)) {
147 %state=readdatafile($statefile);
150 $frame = int($state{'last'}) + $frame +1;
151 %framedata=readdatafile(DATA_PATH.$frame);
154 if(int($state{'state'})==1 && $frame == int($state{'last'}) && $method ne 'HEAD' && !$passwordOK){
156 if($state{'ip1'} ne $IP) {
157 if ($state{'ip1'} eq '') {
158 $newstate{'ip1'} = $IP;
159 writedatafile($statefile,%newstate);
161 elsif($state{'ip2'} ne $IP) {
162 if ($state{'ip2'} eq '') {
163 $newstate{'ip2'} = $IP;
164 writedatafile($statefile,%newstate);
167 $newstate{'state'}=2;
168 $newstate{'ip3'} = $IP;
169 writedatafile($statefile,%newstate);
174 elsif(int($state{'state'})==0 && $frame == 1) {
179 %story = readdatafile(STORY_PATH);
180 %gotolist=readdatafile(LIST_PATH);
181 if(int($story{'state'}) == 17 && int($story{'pass'}) == 1) {
184 $framedata{'ongtime'} = $time;
185 writedatafile(DATA_PATH.$frame,%framedata);
188 $state {'ip1'} = '0.0.0.0';
189 $state {'ip2'} = '0.0.0.0';
191 $state {'nextong'} = (int($time / 3600) + int($settings{'firstongtime'})) * 3600 ;
192 $state{'ongtime'} = int($settings{'firstongtime'});
194 unless(defined($framedata{'ext'})){
195 $framedata{'ext'}=$default{'ext'};
198 $inpath = DATA_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
199 $outpath = WWW_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
201 $gotolist{'title-1'}=$framedata{'title'};
202 $gotolist{'ongtime-1'}=$framedata{'ongtime'};
204 if(copy ($inpath, $outpath)) {
205 writeindex(INDEX_PATH);
206 writedatafile($statefile,%state);
207 writedatafile(LIST_PATH,%gotolist);
224 %nextframedata=readdatafile(DATA_PATH.($frame+1));
225 foreach my $ind (keys %default) {
226 unless(defined($framedata{$ind})){
227 $framedata{$ind}=$default{$ind};
229 unless(defined($nextframedata{$ind})){
230 $nextframedata{$ind}=$default{$ind};
234 $hours=int($state{'nextong'})-$time;
235 $ongtime=int($state{'ongtime'});
237 $ongtime=int($settings{'ongtime'})
240 $showcommand = ($hours < ($ongtime*3600/3));
242 $seconds = sprintf('%02d',$hours % 60);
243 $hours = int($hours/60);
244 $minutes = sprintf('%02d',$hours % 60);
245 $hours = sprintf('%02d',int($hours/60));
247 elsif(($hours>=-15) && (int($state{'state'}) == 2)){
259 if ($passwordOK || (int($state{'state'}) >= 1 && $frame <= int($state{'last'}) && $frame >= 0)) {
264 %framedata = readdatafile(NOACCESS_PATH);
265 foreach my $ind (keys %default) {
266 unless(defined($framedata{$ind})){
267 $framedata{$ind}=$default{$ind};
272 $textmode = int($cgi{'b'});
277 # print "Content-type: text/plain\n\n";
278 # print 'frame='.$frame."\n";
279 # print 'password='.$password."\n";
280 # print 'passwordOK='.$passwordOK."\n";
281 # print 'access='.$access."\n";
282 # print "\n>>>ENV<<<\n\n";
283 # foreach my $ind (keys %ENV) {
284 # print $ind.'='.$ENV{$ind}."\n";
286 # print "\n>>>HTTP<<<\n\n";
287 # foreach my $ind (keys %http) {
288 # print $ind.': '.$http{$ind}."\n";
290 # print "\n>>>CGI<<<\n\n";
291 # foreach my $ind (keys %cgi) {
292 # print $ind.'='.$cgi{$ind}."\n";
294 # print "\n>>>FRAMEDATA<<<\n\n";
295 # foreach my $ind (keys %framedata) {
296 # print $ind.': '.$framedata{$ind}."\n";
298 # print "\n>>>NEXTFRAMEDATA<<<\n\n";
299 # foreach my $ind (keys %nextframedata) {
300 # print $ind.': '.$nextframedata{$ind}."\n";
302 # print "\n>>>SETTINGS<<<\n\n";
303 # foreach my $ind (keys %settings) {
304 # print $ind.': '.$settings{$ind}."\n";
306 # print "\n>>>STATE<<<\n\n";
307 # foreach my $ind (keys %state) {
308 # print $ind.': '.$state{$ind}."\n";
311 print "Content-type: text/html\n";
313 print "Status: 403 Forbidden\n";
316 if($method eq 'HEAD') {
320 print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
321 print '<html lang="en"><head>'."\n";
322 print '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
324 unless($framedata{'title'} eq '' || $framedata{'title'} eq $settings{'story'}) {
325 print entityencode($framedata{'title'}).' • ';
327 print entityencode($settings{'story'}).' • '.WEBSITE_NAME.'</title>'."\n";
328 print '<link rel="icon" type="image/png" href="'.FAVICON_PATH.'">'."\n";
329 print '<link rel="stylesheet" href="'.CSS_PATH.'">'."\n";
330 print '<link rel="index" href="'.GOTO_PATH.($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
331 print '<link rel="start" href="'.VIEWER_PATH.'/0'.($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
332 if($frame>0 && $access) {
333 print '<link rel="prev" href="'.VIEWER_PATH.'/'.($frame - 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
335 if ($passwordOK || $frame<int($state{'last'})) {
336 print '<link rel="next" href="'.VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
337 print '<link rel="prefetch" href="'.VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
339 if($frame==int($state{'last'}) && int($state{'state'}) >= 1 && int($state{'state'}) < 3) {
340 print '<!-- <script src="'.TIMER_PATH.'"></script> -->'."\n";
342 print '</head><body>'."\n";
343 print '<a href="/"><img id="botmlogo" src="'.LOGO_PATH.'" alt="'.WEBSITE.'"></a>'."\n";
344 print '<div id="all">'."\n";
346 print '<div id="inst" class="ins">'."\n";
348 print '<div id="title">'."\n";
349 print '<H1 id="titletext">'.entityencode($framedata{'title'}).'</H1>'."\n";
352 print '</div><div id="framespace">'."\n";
354 print '<img src="'.CGI_PATH.$framedata{'frame'}.'" id ="frame" alt="'.$frame.'" title="'.entityencode($framedata{'title'}).'">'."\n";
358 if($frame<=int($state{'last'}) && int($state{'state'}) >= 1) {
359 print CGI_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
362 print FRAME_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'');
364 print '" id="frame" alt="'.$frame.'" title="'.entityencode($framedata{'title'}).'">'."\n";
366 print '</div><div id="insb" class="ins">'."\n";
369 print '<div id="chat">'."\n";
371 if ($passwordOK || $frame<int($state{'last'}) || (int($state{'state'}) >= 2 && $showcommand)) {
372 $framedata{'command'}=$nextframedata{'title'};
375 $framedata{'frame'}=sprintf($settings{'frame'},$frame,$framedata{'ext'});
378 printdatafileht(%framedata);
382 print '<div id="chat">'."\n";
383 print '[quote][center][size=200]'.entityencode($framedata{'title'}).'[/size]<br>'."\n";
384 print '[url=http://'.WEBSITE.VIEWER_PATH.'/'.$frame.'][img]http://'.WEBSITE.CGI_PATH.($access?sprintf($settings{'frame'},$frame,$framedata{'ext'}):$framedata{'frame'}).'[/img][/url][/center]<br>'."\n";
385 print bb2bbf($framedata{'content'}).'[/quote]</div>'."\n";
387 elsif($framedata{'content'} ne ''){
388 print '<div id="undertext">'."\n";
389 print bb2htf($framedata{'content'})."\n";
393 print '<div id="command">'."\n";
394 if($frame==int($state{'last'}) && int($state{'state'}) >= 1 && int($state{'state'}) < 3) {
395 print '[<span id="ongh" class="';
396 if(int($state{'state'}) >= 2 || $state{'ip1'} ne '') {
402 print '">'.$hours.'</span>:<span id="ongm" class="';
403 if(int($state{'state'}) >= 2 || $state{'ip2'} ne '') {
409 print '">'.$minutes.'</span>:<span id="ongs" class="';
410 if(int($state{'state'}) >= 2 || $state{'ip3'} ne '') {
416 print '">'.$seconds.'</span>]<br>';
420 print '<a href="'.VIEWER_PATH.'/-1">'.entityencode($framedata{'command'}).'</a><br>'."\n";
423 if ($passwordOK || $frame<int($state{'last'}) || (int($state{'state'}) >= 2 && $showcommand)) {
424 if ($passwordOK || $frame<int($state{'last'})) {
425 print '<a href="'.VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">';
427 if($nextframedata{'title'} ne '') {
428 print entityencode($nextframedata{'title'});
430 elsif ($passwordOK || $frame<int($state{'last'})) {
431 print'<span class="inp">_</span>';
433 if ($passwordOK || $frame<int($state{'last'})) {
437 print'<span class="inp">_</span>';
441 print'<span class="inp">_</span>';
447 print '<div id="underlinks">'."\n";
448 print '<a href="'.CGI_PATH.'">Once again</a>';
449 if($frame>0 && $access) {
450 print ' | <a href="'.VIEWER_PATH.'/'.($frame-1).($passwordOK?('?p='.urlencode($password)):'').'">Before</a>';
452 if($frame != int($state{'last'})) {
453 print ' | <a href="'.VIEWER_PATH.'/'.int($state{'last'}).($passwordOK?('?p='.urlencode($password)):'').'">Now</a>';
455 print ' | <a href="'.GOTO_PATH.($passwordOK?('?p='.urlencode($password)):'').'">GOTO</a>'."\n";
456 print '<span style="float: right;">'."\n";
459 print '<a href="'.VIEWER_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'').'">Without</a> | ';
462 print '<a href="'.(($textmode==2)?(INFO_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'')):(VIEWER_PATH.'/'.$frame.'?b=2'.($passwordOK?('&p='.urlencode($password)):''))).'">Info</a>';
463 print ' | <a href="'.(($textmode==1)?(BBCODE_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'')):(VIEWER_PATH.'/'.$frame.'?b=1'.($passwordOK?('&p='.urlencode($password)):''))).'">BB</a>';
471 print '<a href="/" class="cz">'.WEBSITE.'</a>'."\n";
473 print '</body></html>'."\n";
476 (my $indexpath) = @_;
482 if(ref($indexpath)) {
483 $indexfile=$indexpath;
484 unless (seek($indexfile, 0, 0)) {
489 unless (open ($indexfile, ">", $indexpath)) {
494 %framedata = readdatafile(DATA_PATH.0);
495 %nextframedata = readdatafile(DATA_PATH.1);
496 %default=readdatafile(DEFAULT_PATH);
498 foreach my $ind (keys %default) {
499 unless(defined($framedata{$ind})){
500 $framedata{$ind}=$default{$ind};
502 unless(defined($nextframedata{$ind})){
503 $nextframedata{$ind}=$default{$ind};
507 print $indexfile '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
508 print $indexfile '<html lang="en"><head>'."\n";
509 print $indexfile '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
510 print $indexfile '<title>'.entityencode($settings{'story'}).' • '.WEBSITE_NAME.'</title>'."\n";
511 print $indexfile '<link rel="icon" type="image/png" href="'.FAVICON_PATH.'">'."\n";
512 print $indexfile '<link rel="stylesheet" href="'.CSS_PATH.'">'."\n";
513 print $indexfile '<link rel="index" href="'.GOTO_PATH.'">'."\n";
514 print $indexfile '<link rel="start" href="'.VIEWER_PATH.'/0">'."\n";
515 print $indexfile '<link rel="next" href="'.VIEWER_PATH.'/1">'."\n";
516 print $indexfile '<link rel="prefetch" href="'.VIEWER_PATH.'/1">'."\n";
517 print $indexfile '</head><body>'."\n";
518 print $indexfile '<a href="/"><img id="botmlogo" src="'.LOGO_PATH.'" alt="'.WEBSITE.'"></a>'."\n";
519 print $indexfile '<div id="all">'."\n";
521 print $indexfile '<div id="inst" class="ins">'."\n";
523 print $indexfile '<div id="title">'."\n";
524 print $indexfile '<H1 id="titletext">'.entityencode($settings{'story'}).'</H1>'."\n";
525 print $indexfile '</div>'."\n";
527 print $indexfile '</div><div id="framespace">'."\n";
528 print $indexfile '<img src="'.CGI_PATH.sprintf($settings{'frame'},0,$framedata{'ext'}).'" title="'.entityencode($framedata{'title'}).'" alt="0" id="frame">'."\n";
530 print $indexfile '</div><div id="insb" class="ins">'."\n";
531 print $indexfile '<div id="undertext">'."\n";
532 print $indexfile bb2htf($framedata{'content'})."\n";
533 print $indexfile '</div>'."\n";
535 print $indexfile '<div id="command">'."\n";
536 print $indexfile '><a href="'.VIEWER_PATH.'/1">'.entityencode($nextframedata{'title'}).'</a>'."\n";
537 print $indexfile '</div>'."\n";
539 print $indexfile '<div id="underlinks">'."\n";
542 # <span style="float: right;"><a href="/bsta/v/0?b=2">Info</a> | <a href="/bsta/v/0?b=1">BB</a></span>
544 print $indexfile '<a href="'.VIEWER_PATH.'/-1">Now</a> | <a href="'.GOTO_PATH.'">GOTO</a>';
545 print $indexfile '<span style="float: right;"><a href="'.INFO_PATH.'/0?b=2">Info</a> | <a href="'.VIEWER_PATH.'/0?b=1">BB</a></span>'."\n";
546 print $indexfile '</div>'."\n";
548 print $indexfile '</div>'."\n";
550 print $indexfile '</div>'."\n";
551 print $indexfile '<a href="/" class="cz">'.WEBSITE.'</a>'."\n";
553 print $indexfile '</body></html>'."\n";
555 unless (ref($indexpath)) {
559 truncate ($indexfile , tell($indexfile));
572 while($bb =~ m/(###([^#;]*);)/g) {
575 $pretext = substr($bb,0,pos ($bb)-length($tag));
576 $posttext = substr ($bb,pos ($bb));
578 if ($tagvalue =~ /^att&([0-9]+)$/) {
579 $tagvalue = ATTACH_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
581 elsif ($tagvalue =~ /^vw&([0-9]+)$/) {
582 $tagvalue = VIEWER_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
584 elsif ($tagvalue =~ /^fr&([0-9]+)$/) {
585 $tagvalue = FRAME_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
591 $bb = $pretext.$tagvalue.$posttext;
604 while($bb =~ m/(###([^#;]*);)/g) {
607 $pretext = substr($bb,0,pos ($bb)-length($tag));
608 $posttext = substr ($bb,pos ($bb));
610 if ($tagvalue =~ /^att&([0-9]+)$/) {
611 $tagvalue = 'http://'.WEBSITE.ATTACH_PATH.'/'.int($1);
613 elsif ($tagvalue =~ /^vw&([0-9]+)$/) {
614 $tagvalue = 'http://'.WEBSITE.VIEWER_PATH.'/'.int($1);
616 elsif ($tagvalue =~ /^fr&([0-9]+)$/) {
617 $tagvalue = 'http://'.WEBSITE.FRAME_PATH.'/'.int($1);
623 $bb = $pretext.$tagvalue.$posttext;
626 return linehtml(bb2bb ($bb));