From: b Date: Thu, 31 Aug 2023 22:01:25 +0000 (+0000) Subject: Initial state as of 31.08.2023 X-Git-Tag: v0.0.2 X-Git-Url: http://bicyclesonthemoon.info/git-projects/?a=commitdiff_plain;h=8c4cc224da1b2931a1f77fd7ecdd14a400253e40;p=ott%2Fbsta Initial state as of 31.08.2023 --- 8c4cc224da1b2931a1f77fd7ecdd14a400253e40 diff --git a/2words.1.c b/2words.1.c new file mode 100644 index 0000000..5fd947a --- /dev/null +++ b/2words.1.c @@ -0,0 +1,34 @@ +// 2words.c is generated from 2words.1.c +// 28.09.2016 +// +// This is the wrapper for 2words.pl. +// It's run with SETUID to have accesss to some files where the www server +// should not. That's why it has a C wrapper. In modern systems running scripts +// directly with SETUID is considered unsafe and not allowed. +// +// Copyright (C) 2016 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +###TWOWORDS_PL; +###TWOWORDS_PL_ERRLOG; + +int main(int argc, char *argv[], char *envp[]) +{ + freopen(TWOWORDS_PL_ERRLOG,"at",stderr); + return execve(TWOWORDS_PL,argv,envp); +} diff --git a/2words.1.pl b/2words.1.pl new file mode 100644 index 0000000..590d88b --- /dev/null +++ b/2words.1.pl @@ -0,0 +1,610 @@ +###PERL; +# +# /bsta/2words +# 2words is generated from 2words.1.pl. +# 09.01.2023 +# +# The wordgame interface +# +# Copyright (C) 2016 - 2017, 2023 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(failpage gethttpheader getcgi entityencode readdatafile writedatafile urlencode bb2ht); +use File::Copy; + +###STORY_PATH; +###LOGO_PATH; +###FAVICON_PATH; +###WEBSITE; +###WEBSITE_NAME; +###CSS_PATH; +###TWOWORDS_PATH; +###CGI_PATH; +###SETTINGS_PATH; +###INDEX_PATH; +###INTF_DATE; +###DATA_PATH; +###VIEWER_PATH; +###DEFAULT_PATH; +###STATE_PATH; +###WWW_PATH; +###STORY_LENGTH; +###PAGE_LENGTH; +###FIRSTPAGE_LENGTH; +###COIN_PATH; +###COIN_DATE; +###LIST_PATH; + +my %http; +my %cgi; +my %story; +my %newstory; +my %settings; +my %state; +my %gotolist; + +my $time = time(); +srand ($time-$$); + +my $method; +my $IP; +my $words; +my $color2; +my $lastip; +my $storyid; +my $turn; +my $message; +my $firstletter; +my $secondletter; +my $intfstate; +my $intfpass; +my $intfpause; +my $intfmode; +my $storypath; +my $storyfile; +my $storylock; +my @storylines; +my $ongstate; +my $page; + + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) { + $method=$1; +} +else{ + 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); +} + +%http = gethttpheader (\%ENV); +%cgi = getcgi($ENV{'QUERY_STRING'}); + +if ($method eq 'POST') { + if ($http{'content-type'} eq 'application/x-www-form-urlencoded') { + my %cgipost=getcgi( ); + foreach my $ind (keys %cgipost) { + $cgi{$ind}=$cgipost{$ind}; + } + } + # multipart not supported + else{ + exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}."); + } +} + +if ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) { + $page=int($1); +} +else { + $page=0; +} + +if ($ENV{'HTTP_X_FORWARDED_FOR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) { + $IP=$1; +} +elsif ($ENV{'REMOTE_ADDR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) { + $IP=$1; +} +else { + $IP='0.0.0.0'; +} + +if ($cgi{'words'} ne '') { + $words=$cgi{'words'}; +} + +%settings=readdatafile(SETTINGS_PATH); +%state=readdatafile(STATE_PATH); +$ongstate=int($state{'state'}); + +$storylock=0; +if (open ($storyfile,"+<",STORY_PATH)){ + $storylock=1; + if (flock($storyfile,2)) { + $storylock=2; + } + %story=readdatafile($storyfile); + + if ($story{'lastip'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) { + $lastip=$1; + } + else { + $lastip='0.0.0.0'; + } + + $storyid = int($story{'id'}); + $intfpass = int($story{'pass'}); + $intfstate = int($story{'state'}); + $intfmode = $intfstate; + $intfpause = $intfstate & 1; + if ($intfpause) { + $intfmode -= 1; + } + + if ($IP ne $lastip) { + $turn = 1; + } + else { + $turn = 0 ; + } + + if($words =~ /^bstaaaclear(all)?$/ || $intfstate < 0) { + if($words eq 'bstaaaclearall' || $intfstate < -1) { + $story{'id'}=0; + } + $story{'content'}=''; + $story{'lastip'}='0.0.0.0'; + $story{'letter'}=''; + $story{'pass'}='0'; + $story{'state'}='0'; + $turn=0; + if($ongstate == 0) { + writeindex(INDEX_PATH,0,0,0); + } + writedatafile($storyfile,%story); + } + + if ($words ne '') { + if (!$turn) { + $message = "It's not your turn."; + } + else { + if ($words =~ /^([!"\(\),\.:;\?][ \t]*)?([A-Za-z][A-Za-z'\-]*[A-Za-z']?)([!"\(\),\.:;\? \t][ \t]*)([A-Za-z][A-Za-z'\-]*[A-Za-z']?)([!"\(\),\.:;\?]?[ \t]*)$/) { + + $firstletter = lc(substr($2,0,1)); + $secondletter = lc(substr($4,0,1)); + if (($firstletter ne $story{'letter'})&&($story{'letter'} ne '')) { + $message = 'The first word must start with '.uc($story{'letter'}).'.'; + } + elsif ($firstletter eq $secondletter) { + $message = 'The second word can\'t also start with '.uc($firstletter).'.'; + } + else { + $story{'content'} = $story{'content'} . $words."\n"; + $turn = 0; + $story{'lastip'} = $IP; + $story{'letter'} = $secondletter; + + if ($cgi{'next'} ne '') { + if (split(/\r?\n/,$story{'content'}) >= (STORY_LENGTH-1)) { + $storypath = STORY_PATH.$storyid; + writedatafile($storypath,%story); + $newstory{'id'} = $storyid + 1; + $newstory{'letter'}=''; + $newstory{'lastip'}=$IP; + $newstory{'content'}=''; + $newstory{'pass'}='0'; + $newstory{'state'}='0'; + $intfstate=0; + $intfpass=0; + $intfmode=0; + $intfpause=0; + if($ongstate == 0) { + writeindex(INDEX_PATH,0,0,0); + } + writedatafile($storyfile,%newstory); + } + else { + $message = 'To early to finish this wordgame.'; + writedatafile($storyfile,%story); + } + } + else { + if ($intfpass == 1){ + $intfpass = 2; + $story{'pass'} = '2'; + if($ongstate == 0) { + writeindex(INDEX_PATH,2,0,0); + } + } + elsif(lc($2).' '.lc($4) eq $settings{'unlock'}) { + if ($intfpass == 0) { + if($ongstate == 0) { + my %framedata = readdatafile(DATA_PATH.0); + my %default = readdatafile(DEFAULT_PATH); + my $inpath; + my $outpath; + + $framedata{'ongtime'} = $time; + $gotolist{'title-0'} = $framedata{'title'}; + $gotolist{'ongtime-0'} = $framedata{'ongtime'}; + writedatafile(DATA_PATH.0,%framedata); + writedatafile(LIST_PATH,%gotolist); + + foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + } + + $inpath = DATA_PATH.sprintf($settings{'frame'},0,$framedata{'ext'}); + $outpath = WWW_PATH.sprintf($settings{'frame'},0,$framedata{'ext'}); + + if(copy ($inpath, $outpath)) { + $intfpass = 1; + $intfstate = 0; + $intfmode=0; + $intfpause=0; + $story{'pass'} = '1'; + $story{'state'} = '0'; + writeindex(INDEX_PATH,1,0,0); + } + } + else { + $message = "???"; + } + } + else { + $message = 'The password has already been used in this story.'; + } + } + writedatafile($storyfile,%story); + } + } + } + else { + $message = 'Please, two words, not more, not less (some punctuation is allowed).'; + } + } + } + elsif (($cgi{'s'} ne '') && ($intfpass==1) && ($ongstate == 0)) { + $intfstate = int($cgi{'s'}); + if($intfstate > 63 || $intfstate <0) { + $intfstate = 0; + } + $intfmode = $intfstate; + $intfpause = $intfstate & 1; + if ($intfpause) { + $intfmode -= 1; + } + $story{'state'} = $intfstate; + writeindex(INDEX_PATH,1,$intfmode,$intfpause); + writedatafile($storyfile,%story); + } + @storylines = split(/\r?\n/,$story{'content'}); + if(@storylines & 1) { + $turn = !$turn; + } + + close($storyfile); +} + +print "Content-type: text/html\n\n"; +if($method eq 'HEAD') { + exit; +} + +print ''."\n"; +print ''."\n"; +print 'Two words • '.WEBSITE_NAME.''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print '
'."\n"; + +print '
'."\n"; + +print '
'."\n"; +print '

Two words

'."\n"; +print '
'."\n"; + +if ($page == 0) { + print '
'."\n"; + for (my $i = 0; $i < @storylines; ++$i){ + print ''.entityencode($storylines[$i]).''."\n"; + $turn = !$turn; + } + print '
'."\n"; + + print '
'."\n"; + if ($message ne '') { + print ''.entityencode($message).''."\n"; + } + + if ($turn) { + print '
'."\n"; + if ($message eq '') { + if ($story{"content"} eq '') { + print 'Two words, please:
'."\n"; + } + else { + print 'Please continue, two words:
'."\n"; + } + } + print ''."\n"; + print ''."\n"; + if(@storylines >= (STORY_LENGTH-1)) { + print ''."\n"; + } + print '
'."\n"; + } + else { + if ($message eq '') { + print 'Wait for it.'."\n"; + } + } + print '
'."\n"; +} +elsif ($message ne '') { + print '
'."\n"; + print ''.entityencode($message).''."\n"; + print '
'."\n"; +} + +if(($intfpass == 1) && ($ongstate == 0)) { + print '
'."\n"; + print ''."\n"; + + print ''."\n"; + + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print '
o><<>>^||
'."\n"; +} + +print '
'."\n"; +print '
'."\n"; +for (my $i = $storyid-1-(($page!=0)?((($page-1)*PAGE_LENGTH)+FIRSTPAGE_LENGTH):0); $i > ($storyid-1-($page*PAGE_LENGTH)- FIRSTPAGE_LENGTH) && $i >= 0; --$i) { + $storypath = STORY_PATH.$i; + %newstory = readdatafile($storypath); + print '

'.entityencode($newstory{'content'}).'

'."\n"; +} + +print '
'."\n"; +print ''."\n"; + +print '
'."\n"; +print '
'."\n"; +print ''.WEBSITE.''."\n"; +print ''."\n"; + +sub writeindex { + (my $indexpath, my $pass, my $mode, my $pause) = @_; + my $indexfile; + my $indexof; + + if(ref($indexpath)) { + $indexfile=$indexpath; + unless (seek($indexfile, 0, 0)) { + return 0; + } + } + else { + unless (open ($indexfile, ">", $indexpath)) { + return 0; + } + } + + $indexof = CGI_PATH; + $indexof =~ s/\/$//g; + + my %coin = readdatafile(COIN_PATH); + + if ($pass != 1) { + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ' '."\n"; + print $indexfile ' Index of '.$indexof.''."\n"; + print $indexfile ' '."\n"; + print $indexfile ' '."\n"; + print $indexfile '

Index of '.$indexof.'

'."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile '
[ICO]NameLast modifiedSizeDescription

[DIR]Parent Directory  -  
[DIR]2words/'.INTF_DATE.' -  
[DIR]coin/'.COIN_DATE.' - Coincidence

'."\n"; + print $indexfile '
Apache/2.2.22 (Debian) Server at '.WEBSITE.' Port 80
'."\n"; + print $indexfile ''."\n"; + } + else { + my %framedata; + my %nextframedata; + my %default; + + %framedata = readdatafile(DATA_PATH.0); + %nextframedata = readdatafile(DATA_PATH.1); + %default=readdatafile(DEFAULT_PATH); + + # if($mode == 16 && $pause) { + # $framedata{'ongtime'} = $time; + # writedatafile(DATA_PATH.0,%framedata); + # } + + foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + unless(defined($nextframedata{$ind})){ + $nextframedata{$ind}=$default{$ind}; + } + } + + + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''; + if($mode == 8 || $mode == 4) { + print $indexfile 'Index of'; + } + elsif($mode == 16) { + print $indexfile entityencode($settings{'story'}); + if($pause) { + print $indexfile ' • '.WEBSITE_NAME; + } + } + else { + print $indexfile 'Index of '.$indexof; + } + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile '
'."\n"; + + print $indexfile '
'."\n"; + + print $indexfile '
'."\n"; + print $indexfile '

'; + if($mode == 8 || $mode == 4) { + print $indexfile 'Index of'; + } + elsif($mode == 16) { + print $indexfile entityencode($settings{'story'}); + } + else { + print $indexfile 'Index of '.$indexof; + } + print $indexfile '

