1 ###RUN_PERL: #!/usr/bin/perl
4 # viewer is generated from viewer.1.pl.
8 # Copyright (C) 2016-2017, 2019-2020, 2023 Balthasar SzczepaĆski
10 # This program is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU Affero General Public License as
12 # published by the Free Software Foundation, either version 3 of the
13 # License, or (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU Affero General Public License for more details.
20 # You should have received a copy of the GNU Affero General Public License
21 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 ###PERL_LIB: use lib /botm/lib/bsta
26 use bsta_lib qw(failpage gethttpheader getcgi entityencode readdatafile writedatafile printdatafileht urlencode bb2ht bb2bb linehtml);
29 ###PERL_CGI_PATH: CGI_PATH = /bsta/
30 ###PERL_CGI_ATTACH_PATH: CGI_ATTACH_PATH = /bsta/a
31 ###PERL_CGI_BBCODE_PATH: CGI_BBCODE_PATH = /bsta/b
32 ###PERL_CGI_CSS_PATH: CGI_CSS_PATH = /bsta/bsta.css
33 ###PERL_CGI_FRAME_PATH: CGI_FRAME_PATH = /bsta/f
34 ###PERL_CGI_GOTO_PATH: CGI_GOTO_PATH = /bsta/g
35 ###PERL_CGI_INFO_PATH: CGI_INFO_PATH = /bsta/i
36 ###PERL_CGI_LOGO_PATH: CGI_LOGO_PATH = /bsta/botmlogo.png
37 ###PERL_CGI_TIMER_PATH: CGI_TIMER_PATH = /bsta/timer.js
38 ###PERL_CGI_VIEWER_PATH: CGI_VIEWER_PATH = /bsta/v
40 ###PERL_DATA_PATH: DATA_PATH = /botm/data/bsta/
41 ###PERL_DATA_DEFAULT_PATH: DATA_DEFAULT_PATH = /botm/data/bsta/default
42 ###PERL_DATA_LIST_PATH: DATA_LIST_PATH = /botm/data/bsta/list
43 ###PERL_DATA_NOACCESS_PATH: DATA_NOACCESS_PATH = /botm/data/bsta/noaccess
44 ###PERL_DATA_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/settings
45 ###PERL_DATA_STATE_PATH: DATA_STATE_PATH = /botm/data/bsta/state
46 ###PERL_DATA_STORY_PATH: DATA_STORY_PATH = /botm/data/bsta/story
48 ###PERL_WWW_PATH: WWW_PATH = /botm/www/1190/bsta/
49 ###PERL_WWW_INDEX_PATH: WWW_INDEX_PATH = /botm/www/1190/bsta/index.htm
51 ###PERL_WEBSITE: WEBSITE = 1190.bicyclesonthemoon.info
52 ###PERL_WEBSITE_NAME: WEBSITE_NAME = Bicycles on the Moon
53 ###PERL_FAVICON_PATH: FAVICON_PATH = /img/favicon.png
82 delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
83 ###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
85 if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
89 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);
92 %http = gethttpheader (\%ENV);
93 %cgi = getcgi($ENV{'QUERY_STRING'});
95 if ($method eq 'POST') {
96 if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
97 my %cgipost=getcgi( <STDIN> );
98 foreach my $ind (keys %cgipost) {
99 $cgi{$ind}=$cgipost{$ind};
102 # multipart not supported
104 exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}.");
108 if ($ENV{'HTTP_X_FORWARDED_FOR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) {
111 elsif ($ENV{'REMOTE_ADDR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) {
118 if ($cgi{'f'} =~ /^(.+)$/) {
121 elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) {
128 if ($cgi{'p'} =~ /^(.+)$/) {
134 # print "Content-type: text/plain\n\n";
136 %settings=readdatafile(DATA_SETTINGS_PATH);
137 %default=readdatafile(DATA_DEFAULT_PATH);
138 %framedata=readdatafile(DATA_PATH.$frame);
139 if($password eq $settings{'password'}){
146 if (open ($statefile,"+<",DATA_STATE_PATH)){
147 if (flock($statefile,2)) {
149 %state=readdatafile($statefile);
152 $frame = int($state{'last'}) + $frame +1;
153 %framedata=readdatafile(DATA_PATH.$frame);
156 if(int($state{'state'})==1 && $frame == int($state{'last'}) && $method ne 'HEAD' && !$passwordOK){
158 if($state{'ip1'} ne $IP) {
159 if ($state{'ip1'} eq '') {
160 $newstate{'ip1'} = $IP;
161 writedatafile($statefile,%newstate);
163 elsif($state{'ip2'} ne $IP) {
164 if ($state{'ip2'} eq '') {
165 $newstate{'ip2'} = $IP;
166 writedatafile($statefile,%newstate);
169 $newstate{'state'}=2;
170 $newstate{'ip3'} = $IP;
171 writedatafile($statefile,%newstate);
176 elsif(int($state{'state'})==0 && $frame == 1) {
181 %story = readdatafile(DATA_STORY_PATH);
182 %gotolist=readdatafile(DATA_LIST_PATH);
183 if(int($story{'state'}) == 17 && int($story{'pass'}) == 1) {
186 $framedata{'ongtime'} = $time;
187 writedatafile(DATA_PATH.$frame,%framedata);
190 $state {'ip1'} = '0.0.0.0';
191 $state {'ip2'} = '0.0.0.0';
193 $state {'nextong'} = (int($time / 3600) + int($settings{'firstongtime'})) * 3600 ;
194 $state{'ongtime'} = int($settings{'firstongtime'});
196 unless(defined($framedata{'ext'})){
197 $framedata{'ext'}=$default{'ext'};
200 $inpath = DATA_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
201 $outpath = WWW_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
203 $gotolist{'title-1'}=$framedata{'title'};
204 $gotolist{'ongtime-1'}=$framedata{'ongtime'};
206 if(copy ($inpath, $outpath)) {
207 writeindex(WWW_INDEX_PATH);
208 writedatafile($statefile,%state);
209 writedatafile(DATA_LIST_PATH,%gotolist);
226 %nextframedata=readdatafile(DATA_PATH.($frame+1));
227 foreach my $ind (keys %default) {
228 unless(defined($framedata{$ind})){
229 $framedata{$ind}=$default{$ind};
231 unless(defined($nextframedata{$ind})){
232 $nextframedata{$ind}=$default{$ind};
236 $hours=int($state{'nextong'})-$time;
237 $ongtime=int($state{'ongtime'});
239 $ongtime=int($settings{'ongtime'})
242 $showcommand = ($hours < ($ongtime*3600/3));
244 $seconds = sprintf('%02d',$hours % 60);
245 $hours = int($hours/60);
246 $minutes = sprintf('%02d',$hours % 60);
247 $hours = sprintf('%02d',int($hours/60));
249 elsif(($hours>=-15) && (int($state{'state'}) == 2)){
261 if ($passwordOK || (int($state{'state'}) >= 1 && $frame <= int($state{'last'}) && $frame >= 0)) {
266 %framedata = readdatafile(DATA_NOACCESS_PATH);
267 foreach my $ind (keys %default) {
268 unless(defined($framedata{$ind})){
269 $framedata{$ind}=$default{$ind};
274 $textmode = int($cgi{'b'});
279 # print "Content-type: text/plain\n\n";
280 # print 'frame='.$frame."\n";
281 # print 'password='.$password."\n";
282 # print 'passwordOK='.$passwordOK."\n";
283 # print 'access='.$access."\n";
284 # print "\n>>>ENV<<<\n\n";
285 # foreach my $ind (keys %ENV) {
286 # print $ind.'='.$ENV{$ind}."\n";
288 # print "\n>>>HTTP<<<\n\n";
289 # foreach my $ind (keys %http) {
290 # print $ind.': '.$http{$ind}."\n";
292 # print "\n>>>CGI<<<\n\n";
293 # foreach my $ind (keys %cgi) {
294 # print $ind.'='.$cgi{$ind}."\n";
296 # print "\n>>>FRAMEDATA<<<\n\n";
297 # foreach my $ind (keys %framedata) {
298 # print $ind.': '.$framedata{$ind}."\n";
300 # print "\n>>>NEXTFRAMEDATA<<<\n\n";
301 # foreach my $ind (keys %nextframedata) {
302 # print $ind.': '.$nextframedata{$ind}."\n";
304 # print "\n>>>SETTINGS<<<\n\n";
305 # foreach my $ind (keys %settings) {
306 # print $ind.': '.$settings{$ind}."\n";
308 # print "\n>>>STATE<<<\n\n";
309 # foreach my $ind (keys %state) {
310 # print $ind.': '.$state{$ind}."\n";
313 print "Content-type: text/html\n";
315 print "Status: 403 Forbidden\n";
318 if($method eq 'HEAD') {
322 print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
323 print '<html lang="en"><head>'."\n";
324 print '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
326 unless($framedata{'title'} eq '' || $framedata{'title'} eq $settings{'story'}) {
327 print entityencode($framedata{'title'}).' • ';
329 print entityencode($settings{'story'}).' • '.WEBSITE_NAME.'</title>'."\n";
330 print '<link rel="icon" type="image/png" href="'.FAVICON_PATH.'">'."\n";
331 print '<link rel="stylesheet" href="'.CGI_CSS_PATH.'">'."\n";
332 print '<link rel="index" href="'.CGI_GOTO_PATH.($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
333 print '<link rel="start" href="'.CGI_VIEWER_PATH.'/0'.($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
334 if($frame>0 && $access) {
335 print '<link rel="prev" href="'.CGI_VIEWER_PATH.'/'.($frame - 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
337 if ($passwordOK || $frame<int($state{'last'})) {
338 print '<link rel="next" href="'.CGI_VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
339 print '<link rel="prefetch" href="'.CGI_VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
341 if($frame==int($state{'last'}) && int($state{'state'}) >= 1 && int($state{'state'}) < 3) {
342 print '<!-- <script src="'.CGI_TIMER_PATH.'"></script> -->'."\n";
344 print '</head><body>'."\n";
345 print '<a href="/"><img id="botmlogo" src="'.CGI_LOGO_PATH.'" alt="'.WEBSITE.'"></a>'."\n";
346 print '<div id="all">'."\n";
348 print '<div id="inst" class="ins">'."\n";
350 print '<div id="title">'."\n";
351 print '<H1 id="titletext">'.entityencode($framedata{'title'}).'</H1>'."\n";
354 print '</div><div id="framespace">'."\n";
356 print '<img src="'.CGI_PATH.$framedata{'frame'}.'" id ="frame" alt="'.$frame.'" title="'.entityencode($framedata{'title'}).'">'."\n";
360 if($frame<=int($state{'last'}) && int($state{'state'}) >= 1) {
361 print CGI_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
364 print CGI_FRAME_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'');
366 print '" id="frame" alt="'.$frame.'" title="'.entityencode($framedata{'title'}).'">'."\n";
368 print '</div><div id="insb" class="ins">'."\n";
371 print '<div id="chat">'."\n";
373 if ($passwordOK || $frame<int($state{'last'}) || (int($state{'state'}) >= 2 && $showcommand)) {
374 $framedata{'command'}=$nextframedata{'title'};
377 $framedata{'frame'}=sprintf($settings{'frame'},$frame,$framedata{'ext'});
380 printdatafileht(%framedata);
384 print '<div id="chat">'."\n";
385 print '[quote][center][size=200]'.entityencode($framedata{'title'}).'[/size]<br>'."\n";
386 print '[url=http://'.WEBSITE.CGI_VIEWER_PATH.'/'.$frame.'][img]http://'.WEBSITE.CGI_PATH.($access?sprintf($settings{'frame'},$frame,$framedata{'ext'}):$framedata{'frame'}).'[/img][/url][/center]<br>'."\n";
387 print bb2bbf($framedata{'content'}).'[/quote]</div>'."\n";
389 elsif($framedata{'content'} ne ''){
390 print '<div id="undertext">'."\n";
391 print bb2htf($framedata{'content'})."\n";
395 print '<div id="command">'."\n";
396 if($frame==int($state{'last'}) && int($state{'state'}) >= 1 && int($state{'state'}) < 3) {
397 print '[<span id="ongh" class="';
398 if(int($state{'state'}) >= 2 || $state{'ip1'} ne '') {
404 print '">'.$hours.'</span>:<span id="ongm" class="';
405 if(int($state{'state'}) >= 2 || $state{'ip2'} ne '') {
411 print '">'.$minutes.'</span>:<span id="ongs" class="';
412 if(int($state{'state'}) >= 2 || $state{'ip3'} ne '') {
418 print '">'.$seconds.'</span>]<br>';
422 print '<a href="'.CGI_VIEWER_PATH.'/-1">'.entityencode($framedata{'command'}).'</a><br>'."\n";
425 if ($passwordOK || $frame<int($state{'last'}) || (int($state{'state'}) >= 2 && $showcommand)) {
426 if ($passwordOK || $frame<int($state{'last'})) {
427 print '<a href="'.CGI_VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">';
429 if($nextframedata{'title'} ne '') {
430 print entityencode($nextframedata{'title'});
432 elsif ($passwordOK || $frame<int($state{'last'})) {
433 print'<span class="inp">_</span>';
435 if ($passwordOK || $frame<int($state{'last'})) {
439 print'<span class="inp">_</span>';
443 print'<span class="inp">_</span>';
449 print '<div id="underlinks">'."\n";
450 print '<a href="'.CGI_PATH.'">Once again</a>';
451 if($frame>0 && $access) {
452 print ' | <a href="'.CGI_VIEWER_PATH.'/'.($frame-1).($passwordOK?('?p='.urlencode($password)):'').'">Before</a>';
454 if($frame != int($state{'last'})) {
455 print ' | <a href="'.CGI_VIEWER_PATH.'/'.int($state{'last'}).($passwordOK?('?p='.urlencode($password)):'').'">Now</a>';
457 print ' | <a href="'.CGI_GOTO_PATH.($passwordOK?('?p='.urlencode($password)):'').'">GOTO</a>'."\n";
458 print '<span style="float: right;">'."\n";
461 print '<a href="'.CGI_VIEWER_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'').'">Without</a> | ';
464 print '<a href="'.(($textmode==2)?(CGI_INFO_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'')):(CGI_VIEWER_PATH.'/'.$frame.'?b=2'.($passwordOK?('&p='.urlencode($password)):''))).'">Info</a>';
465 print ' | <a href="'.(($textmode==1)?(CGI_BBCODE_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'')):(CGI_VIEWER_PATH.'/'.$frame.'?b=1'.($passwordOK?('&p='.urlencode($password)):''))).'">BB</a>';
473 print '<a href="/" class="cz">'.WEBSITE.'</a>'."\n";
475 print '</body></html>'."\n";
478 (my $indexpath) = @_;
484 if(ref($indexpath)) {
485 $indexfile=$indexpath;
486 unless (seek($indexfile, 0, 0)) {
491 unless (open ($indexfile, ">", $indexpath)) {
496 %framedata = readdatafile(DATA_PATH.0);
497 %nextframedata = readdatafile(DATA_PATH.1);
498 %default=readdatafile(DATA_DEFAULT_PATH);
500 foreach my $ind (keys %default) {
501 unless(defined($framedata{$ind})){
502 $framedata{$ind}=$default{$ind};
504 unless(defined($nextframedata{$ind})){
505 $nextframedata{$ind}=$default{$ind};
509 print $indexfile '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
510 print $indexfile '<html lang="en"><head>'."\n";
511 print $indexfile '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
512 print $indexfile '<title>'.entityencode($settings{'story'}).' • '.WEBSITE_NAME.'</title>'."\n";
513 print $indexfile '<link rel="icon" type="image/png" href="'.FAVICON_PATH.'">'."\n";
514 print $indexfile '<link rel="stylesheet" href="'.CGI_CSS_PATH.'">'."\n";
515 print $indexfile '<link rel="index" href="'.CGI_GOTO_PATH.'">'."\n";
516 print $indexfile '<link rel="start" href="'.CGI_VIEWER_PATH.'/0">'."\n";
517 print $indexfile '<link rel="next" href="'.CGI_VIEWER_PATH.'/1">'."\n";
518 print $indexfile '<link rel="prefetch" href="'.CGI_VIEWER_PATH.'/1">'."\n";
519 print $indexfile '</head><body>'."\n";
520 print $indexfile '<a href="/"><img id="botmlogo" src="'.CGI_LOGO_PATH.'" alt="'.WEBSITE.'"></a>'."\n";
521 print $indexfile '<div id="all">'."\n";
523 print $indexfile '<div id="inst" class="ins">'."\n";
525 print $indexfile '<div id="title">'."\n";
526 print $indexfile '<H1 id="titletext">'.entityencode($settings{'story'}).'</H1>'."\n";
527 print $indexfile '</div>'."\n";
529 print $indexfile '</div><div id="framespace">'."\n";
530 print $indexfile '<img src="'.CGI_PATH.sprintf($settings{'frame'},0,$framedata{'ext'}).'" title="'.entityencode($framedata{'title'}).'" alt="0" id="frame">'."\n";
532 print $indexfile '</div><div id="insb" class="ins">'."\n";
533 print $indexfile '<div id="undertext">'."\n";
534 print $indexfile bb2htf($framedata{'content'})."\n";
535 print $indexfile '</div>'."\n";
537 print $indexfile '<div id="command">'."\n";
538 print $indexfile '><a href="'.CGI_VIEWER_PATH.'/1">'.entityencode($nextframedata{'title'}).'</a>'."\n";
539 print $indexfile '</div>'."\n";
541 print $indexfile '<div id="underlinks">'."\n";
544 # <span style="float: right;"><a href="/bsta/v/0?b=2">Info</a> | <a href="/bsta/v/0?b=1">BB</a></span>
546 print $indexfile '<a href="'.CGI_VIEWER_PATH.'/-1">Now</a> | <a href="'.CGI_GOTO_PATH.'">GOTO</a>';
547 print $indexfile '<span style="float: right;"><a href="'.CGI_INFO_PATH.'/0?b=2">Info</a> | <a href="'.CGI_VIEWER_PATH.'/0?b=1">BB</a></span>'."\n";
548 print $indexfile '</div>'."\n";
550 print $indexfile '</div>'."\n";
552 print $indexfile '</div>'."\n";
553 print $indexfile '<a href="/" class="cz">'.WEBSITE.'</a>'."\n";
555 print $indexfile '</body></html>'."\n";
557 unless (ref($indexpath)) {
561 truncate ($indexfile , tell($indexfile));
574 while($bb =~ m/(###([^#;]*);)/g) {
577 $pretext = substr($bb,0,pos ($bb)-length($tag));
578 $posttext = substr ($bb,pos ($bb));
580 if ($tagvalue =~ /^att&([0-9]+)$/) {
581 $tagvalue = CGI_ATTACH_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
583 elsif ($tagvalue =~ /^vw&([0-9]+)$/) {
584 $tagvalue = CGI_VIEWER_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
586 elsif ($tagvalue =~ /^fr&([0-9]+)$/) {
587 $tagvalue = CGI_FRAME_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
593 $bb = $pretext.$tagvalue.$posttext;
606 while($bb =~ m/(###([^#;]*);)/g) {
609 $pretext = substr($bb,0,pos ($bb)-length($tag));
610 $posttext = substr ($bb,pos ($bb));
612 if ($tagvalue =~ /^att&([0-9]+)$/) {
613 $tagvalue = 'http://'.WEBSITE.CGI_ATTACH_PATH.'/'.int($1);
615 elsif ($tagvalue =~ /^vw&([0-9]+)$/) {
616 $tagvalue = 'http://'.WEBSITE.CGI_VIEWER_PATH.'/'.int($1);
618 elsif ($tagvalue =~ /^fr&([0-9]+)$/) {
619 $tagvalue = 'http://'.WEBSITE.CGI_FRAME_PATH.'/'.int($1);
625 $bb = $pretext.$tagvalue.$posttext;
628 return linehtml(bb2bb ($bb));