'."\n"; + print $indexfile '
'."\n"; + + print $indexfile '
'."\n"; + print $indexfile '0'."\n"; + + print $indexfile '
'."\n"; + print $indexfile '
'."\n"; + if($mode == 8 || $mode == 4) { + print $indexfile '[DIR] Parent Directory
[DIR] yyyyb/'."\n"; + } + elsif ($mode == 16) { + if($pause) { + print $indexfile bb2ht($framedata{'content'})."\n"; + } + else { + print $indexfile "...\n"; + } + } + else { + print $indexfile '[DIR] Parent Directory
'."\n"; + print $indexfile '[DIR] 2words/ '.INTF_DATE.' -
'."\n"; + print $indexfile '[DIR] coin/ '.COIN_DATE.' - '.entityencode($coin{'server'})."\n"; + } + print $indexfile '
'."\n"; + + print $indexfile '
'."\n"; + if ($mode == 8) { + print $indexfile '[EE:EE:EE]'."\n"; + } + elsif ($mode == 4) { + print $indexfile '[EE:EE:EE]'."\n"; + } + elsif ($mode == 16) { + if($pause) { + print $indexfile '[00:00:00]
'."\n"; + print $indexfile '>'.entityencode($nextframedata{'title'}).''."\n"; + } + else { + print $indexfile '[--:--:--]
'."\n"; + print $indexfile '>..._'."\n"; + } + } + else { + } + print $indexfile '
'."\n"; + + print $indexfile '
'."\n"; + + print $indexfile '
'."\n"; + print $indexfile ''.WEBSITE.''."\n"; + + print $indexfile ''."\n"; + } + + unless (ref($indexpath)) { + close ($indexfile); + } + else { + truncate ($indexfile , tell($indexfile)); + } + + return 1; +} diff --git a/attach.1.c b/attach.1.c new file mode 100644 index 0000000..af32854 --- /dev/null +++ b/attach.1.c @@ -0,0 +1,34 @@ +// attach.c is generated from attach.1.c +// 19.10.2016 +// +// This is the wrapper for frame.pl. +// It's run with SETUID to have accesss to some files where the www server +// should not. That's why it has a C wrapper. In modern systems running scripts +// directly with SETUID is considered unsafe and not allowed. +// +// Copyright (C) 2016 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +###ATTACH_PL; +###ATTACH_PL_ERRLOG; + +int main(int argc, char *argv[], char *envp[]) +{ + freopen(ATTACH_PL_ERRLOG,"at",stderr); + return execve(ATTACH_PL,argv,envp); +} diff --git a/attach.1.pl b/attach.1.pl new file mode 100644 index 0000000..da38af8 --- /dev/null +++ b/attach.1.pl @@ -0,0 +1,154 @@ +###PERL; +# +# /bsta/a +# attach.pl is generated from attach.1.pl. +# 19.10.2016 +# +# The attachment interface +# +# Copyright (C) 2016 Balthasar Szczepañski +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; + +use bsta_lib qw(failpage gethttpheader getcgi readdatafile); + +###SETTINGS_PATH; +###DATA_PATH; +###STATE_PATH; + +my %http; +my %cgi; +my %settings; +my %state; +my %filedata; + +my $time = time(); +srand ($time-$$); + +my $method; +my $ID; +my $frame; +my $password; +my $passwordOK; +my $IP; +my $buffer; +my @fileinfo; +my $file; +my $filepath; +my $direct; + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) { + $method=$1; +} +else{ + 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); +} + +%http = gethttpheader (\%ENV); +%cgi = getcgi($ENV{'QUERY_STRING'}); + +if ($method eq 'POST') { + if ($http{'content-type'} eq 'application/x-www-form-urlencoded') { + my %cgipost=getcgi( ); + foreach my $ind (keys %cgipost) { + $cgi{$ind}=$cgipost{$ind}; + } + } + # multipart not supported + else{ + exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}."); + } +} + +# print "content-type: text/plain\n\n"; + +if ($cgi{'i'} =~ /^(.+)$/) { + $ID=int($1); +} +elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) { + $ID=int($1); +} +else { + $ID = 0; +} + +if ($cgi{'p'} =~ /^(.+)$/) { + $password=$1; +} +else { + $password=''; +} + +%settings=readdatafile(SETTINGS_PATH); +%state=readdatafile(STATE_PATH); +%filedata=readdatafile(DATA_PATH.'a'.$ID); +if ($filedata{'frame'} ne '') { + $frame=int($filedata{'frame'}); +} +else { + $frame = -1; +} + +if($password eq $settings{'password'}){ + $passwordOK = 1; +} +else{ + $passwordOK = 0; +} + +if ($filedata{'filename'} ne '' && ($passwordOK || (int($state{'state'}) >= 1 && $frame <= int($state{'last'}) && $frame >=0))) { +} +else { + exit failpage("Status: 404 Not Found\n","404 Not Found"," Attachment ".$ID." not found."); +} + +if ($filedata{'content'} ne '') { + $direct=1; +} +else { + $direct = 0; + $filepath=DATA_PATH.$filedata{'filename'}; + open($file,'<',$filepath) or exit failpage("Status: 404 Not Found\n","404 Not Found"," Attachment ".$ID." not found."); + unless(binmode($file)) { + close($file); + return failpage("Status: 500 Internal Server Error\n","500 Internal Server Error"," Can't switch to binary mode."); + } + if (my @fileinfo = stat($filepath)){ + print 'Content-length: '.$fileinfo[7]."\n"; + } +} +print 'Content-type: '.$filedata{'content-type'}."\n"; +print 'Content-disposition: attachment; filename="'.$filedata{'filename'}.'"'."\n"; +print "\n"; +if($method ne 'HEAD'){ + if($direct) { + print $filedata{'content'}; + } + else { + while (read ($file,$buffer,1024)) { + print (STDOUT $buffer); + } + } +} +if (!$direct) { + close($file); +} + diff --git a/bbcode.1.c b/bbcode.1.c new file mode 100644 index 0000000..deee30b --- /dev/null +++ b/bbcode.1.c @@ -0,0 +1,34 @@ +// bbcode.c is generated from bbcode.1.c +// 05.06.2017 +// +// This is the wrapper for bbcode.pl. +// It's run with SETUID to have accesss to some files where the www server +// should not. That's why it has a C wrapper. In modern systems running scripts +// directly with SETUID is considered unsafe and not allowed. +// +// Copyright (C) 2017 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +###BBCODE_PL; +###BBCODE_PL_ERRLOG; + +int main(int argc, char *argv[], char *envp[]) +{ + freopen(BBCODE_PL_ERRLOG,"at",stderr); + return execve(BBCODE_PL,argv,envp); +} diff --git a/bbcode.1.pl b/bbcode.1.pl new file mode 100644 index 0000000..34503b8 --- /dev/null +++ b/bbcode.1.pl @@ -0,0 +1,181 @@ +###PERL; +# +# /bsta/b +# bbcode.pl is generated from bbcode.1.pl. +# 05.06.2017 +# +# The bbcode interface +# +# Copyright (C) 2017 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(failpage gethttpheader getcgi readdatafile bb2bb linehtml); +use File::Copy; + +###DATA_PATH; +###DEFAULT_PATH; +###SETTINGS_PATH; +###STATE_PATH; +###NOACCESS_PATH; +###WEBSITE; +###VIEWER_PATH; +###ATTACH_PATH; +###FRAME_PATH; +###CGI_PATH; + +my %http; +my %cgi; +my %framedata; +my %default; +my %settings; +my %state; + +my $time = time(); +srand ($time-$$); + +my $method; +my $frame; +my $password; +my $passwordOK; +my $access; +my $showcommand; +my $ongtime; +my $seconds; + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) { + $method=$1; +} +else{ + 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); +} + +%http = gethttpheader (\%ENV); +%cgi = getcgi($ENV{'QUERY_STRING'}); + +if ($method eq 'POST') { + if ($http{'content-type'} eq 'application/x-www-form-urlencoded') { + my %cgipost=getcgi( ); + foreach my $ind (keys %cgipost) { + $cgi{$ind}=$cgipost{$ind}; + } + } + # multipart not supported + else{ + exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}."); + } +} + +if ($cgi{'f'} =~ /^(.+)$/) { + $frame=int($1); +} +elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) { + $frame=int($1); +} +else { + $frame = 0; +} + +if ($cgi{'p'} =~ /^(.+)$/) { + $password=$1; +} +else { + $password=''; +} + +%settings=readdatafile(SETTINGS_PATH); +%default=readdatafile(DEFAULT_PATH); +%framedata=readdatafile(DATA_PATH.$frame); +%state=readdatafile(STATE_PATH); +if($password eq $settings{'password'}){ + $passwordOK = 1; +} +else{ + $passwordOK = 0; +} + +if($frame<0) { + $frame = int($state{'last'}) + $frame +1; + %framedata=readdatafile(DATA_PATH.$frame); +} + +foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } +} + +if ($passwordOK || (int($state{'state'}) >= 1 && $frame <= int($state{'last'}) && $frame >= 0)) { + $access=1; +} +else { + $access=0; + %framedata = readdatafile(NOACCESS_PATH); + foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + } +} + +print "Content-type: text/plain\n"; +if(!$access) { + print "Status: 403 Forbidden\n"; +} +print "\n"; +if($method eq 'HEAD') { + exit; +} + +print '[quote][center][size=200]'.$framedata{'title'}.'[/size]'."\n"; +print '[url=http://'.WEBSITE.VIEWER_PATH.'/'.$frame.'][img]http://'.WEBSITE.CGI_PATH.($access?sprintf($settings{'frame'},$frame,$framedata{'ext'}):$framedata{'frame'}).'[/img][/url][/center]'."\n"; +print bb2bbf($framedata{'content'}).'[/quote]'."\n"; + +sub bb2bbf { + (my $bb) = @_; + my $tag; + my $tagvalue; + my $pretext; + my $posttext; + + while($bb =~ m/(###([^#;]*);)/g) { + $tag = $1; + $tagvalue = $2; + $pretext = substr($bb,0,pos ($bb)-length($tag)); + $posttext = substr ($bb,pos ($bb)); + + if ($tagvalue =~ /^att&([0-9]+)$/) { + $tagvalue = 'http://'.WEBSITE.ATTACH_PATH.'/'.int($1); + } + elsif ($tagvalue =~ /^vw&([0-9]+)$/) { + $tagvalue = 'http://'.WEBSITE.VIEWER_PATH.'/'.int($1); + } + elsif ($tagvalue =~ /^fr&([0-9]+)$/) { + $tagvalue = 'http://'.WEBSITE.FRAME_PATH.'/'.int($1); + } + else { + $tagvalue = ''; + } + + $bb = $pretext.$tagvalue.$posttext; + } + + return bb2bb ($bb); +} diff --git a/bsta.css b/bsta.css new file mode 100644 index 0000000..652f9fc --- /dev/null +++ b/bsta.css @@ -0,0 +1,346 @@ +html +{ + background-color: #46a3ff; + /* background-color: #d9ecff; */ + border-color: #000000; + color: #000000; + text-align: center; +} +a +{ + border-color: #0057af; + color: #0057af; + text-decoration:underline; +} +a:visited +{ + border-color: #bb6622; + color: #bb6622; +} +a:hover +{ + border-color: #bb6622; + color: #bb6622; +} +a:hover:visited +{ + border-color: #0057af; + color: #0057af; +} +::selection +{ + color: #ffffff; + background-color: #bb6622; +} + +div#all +{ + background-color: #d9ecff; + /* background-color: #ffffff; */ + margin-left: auto; + margin-right: auto; + margin-top: 0px; + margin-bottom: 0px; + width: 656px; + padding-top: 27px; + padding-bottom: 27px; + text-align: center; +} +div.all +{ + background-color: #d9ecff; + /* background-color: #ffffff; */ + margin-left: auto; + margin-right: auto; + margin-top: 0px; + margin-bottom: 0px; + width: 656px; + padding-top: 27px; + padding-bottom: 27px; + text-align: center; +} + +div.ins +{ + background-color: #ffffff; + margin-left: auto; + margin-right: auto; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; + border: 0px; + width: 580px; +} +div#inst +{ + /* margin-top: 27px; */ + /* margin-bottom: 0px; */ +} +div#insb +{ + /* margin-top: 0px; */ + /* margin-bottom: 27px; */ +} + +div#title +{ + text-align: center; + padding-top: 21px; + padding-bottom: 21px; + padding-left: 0px; + padding-right: 0px; + border: 0px; + margin: 0px; +} + +h1#titletext +{ + margin: 0px; + border: 0px; + padding: 0px; +} + +div#storypuzzle +{ + text-align: left; + padding: 8px; + margin: 0px; + border: 0px; + font-weight: bold; +} + +div#framespace +{ + background-color: #ffffff; + margin-left: auto; + margin-right: auto; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; + border: 0px; + width: 656px; +} + +img#frame +{ + border: solid #0057af; + border-width:27px 38px; + padding: 0px; + margin: 0px; +} + +img.intf +{ + border-width: 0px; + padding: 0px; + margin: 0px; +} + +tr.intf +{ + border-width: 0px; + padding: 0px; + margin: 0px; +} + +td.intf +{ + border-width: 0px; + padding: 0px; + margin: 0px; +} + +table#intftable +{ + border: solid #0057af; + border-width:27px 38px; + padding: 0px; + margin: 0px; + background-color: #00ff00; + border-collapse: collapse; + border-spacing: 0px; +} + +img#frame:hover +{ + border-color: #bb6622; +} + +div#undertext +{ + text-align: left; + padding: 8px; + margin: 0px; + border: 0px; +} + +div#chat +{ + text-align: left; + padding: 8px; + margin: 0px; + border: 0px; + font-family: monospace; +} + +div.fq +{ + text-align: left; + border: solid #0057af 4px; + font-family: monospace; +} + +div.fq:hover +{ + border-color: #bb6622; +} + +div.tq +{ + text-align: left; + border: solid #0057af 4px; +} + +div.tq:hover +{ + border-color: #bb6622; +} + +div#command +{ + text-align: left; + margin: 0px; + border: 0px; + padding: 8px; + font-family: monospace; + font-size: 150%; + /* font-weight: bold; */ +} + +div#underlinks +{ + text-align: left; + padding: 8px; + margin: 0px; + border: 0px; + font-family: monospace; +} + +span.inp +{ + animation: inp 2380ms step-start infinite; +} + +@keyframes inp +{ + 50% { opacity: 0.0;} +} + +input.intx +{ + border-color: #0057af; + color: #000000; + background-color: #ffffff; + border-width: 2px; + border-style: solid; + margin: 2px; + font-family: monospace; + /* font-size: 150%; */ +} + +input.intx:focus +{ + border-color: #bb6622; +} + +input.intxc +{ + border-color: #0057af; + color: #000000; + background-color: #ffffff; + border-width: 2px; + border-style: solid; + margin: 2px; + font-family: monospace; + width: 100%; + /* font-size: 150%; */ +} + +input.intxc:focus +{ + border-color: #bb6622; +} + +/* table.intxc +{ + width=100%; +} */ + +textarea.inta +{ + border-color: #0057af; + color: #000000; + background-color: #ffffff; + border-width: 2px; + border-style: solid; + width: 100%; + margin: 2px; + resize: none; +} + +textarea.inta:focus +{ + border-color: #bb6622; +} + +input.inbt +{ + border-color: #0057af; + color: #000000; + background-color: #ffffff; + border-width: 2px; + border-style: solid; + margin: 2px; + font-family: monospace; + /* font-size: 150%; */ +} + +input.inbt:focus +{ + border-color: #bb6622; +} + +.br +{ + border-color: #bb6622!important; + color: #bb6622!important; +} +.po +{ + border-color: #ff8800!important; + color: #ff8800!important; +} +.ni +{ + border-color: #0057af!important; + color: #0057af!important; +} +.bi +{ + border-color: #ffffff!important; + color: #ffffff!important; +} +.cz +{ + border-color: #000000!important; + color: #000000!important; +} + +div.le +{ + float: left; +} +div.pr +{ + float: right; +} \ No newline at end of file diff --git a/bsta_lib.1.pm b/bsta_lib.1.pm new file mode 100644 index 0000000..1105a4b --- /dev/null +++ b/bsta_lib.1.pm @@ -0,0 +1,1293 @@ +# bsta_lib.pm is generated from bsta_lib.1.pm +# 22.09.2022 +# +# Library of functions +# +# Copyright (C) 2016-2017, 2019-2020, 2022 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +package bsta_lib; + +use strict; +#use warnings +use Exporter; +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + +use constant entitycode => { + 'amp' => '&', + 'gt' => '>', + 'lt' => '<', + 'quot' => '"', + 'acute' => '´', + 'cedil' => '¸', + 'circ' => 'ˆ', + 'macr' => '¯', + 'middot' => '·', + 'tilde' => '˜', + 'uml' => '¨', + 'Aacute' => 'Á', + 'aacute' => 'á', + 'Acirc' => 'Â', + 'acirc' => 'â', + 'AElig' => 'Æ', + 'aelig' => 'æ', + 'Agrave' => 'À', + 'agrave' => 'à', + 'Aring' => 'Å', + 'aring' => 'Ã¥', + 'Atilde' => 'Ã', + 'atilde' => 'ã', + 'Auml' => 'Ä', + 'auml' => 'ä', + 'Ccedil' => 'Ç', + 'ccedil' => 'ç', + 'Eacute' => 'É', + 'eacute' => 'é', + 'Ecirc' => 'Ê', + 'ecirc' => 'ê', + 'Egrave' => 'È', + 'egrave' => 'è', + 'ETH' => 'Ð', + 'eth' => 'ð', + 'Euml' => 'Ë', + 'euml' => 'ë', + 'Iacute' => 'Í', + 'iacute' => 'í', + 'Icirc' => 'Î', + 'icirc' => 'î', + 'Igrave' => 'Ì', + 'igrave' => 'ì', + 'Iuml' => 'Ï', + 'iuml' => 'ï', + 'Ntilde' => 'Ñ', + 'ntilde' => 'ñ', + 'Oacute' => 'Ó', + 'oacute' => 'ó', + 'Ocirc' => 'Ô', + 'ocirc' => 'ô', + 'OElig' => 'Œ', + 'oelig' => 'œ', + 'Ograve' => 'Ò', + 'ograve' => 'ò', + 'Oslash' => 'Ø', + 'oslash' => 'ø', + 'Otilde' => 'Õ', + 'otilde' => 'õ', + 'Ouml' => 'Ö', + 'ouml' => 'ö', + 'Scaron' => 'Å ', + 'scaron' => 'Å¡', + 'szlig' => 'ß', + 'THORN' => 'Þ', + 'thorn' => 'þ', + 'Uacute' => 'Ú', + 'uacute' => 'ú', + 'Ucirc' => 'Û', + 'ucirc' => 'û', + 'Ugrave' => 'Ù', + 'ugrave' => 'ù', + 'Uuml' => 'Ü', + 'uuml' => 'ü', + 'Yacute' => 'Ý', + 'yacute' => 'ý', + 'yuml' => 'ÿ', + 'Yuml' => 'Ÿ', + 'cent' => '¢', + 'curren' => '¤', + 'euro' => '€', + 'pound' => '£', + 'yen' => 'Â¥', + 'brvbar' => '¦', + 'bull' => '•', + 'copy' => '©', + 'dagger' => '†', + 'Dagger' => '‡', + 'frasl' => '⁄', + 'hellip' => '…', + 'iexcl' => '¡', + 'image' => 'ℑ', + 'iquest' => '¿', + 'lrm' => '‎', + 'mdash' => '—', + 'ndash' => '–', + 'not' => '¬', + 'oline' => '‾', + 'ordf' => 'ª', + 'ordm' => 'º', + 'para' => '¶', + 'permil' => '‰', + 'prime' => '′', + 'Prime' => '″', + 'real' => 'ℜ', + 'reg' => '®', + 'rlm' => '‏', + 'sect' => '§', + 'shy' => '­', + 'sup1' => '¹', + 'trade' => '™', + 'weierp' => '℘', + 'bdquo' => '„', + 'laquo' => '«', + 'ldquo' => '“', + 'lsaquo' => '‹', + 'lsquo' => '‘', + 'raquo' => '»', + 'rdquo' => '”', + 'rsaquo' => '›', + 'rsquo' => '’', + 'sbquo' => '‚', + 'emsp' => ' ', + 'ensp' => ' ', + 'nbsp' => ' ', + 'thinsp' => ' ', + 'zwj' => '‍', + 'zwnj' => '‌', + 'deg' => '°', + 'divide' => '÷', + 'frac12' => '½', + 'frac14' => '¼', + 'frac34' => '¾', + 'ge' => '≥', + 'le' => '≤', + 'minus' => '−', + 'sup2' => '²', + 'sup3' => '³', + 'times' => '×', + 'alefsym' => 'ℵ', + 'and' => '∧', + 'ang' => '∠', + 'asymp' => '≈', + 'cap' => '∩', + 'cong' => '≅', + 'cup' => '∪', + 'empty' => '∅', + 'equiv' => '≡', + 'exist' => '∃', + 'fnof' => 'ƒ', + 'forall' => '∀', + 'infin' => '∞', + 'int' => '∫', + 'isin' => '∈', + 'lang' => '⟨', + 'lceil' => '⌈', + 'lfloor' => '⌊', + 'lowast' => '∗', + 'micro' => 'µ', + 'nabla' => '∇', + 'ne' => '≠', + 'ni' => '∋', + 'notin' => '∉', + 'nsub' => '⊄', + 'oplus' => '⊕', + 'or' => '∨', + 'otimes' => '⊗', + 'part' => '∂', + 'perp' => '⊥', + 'plusmn' => '±', + 'prod' => '∏', + 'prop' => '∝', + 'radic' => '√', + 'rang' => '⟩', + 'rceil' => '⌉', + 'rfloor' => '⌋', + 'sdot' => '⋅', + 'sim' => '∼', + 'sub' => '⊂', + 'sube' => '⊆', + 'sum' => '∑', + 'sup' => '⊃', + 'supe' => '⊇', + 'there4' => '∴', + 'Alpha' => 'Α', + 'alpha' => 'α', + 'Beta' => 'Β', + 'beta' => 'β', + 'Chi' => 'Χ', + 'chi' => 'χ', + 'Delta' => 'Δ', + 'delta' => 'δ', + 'Epsilon' => 'Ε', + 'epsilon' => 'ε', + 'Eta' => 'Η', + 'eta' => 'η', + 'Gamma' => 'Γ', + 'gamma' => 'γ', + 'Iota' => 'Ι', + 'iota' => 'ι', + 'Kappa' => 'Κ', + 'kappa' => 'κ', + 'Lambda' => 'Λ', + 'lambda' => 'λ', + 'Mu' => 'Μ', + 'mu' => 'μ', + 'Nu' => 'Ν', + 'nu' => 'ν', + 'Omega' => 'Ω', + 'omega' => 'ω', + 'Omicron' => 'Ο', + 'omicron' => 'ο', + 'Phi' => 'Φ', + 'phi' => 'φ', + 'Pi' => 'Π', + 'pi' => 'π', + 'piv' => 'ϖ', + 'Psi' => 'Ψ', + 'psi' => 'ψ', + 'Rho' => 'Ρ', + 'rho' => 'ρ', + 'Sigma' => 'Σ', + 'sigma' => 'σ', + 'sigmaf' => 'ς', + 'Tau' => 'Τ', + 'tau' => 'τ', + 'Theta' => 'Θ', + 'theta' => 'θ', + 'thetasym' => 'ϑ', + 'upsih' => 'ϒ', + 'Upsilon' => 'Î¥', + 'upsilon' => 'υ', + 'Xi' => 'Ξ', + 'xi' => 'ξ', + 'Zeta' => 'Ζ', + 'zeta' => 'ζ', + 'crarr' => '↵', + 'darr' => '↓', + 'dArr' => '⇓', + 'harr' => '↔', + 'hArr' => '⇔', + 'larr' => '←', + 'lArr' => '⇐', + 'rarr' => '→', + 'rArr' => '⇒', + 'uarr' => '↑', + 'uArr' => '⇑', + 'clubs' => '♣', + 'diams' => '♦', + 'hearts' => '♥', + 'spades' => '♠', + 'loz' => '◊', +}; + +use constant tagsbb => { + 'ht' => '', + '/ht' => '', + 'fq' => '[quote]', + '/fq' => '[/quote]', + 'tq' => '[quote]', + '/tq' => '[/quote]', + 'ni' => '[color=#0057AF]', + '/ni' => '[/color]', + 'br' => '[color=#BB6622]', + '/br' => '[/color]', + 'po' => '[color=#FF8800]', + '/po' => '[/color]', + 'url' => '[url]', + 'url=' => '[url=', + 'url/=' => ']', + '/url' => '[/url]', + 'i' => '[i]', + '/i' => '[/i]', + 'list' => '[list]', + 'list=' => '[list=', + 'list/='=> ']', + '/list' => '[/list]', + '*' => '[*]', + '/*' => '[/*]', + '?' => '[unknown!]', + '/?' => '[/unknown!]', +}; +use constant tagsht => { + 'ht' => '', + '/ht' => '', + 'fq' => '
', + '/fq' => '
', + 'tq' => '
', + '/tq' => '
', + 'ni' => '', + '/ni' => '', + 'br' => '', + '/br' => '', + 'po' => '', + '/po' => '', + 'url' => '',#think: how to add selfincluding? + 'url=' => '', + '/url' => '', + 'i' => '', + '/i' => '', + 'list' => '
    ', + 'list=' => '
      ', + '/list' => '
', + '/list=' => '', + '*' => '
  • ', + '/*' => '
  • ', + '?' => '[unknown!]', + '/?' => '[/unknown!]', +}; + +$VERSION = 0.000002; +@ISA = qw(Exporter); +@EXPORT = (); +@EXPORT_OK = qw(entityencode failpage gethttpheader getcgi urldecode readdatafile writedatafile printdatafile printdatafileht urlencode linehtml bb2ht bb2bb); +%EXPORT_TAGS = (); + +# Function to show an error page +# arguments: 1 - header fields, 2 - page title, 3 - error message, 4 method +sub failpage { + (my $header, my $title, my $message, my $method)=@_; + if($header ne ''){ + print $header; + } + if($method eq 'HEAD') { + print "\n"; + return; + } + print "Content-type: text/html\n\n"; + print ''."\n"; + print ''."\n"; + if($title ne ''){ + print ''.entityencode($title).''."\n"; + } + print ''."\n"; + print ''."\n"; + if($title ne ''){ + print '

    '.entityencode($title).'

    '."\n"; + } + if($message ne ''){ + print '

    '.entityencode($message).'

    '."\n"; + } + print ''."\n"; +} + +# function to encode entities, decimal, +sub entityencode { + (my $t, my $all) = @_; + if ($all) { + $t =~ s/(.)/sprintf('\&#%02hu;',ord($1))/eg; + } + else { + $t =~ s/([\"=><\&])/sprintf('&#%02hu;',ord($1))/eg; + } + return $t; +} + +# function to get values of http header fields. Returns a hash. names of header +# fields are lowercase +sub gethttpheader { + (my $env) = @_; + + my %http; + + foreach my $ind (keys %$env) { + my $name = ''; + my $value= ''; + + if ($ind =~ /^HTTP_([A-Z0-9_]+)$/) { + $name=$1; + } + elsif ($ind =~ /^(CONTENT_[A-Z0-9_]+)$/) { + $name=$1; + } + else{ + next; + } + $name =~ s/_/-/g; + $name = lc($name); + if ($$env{$ind} =~ /^([\x20-\x7e]*)$/) { + $value=$1; + } + else { + next; + } + $http{$name}=$value; + } + return %http; +} + +# The function to get CGI parameters from string. +# Format is: name=url_encoded_value&name=url_encoded_value& ... &name=url_encoded_value +sub getcgi { + my $arg; + my $val; + my %cgi; + my $i = $_[0]; + $i =~ s/[\r\n]//g; + my @s = split('&',$i); + foreach my $l ( @s) { + ($arg,$val)=split('=',$l); + $cgi{$arg}=urldecode($val); + } + return %cgi; +} + +# Function for decoding URL-encoded text +sub urldecode { + my $t = $_[0]; + $t =~ s/\+/ /g; + $t =~ s/%([a-fA-F0-9]{2})/chr(hex($1))/eg; + return $t; +} + +# Function to read data from datafiles. +# Very similar to http header file reading. (function readheaderfile() in proxy +# library) +# +# Differences: +# +# 1. After field name and colon there must be exactly one whitespace (space or +# tab). Any other leading or trailing whitespace (but not the newline character +# at the end of the line) is treated as part of the field value. +# +# 2. Instead of colon an equal sign can be used. The number of whitespaces after +# it is then zero and not one. +# +# 3. When header field is split into multiple lines the next lines must start +# with exactly one whitespace (tab or space) Any other leading or trailing +# whitespace (but not the newline character at the end of the line) is treated +# as part of the field value. the lines will be joined with a newline between +# them. +# +# 4. When the same field name appears it replaces the previous one. +# +# 5. Line separator is LF and not CR LF. The CR character is treated as part of +# the field value. +# +# 6. After the end of header (double newline) all next lines are treated as the +# value of the "content" field. +# +# Returns a hash containing the values. +# Names are case sensitive and are converted to lowercase +# +# Argument can be a path or a file handle. In case of a file handle it will just +# read the file. In case of path it opens the file before reading and closes +# after. On failure (file not open) returns empty hash. +# +sub readdatafile { + (my $datapath) = @_; + my $datafile; + my %data; + my $eoh=0; + + # check if $datapath is actually a path or maybe a filehandle + # filehandles are references. + if(ref($datapath)) { + $datafile=$datapath; + unless (seek($datafile, 0, 0)) { + return %data; + } + } + else { + unless (open ($datafile, "<", $datapath)) { + return %data; + } + } + + # The name of header field in previous line. Required for header fields that + # occupy multiple lines. + my $lastname=''; + + while (defined(my $line = <$datafile>)) { + my $name=''; + my $value=''; + + if ($eoh){ + unless($line eq'') { + $data{'content'} = $data{'content'}.$line; + } + next; + } + + $line =~ s/[\n]$//g; + + # Empty line - end of header. + if ($line eq ''){ + $eoh=1; + } + # Line starts with whitespace. It's a continuation of the previous line. + # Concatenate the field value, separated by newline. + elsif($line =~ /^[ \t](.*)$/){ + if($lastname ne '') { + $data{$lastname}.="\n".$1; + } + } + # Line starts with a name followed by colon/equal sign. Save the value + elsif ($line =~ /^([^:=]+)((:[ \t])|=)(.*)$/) { + $name = lc($1); + $value = $4; + + $data{$name}=$value; + + $lastname = $name; + } + } + + # If argument was a path the file must be closed. + unless (ref($datapath)) { + close ($datafile); + } + + return %data; +} + +# the function to write data to datafiles (see readdatafile() description) +# +# First argument can be a path or a file handle. In case of a file handle it +# will just write the file. In case of path it opens the file before writing and +# closes after. +# +# On failure (file not open) returns 0. +# On success returns 1. +# +sub writedatafile { + (my $headerpath, my %header) = @_; + my $headerfile; + + if(ref($headerpath)) { + $headerfile=$headerpath; + unless (seek($headerfile, 0, 0)) { + return 0; + } + } + else { + unless (open ($headerfile, ">", $headerpath)) { + return 0; + } + } + + foreach my $ind (keys %header) { + unless($ind eq 'content') { + my $headname = $ind; + my $headval = $header{$ind}; + $headval =~ s/\r//g; + $headval =~ s/\n/\n /g; + print $headerfile "$headname: $headval\n"; + } + } + print $headerfile "\n".$header{'content'}; + + unless (ref($headerpath)) { + close ($headerfile); + } + else { + truncate ($headerfile , tell($headerfile)); + } + + return 1; +} + +# the function to print data to stdout (see readdatafile() description) +# +# On success returns 1. +# +sub printdatafile { + (my %header) = @_; + + foreach my $ind (keys %header) { + unless($ind eq 'content') { + my $headname = $ind; + my $headval = $header{$ind}; + $headval =~ s/\r//g; + $headval =~ s/\n/\n /g; + print "$headname: $headval\n"; + } + } + print "\n".$header{'content'}; + + return 1; +} + +# the function to print data to stdout as html (see readdatafile() description) +# +# On success returns 1. +# +sub printdatafileht { + (my %header) = @_; + + foreach my $ind (keys %header) { + unless($ind eq 'content') { + my $headname = $ind; + my $headval = $header{$ind}; + $headval =~ s/\r//g; + $headval =~ s/\n/\n /g; + print linehtml("$headname: $headval\n"); + } + } + print linehtml("\n".$header{'content'}); + + return 1; +} + + +sub urlencode { + (my $t, my $all) = @_; + if ($all) { + $t =~ s/(.)/sprintf('%%%02hX',ord($1))/eg; + } + else { + $t =~ s/([^0-9A-Za-z.~\-_])/sprintf('%%%02hX',ord($1))/eg; + } + return $t; +} + +#analyse bbcode text to build tag tree #TODO make [/*] optional! +sub bbtree { + (my $bb, my $printdebug) = @_; + my %bbtree; + my $ind; + my $tag; + my $tagname; + my $tagvalue; + my $tagend; + my $level=0; + my $pretext; + my $debug; + + $ind="_"; + $level=0; + $bbtree{"_.n"}="ht"; + $bbtree{"_.v"}=''; + $bbtree{"_.t"}="tg"; + $bbtree{"_.e"}=0; + $bbtree{"_.c"}=''; + $debug .= debug($printdebug, "\n\n"); + $bbtree{'_.'.$bbtree{"_.e"}.'.t'}="tg"; + $bbtree{'_.'.$bbtree{"_.e"}.'.n'}='/ht'; + $bbtree{"_.e"}+=1; + $bbtree{"_.c"}=1; + + return ($debug, %bbtree); +} + +#convert tag tree to final text +sub convtree { + (my $printdebug, my $debug, my $lang, my %bbtree) = @_; + my $ht; + my $ind; + my $indd; + my $level=0; + my $tagsr = ($lang eq 'html') ? tagsht : tagsbb; + my %tags = %$tagsr; + my $escape = ($lang eq 'html'); + + # $debug .= debug($printdebug, "\n****\n"); + # foreach my $iiii (keys %tags) { + # $debug .= debug($printdebug, $iiii.'='.$tags{$iiii}."\n"); + # } + # $debug .= debug($printdebug, "****\n"); + + $level=0; + $ind='_'; + $ht=''; + $debug .= debug($printdebug, "\n\n"); + return ($debug, $ht); +} + +#bbcode to html, TBD +sub bb2ht { + (my $bb, my $printdebug) = @_; + my $ht; + my %bbtree; + my $debug; + + ($debug, %bbtree) = bbtree($bb,$printdebug); + ($debug, $ht) = convtree ($printdebug, $debug, 'html', %bbtree); + + return $ht; + + # $level=0; + # $ind='_'; + # $ht=''; + # $debug .= debug($printdebug, "\n\n"); + # # print $debug; + + + +} + +#bbcode to bb, TBD +sub bb2bb { + (my $bb, my $printdebug) = @_; + my $ht; + my %bbtree; + my $debug; + + ($debug, %bbtree) = bbtree($bb,$printdebug); + ($debug, $ht) = convtree ($printdebug, $debug, 'bb', %bbtree); + + return $ht; + + # $level=0; + # $ind='_'; + # $ht=''; + # $debug .= debug($printdebug, "\n\n"); + # # print $debug; + + + +} + +sub linehtml { + (my $ht) = @_; + my $esc; + my $ind; + + $ht =~ s/\r\n/\n/g; + $ht =~ s/\r/\n/g; + + while ($ht ne '') { + $ind = index($ht,"\n"); + if($ind>=0){ + $esc = $esc.entityencode(substr($ht,0,$ind))."
    \n"; + $ht=substr($ht,$ind+1); + } + else + { + $esc = $esc.entityencode($ht); + $ht = ''; + } + } + return $esc; +} + +sub debug { + (my $print, my $text) = @_; + + if ($print) { + print $text; + } + + return $text; +} + +1 diff --git a/chat.1.c b/chat.1.c new file mode 100644 index 0000000..2acd182 --- /dev/null +++ b/chat.1.c @@ -0,0 +1,34 @@ +// chat.c is generated from chat.1.c +// 13.11.2016 +// +// This is the wrapper for chat.pl. +// It's run with SETUID to have accesss to some files where the www server +// should not. That's why it has a C wrapper. In modern systems running scripts +// directly with SETUID is considered unsafe and not allowed. +// +// Copyright (C) 2016 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +###CHAT_PL; +###CHAT_PL_ERRLOG; + +int main(int argc, char *argv[], char *envp[]) +{ + freopen(CHAT_PL_ERRLOG,"at",stderr); + return execve(CHAT_PL,argv,envp); +} diff --git a/chat.1.pl b/chat.1.pl new file mode 100644 index 0000000..ac274ba --- /dev/null +++ b/chat.1.pl @@ -0,0 +1,439 @@ +###PERL; +# +# /bsta/coin +# chat.pl is generated from chat.1.pl. +# 11.01.2017 +# +# The coincidence interface +# +# Copyright (C) 2016-2017 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(failpage gethttpheader getcgi entityencode readdatafile writedatafile urlencode); +use File::Copy; + +###LOGO_PATH; +###FAVICON_PATH; +###COIN_PATH; +###CHAT_PATH; +###WEBSITE_NAME; +###FAVICON_PATH; +###CSS_PATH; +###LOGO_PATH; +###WEBSITE; +###COINCIDENCE_PATH; +###CGI_PATH; + +my %http; +my %cgi; +my %coin; +my %chat; + +my $time = time(); +srand ($time-$$); + +my $method; +my $IP; +my $page; +my $words; +my $username; +my $action; +my $password; +my $chatfile; +my $state; +my $passwordOK; +my @chatlines; +my $chatstate; +my $message; +my $chatid; +my $lastid; + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) { + $method=$1; +} +else{ + 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); +} + +%http = gethttpheader (\%ENV); +%cgi = getcgi($ENV{'QUERY_STRING'}); + +if ($method eq 'POST') { + if ($http{'content-type'} eq 'application/x-www-form-urlencoded') { + my %cgipost=getcgi( ); + foreach my $ind (keys %cgipost) { + $cgi{$ind}=$cgipost{$ind}; + } + } + # multipart not supported + else{ + exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}."); + } +} + +if ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) { + $page=int($1); +} +else { + $page=-1; +} + +if ($ENV{'REMOTE_ADDR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) { + $IP=$1; +} +else { + $IP='0.0.0.0'; +} + +if ($cgi{'words'} ne '') { + $words=$cgi{'words'}; +} +if ($cgi{'username'} ne '') { + $username=$cgi{'username'}; +} +if ($cgi{'join'} ne '') { + $action=1; +} +elsif ($cgi{'leave'} ne '') { + $action=2; +} +elsif ($cgi{'nopost'} ne '') { + $action=3; +} +elsif ($cgi{'file'} ne '') { + $action=4; +} +else { + $action=0; +} +if ($cgi{'p'} ne '') { + $password=$cgi{'p'}; +} + +%coin=readdatafile(COIN_PATH); + +if($password eq $coin{'password'}){ + $passwordOK = 1; +} +else{ + $passwordOK = 0; + $username = ''; +} + +if($page < 0) { + if (open ($chatfile,"+<",CHAT_PATH)){ + if (flock($chatfile,2)) { + %chat=readdatafile($chatfile); + + $chatstate=int($chat{'state'}); + $chatid=int($chat{'id'}); + $lastid=$chatid; + + if($action==0 && $cgi{'words'} ne '') { + if($chatstate < 1 && !$passwordOK) { + $message = 'Not connected.'; + } + else { + if ($cgi{'words'} !~ /[\r\n]/) { + if($username =~ /^[A-Za-z]*$/) { + $chat{'content'}=$chat{'content'}.$username.': '.$cgi{'words'}."\n"; + if($chatstate < 2) { + $chat{'state'} = 2; + $chatstate = 2; + } + writedatafile($chatfile,%chat); + } + else { + $message='Invalid username.'; + } + } + else { + $message='Invalid text.'; + } + } + } + elsif ($action==1) { + if($chatstate > 0 && !$passwordOK) { + $message = 'Already connected.'; + } + else { + if($username =~ /^[A-Za-z]*$/) { + if ($passwordOK || $cgi{'words'} eq $coin{'server'}) { + $chat{'content'}=$chat{'content'}.'join@'.$username.': '.$cgi{'words'}."\n"; + if($chatstate < 1) { + $chat{'state'} = 1; + $chatstate = 1; + } + writedatafile($chatfile,%chat); + } + elsif ($cgi{'words'} eq '') { + $message='Server ID missing.'; + } + elsif ($cgi{'words'} !~ /^[0-9]+$/) { + $message='Invalid server ID.'; + } + else { + $message='No active Coincidence server with this ID.'; + } + } + else { + $message = 'Invalid username.'; + } + } + } + elsif ($action==2) { + if($chatstate < 1 && !$passwordOK) { + $message = 'Already disconnected.'; + } + else { + if($username =~ /^[A-Za-z]*$/) { + $chat{'content'}=$chat{'content'}.'leave@'.$username.': '.$cgi{'words'}."\n"; + if($username ne '') { + writedatafile($chatfile,%chat); + } + elsif ($chatstate > 1) { + writedatafile(CHAT_PATH.$chatid,%chat); + my %newchat; + $newchat{'id'}=$chatid+1; + $newchat{'state'}=0; + $newchat{'content'}=''; + writedatafile($chatfile,%newchat); + } + else { + my %newchat; + $newchat{'id'}=$chatid; + $newchat{'state'}=0; + $newchat{'content'}=''; + writedatafile($chatfile,%newchat); + } + } + else { + $message = 'Invalid username.'; + } + } + } + elsif($action==4 && $cgi{'file'} ne '' && $cgi{'words'} ne '' && $passwordOK) { + if ($cgi{'words'} !~ /[\r\n]/) { + if($username =~ /^[A-Za-z]*$/) { + $chat{'content'}=$chat{'content'}.'file@'.$username.': '.$cgi{'words'}."\n"; + if($chatstate < 2) { + $chat{'state'} = 2; + $chatstate = 2; + } + writedatafile($chatfile,%chat); + } + else { + $message='Invalid username.'; + } + } + else { + $message='Invalid text.'; + } + } + + @chatlines = split(/\r?\n/,$chat{'content'}); + } + else{ + $chatstate=0; + $message='Can\'t lock data file!'; + } + + + close($chatfile); + } + else { + $chatstate=0; + $message='Can\'t open data file!'; + } +} +else { + # %chat=readdatafile(CHAT_PATH); + # $chatid=int($chat{'id'})-$page; + %chat=readdatafile(CHAT_PATH); + $lastid=int($chat{'id'}); + %chat=readdatafile(CHAT_PATH.$page); + $chatid=int($chat{'id'}); + $chatstate=int($chat{'state'}); + @chatlines = split(/\r?\n/,$chat{'content'}); +} + + +# print "Content-type: text/plain\n\n"; +# print CHAT_PATH."\n"; +# print 'state: '.$chat{'state'}."\n"; +# print 'id: '.$chat{'id'}."\n\n"; +# print $chat{'content'}; + +print "Content-type: text/html\n\n"; +if($method eq 'HEAD') { + exit; +} + +print ''."\n"; +print ''."\n"; +print 'Coincidence • '.WEBSITE_NAME.''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print '
    '."\n"; + +print '
    '."\n"; + +print '
    '."\n"; +print '

    Coincidence

    '."\n"; +print '
    '."\n"; + +print '
    '."\n"; +if ($page >= 0) { + print 'Before: '.$chatid."\n"; +} +elsif ($chatstate>0){ + print 'Connected to server '.entityencode($coin{'server'}).' as user '.entityencode(($username ne '')?$username:$coin{'name'}).' ('.entityencode(abbrname(($username ne '')?$username:$coin{'name'})).'), public key '.entityencode($coin{'key'}).'.'."\n"; +} +else{ + print 'Not connected.'; +} +print '
    '."\n"; +print '
    '."\n"; +if ($message ne '') { + print ''.entityencode($message).''."\n"; +} +if ($page < 0) { + print '
    '."\n"; + if ($passwordOK) { + print ''."\n"; + print ''."\n"; + print "|\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + } + elsif ($chatstate>0) { + print ''."\n"; + print ''."\n"; + print "|\n"; + print ''."\n"; + print ''."\n"; + } + else { + print ''."\n"; + print ''."\n"; + } + print '
    '."\n"; +} +print '
    '."\n"; + +print '
    '."\n"; + +print '
    '."\n"; +if ($page < 0) { + for (my $i = @chatlines-1; $i>=0; --$i) { + print chatline($chatlines[$i])."
    \n"; + } +} +else { + for (my $i = 0; $i<@chatlines; ++$i) { + print chatline($chatlines[$i])."
    \n"; + } +} +print '
    '."\n"; + +print ''."\n"; + +print '
    '."\n"; +print '
    '."\n"; +print ''.WEBSITE.''."\n"; +print ''."\n"; + + + +# print CHAT_PATH."\n"; +# print 'state: '.$chat{'state'}."\n"; +# print 'id: '.$chat{'id'}."\n\n"; +# print $chat{'content'}; + +sub abbrname { + (my $name) = @_; + my $abbr; + + if($name !~ /^[A-Za-z]+$/) { + return '?'; + } + + $abbr = uc(substr($name,0,1)); + $name = substr($name,1); + while($name =~ m/([A-Z])/g) { + $abbr = $abbr.$1; + } + return $abbr; +} + +sub chatline { + (my $line) = @_; + my $action; + my $name; + my $text; + + if ($line =~ /^([a-z]*@)?([A-Za-z]*): (.*)$/) { + $action=$1; + $name=$2; + $text=$3; + + if($action ne ''){ + if ($action eq 'join@') { + return entityencode(($name ne '')?$name:$coin{'name'}).' ('.entityencode(abbrname(($name ne '')?$name:$coin{'name'})).') joined the public chat on server '.entityencode($coin{'server'}).'.'; + } + elsif ($action eq 'leave@') { + return entityencode(($name ne '')?$name:$coin{'name'}).' ('.entityencode(abbrname(($name ne '')?$name:$coin{'name'})).') left the public chat on server '.entityencode($coin{'server'}).'.'; + } + elsif ($action eq 'file@') { + return entityencode(($name ne '')?$name:$coin{'name'}).' ('.entityencode(abbrname(($name ne '')?$name:$coin{'name'})).') sent the file '.entityencode($text).'.'; + } + else { + return 'E:E:E'; + } + } + else { + return ''.entityencode(abbrname(($name ne '')?$name:$coin{'name'})).': '.entityencode($text).''; + } + } + else { + return 'E:E:E'; + } +} diff --git a/config.1.txt b/config.1.txt new file mode 100644 index 0000000..be78fb5 --- /dev/null +++ b/config.1.txt @@ -0,0 +1,29 @@ +# config.txt is generated from config.1.txt +# 20.08.2016 +# +# The file with the autogenerated configurations for Apache2 and crontab +# +# Copyright (C) 2016 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# ! the license is for config.1.txt, not config.txt. + +################################################################################ +#copy this to your Apache2 configuration, + +###VIEWER_ALIAS; +###FRAME_ALIAS; + +################################################################################ diff --git a/config.txt b/config.txt new file mode 100644 index 0000000..9f32353 --- /dev/null +++ b/config.txt @@ -0,0 +1,29 @@ +# config.txt is generated from config.1.txt +# 20.08.2016 +# +# The file with the autogenerated configurations for Apache2 and crontab +# +# Copyright (C) 2016 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# ! the license is for config.1.txt, not config.txt. + +################################################################################ +#copy this to your Apache2 configuration, + +ScriptAlias /bsta/v /eizm/bin/bsta/viewer +ScriptAlias /bsta/v /eizm/bin/bsta/frame + +################################################################################ diff --git a/configure.pl b/configure.pl new file mode 100644 index 0000000..b397ac5 --- /dev/null +++ b/configure.pl @@ -0,0 +1,137 @@ +#!/usr/bin/perl + +# configure.pl +# 02.07.2017 +# +# This script is called from the makefile. It reads the settings file and +# inserts the information in the source files. +# +# Copyright (C) 2015-2017 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +unless ($ARGV[0]) { + print STDERR "Configfile missing.\n"; + exit 1; +} + +unless (open $configfile, "<", $ARGV[0]) { + print STDERR "Cannot open configfile\n"; + exit 2; +} + +# Read the config file, line format: +# some_name = some value # some comment +while (defined(my $line = <$configfile>)) { + $line =~ s/[\r\n]//g; + $line =~ s/#.*$//; #comment + if ($line =~ /^[ \t]*([a-zA-Z0-9_\-\.]+)[ \t]*=[ \t]*([^ \t](.*[^ \t])?)[ \t]*$/){ + my $name=$1; + my $value=$2; + $set{$name}=$value; + } +} +close ($configfile); + +# Now generate things to be inserted. + +$def{'GZIP_PATH'} = "use constant GZIP_PATH => '".$set{'gzip'}."';"; +$def{'LOG_PATH'} = "use constant LOG_PATH => '".$set{'log_path'}."';"; + +$def{'DATA_PATH'} = "use constant DATA_PATH => '".$set{'data_path'}."';"; +$def{'DEFAULT_PATH'} = "use constant DEFAULT_PATH => '".$set{'data_path'}."default';"; +$def{'SETTINGS_PATH'} = "use constant SETTINGS_PATH => '".$set{'data_path'}."settings';"; +$def{'NOACCESS_PATH'} = "use constant NOACCESS_PATH => '".$set{'data_path'}."noaccess';"; +$def{'STATE_PATH'} = "use constant STATE_PATH => '".$set{'data_path'}."state';"; +$def{'STORY_PATH'} = "use constant STORY_PATH => '".$set{'data_path'}."story';"; +$def{'CHAT_PATH'} = "use constant CHAT_PATH => '".$set{'data_path'}."chat';"; +$def{'COIN_PATH'} = "use constant COIN_PATH => '".$set{'data_path'}."coincidence';"; +$def{'LIST_PATH'} = "use constant LIST_PATH => '".$set{'data_path'}."list';"; +$def{'WWW_PATH'} = "use constant WWW_PATH => '".$set{'www_path'}."';"; +$def{'INDEX_PATH'} = "use constant INDEX_PATH => '".$set{'www_path'}."index.htm';"; +$def{'CGI_PATH'} = "use constant CGI_PATH => '".$set{'cgi_path'}."';"; +$def{'CSS_PATH'} = "use constant CSS_PATH => '".$set{'cgi_path'}."bsta.css';"; +$def{'LOGO_PATH'} = "use constant LOGO_PATH => '".$set{'cgi_path'}."botmlogo.png';"; +$def{'FRAME_PATH'} = "use constant FRAME_PATH => '".$set{'cgi_path'}."f';"; +$def{'VIEWER_PATH'} = "use constant VIEWER_PATH => '".$set{'cgi_path'}."v';"; +$def{'ATTACH_PATH'} = "use constant ATTACH_PATH => '".$set{'cgi_path'}."a';"; +$def{'INFO_PATH'} = "use constant INFO_PATH => '".$set{'cgi_path'}."i';"; +$def{'BBCODE_PATH'} = "use constant BBCODE_PATH => '".$set{'cgi_path'}."b';"; +$def{'GOTO_PATH'} = "use constant GOTO_PATH => '".$set{'cgi_path'}."g';"; +$def{'TWOWORDS_PATH'} = "use constant TWOWORDS_PATH => '".$set{'cgi_path'}."2words';"; +$def{'COINCIDENCE_PATH'} = "use constant COINCIDENCE_PATH => '".$set{'cgi_path'}."coin';"; +$def{'TIMER_PATH'} = "use constant TIMER_PATH => '".$set{'cgi_path'}."timer.js';"; +$def{'FAVICON_PATH'} = "use constant FAVICON_PATH => '".$set{'favicon_path'}."';"; +$def{'WEBSITE'} = "use constant WEBSITE => '".$set{'website'}."';"; +$def{'WEBSITE_NAME'} = "use constant WEBSITE_NAME => '".$set{'website_name'}."';"; +$def{'INTF_DATE'} = "use constant INTF_DATE => '".$set{'intf_date'}."';"; +$def{'COIN_DATE'} = "use constant COIN_DATE => '".$set{'coin_date'}."';"; +$def{'LOG_SIZE_LIMIT'} = "use constant LOG_SIZE_LIMIT => ".$set{'log_size_limit'}.";"; +$def{'LOGS_UNCOMPRESSED'} = "use constant LOGS_UNCOMPRESSED => ".$set{'logs_uncompressed'}.";"; +$def{'LOGS_TOTAL'} = "use constant LOGS_TOTAL => ".$set{'logs_total'}.";"; +$def{'STORY_LENGTH'} = "use constant STORY_LENGTH => ".int($set{'story_length'}).";"; +$def{'PAGE_LENGTH'} = "use constant PAGE_LENGTH => ".int($set{'page_length'}).";"; +$def{'FIRSTPAGE_LENGTH'} = "use constant FIRSTPAGE_LENGTH => ".int($set{'firstpage_length'}).";"; + +$def{'VIEWER_ALIAS'} = 'ScriptAlias '.$set{'cgi_path'}.'v '.$set{'bin_path'}.'viewer'; +$def{'FRAME_ALIAS' } = 'ScriptAlias '.$set{'cgi_path'}.'v '.$set{'bin_path'}.'frame'; + +$def{'LIB'} = "use lib '".$set{'lib_path'}."';"; + +$def{'PATH'} = "\$ENV{'PATH'} = '".$set{'path'}."';"; + +$def{'PERL'} = "#!".$set{'perl'}; + +$def{'FRAME_PL'} = '#define FRAME_PL "'.$set{'bin_path'}.'frame.pl"'; +$def{'VIEWER_PL'} = '#define VIEWER_PL "'.$set{'bin_path'}.'viewer.pl"'; +$def{'ATTACH_PL'} = '#define ATTACH_PL "'.$set{'bin_path'}.'attach.pl"'; +$def{'TWOWORDS_PL'} = '#define TWOWORDS_PL "'.$set{'bin_path'}.'2words.pl"'; +$def{'CHAT_PL'} = '#define CHAT_PL "'.$set{'bin_path'}.'chat.pl"'; +$def{'INFO_PL'} = '#define INFO_PL "'.$set{'bin_path'}.'info.pl"'; +$def{'GOTO_PL'} = '#define GOTO_PL "'.$set{'bin_path'}.'goto.pl"'; +$def{'BBCODE_PL'} = '#define BBCODE_PL "'.$set{'bin_path'}.'bbcode.pl"'; +$def{'FRAME_PL_ERRLOG'} = '#define FRAME_PL_ERRLOG "'.$set{'log_path'}.'frame-stderr.log"'; +$def{'VIEWER_PL_ERRLOG'} = '#define VIEWER_PL_ERRLOG "'.$set{'log_path'}.'viewer-stderr.log"'; +$def{'ATTACH_PL_ERRLOG'} = '#define ATTACH_PL_ERRLOG "'.$set{'log_path'}.'attach-stderr.log"'; +$def{'TWOWORDS_PL_ERRLOG'} = '#define TWOWORDS_PL_ERRLOG "'.$set{'log_path'}.'2words-stderr.log"'; +$def{'CHAT_PL_ERRLOG'} = '#define CHAT_PL_ERRLOG "'.$set{'log_path'}.'chat-stderr.log"'; +$def{'INFO_PL_ERRLOG'} = '#define INFO_PL_ERRLOG "'.$set{'log_path'}.'info-stderr.log"'; +$def{'GOTO_PL_ERRLOG'} = '#define GOTO_PL_ERRLOG "'.$set{'log_path'}.'goto-stderr.log"'; +$def{'BBCODE_PL_ERRLOG'} = '#define BBCODE_PL_ERRLOG "'.$set{'log_path'}.'bbcode-stderr.log"'; + +$def{'CC'} = 'CC='.$set{'gcc'}; +$def{'CF'} = 'CF='.$set{'c_flags'}; +$def{'PL'} = 'PL='.$set{'perl'}; +$def{'MV'} = 'MV='.$set{'mv'}; +$def{'CP'} = 'CP='.$set{'cp'}; +$def{'RM'} = 'RM='.$set{'rm'}; +$def{'OD'} = 'OD='.$set{'bin_path'}; +$def{'LD'} = 'LD='.$set{'lib_path'}; +$def{'WD'} = 'WD='.$set{'www_path'}; +$def{'CM'} = 'CM='.$set{'chmod'}; + + +# Now go through input file, find lines to be replaced. Format: +# ###SOME_NAME; +# If found - replace. + +while (defined($line = )) { + $line =~ s/[\r\n]//g; + if ($line =~ /###([a-zA-Z0-9_]+);/) { + print "$def{$1}\n"; + } + else { + print "$line\n"; + } +} diff --git a/frame.1.c b/frame.1.c new file mode 100644 index 0000000..0f74d7e --- /dev/null +++ b/frame.1.c @@ -0,0 +1,34 @@ +// frame.c is generated from frame.1.c +// 21.08.2016 +// +// This is the wrapper for frame.pl. +// It's run with SETUID to have accesss to some files where the www server +// should not. That's why it has a C wrapper. In modern systems running scripts +// directly with SETUID is considered unsafe and not allowed. +// +// Copyright (C) 2016 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +###FRAME_PL; +###FRAME_PL_ERRLOG; + +int main(int argc, char *argv[], char *envp[]) +{ + freopen(FRAME_PL_ERRLOG,"at",stderr); + return execve(FRAME_PL,argv,envp); +} diff --git a/frame.1.pl b/frame.1.pl new file mode 100644 index 0000000..ad58411 --- /dev/null +++ b/frame.1.pl @@ -0,0 +1,154 @@ +###PERL; +# +# /bsta/f +# viewer.pl is generated from viewer.1.pl. +# 19.10.2016 +# +# The frame interface +# +# Copyright (C) 2016 Balthasar Szczepañski +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; + +use bsta_lib qw(failpage gethttpheader getcgi readdatafile); + +###SETTINGS_PATH; +###DEFAULT_PATH; +###DATA_PATH; +###STATE_PATH; +###NOACCESS_PATH; + +my %http; +my %cgi; +my %framedata; +my %default; +my %settings; +my %state; + +my $time = time(); +srand ($time-$$); + +my $method; +my $frame; +my $password; +my $passwordOK; +my $IP; +my $access; +my $framepath; +my $framefile; +my $buffer; +my @fileinfo; + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) { + $method=$1; +} +else{ + 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); +} + +%http = gethttpheader (\%ENV); +%cgi = getcgi($ENV{'QUERY_STRING'}); + +if ($method eq 'POST') { + if ($http{'content-type'} eq 'application/x-www-form-urlencoded') { + my %cgipost=getcgi( ); + foreach my $ind (keys %cgipost) { + $cgi{$ind}=$cgipost{$ind}; + } + } + # multipart not supported + else{ + exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}."); + } +} + +if ($cgi{'f'} =~ /^(.+)$/) { + $frame=int($1); +} +elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) { + $frame=int($1); +} +else { + $frame = 0; +} + +if ($cgi{'p'} =~ /^(.+)$/) { + $password=$1; +} +else { + $password=''; +} + +%settings=readdatafile(SETTINGS_PATH); +%default=readdatafile(DEFAULT_PATH); +%state=readdatafile(STATE_PATH); +if($frame<0) { + $frame = $state{'last'} + $frame +1; +} +%framedata=readdatafile(DATA_PATH.$frame); +foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } +} +if($password eq $settings{'password'}){ + $passwordOK = 1; +} +else{ + $passwordOK = 0; +} + +if ($passwordOK || (int($state{'state'}) >= 1 && $frame <= int($state{'last'}) && $frame > 0)) { + $access=1; +} +else { + $access=0; + %framedata = readdatafile(NOACCESS_PATH); + foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + } +} + +if($access){ + $framepath=DATA_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'}); +} +else { + $framepath=DATA_PATH.$framedata{'frame'}; +} + +open($framefile,'<',$framepath) or exit failpage("Status: 404 Not Found\n","404 Not Found"," Can't open image file."); +unless(binmode($framefile)) { + close($framefile); + exit failpage("Status: 500 Internal Server Error\n","500 Internal Server Error"," Can't switch to binary mode."); +} +if (my @fileinfo = stat($framepath)){ + print 'Content-length: '.$fileinfo[7]."\n"; +} +print 'Content-type: '.$framedata{'content-type'}."\n"; +print "\n"; +if($method ne 'HEAD'){ + while (read ($framefile,$buffer,1024)) { + print (STDOUT $buffer); + } +} +close($framefile); diff --git a/goto.1.c b/goto.1.c new file mode 100644 index 0000000..110e0b7 --- /dev/null +++ b/goto.1.c @@ -0,0 +1,34 @@ +// info.c is generated from info.1.c +// 29.06.2017 +// +// This is the wrapper for info.pl. +// It's run with SETUID to have accesss to some files where the www server +// should not. That's why it has a C wrapper. In modern systems running scripts +// directly with SETUID is considered unsafe and not allowed. +// +// Copyright (C) 2017 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +###GOTO_PL; +###GOTO_PL_ERRLOG; + +int main(int argc, char *argv[], char *envp[]) +{ + freopen(GOTO_PL_ERRLOG,"at",stderr); + return execve(GOTO_PL,argv,envp); +} diff --git a/goto.1.pl b/goto.1.pl new file mode 100644 index 0000000..dcc2072 --- /dev/null +++ b/goto.1.pl @@ -0,0 +1,172 @@ +###PERL; +# +# /bsta/g +# goto.pl is generated from goto.1.pl. +# 02.07.2017 +# +# The frame list +# +# Copyright (C) 2017 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(failpage gethttpheader getcgi readdatafile printdatafile entityencode urlencode); +use File::Copy; + +###DATA_PATH; +###SETTINGS_PATH; +###STATE_PATH; +###LIST_PATH; +###WEBSITE_NAME; +###FAVICON_PATH; +###CSS_PATH; +###LOGO_PATH; +###WEBSITE; +###CGI_PATH; +###VIEWER_PATH; + + +my %http; +my %cgi; +my %settings; +my %state; +my %gotolist; + +my @timetab; + +my $time = time(); +srand ($time-$$); + +my $method; +my $password; +my $passwordOK; + +my $frame; +my $last; +my $title; +my $ongtime; +my $ongstate; +my $line; + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) { + $method=$1; +} +else{ + 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); +} + +%http = gethttpheader (\%ENV); +%cgi = getcgi($ENV{'QUERY_STRING'}); + +if ($method eq 'POST') { + if ($http{'content-type'} eq 'application/x-www-form-urlencoded') { + my %cgipost=getcgi( ); + foreach my $ind (keys %cgipost) { + $cgi{$ind}=$cgipost{$ind}; + } + } + # multipart not supported + else{ + exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}."); + } +} + +if ($cgi{'p'} =~ /^(.+)$/) { + $password=$1; +} +else { + $password=''; +} + +%settings=readdatafile(SETTINGS_PATH); +%state=readdatafile(STATE_PATH); +%gotolist=readdatafile(LIST_PATH); + +if($password eq $settings{'password'}){ + $passwordOK = 1; +} +else{ + $passwordOK = 0; +} + +print "Content-type: text/html\n"; +print "\n"; +if($method eq 'HEAD') { + exit; +} + +print ''."\n"; +print ''."\n"; +print 'GOTO • '.entityencode($settings{'story'}).' • '.WEBSITE_NAME.''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print '
    '."\n"; + +print '
    '."\n"; + +print '
    '."\n"; +print '

    '.entityencode($settings{'story'}).'

    '."\n"; +print '
    '."\n"; + +print '
    '."\n"; + +print '
    '."\n"; + +$last=int($state{'last'}); +$ongstate=int($state{'state'}); +for ($frame=0; ; ++$frame) { + if((($frame > $last) || $ongstate<1) && !$passwordOK) { + last; + } + + $ongtime=$gotolist{'ongtime-'.$frame}; + $title=$gotolist{'title-'.$frame}; + if ($ongtime eq '') { + last; + } + @timetab=gmtime($ongtime); + + print ''.sprintf('%03d',$frame).' '.sprintf('%02d.%02d.%02d %02d:%02d',$timetab[3],$timetab[4]+1,$timetab[5]-100,$timetab[2],$timetab[1]).' '.entityencode($title).'
    '."\n"; +} + +print '
    '."\n"; + +print ''."\n"; + +print '
    '."\n"; + +print '
    '."\n"; +print ''.WEBSITE.''."\n"; + + +print ''."\n"; + + + + + + diff --git a/info.1.c b/info.1.c new file mode 100644 index 0000000..7f55f1e --- /dev/null +++ b/info.1.c @@ -0,0 +1,34 @@ +// info.c is generated from info.1.c +// 02.02.2017 +// +// This is the wrapper for info.pl. +// It's run with SETUID to have accesss to some files where the www server +// should not. That's why it has a C wrapper. In modern systems running scripts +// directly with SETUID is considered unsafe and not allowed. +// +// Copyright (C) 2017 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +###INFO_PL; +###INFO_PL_ERRLOG; + +int main(int argc, char *argv[], char *envp[]) +{ + freopen(INFO_PL_ERRLOG,"at",stderr); + return execve(INFO_PL,argv,envp); +} diff --git a/info.1.pl b/info.1.pl new file mode 100644 index 0000000..8e16798 --- /dev/null +++ b/info.1.pl @@ -0,0 +1,181 @@ +###PERL; +# +# /bsta/i +# info.pl is generated from info.1.pl. +# 05.06.2017 +# +# The frame/story info interface +# +# Copyright (C) 2017 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(failpage gethttpheader getcgi readdatafile printdatafile); +use File::Copy; + +###DATA_PATH; +###DEFAULT_PATH; +###SETTINGS_PATH; +###STATE_PATH; +###NOACCESS_PATH; + +my %http; +my %cgi; +my %framedata; +my %nextframedata; +my %default; +my %settings; +my %state; + +my $time = time(); +srand ($time-$$); + +my $method; +my $frame; +my $password; +my $passwordOK; +my $access; +my $showcommand; +my $ongtime; +my $seconds; + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) { + $method=$1; +} +else{ + 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); +} + +%http = gethttpheader (\%ENV); +%cgi = getcgi($ENV{'QUERY_STRING'}); + +if ($method eq 'POST') { + if ($http{'content-type'} eq 'application/x-www-form-urlencoded') { + my %cgipost=getcgi( ); + foreach my $ind (keys %cgipost) { + $cgi{$ind}=$cgipost{$ind}; + } + } + # multipart not supported + else{ + exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}."); + } +} + +if ($cgi{'f'} =~ /^(.+)$/) { + $frame=int($1); +} +elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) { + $frame=int($1); +} +else { + $frame = ''; +} + +if ($cgi{'p'} =~ /^(.+)$/) { + $password=$1; +} +else { + $password=''; +} + +%settings=readdatafile(SETTINGS_PATH); +%default=readdatafile(DEFAULT_PATH); +%framedata=readdatafile(DATA_PATH.$frame); +%state=readdatafile(STATE_PATH); +if($password eq $settings{'password'}){ + $passwordOK = 1; +} +else{ + $passwordOK = 0; +} + +if ($frame eq '') { + unless($passwordOK) { + if ($state{'ip1'} ne '') { + $state{'ip1'}=1; + } + if ($state{'ip2'} ne '') { + $state{'ip2'}=1; + } + if ($state{'ip3'} ne '') { + $state{'ip3'}=1; + } + } + print "Content-type: text/plain\n\n"; + if($method eq 'HEAD') { + exit; + } + printdatafile(%state); +} + +else { + if($frame<0) { + $frame = int($state{'last'}) + $frame +1; + %framedata=readdatafile(DATA_PATH.$frame); + } + + %nextframedata=readdatafile(DATA_PATH.($frame+1)); + + foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + unless(defined($nextframedata{$ind})){ + $nextframedata{$ind}=$default{$ind}; + } + } + $seconds=int($state{'nextong'})-$time; + $ongtime=int($state{'ongtime'}); + if($ongtime == 0) { + $ongtime=int($settings{'ongtime'}) + } + $showcommand = ($seconds < ($ongtime*3600/3)); + + if ($passwordOK || (int($state{'state'}) >= 1 && $frame <= int($state{'last'}) && $frame >= 0)) { + $access=1; + + if ($passwordOK || $frame= 2 && $showcommand)) { + $framedata{'command'}=$nextframedata{'title'}; + } + $framedata{'frame'}=sprintf($settings{'frame'},$frame,$framedata{'ext'}); + } + else { + $access=0; + %framedata = readdatafile(NOACCESS_PATH); + foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + } + } + + # $framedata{'frame'}=sprintf($settings{'frame'},$frame,$framedata{'ext'}); + + print "Content-type: text/plain\n"; + if(!$access) { + print "Status: 403 Forbidden\n"; + } + print "\n"; + if($method eq 'HEAD') { + exit; + } + printdatafile(%framedata); +} diff --git a/make.sh b/make.sh new file mode 100755 index 0000000..38d663e --- /dev/null +++ b/make.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# make.sh +# 13.01.2016 +# +# This is the script for making the software. Normally, the makefile is used for +# this purpose. But the makefile has to be generated first. +# This script generates the makefile and then uses it and finally removes it. +# +# Copyright (C) 2015-2016 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +set -x +perl configure.pl settings makefile +make +# rm makefile diff --git a/makefile b/makefile new file mode 100644 index 0000000..ad0f7d2 --- /dev/null +++ b/makefile @@ -0,0 +1,151 @@ +# makefile is generated from makefile.1.mak. +# 2.07.2017 +# +# This is the makefile +# +# Copyright (C) 2016 - 2017 Balthasar Szczepañski +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +CC=/usr/bin/gcc +CF=-g -Wall +PL=/usr/bin/perl +CP=/bin/cp +MV=/bin/mv +RM=/bin/rm +CM=/bin/chmod +OD=/eizm/bin/bsta/ +LD=/eizm/lib/bsta/ +WD=/eizm/www/time/bsta/ + +all: moveout copyoutwww moveoutlib remove config.txt + +moveout: viewer viewer.pl frame frame.pl 2words 2words.pl chat chat.pl ong.pl updlist.pl oldlogs.pl attach attach.pl info info.pl goto goto.pl bbcode bbcode.pl setuid exec + $(MV) viewer viewer.pl frame frame.pl 2words 2words.pl chat chat.pl ong.pl updlist.pl oldlogs.pl attach attach.pl info info.pl goto goto.pl bbcode bbcode.pl $(OD) + +copyout: setuid exec +# $(CP) access.pl $(OD) + +copyoutwww: timer.js bsta.css setuid exec + $(CP) timer.js bsta.css $(WD) + + +moveoutlib: bsta_lib.pm setuid exec + $(MV) bsta_lib.pm $(LD) + +setuid: viewer frame 2words attach chat info goto bbcode + $(CM) u+s viewer frame 2words attach chat info goto bbcode + +exec: viewer.pl frame.pl 2words.pl ong.pl updlist.pl oldlogs.pl attach.pl chat.pl info.pl goto.pl bbcode.pl + $(CM) +x viewer.pl frame.pl 2words.pl ong.pl updlist.pl oldlogs.pl attach.pl chat.pl info.pl goto.pl bbcode.pl + +remove: viewer.c frame.c 2words.c chat.c attach.c info.c goto.c bbcode.c copyout moveout setuid exec + $(RM) viewer.c frame.c 2words.c chat.c attach.c info.c goto.c bbcode.c + + +bsta_lib.pm: bsta_lib.1.pm configure.pl settings + $(PL) configure.pl settings bsta_lib.pm + + +viewer: viewer.c + $(CC) $(CF) -o viewer viewer.c + +viewer.c: viewer.1.c configure.pl settings + $(PL) configure.pl settings viewer.c + +viewer.pl: viewer.1.pl configure.pl settings + $(PL) configure.pl settings viewer.pl + + +frame: frame.c + $(CC) $(CF) -o frame frame.c + +frame.c: frame.1.c configure.pl settings + $(PL) configure.pl settings frame.c + +frame.pl: frame.1.pl configure.pl settings + $(PL) configure.pl settings frame.pl + + +2words: 2words.c + $(CC) $(CF) -o 2words 2words.c + +2words.c: 2words.1.c configure.pl settings + $(PL) configure.pl settings <2words.1.c >2words.c + +2words.pl: 2words.1.pl configure.pl settings + $(PL) configure.pl settings <2words.1.pl >2words.pl + + +attach: attach.c + $(CC) $(CF) -o attach attach.c + +attach.c: attach.1.c configure.pl settings + $(PL) configure.pl settings attach.c + +attach.pl: attach.1.pl configure.pl settings + $(PL) configure.pl settings attach.pl + + +chat: chat.c + $(CC) $(CF) -o chat chat.c + +chat.c: chat.1.c configure.pl settings + $(PL) configure.pl settings chat.c + +chat.pl: chat.1.pl configure.pl settings + $(PL) configure.pl settings chat.pl + + +info: info.c + $(CC) $(CF) -o info info.c + +info.c: info.1.c configure.pl settings + $(PL) configure.pl settings info.c + +info.pl: info.1.pl configure.pl settings + $(PL) configure.pl settings info.pl + +goto: goto.c + $(CC) $(CF) -o goto goto.c + +goto.c: goto.1.c configure.pl settings + $(PL) configure.pl settings goto.c + +goto.pl: goto.1.pl configure.pl settings + $(PL) configure.pl settings goto.pl + + +bbcode: bbcode.c + $(CC) $(CF) -o bbcode bbcode.c + +bbcode.c: bbcode.1.c configure.pl settings + $(PL) configure.pl settings bbcode.c + +bbcode.pl: bbcode.1.pl configure.pl settings + $(PL) configure.pl settings bbcode.pl + + +ong.pl: ong.1.pl configure.pl settings + $(PL) configure.pl settings ong.pl + +updlist.pl: updlist.1.pl configure.pl settings + $(PL) configure.pl settings updlist.pl + +oldlogs.pl: oldlogs.1.pl configure.pl settings + $(PL) configure.pl settings oldlogs.pl + + +config.txt: config.1.txt configure.pl settings + $(PL) configure.pl settings config.txt diff --git a/makefile.1.mak b/makefile.1.mak new file mode 100644 index 0000000..cdeb46e --- /dev/null +++ b/makefile.1.mak @@ -0,0 +1,156 @@ +# makefile is generated from makefile.1.mak. +# 2.07.2017 +# +# This is the makefile +# +# Copyright (C) 2016 - 2017 Balthasar Szczepañski +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +###CC; +###CF; +###PL; +###CP; +###MV; +###RM; +###CM; +###OD; +###LD; +###WD; + +all: moveout copyoutwww moveoutlib remove config.txt + +moveout: reset.pl viewer viewer.pl frame frame.pl 2words 2words.pl chat chat.pl ong.pl updlist.pl oldlogs.pl attach attach.pl info info.pl goto goto.pl bbcode bbcode.pl setuid exec + $(MV) reset.pl viewer viewer.pl frame frame.pl 2words 2words.pl chat chat.pl ong.pl updlist.pl oldlogs.pl attach attach.pl info info.pl goto goto.pl bbcode bbcode.pl $(OD) + +copyout: setuid exec +# $(CP) access.pl $(OD) + +copyoutwww: timer.js bsta.css setuid exec + $(CP) timer.js bsta.css $(WD) + + +moveoutlib: bsta_lib.pm setuid exec + $(MV) bsta_lib.pm $(LD) + +setuid: viewer frame 2words attach chat info goto bbcode + $(CM) u+s viewer frame 2words attach chat info goto bbcode + +exec: reset.pl viewer.pl frame.pl 2words.pl ong.pl updlist.pl oldlogs.pl attach.pl chat.pl info.pl goto.pl bbcode.pl + $(CM) +x reset.pl viewer.pl frame.pl 2words.pl ong.pl updlist.pl oldlogs.pl attach.pl chat.pl info.pl goto.pl bbcode.pl + +remove: viewer.c frame.c 2words.c chat.c attach.c info.c goto.c bbcode.c copyout moveout setuid exec + $(RM) viewer.c frame.c 2words.c chat.c attach.c info.c goto.c bbcode.c + + +bsta_lib.pm: bsta_lib.1.pm configure.pl settings + $(PL) configure.pl settings bsta_lib.pm + + +viewer: viewer.c + $(CC) $(CF) -o viewer viewer.c + +viewer.c: viewer.1.c configure.pl settings + $(PL) configure.pl settings viewer.c + +viewer.pl: viewer.1.pl configure.pl settings + $(PL) configure.pl settings viewer.pl + + +frame: frame.c + $(CC) $(CF) -o frame frame.c + +frame.c: frame.1.c configure.pl settings + $(PL) configure.pl settings frame.c + +frame.pl: frame.1.pl configure.pl settings + $(PL) configure.pl settings frame.pl + + +2words: 2words.c + $(CC) $(CF) -o 2words 2words.c + +2words.c: 2words.1.c configure.pl settings + $(PL) configure.pl settings <2words.1.c >2words.c + +2words.pl: 2words.1.pl configure.pl settings + $(PL) configure.pl settings <2words.1.pl >2words.pl + + +attach: attach.c + $(CC) $(CF) -o attach attach.c + +attach.c: attach.1.c configure.pl settings + $(PL) configure.pl settings attach.c + +attach.pl: attach.1.pl configure.pl settings + $(PL) configure.pl settings attach.pl + + +chat: chat.c + $(CC) $(CF) -o chat chat.c + +chat.c: chat.1.c configure.pl settings + $(PL) configure.pl settings chat.c + +chat.pl: chat.1.pl configure.pl settings + $(PL) configure.pl settings chat.pl + + +info: info.c + $(CC) $(CF) -o info info.c + +info.c: info.1.c configure.pl settings + $(PL) configure.pl settings info.c + +info.pl: info.1.pl configure.pl settings + $(PL) configure.pl settings info.pl + + +goto: goto.c + $(CC) $(CF) -o goto goto.c + +goto.c: goto.1.c configure.pl settings + $(PL) configure.pl settings goto.c + +goto.pl: goto.1.pl configure.pl settings + $(PL) configure.pl settings goto.pl + + +bbcode: bbcode.c + $(CC) $(CF) -o bbcode bbcode.c + +bbcode.c: bbcode.1.c configure.pl settings + $(PL) configure.pl settings bbcode.c + +bbcode.pl: bbcode.1.pl configure.pl settings + $(PL) configure.pl settings bbcode.pl + + +ong.pl: ong.1.pl configure.pl settings + $(PL) configure.pl settings ong.pl + +updlist.pl: updlist.1.pl configure.pl settings + $(PL) configure.pl settings updlist.pl + +oldlogs.pl: oldlogs.1.pl configure.pl settings + $(PL) configure.pl settings oldlogs.pl + +reset.pl: reset.1.pl configure.pl settings + $(PL) configure.pl settings reset.pl + + + +config.txt: config.1.txt configure.pl settings + $(PL) configure.pl settings config.txt diff --git a/oldlogs.1.pl b/oldlogs.1.pl new file mode 100644 index 0000000..67fca65 --- /dev/null +++ b/oldlogs.1.pl @@ -0,0 +1,119 @@ +###PERL; + +# oldlogs is generated from oldlogs.1.pl. +# 02.01.2016 +# +# This script renames log files if they are big enough. +# Compresses or removes older log files. +# +# Copyright (C) 2015-2016 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + + +###GZIP_PATH; +###LOG_PATH; +###LOG_SIZE_LIMIT; +###LOGS_TOTAL; +###LOGS_UNCOMPRESSED; + +if ($ARGV[0] ne '') { + $log_path = $ARGV[0]; +} +else { + $log_path = LOG_PATH; +} +if ($ARGV[1] =~ /^([0-9]+)$/) { + $log_size_limit = $1; +} +else { + $log_size_limit = LOG_SIZE_LIMIT; +} +if ($ARGV[2] =~ /^([0-9]+)$/) { + $logs_total = $1; +} +else { + $logs_total = LOGS_TOTAL; +} +if ($ARGV[3] =~ /^([0-9]+)$/) { + $logs_uncompressed = $1; +} +else { + $logs_uncompressed = LOGS_UNCOMPRESSED; +} + +if ( opendir ($dir, $log_path)) { + while ($subpath = readdir $dir) { + if ($subpath !~ /\.log$/) { + next; + } + $fullpath=$log_path.$subpath; + unless (-f $fullpath) { + next; + } + unless (@stat = stat($fullpath)) { + next; + } + if ($stat[7] > $log_size_limit) { + movelog($fullpath,0,0); + } + + } + closedir($dir); +} + +sub movelog { + (my $path, my $number, my $gz) = @_; + my $nextgz = 0; + my $thispath; + my $nextpath; + my $nextnumber=$number+1; + my @gzip_arg = (GZIP_PATH, '-q', '-9','-f'); + + $thispath = $path.(($number != 0)?'.'.$number.($gz?'.gz':''):''); + if ($number == $logs_total) { + if (unlink $thispath) { + return 1; + } + else { + return 0; + } + } + if ($number == $logs_uncompressed) { + $nextgz=1; + $nextpath = $path.'.'.$nextnumber.'.gz'; + } + else { + $nextpath = $path.'.'.$nextnumber.($gz?'.gz':''); + } + + if (-e $nextpath) { + unless (movelog($path,$nextnumber,($nextgz or $gz)?1:0)) { + return 0; + } + } + + if ($nextgz) { + push @gzip_arg, $thispath; + unless (! system (@gzip_arg)) { + return 0; + } + $thispath .= '.gz'; + } + + unless (rename ($thispath, $nextpath)) { + return 0; + } + return 1; +} diff --git a/ong.1.pl b/ong.1.pl new file mode 100644 index 0000000..8da5522 --- /dev/null +++ b/ong.1.pl @@ -0,0 +1,155 @@ +###PERL; +# +# ong.pl is generated from ong.1.pl. +# 29.06.2017 +# +# The ONG bot +# +# Copyright (C) 2016-2017 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(entityencode readdatafile writedatafile urlencode); +use File::Copy; + +###DATA_PATH; +###WWW_PATH; +###SETTINGS_PATH; +###STATE_PATH; +###DEFAULT_PATH; +###LIST_PATH; + +my %framedata; +my %nextframedata; +my %default; +my %settings; +my %state; +my %gotolist; + +my $statefile; +my $ongstate; +my $frame; +my $nextong; +my $inpath; +my $outpath; +my $ongtime; +my $static; +my $dynamic; +my $last; + +my $time = time(); +srand ($time-$$); +$ongtime = int($time / 3600) * 3600; + +print $time.' - '.$ongtime."\n"; + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + + +if (open ($statefile,"+<",STATE_PATH)){ + if (flock($statefile,2)) { + %state=readdatafile($statefile); + $ongstate=int($state{'state'}); + print 'state: '.$ongstate."\n"; + if($ongstate > 0) { + $nextong = int($state{'nextong'}); + print 'ongtime: '.$nextong."\n"; + + if($ongtime >= $nextong) { + %settings=readdatafile(SETTINGS_PATH); + $static=int($settings{'ongtime'}); + $dynamic=int($settings{'dynamicongtime'}); + $last=int($settings{'last'}); + $frame=int($state{'last'})+1; + + if($dynamic > 0 && $frame < $last) { + $dynamic = int($dynamic/($last-$frame)); + } + else { + $dynamic=0; + } + + if($static>$dynamic){ + $dynamic=$static; + } + $nextong=$ongtime+($dynamic*3600); + $state{'nextong'}=$nextong; + print 'next ongtime: '.$nextong.' (+'.$dynamic.")\n"; + $state{'ongtime'}=$dynamic; + + if($ongstate == 2) { + print 'next frame: '.$frame."\n"; + %framedata=readdatafile(DATA_PATH.$frame); + %default=readdatafile(DEFAULT_PATH); + %gotolist=readdatafile(LIST_PATH); + + $framedata{'ongtime'}=$time; + $framedata{'timer'}=$dynamic; + $gotolist{'title-'.$frame}=$framedata{'title'}; + $gotolist{'ongtime-'.$frame}=$framedata{'ongtime'}; + writedatafile(DATA_PATH.$frame,%framedata); + writedatafile(LIST_PATH,%gotolist); + + foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + unless(defined($nextframedata{$ind})){ + $nextframedata{$ind}=$default{$ind}; + } + } + + $inpath = DATA_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'}); + $outpath = WWW_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'}); + + print $inpath.' -> '.$outpath."\n"; + + # ALSO-ATTACHMENTS!!! (here) + + if(copy ($inpath, $outpath)) { + $state{'last'}=$frame; + $state{'state'}=1; + $state{'ip1'}=''; + $state{'ip2'}=''; + $state{'ip3'}=''; + $state{'ongtime'}=$dynamic; + print "ONG\n"; + } + else { + print "NO ONG\n"; + } + } + writedatafile($statefile,%state); + } + else { + print "WAIT\n"; + } + } + else { + print "INACTIVE\n"; + } + } + else { + print "NO STATELOCK\n"; + } + close ($statefile); +} +else { + print "NO STATEFILE\n"; +} +print "\n"; \ No newline at end of file diff --git a/ongtimes.pl b/ongtimes.pl new file mode 100755 index 0000000..e44ff45 --- /dev/null +++ b/ongtimes.pl @@ -0,0 +1,49 @@ +#!/usr/bin/perl +# 01.02.2017 + +use strict; +#use warnings; +use lib '/eizm/lib/bstatest/'; +use bsta_lib qw(readdatafile writedatafile); + +use constant DATA_PATH => '/eizm/data/bsta/'; +use constant SETTINGS_PATH => '/eizm/data/bsta/settings'; +use constant STATE_PATH => '/eizm/data/bsta/state'; + +my %framedata; +my %settings; +my %state; + +my $last; +my $ongtime; +my @timetab; +my $timer; +my $prevongtime; +my $cleantimer; +my $nicetime; + +%state=readdatafile(STATE_PATH); +$last=int($state{'last'}); + +for (my $f=$last; $f>=0; --$f) { + %framedata=readdatafile(DATA_PATH.$f); $ongtime=int($framedata{'ongtime'}); + @timetab=gmtime($ongtime); + $nicetime=sprintf('UTC %04d.%02d.%02d %02d:%02d:%02d',$timetab[5]+1900,$timetab[4]+1,$timetab[3],$timetab[2],$timetab[1],$timetab[0]); + + if($framedata{'timer'}ne'') { + $timer=int($framedata{'timer'}); + $cleantimer=$timer; + } + # elsif($f<$last) { + # $timer=($prevongtime-$ongtime)/3600; + # $cleantimer=0-int($timer+0.5); + # $framedata{'timer'}=0-$cleantimer; + # writedatafile(DATA_PATH.$f,%framedata); + # } + + print "$f\t$nicetime\t$ongtime\t\t$timer\n"; + $prevongtime=$ongtime; +} +for (my $f=0; $f<=$last; ++$f) { + +} \ No newline at end of file diff --git a/reset.1.pl b/reset.1.pl new file mode 100644 index 0000000..353814b --- /dev/null +++ b/reset.1.pl @@ -0,0 +1,116 @@ +###PERL; +# +# /bsta/2words +# reset is generated from reset.1.pl. +# 26.03.2018 +# +# Reset BSTA state +# +# Copyright (C) 2016 - 2018 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(writedatafile); + +###STORY_PATH; +###WEBSITE; +###CGI_PATH; +###INDEX_PATH; +###INTF_DATE; +###STATE_PATH; +###COIN_DATE; +###CHAT_PATH; + +my %story = ( + 'id' => '0', + 'letter' => '', + 'lastip' => '0.0.0.0', + 'content' => '', + 'pass' => '0', + 'state' => '0' +); +my %state = ( + 'state' => '0', + 'last' => '0', + 'ongtime' => '', + 'nextong' => '', + 'ip1' => '', + 'ip2' => '', + 'ip3' => '' +); +my %chat = ( + 'id' => '0', + 'state' => '0', + 'content' => '' +); + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +writedatafile(STATE_PATH,%state); +writedatafile(STORY_PATH,%story); +writedatafile(CHAT_PATH,%chat); + +writeindex(INDEX_PATH); + +#function borrowed from 2words.pl - keep consistent! +sub writeindex { + (my $indexpath) = @_; + my $indexfile; + my $indexof; + + if(ref($indexpath)) { + $indexfile=$indexpath; + unless (seek($indexfile, 0, 0)) { + return 0; + } + } + else { + unless (open ($indexfile, ">", $indexpath)) { + return 0; + } + } + + $indexof = CGI_PATH; + $indexof =~ s/\/$//g; + + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ' '."\n"; + print $indexfile ' Index of '.$indexof.''."\n"; + print $indexfile ' '."\n"; + print $indexfile ' '."\n"; + print $indexfile '

    Index of '.$indexof.'

    '."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile ''."\n"; + print $indexfile '
    [ICO]NameLast modifiedSizeDescription

    [DIR]Parent Directory  -  
    [DIR]2words/'.INTF_DATE.' -  
    [DIR]coin/'.COIN_DATE.' - Coincidence

    '."\n"; + print $indexfile '
    Apache/2.2.22 (Debian) Server at '.WEBSITE.' Port 80
    '."\n"; + print $indexfile ''."\n"; + + + unless (ref($indexpath)) { + close ($indexfile); + } + else { + truncate ($indexfile , tell($indexfile)); + } + + return 1; +} diff --git a/settings b/settings new file mode 100644 index 0000000..65579ae --- /dev/null +++ b/settings @@ -0,0 +1,64 @@ +# settings +# 19.11.2016 +# +# In this file are defined values specific for the user's system +# +# Copyright (C) 2016 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +#all directory paths must end with '/' and must already exist. + +bin_path = /eizm/bin/bsta/ #Where the software will be located +data_path = /eizm/data/bsta/ #where the software will remember data; subdir: + #group, groupsettings +log_path = /eizm/log/bsta/ #where the software will remember data +tmp_path = /eizm/tmp/bsta/ #for temporary fies +www_path = /eizm/www/time/bsta/ #for the www server +lib_path = /eizm/lib/bsta/ +cgi_path = /bsta/ + +path = /usr/local/bin:/usr/bin:/bin #The path environment variable. Must be + #overwritten if SETUID. Otherwise + #launching programs may fail. (Perl + #security...) + + +#paths to software +perl = /usr/bin/perl +chmod = /bin/chmod +cp = /bin/cp +mv = /bin/mv +rm = /bin/rm +gcc = /usr/bin/gcc +gzip = /bin/gzip +c_flags = -g -Wall + +log_size_limit = 65536 # How big can a log file be +logs_uncompressed = 2 # How many uncompressed old logs to keep +logs_total = 10 # How many old logs to keep + +rm_access_crontab = 10 2 * * * # How often to remove leftover unlock info. +oldlogs_crontab = 0 2 * * * # How often to deal with old logs +bot_crontab = 20 2 * * * # How often to run the bot + +website = 1190.bicyclesonthemoon.info +website_name = Bicycles on the Moon +favicon_path = /img/favicon.png +intf_date = 28-Sep-2016 20:34 +coin_date = 13-Nov-2016 22:15 + +story_length = 16 +firstpage_length = 4 +page_length = 16 diff --git a/settings-again b/settings-again new file mode 100644 index 0000000..ee732f9 --- /dev/null +++ b/settings-again @@ -0,0 +1,64 @@ +# settings +# 19.11.2016 +# +# In this file are defined values specific for the user's system +# +# Copyright (C) 2016 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +#all directory paths must end with '/' and must already exist. + +bin_path = /eizm/bin/bstagain/ #Where the software will be located +data_path = /eizm/data/bstagain/ #where the software will remember data; subdir: + #group, groupsettings +log_path = /eizm/log/bstagain/ #where the software will remember data +tmp_path = /eizm/tmp/bstagain/ #for temporary fies +www_path = /eizm/www/time/bstagain/ #for the www server +lib_path = /eizm/lib/bstagain/ +cgi_path = /bstagain/ + +path = /usr/local/bin:/usr/bin:/bin #The path environment variable. Must be + #overwritten if SETUID. Otherwise + #launching programs may fail. (Perl + #security...) + + +#paths to software +perl = /usr/bin/perl +chmod = /bin/chmod +cp = /bin/cp +mv = /bin/mv +rm = /bin/rm +gcc = /usr/bin/gcc +gzip = /bin/gzip +c_flags = -g -Wall + +log_size_limit = 65536 # How big can a log file be +logs_uncompressed = 2 # How many uncompressed old logs to keep +logs_total = 10 # How many old logs to keep + +rm_access_crontab = 10 2 * * * # How often to remove leftover unlock info. +oldlogs_crontab = 0 2 * * * # How often to deal with old logs +bot_crontab = 20 2 * * * # How often to run the bot + +website = 1190.bicyclesonthemoon.info +website_name = Bicycles on the Moon +favicon_path = /img/favicon.png +intf_date = 28-Sep-2016 20:34 +coin_date = 13-Nov-2016 22:15 + +story_length = 16 +firstpage_length = 4 +page_length = 16 diff --git a/settings-test b/settings-test new file mode 100644 index 0000000..93bb2de --- /dev/null +++ b/settings-test @@ -0,0 +1,64 @@ +# settings +# 19.11.2016 +# +# In this file are defined values specific for the user's system +# +# Copyright (C) 2016 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +#all directory paths must end with '/' and must already exist. + +bin_path = /eizm/bin/bstatest/ #Where the software will be located +data_path = /eizm/data/bstatest/ #where the software will remember data; subdir: + #group, groupsettings +log_path = /eizm/log/bstatest/ #where the software will remember data +tmp_path = /eizm/tmp/bstatest/ #for temporary fies +www_path = /eizm/www/time/tbst/ #for the www server +lib_path = /eizm/lib/bstatest/ +cgi_path = /tbst/ + +path = /usr/local/bin:/usr/bin:/bin #The path environment variable. Must be + #overwritten if SETUID. Otherwise + #launching programs may fail. (Perl + #security...) + + +#paths to software +perl = /usr/bin/perl +chmod = /bin/chmod +cp = /bin/cp +mv = /bin/mv +rm = /bin/rm +gcc = /usr/bin/gcc +gzip = /bin/gzip +c_flags = -g -Wall + +log_size_limit = 65536 # How big can a log file be +logs_uncompressed = 2 # How many uncompressed old logs to keep +logs_total = 10 # How many old logs to keep + +rm_access_crontab = 10 2 * * * # How often to remove leftover unlock info. +oldlogs_crontab = 0 2 * * * # How often to deal with old logs +bot_crontab = 20 2 * * * # How often to run the bot + +website = 1190.bicyclesonthemoon.info +website_name = Bicycles on the Moon +favicon_path = /img/favicon.png +intf_date = 28-Sep-2016 20:34 +coin_date = 13-Nov-2016 22:15 + +story_length = 16 +firstpage_length = 4 +page_length = 16 diff --git a/testhtml.pl b/testhtml.pl new file mode 100644 index 0000000..97f72fb --- /dev/null +++ b/testhtml.pl @@ -0,0 +1,15 @@ +#!/usr/bin/perl +use lib '/eizm/lib/bstatest/'; +use strict; +use bsta_lib qw(failpage gethttpheader getcgi entityencode readdatafile writedatafile printdatafileht urlencode bb2ht bb2bb linehtml); + +my $bb; +my $ht; + +$bb="[fq][/fq][tq][/tq][ni][/ni][br]
    [/br][po][/po][url=][/url][i][/i]\n"; +$ht=bb2bb($bb,1); +print $ht."\n"; +$ht=bb2ht($bb,1); +print $ht."\n"; + +# print ht; diff --git a/timer.js b/timer.js new file mode 100644 index 0000000..7ca7807 --- /dev/null +++ b/timer.js @@ -0,0 +1,85 @@ +// timer.js +// 3.07.2017 +// +// The countdown script. +// +// Copyright (C) 2017 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +window.onload = function () { + var ongh; + var ongm; + var ongs; + var ongvh; + var ongvm; + var ongvs; + var timer; + + ongh = document.getElementById("ongh"); + ongm = document.getElementById("ongm"); + ongs = document.getElementById("ongs"); + + if(ongh == null || ongm == null || ongs == null) { + // window.alert("NUL"); + } + else { + timer = setInterval (function() { + ongvh = +(ongh.innerHTML); + ongvm = +(ongm.innerHTML); + ongvs = +(ongs.innerHTML); + + if(isNaN(ongvh) || isNaN(ongvm) || isNaN(ongvs)) { + // window.alert("NAN"); + clearInterval(timer); + return; + } + + if(ongvs == 0) { + ongvs = 59; + if(ongvm == 0) { + ongvm == 59; + if(ongvh ==0) { + ongvm = 0; + ongvs = 0; + } + else { + ongvh -= 1; + } + } + else { + ongvm -= 1; + } + } + else { + ongvs -= 1; + } + + if(ongvh == 0 && ongvm == 0 && ongvs == 0) { + ongh.innerHTML = "00"; + ongm.innerHTML = "00"; + ongs.innerHTML = "NG"; + // window.alert("ONG"); + clearInterval(timer); + return; + } + else { + ongh.innerHTML = ((ongvh<10)?"0":"")+ongvh; + ongm.innerHTML = ((ongvm<10)?"0":"")+ongvm; + ongs.innerHTML = ((ongvs<10)?"0":"")+ongvs; + } + + }, 1000); + } +}; diff --git a/updlist.1.pl b/updlist.1.pl new file mode 100644 index 0000000..8e8e6a2 --- /dev/null +++ b/updlist.1.pl @@ -0,0 +1,55 @@ +###PERL; +# +# updlist.pl is generated from updlist.1.pl. +# 29.06.2017 +# +# The framelist update bot +# +# Copyright (C) 2016-2017 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(readdatafile writedatafile); +use File::Copy; + +###DATA_PATH; +###WWW_PATH; +###SETTINGS_PATH; +###STATE_PATH; +###DEFAULT_PATH; +###LIST_PATH; + +my %framedata; +my %gotolist; + +my $frame; + +%gotolist=readdatafile(LIST_PATH); + +for($frame=0; ; ++$frame) { + %framedata=readdatafile(DATA_PATH.$frame); + if($framedata{'ongtime'} eq '') { + last; + } + + print $frame.' '.$framedata{'ongtime'}.' '.$framedata{'title'}."\n"; + + $gotolist{'title-'.$frame}=$framedata{'title'}; + $gotolist{'ongtime-'.$frame}=$framedata{'ongtime'}; +} + +writedatafile (LIST_PATH,%gotolist); diff --git a/viewer.1.c b/viewer.1.c new file mode 100644 index 0000000..2a3f1a6 --- /dev/null +++ b/viewer.1.c @@ -0,0 +1,34 @@ +// viewer.c is generated from viewer.1.c +// 20.08.2016 +// +// This is the wrapper for viewer.pl. +// It's run with SETUID to have accesss to some files where the www server +// should not. That's why it has a C wrapper. In modern systems running scripts +// directly with SETUID is considered unsafe and not allowed. +// +// Copyright (C) 2016 Balthasar Szczepański +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include + +###VIEWER_PL; +###VIEWER_PL_ERRLOG; + +int main(int argc, char *argv[], char *envp[]) +{ + freopen(VIEWER_PL_ERRLOG,"at",stderr); + return execve(VIEWER_PL,argv,envp); +} diff --git a/viewer.1.pl b/viewer.1.pl new file mode 100644 index 0000000..7afe8a1 --- /dev/null +++ b/viewer.1.pl @@ -0,0 +1,627 @@ +###PERL; +# +# /bsta/v +# viewer is generated from viewer.1.pl. +# 09.01.2023 +# +# The viewer interface +# +# Copyright (C) 2016-2017, 2019-2020, 2023 Balthasar Szczepański +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use strict; +#use warnings; +###LIB; +use bsta_lib qw(failpage gethttpheader getcgi entityencode readdatafile writedatafile printdatafileht urlencode bb2ht bb2bb linehtml); +use File::Copy; + +###DATA_PATH; +###DEFAULT_PATH; +###SETTINGS_PATH; +###STATE_PATH; +###LOGO_PATH; +###FAVICON_PATH; +###WEBSITE; +###WEBSITE_NAME; +###CSS_PATH; +###CGI_PATH; +###FRAME_PATH; +###VIEWER_PATH; +###NOACCESS_PATH; +###STORY_PATH; +###WWW_PATH; +###INDEX_PATH; +###ATTACH_PATH; +###INFO_PATH; +###BBCODE_PATH; +###GOTO_PATH; +###LIST_PATH; +###TIMER_PATH; + +my %http; +my %cgi; +my %framedata; +my %nextframedata; +my %default; +my %settings; +my %state; +my %newstate; +my %gotolist; + +my $time = time(); +srand ($time-$$); + +my $method; +my $frame; +my $password; +my $passwordOK; +my $IP; +my $access; +my $seconds; +my $minutes; +my $hours; +my $statefile; +my $showcommand; +my $ongtime; +my $textmode; + +delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; +###PATH; + +if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) { + $method=$1; +} +else{ + 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); +} + +%http = gethttpheader (\%ENV); +%cgi = getcgi($ENV{'QUERY_STRING'}); + +if ($method eq 'POST') { + if ($http{'content-type'} eq 'application/x-www-form-urlencoded') { + my %cgipost=getcgi( ); + foreach my $ind (keys %cgipost) { + $cgi{$ind}=$cgipost{$ind}; + } + } + # multipart not supported + else{ + exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}."); + } +} + +if ($ENV{'HTTP_X_FORWARDED_FOR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) { + $IP=$1; +} +elsif ($ENV{'REMOTE_ADDR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) { + $IP=$1; +} +else { + $IP='0.0.0.0'; +} + +if ($cgi{'f'} =~ /^(.+)$/) { + $frame=int($1); +} +elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) { + $frame=int($1); +} +else { + $frame = 0; +} + +if ($cgi{'p'} =~ /^(.+)$/) { + $password=$1; +} +else { + $password=''; +} +# print "Content-type: text/plain\n\n"; + +%settings=readdatafile(SETTINGS_PATH); +%default=readdatafile(DEFAULT_PATH); +%framedata=readdatafile(DATA_PATH.$frame); +if($password eq $settings{'password'}){ + $passwordOK = 1; +} +else{ + $passwordOK = 0; +} + +if (open ($statefile,"+<",STATE_PATH)){ + if (flock($statefile,2)) { + + %state=readdatafile($statefile); + + if($frame<0) { + $frame = int($state{'last'}) + $frame +1; + %framedata=readdatafile(DATA_PATH.$frame); + } + + if(int($state{'state'})==1 && $frame == int($state{'last'}) && $method ne 'HEAD' && !$passwordOK){ + my %newstate=%state; + if($state{'ip1'} ne $IP) { + if ($state{'ip1'} eq '') { + $newstate{'ip1'} = $IP; + writedatafile($statefile,%newstate); + } + elsif($state{'ip2'} ne $IP) { + if ($state{'ip2'} eq '') { + $newstate{'ip2'} = $IP; + writedatafile($statefile,%newstate); + } + else { + $newstate{'state'}=2; + $newstate{'ip3'} = $IP; + writedatafile($statefile,%newstate); + } + } + } + } + elsif(int($state{'state'})==0 && $frame == 1) { + my %story; + my $inpath; + my $outpath; + + %story = readdatafile(STORY_PATH); + %gotolist=readdatafile(LIST_PATH); + if(int($story{'state'}) == 17 && int($story{'pass'}) == 1) { + #ACTIVATE! + + $framedata{'ongtime'} = $time; + writedatafile(DATA_PATH.$frame,%framedata); + $state{'state'} = 1; + $state{'last'} = 1; + $state {'ip1'} = '0.0.0.0'; + $state {'ip2'} = '0.0.0.0'; + $state {'ip3'} = ''; + $state {'nextong'} = (int($time / 3600) + int($settings{'firstongtime'})) * 3600 ; + $state{'ongtime'} = int($settings{'firstongtime'}); + + unless(defined($framedata{'ext'})){ + $framedata{'ext'}=$default{'ext'}; + } + + $inpath = DATA_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'}); + $outpath = WWW_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'}); + + $gotolist{'title-1'}=$framedata{'title'}; + $gotolist{'ongtime-1'}=$framedata{'ongtime'}; + + if(copy ($inpath, $outpath)) { + writeindex(INDEX_PATH); + writedatafile($statefile,%state); + writedatafile(LIST_PATH,%gotolist); + } + else { + $state{'state'} = 0; + } + } + } + } + else { + $state{'state'} = 0; + } + close ($statefile); +} +else { + $state{'state'} = 0; +} + +%nextframedata=readdatafile(DATA_PATH.($frame+1)); +foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + unless(defined($nextframedata{$ind})){ + $nextframedata{$ind}=$default{$ind}; + } +} + +$hours=int($state{'nextong'})-$time; +$ongtime=int($state{'ongtime'}); +if($ongtime == 0) { + $ongtime=int($settings{'ongtime'}) +} + +$showcommand = ($hours < ($ongtime*3600/3)); +if($hours>0){ + $seconds = sprintf('%02d',$hours % 60); + $hours = int($hours/60); + $minutes = sprintf('%02d',$hours % 60); + $hours = sprintf('%02d',int($hours/60)); +} +elsif(($hours>=-15) && (int($state{'state'}) == 2)){ + $seconds='NG'; + $minutes='00'; + $hours='00'; +} +else{ + $seconds='EE'; + $minutes='EE'; + $hours='EE'; +} + + +if ($passwordOK || (int($state{'state'}) >= 1 && $frame <= int($state{'last'}) && $frame >= 0)) { + $access=1; +} +else { + $access=0; + %framedata = readdatafile(NOACCESS_PATH); + foreach my $ind (keys %default) { + unless(defined($framedata{$ind})){ + $framedata{$ind}=$default{$ind}; + } + } +} + +$textmode = int($cgi{'b'}); +if($textmode > 2) { + $textmode = 0; +} + +# print "Content-type: text/plain\n\n"; +# print 'frame='.$frame."\n"; +# print 'password='.$password."\n"; +# print 'passwordOK='.$passwordOK."\n"; +# print 'access='.$access."\n"; +# print "\n>>>ENV<<<\n\n"; +# foreach my $ind (keys %ENV) { + # print $ind.'='.$ENV{$ind}."\n"; +# } +# print "\n>>>HTTP<<<\n\n"; +# foreach my $ind (keys %http) { + # print $ind.': '.$http{$ind}."\n"; +# } +# print "\n>>>CGI<<<\n\n"; +# foreach my $ind (keys %cgi) { + # print $ind.'='.$cgi{$ind}."\n"; +# } +# print "\n>>>FRAMEDATA<<<\n\n"; +# foreach my $ind (keys %framedata) { + # print $ind.': '.$framedata{$ind}."\n"; +# } +# print "\n>>>NEXTFRAMEDATA<<<\n\n"; +# foreach my $ind (keys %nextframedata) { + # print $ind.': '.$nextframedata{$ind}."\n"; +# } +# print "\n>>>SETTINGS<<<\n\n"; +# foreach my $ind (keys %settings) { + # print $ind.': '.$settings{$ind}."\n"; +# } +# print "\n>>>STATE<<<\n\n"; +# foreach my $ind (keys %state) { + # print $ind.': '.$state{$ind}."\n"; +# } + +print "Content-type: text/html\n"; +if(!$access) { + print "Status: 403 Forbidden\n"; +} +print "\n"; +if($method eq 'HEAD') { + exit; +} + +print ''."\n"; +print ''."\n"; +print ''."\n"; +print ''; +unless($framedata{'title'} eq '' || $framedata{'title'} eq $settings{'story'}) { + print entityencode($framedata{'title'}).' • '; +} +print entityencode($settings{'story'}).' • '.WEBSITE_NAME.''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print ''."\n"; +if($frame>0 && $access) { + print ''."\n"; +} +if ($passwordOK || $frame