]> bicyclesonthemoon.info Git - botm/oldlogs/commitdiff
keep just the old logs tool as standalone version now v1.0.0
authorb <rowerynaksiezycu@gmail.com>
Mon, 12 Feb 2024 22:14:10 +0000 (22:14 +0000)
committerb <rowerynaksiezycu@gmail.com>
Mon, 12 Feb 2024 22:14:10 +0000 (22:14 +0000)
30 files changed:
.gitmodules
2words.1.pl [deleted file]
attach.1.pl [deleted file]
bbcode.1.pl [deleted file]
botm-common
botmlogo.png [deleted file]
bsta.1.conf [deleted file]
bsta.1.cron [deleted file]
bsta.css [deleted file]
bsta_lib.1.pm [deleted file]
chat.1.pl [deleted file]
exec [deleted submodule]
frame.1.pl [deleted file]
goto.1.pl [deleted file]
info.1.pl [deleted file]
install.sh
makefile
makefile.1.mak
oldlogs.1.pl
ong.1.pl [deleted file]
opomba.1.pl [deleted file]
reset.1.pl [deleted file]
settings-again.txt [deleted file]
settings-bsta.txt [deleted file]
settings-debug.txt
settings-release.txt [new file with mode: 0644]
settings.txt
timer.js [deleted file]
update.1.pl [deleted file]
viewer.1.pl [deleted file]

index 7c416db9864cd7e930b84e2e70530b5bd51fd40b..55b1b1e33957bfe12e05533a7a0e309dcd705e79 100644 (file)
@@ -1,9 +1,6 @@
 [submodule "config"]
        path = config
        url = ../../botm/config
-[submodule "exec"]
-       path = exec
-       url = ../../botm/exec
 [submodule "botm-common"]
        path = botm-common
        url = ../../botm/common-perl
diff --git a/2words.1.pl b/2words.1.pl
deleted file mode 100644 (file)
index 1bc2d74..0000000
+++ /dev/null
@@ -1,676 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/2words
-# 2words is generated from 2words.1.pl.
-#
-# The wordgame interface
-#
-# Copyright (C) 2016, 2017, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'http_header_status', 'http_header_allow',
-       'merge_url',
-       'read_header_env',
-       'html_entity_encode_dec',
-       'url_query_decode', 'url_query_encode',
-       'open_encoded'
-);
-use bsta_lib (
-       'STATE', 'INTF_STATE',
-       'get_id',
-       'fail_method', 'fail_content_type',
-       'print_html_start', 'print_html_end',
-       'print_html_head_start', 'print_html_head_end',
-       'print_html_body_start', 'print_html_body_end',
-       'write_index',
-       'get_remote_addr', 'get_password',
-       'merge_settings',
-       'ong',
-       'read_story', 'write_story',
-       'read_settings', 'read_state'
-);
-
-###PERL_CGI_PATH:           CGI_PATH           = /bsta/
-###PERL_CGI_2WORDS_PATH:    CGI_2WORDS_PATH    = /bsta/2words
-
-###PERL_DATA_STORY_PATH:    DATA_STORY_PATH    = /botm/data/bsta/story
-
-###PERL_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
-
-###PERL_STORY_LENGTH:       STORY_LENGTH       = 16
-###PERL_PAGE_LENGTH:        PAGE_LENGTH        = 16
-###PERL_FIRSTPAGE_LENGTH:   FIRSTPAGE_LENGTH   = 4
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my %http;
-my %cgi;
-my %story;
-my %new_story;
-my %settings;
-my %state;
-
-my $time = time();
-srand ($time-$$);
-
-my $method;
-my $IP;
-my $words;
-my $color2;
-my $last_IP;
-my $story_id;
-my $turn;
-my $status;
-my $allow;
-my $message;
-my $first_letter;
-my $second_letter;
-my $last_letter;
-my $intf_state;
-my $intf_pass;
-my $intf_pause;
-my $intf_mode;
-my $fh;
-my $story_lock;
-my @story_lines;
-my $ong_state;
-my $page;
-my $password;
-my $password_ok;
-
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else {
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET','POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else{
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-
-$IP = get_remote_addr();
-$page = get_id(\%cgi);
-$password = get_password(\%cgi);
-if ($cgi{'words'} ne '') {
-       $words = $cgi{'words'};
-}
-
-%settings = read_settings();
-%state    = read_state();
-$ong_state = int($state{'state'});
-
-$password_ok = ($password eq $settings{'password'});
-if ($password_ok) {
-       $IP .= ' OK';
-}
-
-$story_lock=0;
-if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
-       $story_lock=1;
-       if (flock($fh,2)) {
-               $story_lock=2;
-       }
-       %story = read_story($fh);
-       
-       if ($story{'lastip'} =~ /^.+$/) {
-               $last_IP=$&;
-       }
-       else {
-               $last_IP='0.0.0.0';
-       }
-       
-       $last_letter = lc($story{'letter'});
-       $story_id   = int($story{'id'});
-       $intf_pass  = int($story{'pass'});
-       $intf_state = int($story{'state'});
-       $intf_mode  = $intf_state & INTF_STATE->{'mode'};
-       $intf_pause = $intf_state & INTF_STATE->{'||'};
-       
-       if ($IP ne $last_IP) {
-               $turn = 1;
-       }
-       else {
-               $turn = 0;
-       }
-       
-       if (
-               ($intf_state < 0) || (
-                       ($method eq 'POST') && (
-                               ($cgi{'clear'} ne '') || 
-                               ($cgi{'clear_all'} ne '')
-                       )
-               )
-       ) {
-               if (
-                       ($cgi{'clear_all'} ne '') ||
-                       ($intf_state < -1)
-               ) {
-                       $story{'id'} = 0;
-               }
-               $story{'content'} = '';
-               $story{'lastip' } = '0.0.0.0';
-               $story{'letter' } = '';
-               $story{'pass'   } = 0;
-               $story{'state'  } = INTF_STATE->{'X'};
-               $turn = 0;
-               if ($ong_state == STATE->{'inactive'}) {
-                       write_index(
-                               \%state,
-                               \%settings,
-                               $story{'pass'},
-                               $story{'state'},
-                               0 # pause
-                       );
-               }
-               write_story($fh, \%story);
-       }
-       
-       if (($words ne '') && ($method eq 'POST')) {
-               if (
-                       (!$turn) &&
-                       (!$password_ok)
-               ) {
-                       $status = HTTP_STATUS->{'forbidden'};
-                       $message = "It's not your turn.";
-               }
-               # TODO: consider allowing non-ASCII letters in words.
-               # (not very important in English language)
-               elsif (
-                       ($words =~ /^([!"\(\),\.:;\?][ \t]*)?([A-Za-z][A-Za-z'\-]*[A-Za-z']?)([!"\(\),\.:;\? \t][ \t]*)([A-Za-z][A-Za-z'\-]*[A-Za-z']?)([!"\(\),\.:;\?]?[ \t]*)$/) ||
-                       ($password_ok && ($words ne ''))
-               ) {
-                       # we have 2 words
-                       $first_letter  = lc(substr($2, 0, 1));
-                       $second_letter = lc(substr($4, 0, 1));
-                       if (
-                               ($first_letter ne $last_letter) &&
-                               ($last_letter ne '') && 
-                               (!$password_ok)
-                       ) {
-                               $status = HTTP_STATUS->{'bad_request'};
-                               $message = 'The first word must start with '.uc($last_letter).'.';
-                       }
-                       elsif (
-                               ($first_letter eq $second_letter) &&
-                               (!$password_ok)
-                       ) {
-                               $status = HTTP_STATUS->{'bad_request'};
-                               $message = 'The second word can\'t also start with '.uc($first_letter).'.';
-                       }
-                       else {
-                               # words are valid
-                               # update state
-                               $story{'content'} = $story{'content'} . $words."\n";
-                               $turn = 0;
-                               $story{'lastip'} = $IP;
-                               $story{'letter'} = $second_letter;
-                               
-                               if ($cgi{'next'} ne '') {
-                                       # start next game
-                                       if (
-                                               $password_ok ||
-                                               (split(/\r?\n/,$story{'content'}) >= (STORY_LENGTH-1))
-                                       ) {
-                                               # store finished game
-                                               write_story($story_id, \%story);
-                                               # init new game
-                                               $new_story{'id'     } = $story_id + 1;
-                                               $new_story{'letter' } = '';
-                                               $new_story{'lastip' } = $IP;
-                                               $new_story{'content'} = '';
-                                               $new_story{'pass'   } = 0;
-                                               $new_story{'state'  } = INTF_STATE->{'X'};
-                                               # reset hidden interface
-                                               $intf_state = INTF_STATE->{'X'};
-                                               $intf_pass = 0;
-                                               $intf_mode = INTF_STATE->{'X'};
-                                               $intf_pause= 0;
-                                               if($ong_state == STATE->{'inactive'}) {
-                                                       # ONG not activated yet; reset index
-                                                       write_index(
-                                                               \%state,
-                                                               \%settings,
-                                                               $intf_pass,
-                                                               $intf_mode,
-                                                               $intf_pause
-                                                       );
-                                               }
-                                               # save new game
-                                               write_story($fh, \%new_story);
-                                       }
-                                       else {
-                                               $message = 'To early to finish this wordgame.';
-                                               write_story($fh, \%story);
-                                       }
-                               }
-                               else {
-                                       # continue the game
-                                       if ($intf_pass == 1) {
-                                               # hidden interface was already active; deactivate
-                                               $intf_pass = 2;
-                                               $story{'pass'} = 2;
-                                               if($ong_state == STATE->{'inactive'}) {
-                                                       write_index(
-                                                               \%state,
-                                                               \%settings,
-                                                               $intf_pass,
-                                                               $intf_mode,
-                                                               $intf_pause
-                                                       );
-                                               }
-                                       }
-                                       elsif(lc($2).' '.lc($4) eq $settings{'unlock'}) {
-                                               # correct password for the hidden interface!
-                                               if ($intf_pass != 0) {
-                                                       $message = 'The password has already been used in this story.';
-                                               }
-                                               elsif ($ong_state != STATE->{'inactive'}) {
-                                                       # ONG already active, nothing to do here
-                                                       $message = "???";
-                                               }
-                                               else {
-                                                       # ready to activate?
-                                                       my $r;
-                                                       
-                                                       # ONG tape interface
-                                                       $r = ong(
-                                                               'i',   # ID: tape interface
-                                                               $time, # ONG time;    not relevant
-                                                               0,     # timer;       not relevant
-                                                               0,     # update;      not relevant
-                                                               0,     # print
-                                                               \%settings,         # not relevant
-                                                               '',    # %default;    not relevant
-                                                               '',    # %frame_data; not relevant
-                                                               ''     # $goto_list;  not relevant
-                                                       );
-                                                       if ($r) {
-                                                               # ONG CFRT
-                                                               $r = ong(
-                                                                       'c',   # ID: CFRT
-                                                                       $time, # ONG time;   not relevant
-                                                                       0,     # timer;      not relevant
-                                                                       0,     # update;     not relevant
-                                                                       0,     # print
-                                                                       \%settings,
-                                                                       '',    # %default
-                                                                       '',    # %frame_data
-                                                                       ''     # $goto_list; not relevant
-                                                               );
-                                                       }
-                                                       if ($r) {
-                                                               # ONG frame 0!
-                                                               $r = ong(
-                                                                       0,     # frame ID
-                                                                       $time, # ONG time; might get overwritten later
-                                                                       0,     # timer
-                                                                       0,     # update
-                                                                       0,     # print
-                                                                       \%settings,
-                                                                       '',    # %default
-                                                                       '',    # %frame_data
-                                                                       ''     # $goto_list
-                                                               );
-                                                       }
-                                                       if($r) {
-                                                               # new state of hidden interface
-                                                               $intf_pass = 1;
-                                                               $intf_state = INTF_STATE->{'X'};
-                                                               $intf_mode  = INTF_STATE->{'X'};
-                                                               $intf_pause = 0;
-                                                               $story{'pass'} = 1;
-                                                               $story{'state'} = INTF_STATE->{'X'};
-                                                               write_index(
-                                                                       \%state,
-                                                                       \%settings,
-                                                                       $intf_pass,
-                                                                       $intf_mode,
-                                                                       $intf_pause
-                                                               );
-                                                       }
-                                               }
-                                       }
-                                       write_story($fh, \%story);
-                               }
-                       }
-               }
-               else {
-                       $status = HTTP_STATUS->{'bad_request'};
-                       $message = 'Please, two words, not more, not less (some punctuation is allowed).';
-               }
-       }
-       elsif (
-               ($cgi{'s'} ne '') &&
-               ($intf_pass == 1) &&
-               ($ong_state == STATE->{'inactive'})
-       ) {
-               $intf_state = int($cgi{'s'}) & INTF_STATE->{'mask'};
-               $intf_mode  = $intf_state & INTF_STATE->{'mode'};
-               $intf_pause = $intf_state & INTF_STATE->{'||'};
-               $story{'state'} = $intf_state;
-               write_index(
-                       \%state,
-                       \%settings,
-                       $intf_pass,
-                       $intf_mode,
-                       $intf_pause
-               );
-               write_story($fh, \%story);
-       }
-       @story_lines = split(/\r?\n/, $story{'content'});
-       if(@story_lines & 1) {
-               $turn = !$turn;
-       }
-       
-       close($fh);
-}
-
-if ($status ne '') {
-       print http_header_status($status);
-}
-if ($allow ne '') {
-       print http_header_allow($allow);
-}
-print "Content-type: text/html; charset=UTF-8\n\n";
-
-if($method eq 'HEAD') {
-       exit;
-}
-
-my $max_page = int(($story_id + PAGE_LENGTH - FIRSTPAGE_LENGTH - 1) / PAGE_LENGTH);
-my $newer_available = ($page > 0);
-my $older_available = ($page < $max_page);
-my $show_intf = ($intf_pass == 1) && ($ong_state == STATE->{'inactive'});
-my $id_start = 
-       $story_id-1 -(
-               ($page == 0)    ? 0 : (
-                       (($page-1) * PAGE_LENGTH ) + FIRSTPAGE_LENGTH
-               )
-       );
-my $id_stop = $story_id-1 - (($page*PAGE_LENGTH) + FIRSTPAGE_LENGTH);
-if ($id_stop < 0) {
-       $id_stop = -1;
-}
-
-my $bsta_url = CGI_PATH;
-my $twowords_url = CGI_2WORDS_PATH;
-my $newer_url;
-my $older_url;
-my $oldest_url;
-my $newest_url = merge_url(
-       {'path' => $twowords_url},
-       {'path' => 0}
-);
-if ($newer_available) {
-       $newer_url = merge_url(
-               {'path' => $twowords_url},
-               {'path' => $page-1}
-       );
-}
-if ($older_available) {
-       $older_url = merge_url(
-               {'path' => $twowords_url},
-               {'path' => $page+1}
-       );
-       $oldest_url = merge_url(
-               {'path' => $twowords_url},
-               {'path' => $max_page}
-       );
-}
-my $button_4_url = merge_url(
-       {'path' => $twowords_url},
-       {'query' => {'s' => (INTF_STATE->{'>'} | $intf_pause)}}
-);
-my $button_3_url = merge_url(
-       {'path' => $twowords_url},
-       {'query' => {'s' => (INTF_STATE->{'<<'} | $intf_pause)}}
-);
-my $button_2_url = merge_url(
-       {'path' => $twowords_url},
-       {'query' => {'s' => (INTF_STATE->{'>>'} | $intf_pause)}}
-);
-my $button_1_url = merge_url(
-       {'path' => $twowords_url},
-       {'query' => {'s' => INTF_STATE->{'X'}}}
-);
-my $button_0_url = merge_url(
-       {'path' => $twowords_url},
-       {'query' => {'s' => ($intf_pause ? $intf_mode : ($intf_mode | INTF_STATE->{'||'}))}}
-);
-my $button_5_img = merge_url(
-       {'path' => CGI_PATH()},
-       {'path' => 'intf-20.gif'}
-);
-my $button_4_img = merge_url(
-       {'path' => CGI_PATH()},
-       {'path' => 'intf-10'.(($intf_mode == INTF_STATE->{'>'}) ? '_' : '').'.gif'}
-);
-my $button_3_img = merge_url(
-       {'path' => CGI_PATH()},
-       {'path' => 'intf-08'.(($intf_mode == INTF_STATE->{'<<'}) ? '_' : '').'.gif'}
-);
-my $button_2_img = merge_url(
-       {'path' => CGI_PATH()},
-       {'path' => 'intf-04'.(($intf_mode == INTF_STATE->{'>>'}) ? '_' : '').'.gif'}
-);
-my $button_1_img = merge_url(
-       {'path' => CGI_PATH()},
-       {'path' => 'intf-02.gif'}
-);
-my $button_0_img = merge_url(
-       {'path' => CGI_PATH()},
-       {'path' => 'intf-01'.($intf_pause ? '_' : '').'.gif'}
-);
-my $intf_img_id = '';
-if ($intf_state == INTF_STATE->{'>'}) {
-       $intf_img_id = '_10'
-}
-elsif ($intf_mode == INTF_STATE->{'<<'}) {
-       $intf_img_id = '_08'
-}
-elsif ($intf_mode == INTF_STATE->{'>>'}) {
-       $intf_img_id = '_04'
-}
-my $intf_img = merge_url(
-       {'path' => CGI_PATH()},
-       {'path' => 'intf-00'.$intf_img_id.'.gif'}
-);
-
-if ($password_ok) {
-       my $password_query = url_query_encode({'p', $settings{'password'}});
-       $twowords_url = merge_url($twowords_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $newest_url   = merge_url($newest_url   , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $newer_url    = merge_url($newer_url    , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $older_url    = merge_url($older_url    , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $button_4_url = merge_url($button_4_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $button_3_url = merge_url($button_3_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $button_2_url = merge_url($button_2_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $button_1_url = merge_url($button_1_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $button_0_url = merge_url($button_0_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-}
-
-my $_password = $password_ok ? html_entity_encode_dec($settings{'password'}, 1): '';
-my $_bsta_url     = html_entity_encode_dec($bsta_url     , 1);
-my $_twowords_url = html_entity_encode_dec($twowords_url , 1);
-my $_newest_url   = html_entity_encode_dec($newest_url   , 1);
-my $_newer_url    = html_entity_encode_dec($newer_url    , 1);
-my $_older_url    = html_entity_encode_dec($older_url    , 1);
-my $_oldest_url   = html_entity_encode_dec($oldest_url   , 1);
-my $_button_4_url = html_entity_encode_dec($button_4_url , 1);
-my $_button_3_url = html_entity_encode_dec($button_3_url , 1);
-my $_button_2_url = html_entity_encode_dec($button_2_url , 1);
-my $_button_1_url = html_entity_encode_dec($button_1_url , 1);
-my $_button_0_url = html_entity_encode_dec($button_0_url , 1);
-my $_button_5_img = html_entity_encode_dec($button_5_img , 1);
-my $_button_4_img = html_entity_encode_dec($button_4_img , 1);
-my $_button_3_img = html_entity_encode_dec($button_3_img , 1);
-my $_button_2_img = html_entity_encode_dec($button_2_img , 1);
-my $_button_1_img = html_entity_encode_dec($button_1_img , 1);
-my $_button_0_img = html_entity_encode_dec($button_0_img , 1);
-my $_intf_img     = html_entity_encode_dec($intf_img     , 1);
-my $_message      = html_entity_encode_dec($message      , 1);
-my $_website_name = html_entity_encode_dec(WEBSITE_NAME(), 1);
-
-print_html_start(\*STDOUT);
-print_html_head_start(\*STDOUT);
-
-
-print '  <title>Two words &bull; '.$_website_name.'</title>'."\n";
-print '  <link rel="start" href="'.$_oldest_url.'">'."\n";
-if ($older_available) {
-       print '  <link rel="prev" href="'.$_older_url.'">'."\n";
-}
-if ($newer_available) {
-       print '  <link rel="next" href="'.$_newer_url.'">'."\n";
-}
-
-print_html_head_end(\*STDOUT);
-print_html_body_start(\*STDOUT);
-
-print '   <div id="inst" class="ins">'."\n";
-
-print '    <div id="title">'."\n";
-print '     <h1 id="titletext">Two words</h1>'."\n";
-print '    </div>'."\n";
-
-if ($page == 0) {
-       print '    <div id="storypuzzle">'."\n";
-       for (my $i = 0; $i < @story_lines; ++$i) {
-               print '     <span class="'.($turn ? 'ni':'br').'">'.html_entity_encode_dec($story_lines[$i], 1).'</span>'."\n";
-               $turn = !$turn;
-       }
-       print '    </div>'."\n";
-
-       print '    <div id="command">'."\n";
-       if ($message ne '') {
-               print '     <span class="br">'.$_message.'</span>'."\n";
-       }
-       
-       if ($turn || $password_ok) {
-               print '     <form method="post" action="'.$_twowords_url.'">'."\n";
-               if ($message eq '') {
-                       if ($story{"content"} eq '') {
-                               print '      Two words, please:<br>'."\n";
-                       }
-                       else {
-                               print '      Please continue, two words:<br>'."\n";
-                       }
-               }
-               print '      <input class="intx" type="text" name="words">'."\n";
-               print '      <input class="inbt" type="submit" value="enter">'."\n";
-               if ((@story_lines >= (STORY_LENGTH-1)) || $password_ok ) {
-                       print '      <input class="inbt" type="submit" name="next" value="enter and then start a new one">'."\n";
-               }
-               if ($password_ok) {
-                       print '      <input class="inbt" type="submit" name="clear" value="clear">'."\n";
-                       print '      <input class="inbt" type="submit" name="clear_all" value="clear all">'."\n";
-                       print '      <input type="hidden" name="p" value="'.$_password.'">'."\n";
-               }
-               print '     </form>'."\n";
-       }
-       else {
-               if ($message eq '') {
-                       print '     Wait for it.'."\n";
-               }
-       }
-       print '    </div>'."\n";
-}
-elsif ($message ne '') {
-       print '    <div id="command">'."\n";
-       print '     <span class="br">'.$_message.'</span>'."\n";
-       print '    </div>'."\n";
-}
-print '   </div>'."\n";
-
-if ($show_intf) {
-       print '   <div id="framespace">'."\n";
-       print '    <table id="intftable" cellspacing="0" cellpadding="0">'."\n";
-       print '     <tr class="intf">'."\n";
-       print '      <td colspan="6" class="intf"><img src="'.$_intf_img.'" alt="" class="intf"></td>'."\n";
-       print '     </tr>'."\n";
-       
-       print '     <tr class="intf">'."\n";
-       print '      <td class="intf"><img src="'.$_button_5_img.'" alt="o" class="intf"></td>'."\n";
-       print '      <td class="intf"><a href="'.$_button_4_url.'"><img src="'.$_button_4_img.'" class="intf" alt="&gt;"></a></td>'."\n";
-       print '      <td class="intf"><a href="'.$_button_3_url.'"><img src="'.$_button_3_img.'" class="intf" alt="&lt;&lt;"></a></td>'."\n";
-       print '      <td class="intf"><a href="'.$_button_2_url.'"><img src="'.$_button_2_img.'" class="intf" alt="&gt;&gt;"></a></td>'."\n";
-       print '      <td class="intf"><a href="'.$_button_1_url.'"><img src="'.$_button_1_img.'" class="intf" alt="^"></a></td>'."\n";
-       print '      <td class="intf"><a href="'.$_button_0_url.'"><img src="'.$_button_0_img.'" class="intf" alt="||"></a></td>'."\n";
-       print '     </tr>'."\n";
-       print '    </table>'."\n";
-       print '   </div>'."\n";
-}
-
-print '   <div id="insb" class="ins">'."\n";
-
-print '    <div id="undertext">'."\n";
-for (my $i = $id_start; $i > $id_stop; --$i) {
-       %new_story = read_story($i);
-       print '     <p class="'.(($i&1)?'br':'ni').'" id="s'.$i.'">'.html_entity_encode_dec($new_story{'content'}).'</p>'."\n";
-}
-print '    </div>'."\n";
-
-print '    <div id="underlinks">'."\n";
-print '     <a href="'.$_bsta_url.'">BSTA</a> |'."\n";
-print '     <a href="'.$_twowords_url.'">Once again</a>';
-if ($older_available) {
-       print ' |'."\n";
-       print '     <a href="'.$_older_url.'">Before</a>';
-}
-if ($newer_available) {
-       print ' |'."\n";
-       print '     <a href="'.$newer_url.'">Unbefore</a>';
-}
-if ($older_available) {
-       print ' |'."\n";
-       print '<a href="'.$_oldest_url.'">Initially</a>';
-}
-if($turn) {
-       print ' |'."\n";
-       print '     (Entering words here is irreversible. Your actions might be remembered forever. So please be reasonable.)';
-}
-print "\n";
-print '    </div>'."\n";
-
-print '   </div>'."\n";
-
-print_html_body_end(\*STDOUT, $ong_state == STATE->{'inactive'});
-print_html_end(\*STDOUT);
diff --git a/attach.1.pl b/attach.1.pl
deleted file mode 100644 (file)
index cb34f63..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/a
-# attach.pl is generated from attach.1.pl.
-#
-# The attachment interface
-#
-# Copyright (C) 2016, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'read_header_env',
-       'url_query_decode',
-       'join_path',
-       'merge_url',
-       'open_encoded', 'stat_encoded',
-       'http_header_line', 'http_header_content_length', 'http_header_content_disposition'
-);
-use bsta_lib (
-       'STATE',
-       'merge_settings',
-       'get_id', 'get_password',
-       'fail_method', 'fail_content_type', 'fail_attachment', 'fail_500',
-       'redirect',
-       'read_settings', 'read_state', 'read_attachment'
-);
-
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_CGI_PATH:           CGI_PATH           = /bsta/
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta
-###PERL_WWW_PATH:           WWW_PATH           = /botm/www/1190/bsta/
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %http;
-my %cgi;
-my %settings;
-my %state;
-my %file_data;
-
-my $method;
-my $ID;
-my $frame;
-my $last_frame;
-my $ong_state;
-my $password;
-my $password_ok;
-my $IP;
-my $try_onged;
-my $buffer;
-my $fh;
-my $file_path;
-my $file_name;
-my $direct;
-my $r = 0;
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else{
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else{
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-
-$ID       = get_id(      \%cgi);
-$password = get_password(\%cgi);
-
-%settings  = read_settings();
-%state     = read_state();
-%file_data = read_attachment($ID);
-$frame = ($file_data{'frame'} ne '') ? int($file_data{'frame'}) : -1;
-$last_frame = int($state{'last'});
-$ong_state  = int($state{'state'});
-$file_name  = $file_data{'filename'};
-
-$password_ok = ($password eq $settings{'password'});
-
-unless (
-       ($file_name ne '') && (
-               $password_ok || (
-                       ($ong_state >= STATE->{'waiting'}) &&
-                       ($frame <= $last_frame) &&
-                       ($frame >=0)
-               )
-       )
-) {
-       exit fail_attachment($method, $ID);
-}
-
-if ($file_data{'content'} ne '') {
-       $direct = 1;
-}
-else {
-       $direct = 0;
-       $try_onged = (
-               ($ong_state >= STATE->{'waiting'}) &&
-               ($frame <= $last_frame) &&
-               ($frame >=0)
-       );
-       if ($try_onged) {
-               $file_path = join_path(PATH_SEPARATOR(), WWW_PATH(), $file_name);
-               $r = open_encoded($fh, '<' , $file_path);
-               if ($r) {
-                       close($r);
-                       $file_path = merge_url(
-                               {'path' => CGI_PATH()},
-                               {'path' => $file_name}
-                       );
-                       exit redirect ($method, $file_path, HTTP_STATUS->{'see_other'});
-               }
-       }
-       unless ($r) {
-               $file_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $file_name);
-               $r = open_encoded($fh,'<', $file_path);
-               unless ($r) {
-                       exit fail_attachment($method, $ID);
-               }
-       }
-       unless (binmode($fh)) {
-               close($fh);
-               exit fail_500("Can't switch file to binary mode.");
-       }
-       if (my @file_info = stat_encoded($file_path)) {
-               print http_header_content_length($file_info[7]);
-       }
-}
-if ($file_data{'content-type'} ne '') {
-       print http_header_line('content-type', $file_data{'content-type'});
-}
-if ($file_name ne '') {
-       print http_header_content_disposition('inline', $file_name);
-}
-unless ($direct) {
-       unless (binmode STDOUT) {
-               close($fh);
-               exit fail_500("Can't switch output to binary mode.");
-       }
-}
-print "\n";
-
-if($method ne 'HEAD'){
-       if($direct) {
-               print $file_data{'content'};
-       }
-       else {
-               while (read ($fh, $buffer, 1024)) {
-                       print (STDOUT $buffer);
-               }
-       }
-}
-unless ($direct) {
-       close($fh);
-}
diff --git a/bbcode.1.pl b/bbcode.1.pl
deleted file mode 100644 (file)
index 28e5e6d..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/b
-# bbcode.pl is generated from bbcode.1.pl.
-#
-# The bbcode interface
-#
-# Copyright (C) 2017, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'read_header_env',
-       'url_query_decode',
-       'merge_url',
-       'http_header_status'
-);
-use bsta_lib (
-       'STATE',
-       'fail_method', 'fail_content_type',
-       'get_frame', 'get_password',
-       'merge_settings',
-       'eval_bb', 'bb_to_bbcode',
-       'get_frame_file',
-       'read_frame_data', 'read_default', 'read_noaccess',
-       'read_settings', 'read_state'
-);
-
-###PERL_CGI_PATH:           CGI_PATH           = /bsta/
-###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v
-
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta/
-
-###PERL_SCHEME:             SCHEME             = http
-###PERL_WEBSITE:            WEBSITE            = 1190.bicyclesonthemoon.info
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %http;
-my %cgi;
-my %frame_data;
-my %default;
-my %settings;
-my %state;
-
-my $method;
-my $frame;
-my $password;
-my $password_ok;
-my $access;
-my $ongtime;
-my $ong_state;
-my $last_frame;
-my $frame_data_path;
-my $frame_file;
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else{
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else{
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-
-$frame  = get_frame(\%cgi);
-$password = get_password(\%cgi);
-
-%settings   = read_settings();
-%default    = read_default();
-%state      = read_state();
-
-$ong_state  = int($state{'state'});
-$last_frame = int($state{'last'});
-
-$password_ok = ($password eq $settings{'password'});
-
-if ($frame < 0) {
-       $frame = $last_frame + $frame +1;
-}
-%frame_data = read_frame_data($frame, \%default);
-
-if (
-       $password_ok || (
-               ($ong_state >= STATE->{'waiting'}) &&
-               ($frame <= $last_frame) &&
-               ($frame >= 0)
-       )
-) {
-       $access = 1;
-}
-else {
-       $access=0;
-       %frame_data = read_noaccess(\%default);
-}
-$frame_file = get_frame_file($frame, \%frame_data, \%settings);
-
-print "Content-type: text/plain; charset=UTF-8\n";
-if(!$access) {
-       print http_header_status(HTTP_STATUS->{'forbidden'});
-}
-print "\n";
-if($method eq 'HEAD') {
-       exit;
-}
-
-my $viewer_url = merge_url(
-       {'scheme' => SCHEME(), 'host' => WEBSITE()},
-       {'path' => CGI_VIEWER_PATH()},
-       {'path' => $frame}
-);
-my $frame_url = merge_url(
-       {'scheme' => SCHEME(), 'host' => WEBSITE()},
-       {'path' => CGI_PATH()},
-       {'path' => $frame_file}
-);
-my $content = bb_to_bbcode(
-       eval_bb(
-               $frame_data{'content'},
-               1
-       )
-);
-
-print '[quote][center][size=200]'.$frame_data{'title'}.'[/size]'."\n";
-print '[url='.$viewer_url.'][img]'.$frame_url.'[/img][/url][/center]'."\n";
-print $content.'[/quote]'."\n";
index 54a9ab5889510496f8820da830f46068703aa8d6..44fbe59bfd7652a0975e601591df4a4b218da40d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 54a9ab5889510496f8820da830f46068703aa8d6
+Subproject commit 44fbe59bfd7652a0975e601591df4a4b218da40d
diff --git a/botmlogo.png b/botmlogo.png
deleted file mode 100644 (file)
index d4aea7f..0000000
Binary files a/botmlogo.png and /dev/null differ
diff --git a/bsta.1.conf b/bsta.1.conf
deleted file mode 100644 (file)
index 43791a2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# bsta.conf is automatically generated from bsta.1.conf
-
-ScriptAlias ###CONF_CGI_2WORDS; ###CONF_BIN_2WORDS;
-ScriptAlias ###CONF_CGI_ATTACH; ###CONF_BIN_ATTACH;
-ScriptAlias ###CONF_CGI_BBCODE; ###CONF_BIN_BBCODE;
-ScriptAlias ###CONF_CGI_COIN; ###CONF_BIN_COIN;
-ScriptAlias ###CONF_CGI_FRAME; ###CONF_BIN_FRAME;
-ScriptAlias ###CONF_CGI_GOTO; ###CONF_BIN_GOTO;
-ScriptAlias ###CONF_CGI_INFO; ###CONF_BIN_INFO;
-ScriptAlias ###CONF_CGI_VIEWER; ###CONF_BIN_VIEWER;
-ScriptAlias ###CONF_CGI_WORDS; ###CONF_BIN_WORDS;
-
-<Directory ###CONF_BIN;>
-       Require all granted
-</Directory>
diff --git a/bsta.1.cron b/bsta.1.cron
deleted file mode 100644 (file)
index 96c38df..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# bsta.cron is automatically generated from bsta.1.cron
-
-###CRON_OLDLOGS_SCHEDULE; ###CRON_USER; ###CRON_OLDLOGS; ###CRON_LOG; ###CRON_LOG_SIZE_LIMIT; ###CRON_LOGS_TOTAL; ###CRON_LOGS_UNCOMPRESSED;
-###CRON_ONG_SCHEDULE; ###CRON_USER; ###CRON_ONG; >> ###CRON_ONG_LOG;
-###CRON_RESET_SCHEDULE; ###CRON_USER; ###CRON_RESET; ###CRON_RESET_PASSWORD;
diff --git a/bsta.css b/bsta.css
deleted file mode 100644 (file)
index da52470..0000000
--- a/bsta.css
+++ /dev/null
@@ -1,492 +0,0 @@
-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;
-}
-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;
-}
-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#frame:hover
-{
-       border-color: #bb6622;
-}
-img#frame.double
-{
-       border-width: 54px 38px;
-}
-img#frame.full
-{
-       border-width: 0px;
-       background-color: #0057af;
-}
-img#frame.full#hover
-{
-       background-color: #bb6622;
-}
-img#frame.bftf
-{
-       padding-top: 60px;
-       padding-bottom: 60px;
-       padding-left: 85px;
-       padding-right: 85px;
-       background-color: #d9ecff;
-}
-
-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: #ffffff;
-       border-collapse: collapse;
-       border-spacing: 0px;
-}
-
-div#undertext
-{
-       text-align: left;
-       padding: 8px;
-       margin: 0px;
-       border: 0px;
-}
-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;
-       padding: 2px;
-}
-div.fq:hover
-{
-       border-color: #bb6622;
-}
-div.tq
-{
-       text-align: left;
-       border: solid #0057af 4px;
-       padding: 2px;
-}
-div.tq:hover
-{
-       border-color: #bb6622;
-}
-
-div.opomba
-{
-       text-align: left;
-       border: solid #0057af 4px;
-       background-color: #0057af;
-}
-div.opomba:hover
-{
-       border-color: #bb6622;
-       background-color: #bb6622;
-}
-div.opomba:target
-{
-       border-color: #bb6622;
-       background-color: #bb6622;
-}
-div.opomba:target:hover
-{
-       border-color: #bb6622;
-       background-color: #bb6622;
-}
-div.opomba_info
-{
-       color: #ffffff!important;
-       /* font-weight: bold; */
-}
-div.opomba_text
-{
-       background-color: #ffffff;
-       color: #000000;
-       clear: both;
-       padding: 4px;
-}
-
-div.space
-{
-       background-color: #46a3ff;
-       height: 27px;
-       margin-top: 27px;
-       margin-bottom: 27px;
-}
-
-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;
-}
-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.intx:hover
-{
-       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;
-}
-input.intxc:hover
-{
-       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;
-}
-textarea.inta:hover
-{
-       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;
-}
-input.inbt:hover
-{
-       border-color: #bb6622;
-}
-
-input.hl {
-       background:none!important;
-       border:none!important; 
-       padding:0!important;
-/*     font-family:inherit;
-       font-size:inherit; */
-       font: inherit;
-       text-decoration:underline;
-       border-color: #0057af;
-       color: #0057af;
-}
-input.hl:hover {
-       border-color: #bb6622;
-       color: #bb6622;
-}
-form.hl {
-       display: inline
-}
-
-form.goto {
-       clear: both;
-       display: inline
-}
-
-.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;
-}
-
-.hv.ni:hover
-{
-       border-color: #bb6622!important;
-       color: #bb6622!important;
-}
-
-.hv.br:hover
-{
-       border-color: #0057af!important;
-       color: #0057af!important;
-}
-
-.hu
-{
-       text-decoration:none!important;
-}
-.hu:hover
-{
-       text-decoration:underline!important;
-}
-
-div.le
-{
-       float: left;
-}
-div.pr
-{
-       float: right;
-}
diff --git a/bsta_lib.1.pm b/bsta_lib.1.pm
deleted file mode 100644 (file)
index 7545a90..0000000
+++ /dev/null
@@ -1,2934 +0,0 @@
-# bsta_lib.pm is generated from bsta_lib.1.pm
-# 
-# Library of functions
-#
-# Copyright (C) 2016, 2017, 2019, 2020, 2022, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-# TODO: FQ NBSP ?
-# TODO: DEBUG
-# TODO: BB & INFO indent
-
-package bsta_lib;
-
-use strict;
-#use warnings
-
-use utf8;
-use Encode ('encode', 'decode');
-use Exporter;
-use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
-
-###PERL_EXPORT_VERSION: our $VERSION = 'x.x.x';
-our @ISA         = qw(Exporter);
-our @EXPORT      = ();
-our @EXPORT_OK   = (
-       'STATE', 'TEXT_MODE', 'INTF_STATE', 'CHAT_STATE', 'CHAT_ACTION',
-       'failpage',
-       'fail_method', 'fail_content_type', 'fail_open_file', 'fail_attachment', 'fail_500',
-       'redirect',
-       'get_remote_addr', 'get_id', 'get_frame', 'get_password',
-       'merge_settings',
-       'print_html_start', 'print_html_end',
-       'print_html_head_start', 'print_html_head_end',
-       'print_html_body_start', 'print_html_body_end',
-       'print_viewer_page', 'print_goto',
-       'write_index', 'write_static_viewer_page', 'write_static_goto',
-       'get_frame_file', 'get_page_file',
-       'read_frame_data', 'write_frame_data', 'read_default', 'read_noaccess',
-       'read_state', 'write_state',
-       'read_words_list', 'write_words_list', 'read_words', 'write_words',
-       'read_story', 'write_story',
-       'read_goto', 'write_goto',
-       'read_chat', 'write_chat',
-       'read_settings', 'read_attachment', 'read_coincidence',
-       'ong',
-       'eval_bb', 'bb_to_bbcode', 'bb_to_html'
-);
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'url_query_decode', 'url_query_encode',
-       'url_decode', 'url_encode',
-       'html_entity_encode_dec',
-       'merge_url',
-       'read_header_env',
-       'read_data_file', 'write_data_file',
-       'join_path',
-       'copy_encoded', 'open_encoded', '_x_encoded',
-       'http_header_line', 'http_status',
-       'http_header_status', 'http_header_allow', 'http_header_location'
-);
-
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_CGI_PATH:           CGI_PATH           = /bsta/
-###PERL_CGI_ATTACH_PATH:    CGI_ATTACH_PATH    = /bsta/a
-###PERL_CGI_2WORDS_PATH:    CGI_2WORDS_PATH    = /bsta/2words
-###PERL_CGI_BBCODE_PATH:    CGI_BBCODE_PATH    = /bsta/b
-###PERL_DATA_CHAT_PATH:     DATA_CHAT_PATH     = /botm/data/bsta/chat
-###PERL_CGI_COIN_PATH:      CGI_COIN_PATH      = /bsta/coin
-###PERL_CGI_CSS_PATH:       CGI_CSS_PATH       = /bsta/bsta.css
-###PERL_CGI_FRAME_PATH:     CGI_FRAME_PATH     = /bsta/f
-###PERL_CGI_GOTO_PATH:      CGI_GOTO_PATH      = /bsta/g
-###PERL_CGI_INFO_PATH:      CGI_INFO_PATH      = /bsta/i
-###PERL_CGI_LIST_PATH:      CGI_LIST_PATH      = /bsta/goto.htm
-###PERL_CGI_LOGO_PATH:      CGI_LOGO_PATH      = /bsta/botmlogo.png
-###PERL_CGI_TIMER_PATH:     CGI_TIMER_PATH     = /bsta/timer.js
-###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v
-###PERL_CGI_WORDS_PATH:     CGI_WORDS_PATH     = /bsta/w
-
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta/
-###PERL_DATA_ATTACH_PATH:   DATA_ATTACH_PATH   = /botm/data/bsta/a
-###PERL_DATA_COIN_PATH:     DATA_COIN_PATH     = /botm/data/bsta/coincidence
-###PERL_DATA_DEFAULT_PATH:  DATA_DEFAULT_PATH  = /botm/data/bsta/default
-###PERL_DATA_LIST_PATH:     DATA_LIST_PATH     = /botm/data/bsta/list
-###PERL_DATA_NOACCESS_PATH: DATA_NOACCESS_PATH = /botm/data/bsta/noaccess
-###PERL_DATA_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/settings
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
-###PERL_DATA_STORY_PATH:    DATA_STORY_PATH    = /botm/data/bsta/story
-###PERL_DATA_WORDS_PATH:    DATA_WORDS_PATH    = /botm/data/bsta/words/
-
-###PERL_WWW_PATH:           WWW_PATH           = /botm/www/
-###PERL_WWW_GOTO_PATH:      WWW_GOTO_PATH      = /botm/www/1190/bsta/goto.htm
-###PERL_WWW_INDEX_PATH:     WWW_INDEX_PATH     = /botm/www/1190/bsta/index.htm
-
-###PERL_SCHEME:             SCHEME             = http
-###PERL_WEBSITE:            WEBSITE            = 1190.bicyclesonthemoon.info
-###PERL_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
-###PERL_FAVICON_PATH:       FAVICON_PATH       = /img/favicon.png
-
-###PERL_COIN_DATE:          COIN_DATE          = 13-Nov-2016 22:15
-###PERL_INTF_DATE:          INTF_DATE          = 28-Sep-2016 20:34
-
-###PERL_STORY_CREDITS:      STORY_CREDITS      = "BSTA" by Balthasar Szczepański
-###PERL_INTF_CREDITS:       INTF_CREDITS       = Online interface © Balthasar Szczepański; AGPL 3 license
-###PERL_SOURCE_URL:         SOURCE_URL         = http://bicyclesonthemoon.info/git-projects/?p=ott/bsta
-
-###PERL_COMMENT_PAGE_LENGTH:COMMENT_PAGE_LENGTH= 16
-
-use constant STATE => {
-       'inactive' => 0,
-       'waiting'  => 1,
-       'ready'    => 2,
-       'end'      => 3,
-};
-use constant INTF_STATE => {
-       'X'  => 0b000000,
-       'x'  => 0b000000,
-       '||' => 0b000001,
-       '>>' => 0b000100,
-       '>>|'=> 0b000101,
-       '<<' => 0b001000,
-       '|<<'=> 0b001001,
-       '>'  => 0b010000,
-       '>|' => 0b010001,
-       'mask'=>0b111111,
-       'mode'=>0b111110,
-};
-use constant TEXT_MODE => {
-       'normal' => 0,
-       'bb'     => 1,
-       'info'   => 2,
-       'words'  => 3
-};
-use constant CHAT_STATE => {
-       'disconnected' => 0,
-       'ready'        => 1,
-       'active'       => 2,
-};
-use constant CHAT_ACTION => {
-       'none'   => 0,
-       'join'   => 1,
-       'leave'  => 2,
-       'nopost' => 3,
-       'file'   => 4,
-};
-
-use constant tags_bbcode => {
-       'ht'     => '',
-       '/ht'    => '',
-       'fq'     => '[quote]',
-       '/fq'    => '[/quote]',
-       'tq'     => '[quote]',
-       '/tq'    => '[/quote]',
-       'quote'  => '[quote]',
-       'quote=' => '[quote="',
-       'quote/='=> '"]',
-       '/quote' => '[/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 tags_html => {
-       'ht'     => '',
-       '/ht'    => '',
-       'fq'     => '<div class="fq">',
-       '/fq'    => '</div>',
-       'tq'     => '<div class="tq">',
-       '/tq'    => '</div>',
-       'quote'  => '<div class="opomba"><div class="opomba_text">',
-       'quote=' => '<div class="opomba"><div class="opomba_info"><b>',
-       'quote/='=> '</b> wrote:</div><div class="opomba_text">',
-       '/quote' => '</div></div>',
-       'ni'     => '<span class="ni">',
-       '/ni'    => '</span>',
-       'br'     => '<span class="br">',
-       '/br'    => '</span>',
-       'po'     => '<span class="po">',
-       '/po'    => '</span>',
-       'url'    => '<a href="#">',#think: how to add selfincluding?
-       'url='   => '<a href="',
-       'url/='  => '">',
-       '/url'   => '</a>',
-       'i'      => '<i>',
-       '/i'     => '</i>',
-       'list'   => '<ul>',
-       'list='  => '<ol style="list-style-type: ',
-       'list=1' => 'decimal',
-       'list=A' => 'upper-alpha',
-       'list=a' => 'lower-alpha',
-       'list=I' => 'upper-roman',
-       'list=i' => 'lower-roman',
-       'list/=' => '">',
-       '/list'  => '</ul>',
-       '/list=' => '</ol>',
-       '*'      => '<li>',
-       '/*'     => '</li>',
-       '?'      => '[unknown!]',
-       '/?'     => '[/unknown!]',
-};
-
-
-# Function to return 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, my $hyperlink) = @_;
-       
-       if (ref($header)) {
-               foreach my $header_name (keys %$header) {
-                       print http_header_line($header_name, $header->{$header_name});
-               }
-       }
-       elsif($header ne '') {
-               print $header;
-       }
-       if($method eq 'HEAD') {
-               print "\n";
-               return;
-       }
-       my $_title     = html_entity_encode_dec($title    , 1);
-       my $_message   = html_entity_encode_dec($message  , 1);
-       my $_hyperlink = html_entity_encode_dec($hyperlink, 1);
-       
-       print "Content-type: text/html; charset=UTF-8\n\n";
-       
-       print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
-       print ' <html lang="en">'."\n";
-       print '  <head>'."\n";
-       print '   <meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
-       if ($title ne '') {
-               print '   <title>'.$_title.'</title>'."\n";
-       }
-       print '  </head>'."\n";
-       print ' <body>'."\n";
-       if ($title ne '') {
-               print '  <h1>'.$_title.'</h1>'."\n";
-       }
-       if (($message ne '') || ($hyperlink ne '')) {
-               print "  <p>\n";
-               if ($message ne '') {
-                       print '   '.$_message.($hyperlink ne '' ? '<br>' : '')."\n";
-               }
-               if ($hyperlink ne '') {
-                       print '   <a href="'.$_hyperlink.'">'.$_hyperlink."</a>\n";
-               }
-               print "  </p>\n";
-       }
-       print ' </body>'."\n";
-       print '</html>'."\n";
-}
-
-sub fail_method {
-       (my $method, my $allowed) = @_;
-       
-       my $status = http_status(HTTP_STATUS->{'method_not_allowed'});
-       my $header =
-               http_header_line('status', $status) .
-               http_header_allow($allowed);
-       
-       return failpage(
-               $header,
-               $status,
-               "The interface does not support the $method method.",
-               $method
-       );
-}
-
-sub fail_content_type
-{
-       (my $method, my $content_type) = @_;
-       
-       my $status = http_status(HTTP_STATUS->{'unsupported_media_type'});
-       my $header = http_header_line('status', $status);
-       
-       return failpage(
-               $header,
-               $status,
-               "Unsupported Content-type: $content_type.",
-               $method
-       );
-}
-
-sub fail_open_file
-{
-       (my $method, my $type, my $path) = @_;
-       
-       my $status = http_status(HTTP_STATUS->{'not_found'});
-       my $header = http_header_line('status', $status);
-       
-       return failpage(
-               $header,
-               $status,
-                       "Can't open ".
-                       ($type ne '' ? $type : 'file').
-                       ($path ne '' ? ': "'.$path.'"' : '').
-                       '.',
-               $method
-       );
-}
-
-sub fail_attachment
-{
-       (my $method, my $ID) = @_;
-       
-       my $status = http_status(HTTP_STATUS->{'not_found'});
-       my $header = http_header_line('status', $status);
-
-       return failpage(
-               $header,
-               $status,
-               "Attachment $ID not found.",
-               $method
-       );
-}
-
-sub fail_500
-{
-       (my $method, my $text) = @_;
-       
-       my $status = http_status(HTTP_STATUS->{'internal_server_error'});
-       my $header = http_header_line('status', $status);
-       
-       return failpage(
-               $header,
-               $status,
-               $text,
-               $method
-       );
-}
-
-sub redirect
-{
-       (my $method, my $uri, my $code) = @_;
-       my $header;
-       my $status;
-       if ($code eq '') {
-               $code = HTTP_STATUS->{'found'};
-       }
-       # https://insanecoding.blogspot.com/2014/02/http-308-incompetence-expected.html
-       # 301 Moved Permanently
-       # 302 Found
-       # 303 See Other
-       # 307 Temporary Redirect
-       # 308 Permanent Redirect
-       $status = http_status($code);
-       $header = http_header_line('status', $status);
-       $header .= http_header_location($uri);
-       
-       return failpage(
-               $header,
-               $status,
-               '',
-               $method,
-               $uri
-       );
-}
-
-
-# function to obtain address of remote agent
-sub get_remote_addr {
-       if ($ENV{'HTTP_X_FORWARDED_FOR'} =~ /^.+$/) {
-               return $&;
-       }
-       elsif ($ENV{'REMOTE_ADDR'} =~ /^.+$/) {
-               return $&;
-       }
-       else {
-               return '0.0.0.0';
-       }
-}
-
-# functions to get ID/number etc.
-sub get_id {
-       (my $cgi, my $default, my $cgi_name) = @_;
-               if ($default eq '') {
-               $default = 0;
-       }
-       if ($cgi_name eq '') {
-               $cgi_name = 'i';
-       }
-       
-       if ($cgi->{$cgi_name} =~ /^.+$/) {
-               return int($&);
-       }
-       elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) {
-               return int($1);
-       }
-       else {
-               return int($default);
-       }
-}
-
-# function to obtain frame number
-sub get_frame {
-       (my $cgi, my $default) = @_;
-       return get_id($cgi, $default, 'f');
-}
-
-# function to obtain password
-sub get_password {
-       (my $cgi) = @_;
-       
-       if ($cgi->{'p'} =~ /^.+$/) {
-               return $&;
-       }
-       else {
-               return '';
-       }
-}
-
-
-sub merge_settings {
-               my %final_settings;
-       
-       foreach my $settings (@_) {
-               foreach my $ind (keys %$settings) {
-                       $final_settings{$ind} = $settings->{$ind};
-               }
-       }
-       return %final_settings;
-}
-
-
-# BB code stuff
-# different & simpler implementation than in post library
-# to consider:
-# a BBcode library?
-
-#analyse bbcode text to build tag tree
-#TODO make [/*] optional!
-sub bbtree {
-       (my $bb, my $printdebug) = @_;
-       my %bbtree;
-       my $ind;
-       my $tag;
-       my $tag_name;
-       my $tag_value;
-       my $tag_end;
-       my $level=0;
-       my $pre_text;
-       my $debug;
-       
-       $ind="_";
-       $level=0;
-       $bbtree{"_.name" }  = "ht";
-       $bbtree{"_.value" } = '';
-       $bbtree{"_.type"  } = "tag";
-       $bbtree{"_.count" } = 0;
-       $bbtree{"_.closed"} = 0;
-       $debug .= debug($printdebug,
-               "\n".
-               "<!--GENERATING BBCODE TREE:\n".
-               '[_]automatic tag: [ht]'."\n"
-       );
-       
-       while ($bb ne '') {
-               my $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
-               
-               if($bb =~ m/\[(\/?)([A-Za-z]+|\*)(=([^\[\]]*))?\]/g) {
-                       $pre_text = $`;
-                       $tag = $&;
-                       $tag_end = $1;
-                       $tag_name = lc($2);
-                       $tag_value = $4;
-                       $bb = $';
-                       if ($tag_value =~ /^"(.*)"$/) {
-                               $tag_value = $1;
-                       }
-                       
-                       if ($pre_text ne '') {
-                               $debug .= debug($printdebug, "[$new_ind]text: $pre_text\n");
-                               $bbtree{$new_ind.'.type' } = 'text';
-                               $bbtree{$new_ind.'.value'} = $pre_text;
-                               $bbtree{    $ind.'.count'}+= 1;
-                               $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
-                       }
-                       
-                       if($tag_name =~ /^(fq|tq|quote|br|ni|po|url|i|list|\*)$/) {
-                               if ($tag_end ne '') {
-                                       if (
-                                               ($tag_name ne $bbtree{$ind.'.name'}) ||
-                                               ($level <= 0)
-                                       ) {
-                                               $debug .= debug($printdebug, "[$new_ind]text: $tag\n");
-                                               $bbtree{$new_ind.'.type' } = 'text';
-                                               $bbtree{$new_ind.'.value'} = $tag;
-                                               $bbtree{    $ind.'.count'}+= 1;
-                                               # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
-                                       }
-                                       else {
-                                               $debug .= debug($printdebug, "[$new_ind]tag: $tag\n");
-                                               $bbtree{$new_ind.'.type'  } = 'tag';
-                                               $bbtree{$new_ind.'.name'  } = '/'.$tag_name;
-                                               $bbtree{$new_ind.'.value' } = $tag_value;
-                                               $bbtree{    $ind.'.count' }+= 1;
-                                               $bbtree{    $ind.'.closed'} = 1;
-                                               $level -= 1;
-                                               $ind =~ s/\.[0-9]+$//;
-                                               # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
-                                       }
-                               }
-                               else
-                               {
-                                       $debug .= debug($printdebug, "[$new_ind]tag: $tag\n");
-                                       $bbtree{$new_ind.'.type'  } = 'tag';
-                                       $bbtree{$new_ind.'.name'  } = $tag_name;
-                                       $bbtree{$new_ind.'.value' } = $tag_value;
-                                       $bbtree{$new_ind.'.count' } = 0;
-                                       $bbtree{$new_ind.'.closed'} = 0;
-                                       $bbtree{    $ind.'.count' }+= 1;
-                                       $level += 1;
-                                       $ind = $new_ind;
-                                       # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
-                               }
-                       }
-                       else {
-                               $debug .= debug($printdebug, "[$new_ind]text: $tag\n");
-                               $bbtree{$new_ind.'.type' } = 'text';
-                               $bbtree{$new_ind.'.value'} = $tag;
-                               $bbtree{    $ind.'.count'}+= 1;
-                               # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
-                       }
-               }
-               else {
-                       $debug .= debug($printdebug, "[$new_ind]text: $bb\n");
-                       $bbtree{$new_ind.'.type' } = 'text';
-                       $bbtree{$new_ind.'.value'} = $bb;
-                       $bbtree{    $ind.'.count'}+= 1;
-                       # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
-                       $bb = '';
-               }
-       }
-       my $final_ind = '_.'.$bbtree{"_.count"};
-       $debug .= debug($printdebug, "[$final_ind]automatic tag: [/ht]\n -->\n");
-       $bbtree{$final_ind.'.type' } = "tag";
-       $bbtree{$final_ind.'.name' } = '/ht';
-       $bbtree{         '_.count' }+= 1;
-       $bbtree{         '_.closed'} = 1;
-       
-       return ($debug, %bbtree);
-}
-
-#convert tag tree to final text
-sub convtree {
-       (my $printdebug, my $debug, my $lang, my $bbtree) = @_;
-       my $out;
-       my $ind;
-       my $indd;
-       my $level = 0;
-       my $tags = ($lang eq 'html') ? tags_html : tags_bbcode;
-       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 = '_';
-       $out = '';
-       $debug .= debug($printdebug, "\n<!--PROCESSING BBCODE TREE:\n");
-       
-       while ($level >= 0) {
-               my $goto_next = '';
-               $debug .= debug($printdebug, "[$level:$ind:".int($bbtree->{$ind.'.count'})."]");
-               #normal text
-               if ($bbtree->{$ind.'.type'} eq 'text') {
-                       my $text = $bbtree->{$ind.'.value'};
-                       $debug .= debug($printdebug, "text: ".$text);
-                       $out .= $escape ? html_encode_line($text) : $text;
-                       
-                       $goto_next = 'tx';
-               }
-               #tag
-               elsif ($bbtree->{$ind.'.type'} eq 'tag') {
-                       my $name = $bbtree->{$ind.'.name'};
-                       #endtag
-                       if ($name =~ /^\//) {
-                               $debug .= debug($printdebug, "tag: [$name]");
-                               $indd = $ind;
-                               $indd =~ s/\.([0-9]+)$//;
-                               if (exists($tags->{$name.'='}) && ($bbtree->{$indd.'.value'} ne '')) {
-                                       $out .= $tags->{$name.'='};
-                               }
-                               elsif (exists($tags->{$name})) {
-                                       $out .= $tags->{$name};
-                               }
-                               else {
-                                       $out .= $tags->{'/?'};
-                                       $debug .= debug($printdebug, "[unknown!]");
-                               }
-                               
-                               $ind =~ s/\.([0-9]+)$//;
-                               $level -= 1;
-                               $debug .= debug($printdebug, "[<]");
-                               if ($level > 0) {
-                                       $goto_next = 'nd';
-                               }
-                               else {
-                                       # time to end this
-                                       $level = -1;
-                               }
-                       }
-                       #starttag
-                       else {
-                               my $value = $bbtree->{$ind.'.value'};
-                               if($bbtree->{$ind.'.closed'} ne '') {
-                                       $debug .= debug($printdebug, "tag: [$name]");
-                                       
-                                       if (exists($tags->{$name.'='}) && ($value ne '')) {
-                                               if (exists($tags->{$name.'='.$value})) {
-                                                       $out .=
-                                                               $tags->{$name.'='} .
-                                                               $tags->{$name.'='.$value} .
-                                                               $tags->{$name.'/='};
-                                               }
-                                               else {
-                                                       $out .=
-                                                               $tags->{$name.'='} .
-                                                               ($escape ? html_entity_encode_dec($value, 1) : $value) .
-                                                               $tags->{$name.'/='};
-                                               }
-                                       }
-                                       elsif (exists($tags->{$name})) {
-                                               $out .= $tags->{$name};
-                                       }
-                                       else {
-                                               $out .= $out.$tags->{'?'};
-                                               $debug .= debug($printdebug, "[unknown!]");
-                                       }
-                               }
-                               else {
-                                       $debug .= debug($printdebug, "unclosed tag: [$name]");
-                                       my $text = $name . (($value ne '') ? ('='.$value) : '');
-                                       $out .= '['.($escape ? html_encode_line($text) : $text).']';
-                               }
-                               if ($bbtree->{$ind.'.count'} > 0) {
-                                       $ind = $ind.'.0';
-                                       $level += 1;
-                                       $debug .= debug($printdebug, "[>]");
-                               }
-                               else {
-                                       $goto_next = 'st';
-                               }
-                       }
-               }
-               # what is this
-               else {
-                       $debug .= debug($printdebug, "unknown thing: ".$bbtree->{$ind.'.type'});
-                       #should not occur with a correct bbtree
-                       #unless unimplemented
-                       $ind =~ s/\.([0-9]+)$//;
-                       $level -= 1;
-                       $debug .= debug($printdebug, "[<ui]");
-                       if ($level > 0) {
-                               $goto_next = 'un';
-                       }
-                       else {
-                               # time to end this
-                               $level = -1;
-                       }
-               }
-               if ($goto_next ne '') {
-                       {do{
-                               $ind =~ s/\.([0-9]+)$//;
-                               my $i = int($1) + 1;
-                               if (($i < $bbtree->{$ind.'.count'}) and ($1 ne '')){
-                                       # goto next
-                                       $ind = $ind.'.'.$i;
-                                       last;
-                               }
-                               else {
-                                       # step out
-                                       # should not occur with a correct bbtree
-                                       $debug .= debug($printdebug, "[<$goto_next]");
-                                       $level -= 1;
-                               }
-                       } while ($level >= 0);}
-               }
-               
-               $debug .= debug($printdebug, "[>$level:$ind]\n");
-       }
-       
-       $debug .= debug($printdebug, "-->\n");
-       return ($debug, $out);
-}
-
-#bbcode to html, TBD
-sub bb_to_html {
-       (my $bb, my $printdebug) = @_;
-       my $ht;
-       my %bbtree;
-       my $debug;
-       
-       ($debug, %bbtree) = bbtree($bb, $printdebug);
-       ($debug, $ht) = convtree ($printdebug, $debug, 'html', \%bbtree);
-       
-       return $ht;
-}
-
-#bbcode to bb, TBD
-sub bb_to_bbcode {
-       (my $bb, my $printdebug) = @_;
-       my $ht;
-       my %bbtree;
-       my $debug;
-       
-       ($debug, %bbtree) = bbtree($bb, $printdebug);
-       ($debug, $ht) = convtree ($printdebug, $debug, 'bb', \%bbtree);
-       
-       return $ht;
-}
-
-sub eval_bb {
-       (my $bb, my $full_url, my $password) = @_;
-       my $value;
-       my $before;
-       my $after;
-       
-       my $base_url = $full_url ?
-               {'scheme' => SCHEME(), 'host' => WEBSITE()} :
-               {'path' => ''};
-       
-       while ($bb =~ m/###([^#;]*);/g) {
-               $value = $1;
-               $before = $`;
-               $after = $';
-               
-               if ($value =~ /^att&([0-9]+)$/) {
-                       $value = merge_url(
-                               $base_url,
-                               {'path' => CGI_ATTACH_PATH()},
-                               {'path' => int($1)}
-                       )
-               }
-               elsif ($value =~ /^vw&([0-9]+)$/) {
-                       $value = merge_url(
-                               $base_url,
-                               {'path' => CGI_VIEWER_PATH()},
-                               {'path' => int($1)}
-                       )
-               }
-               elsif ($value =~ /^fr&([0-9]+)$/) {
-                       $value = merge_url(
-                               $base_url,
-                               {'path' => CGI_FRAME_PATH()},
-                               {'path' => int($1)}
-                       )
-               }
-               else {
-                       $value = '';
-               }
-               if (($value ne '') && ($password ne '')) {
-                       $value = merge_url(
-                               $value,
-                               {'query' => {'p' => $password}}
-                       );
-               }
-               $bb = $before . $value . $after;
-       }
-       return $bb;
-}
-
-
-sub html_encode_line {
-       (my $text, my $non_ascii, my $all) = @_;
-       my $html;
-       my $ind;
-       
-       $text =~ s/\r\n/\n/gs;
-       $text =~ s/\r/\n/gs;
-       
-       while ($text ne '') {
-               $ind = index($text, "\n");
-               if ($ind >= 0) {
-                       $html .= html_entity_encode_dec(substr($text, 0, $ind), $non_ascii, $all)."<br>\n";
-                       $text = substr($text, $ind+1);
-               }
-               else
-               {
-                       $html .= html_entity_encode_dec($text, 1);
-                       $text = '';
-               }
-       }
-       return $html;
-}
-
-sub debug {
-       (my $print, my $text) = @_;
-       
-       if ($print) {
-               print $text;
-       }
-       
-       return $text;
-}
-
-
-sub print_html_start {
-       (my $fh) = @_;
-       print $fh '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
-       print $fh '<html lang="en">'."\n";
-}
-
-sub print_html_end {
-       (my $fh) = @_;
-       print $fh '</html>'."\n";
-}
-
-sub print_html_head_start {
-       (my $fh) = @_;
-       print $fh ' <head>'."\n";
-       print $fh '  <meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
-       print $fh '  <link rel="icon" type="image/png" href="'.html_entity_encode_dec(FAVICON_PATH(),1).'">'."\n";
-       print $fh '  <link rel="stylesheet" href="'.html_entity_encode_dec(CGI_CSS_PATH(),1).'">'."\n";
-}
-
-sub print_html_head_end {
-       (my $fh) = @_;
-       print $fh ' </head>'."\n";
-}
-       
-sub print_html_body_start {
-       (my $fh) = @_;
-       print $fh ' <body>'."\n";
-       print $fh '  <a href="/"><img id="botmlogo" src="'.html_entity_encode_dec(CGI_LOGO_PATH(),1).'" alt="'.html_entity_encode_dec(WEBSITE(),1).'"></a>'."\n";
-       print $fh '  <div id="all">'."\n";
-}
-
-sub print_html_body_end {
-       (my $fh, my $hide_credits) = @_;
-       print $fh '  </div>'."\n";
-       unless ($hide_credits) {
-               print $fh '  <p>'."\n";
-               print $fh '   '.html_entity_encode_dec(STORY_CREDITS(),1).'<br>'."\n";
-               print $fh '   '.html_entity_encode_dec(INTF_CREDITS(),1).'<br>'."\n";
-               print $fh '   <a href="'.html_entity_encode_dec(SOURCE_URL(),1).'" class="cz">source code</a>'."\n";
-               print $fh '  </p>'."\n";
-       }
-       print $fh '  <a href="/" class="cz">'.html_entity_encode_dec(WEBSITE(),1).'</a>'."\n";
-       print $fh ' </body>'."\n";
-}
-
-sub print_html_data {
-       (my $fh, my $data) = @_;
-       
-       foreach my $key (keys %$data) {
-               unless ($key eq 'content') {
-                       my $val = $data->{$key};
-                       $val =~ s/(\r)?\n/\n /gs; # does the space make sense in HTML anyway?
-                       print $fh html_encode_line("$key: $val\n", 1);
-               }
-       }
-       print $fh html_encode_line("\n".$data->{'content'});
-}
-
-sub print_goto {
-       (
-               my $file,
-               my $state,
-               my $settings,
-               my $goto_list,
-               my $password_ok,
-       ) = @_;
-       
-       my $fh;
-       my $last_frame;
-       my $ong_state;
-       my $password_query;
-       
-       $last_frame = int($state->{'last'});
-       $ong_state  = int($state->{'state'});
-       $password_query = url_query_encode({'p', $settings->{'password'}});
-       
-       my $_title        = html_entity_encode_dec($settings->{'story'}, 1);
-       my $_website_name = html_entity_encode_dec(WEBSITE_NAME()    , 1);
-       my $_base_url     = html_entity_encode_dec(CGI_PATH()        , 1);
-       
-       if (ref($file)) {
-               $fh=$file;
-               unless (seek($fh, 0, 0)) {
-                       #don't actually fail here
-               }
-       }
-       else {
-               unless (open_encoded($fh, ">:encoding(UTF-8)", $file)) {
-                       return 0;
-               }
-       }
-       
-       print_html_start($fh);
-       print_html_head_start($fh);
-       
-       print $fh '  <title>GOTO &bull; '.$_title.' &bull; '.$_website_name.'</title>'."\n";
-
-       print_html_head_end($fh);
-       print_html_body_start($fh);
-       
-       print $fh '   <div id="inst" class="ins">'."\n";
-
-       print $fh '    <div id="title">'."\n";
-       print $fh '     <h1 id="titletext">'.$_title.'</h1>'."\n";
-       print $fh '    </div>'."\n";
-
-       print $fh '   </div>'."\n";
-       print $fh '   <div id="insb" class="ins">'."\n";
-
-       print $fh '    <div id="chat">'."\n";
-       
-       for (my $frame = 0; ; $frame += 1) {
-               unless (
-                       $password_ok || (
-                               ($frame <= $last_frame) &&
-                               ($ong_state >= STATE->{'waiting'})
-                       )
-               ) {
-                       last;
-               }
-               my $title;
-               my $ongtime;
-               my @time_tab;
-               my $time_text;
-               my $timer_color;
-               my $frame_text;
-               my $viewer_url;
-               
-               $ongtime = $goto_list->{'ongtime-'.$frame};
-               $title   = $goto_list->{'title-'  .$frame};
-               if (($ongtime eq '') && ($title eq '')) {
-                       my %frame_data = read_frame_data($frame);
-                       $ongtime = $frame_data{'ongtime'};
-                       $title   = $frame_data{'title'};
-                       unless (keys %frame_data) {
-                               last;
-                       }
-               }
-               
-               if ($ongtime ne '') {
-                       @time_tab = gmtime($ongtime);
-                       $time_text = sprintf(
-                               '%02d.%02d.%02d %02d:%02d',
-                               $time_tab[3],
-                               $time_tab[4]+1,
-                               $time_tab[5]%100,
-                               $time_tab[2],
-                               $time_tab[1]
-                       );
-               }
-               else {
-                       $time_text = (($frame <= $last_frame) && ($ong_state >= STATE->{'waiting'})) ?
-                               'EE.EE.EE EE:EE' : '--.--.-- --:--';
-               }
-               if ($title eq '') {
-                       $title = '_';
-               }
-               $timer_color = (($frame > $last_frame) || ($ong_state < STATE->{'waiting'})) ?
-                       'cz' : (
-                               (($frame == $last_frame) && ($ong_state < STATE->{'ready'})) ?
-                                       'ni' : 'br'
-                       );
-               $frame_text = sprintf('%03d',$frame);
-               $viewer_url = merge_url(
-                       {'path' => CGI_VIEWER_PATH()},
-                       {'path' => $frame}
-               ); # TODO: consider static here?
-               if ($password_ok) {
-                       $viewer_url = merge_url($viewer_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               }
-               
-               my $_viewer_url = html_entity_encode_dec($viewer_url, 1);
-               my $_title      = html_entity_encode_dec($title     , 1);
-               
-               print $fh '     <span class="'.$timer_color.'">'.$frame_text.'</span> '.$time_text.' <a href="'.$_viewer_url.'">'.$_title.'</a><br>'."\n";
-       }
-       print $fh '    </div>'."\n";
-
-       print $fh '    <div id="underlinks">'."\n";
-       print $fh '     <a href="'.$_base_url.'">BSTA</a>'."\n";
-       print $fh '    </div>'."\n";
-
-       print $fh '   </div>'."\n";
-
-       print_html_body_end($fh, $ong_state == STATE->{'inactive'});
-       print_html_end($fh);
-       
-       unless (ref($file)) {
-               close ($fh);
-       }
-       else {
-               truncate ($fh , tell($fh));
-       }
-       
-       return 1;
-}
-
-sub print_viewer_page {
-       (
-               my $file,
-               my $context,
-               my $state,
-               my $settings,
-               my $frame_data,
-               my $prev_frame_data,
-               my $next_frame_data,
-               my $words_data,
-       ) = @_;
-       my $fh;
-       
-       my $launch      = $context->{'launch'};
-       my $access      = $context->{'access'};
-       my $password_ok = $context->{'password_ok'};
-       my $static      = $context->{'static'};
-       
-       my $goto           = int($context->{'goto'});
-       my $frame          = int($context->{'frame'});
-       my $text_mode      = int($context->{'text_mode'});
-       my $timer_unlocked = int($context->{'timer_unlocked'});
-       my $timer          = int($context->{'timer'});
-       # my $words_page     = int($context->{'words_page'});
-       
-       my $prev_frame = $frame - 1;
-       my $next_frame = $frame + 1;
-       
-       my $story = $settings->{'story'};
-       my $title = $frame_data->{'title'};
-       my $command = ($frame_data->{'command'} ne '') ?
-               $frame_data->{'command'} :
-               $next_frame_data->{'title'};
-       
-       my $last_frame = int($state->{'last'});
-       my $ong_state  = int($state->{'state'});
-       
-       my $width  = int($frame_data->{'width'});
-       my $height = int($frame_data->{'height'});
-       my $frame_type = $frame_data->{'frametype'};
-       
-       my $timer_color_h = (($timer_unlocked >= 1) || ($ong_state >= STATE->{'ready'})) ? 'br' : 'ni';
-       my $timer_color_m = (($timer_unlocked >= 2) || ($ong_state >= STATE->{'ready'})) ? 'br' : 'ni';
-       my $timer_color_s = (($timer_unlocked >= 3) || ($ong_state >= STATE->{'ready'})) ? 'br' : 'ni';
-       
-       my $timer_h;
-       my $timer_m;
-       my $timer_s;
-       if (
-               ($timer > 0) ||
-               (($timer >= 0) && ($frame == 0))
-       ) {
-               $timer_s = sprintf('%02d', $timer % 60);
-               $timer_h = int($timer / 60);
-               $timer_m = sprintf('%02d', $timer_h % 60);
-               $timer_h = sprintf('%02d', $timer_h / 60);
-       }
-       elsif (($timer >= -15) && ($ong_state >= STATE->{'ready'})) {
-               $timer_h = '00';
-               $timer_m = '00';
-               $timer_s = 'NG';
-       }
-       else {
-               $timer_h = 'EE';
-               $timer_m = 'EE';
-               $timer_s = 'EE';
-       }
-       
-       my $words_posts = int($words_data->{'posts'});
-       my $words_link_text = 'Words'.(($words_posts > 0) ? "[$words_posts]" : '');
-       
-       my $prev_available = (($frame > 0) && $access);
-       my $next_available = ($launch || $password_ok || ($next_frame <= $last_frame));
-       my $prefetch_prev = (
-               $password_ok ||
-               ($prev_frame < $last_frame) || (  # avoid unseen trigger!
-                       ($prev_frame <= $last_frame) &&
-                       ($ong_state >= STATE->{'ready'})
-               )
-       );
-       my $prefetch_next  = (
-               $password_ok ||
-               ($next_frame < $last_frame) || (  # avoid unseen trigger!
-                       ($next_frame <= $last_frame) &&
-                       ($ong_state >= STATE->{'ready'})
-               )
-       );
-       my $show_timer = (
-               (
-                       $access && $launch
-               ) || (
-                       ($frame == $last_frame) && (
-                               ($ong_state == STATE->{'waiting'}) ||
-                               ($ong_state == STATE->{'ready'})
-                       )
-               )
-       );
-       my $show_command = (
-               $launch ||
-               $password_ok ||
-               (!$access) ||
-               ($frame < $last_frame) || (
-                       ($ong_state >= STATE->{'ready'}) &&
-                       $context->{'show_command'}
-               )
-       );
-       my $show_command_link = ($next_available || (!$access));
-       my $show_command_cursor = ((!$next_available) || ($command eq ''));
-       my $show_words = ($password_ok || ($access && !$launch));
-       
-       my $frame_indirect = !(
-               (!$access) || (
-                       ($frame <= $last_frame) &&
-                       ($ong_state > STATE->{'inactive'})
-               )
-       );
-       my $prevframe_indirect = !($prev_frame <= $last_frame);
-       my $nextframe_indirect = !($next_frame <= $last_frame);
-       
-       my $password_query;
-       
-       my $base_url   = CGI_PATH();
-       my $timer_url  = CGI_TIMER_PATH();
-       my $viewer_full_url = merge_url(
-               {'scheme' => SCHEME(), 'host' => WEBSITE()},
-               {'path' => CGI_VIEWER_PATH()},
-               {'path' => $frame}
-       );
-       my $viewer_url = merge_url(
-               {'path' => CGI_VIEWER_PATH()},
-               {'path' => $frame}
-       );
-       my $viewer_0_url = merge_url(
-               {'path' => CGI_VIEWER_PATH()},
-               {'path' => 0}
-       );
-       my $viewer_prev_url = merge_url(
-               {'path' => CGI_VIEWER_PATH()},
-               {'path' => $prev_frame}
-       );
-       my $viewer_next_url = merge_url(
-               {'path' => CGI_VIEWER_PATH()},
-               {'path' => $next_frame}
-       );
-       my $viewer_last_url = merge_url(
-               {'path' => CGI_VIEWER_PATH()},
-               {'path' => ($static ? -1 : $last_frame)}
-       );
-       my $goto_url = ($goto) ?
-               CGI_GOTO_PATH() :
-               merge_url(
-                       {'path' => $viewer_url},
-                       {
-                               'query' => {'g' => 1},
-                               'fragment' => 'goto'
-                       }
-               );
-       
-       unless ($password_ok) {
-               my $page_file;
-               $viewer_0_url = $base_url;
-               if ($prev_frame == 0) {
-                       $viewer_prev_url = $viewer_0_url;
-               }
-               else {
-                       $page_file = get_page_file($prev_frame, $prev_frame_data, $settings);
-                       if (_x_encoded('-f',
-                               join_path(PATH_SEPARATOR(), WWW_PATH() , $page_file)
-                       )) {
-                               $viewer_prev_url = merge_url(
-                                       {'path' => $base_url},
-                                       {'path' => $page_file}
-                               );
-                       }
-               }
-               if ($next_frame < $last_frame) {
-                       $page_file = get_page_file($next_frame, $next_frame_data, $settings);
-                       if (_x_encoded('-f',
-                               join_path(PATH_SEPARATOR(), WWW_PATH() , $page_file)
-                       )) {
-                               $viewer_next_url = merge_url(
-                                       {'path' => $base_url},
-                                       {'path' => $page_file}
-                               );
-                       }
-               }
-               if (
-                       $goto &&
-                       (_x_encoded('-f',WWW_GOTO_PATH()))
-               ) {
-                       $goto_url = CGI_LIST_PATH();
-               }
-       }
-       my $bbcode_url = ($text_mode == TEXT_MODE->{'bb'}) ?
-               merge_url(
-                       {'path' => CGI_BBCODE_PATH()},
-                       {'path' => $frame}
-               ) :
-               merge_url (
-                       $viewer_url,
-                       {
-                               'query'=>{
-                               'b' => TEXT_MODE->{'bb'}
-                               },
-                               'fragment'=>'insb'
-                       }
-               );
-       my $info_url = ($text_mode == TEXT_MODE->{'info'}) ?
-               merge_url(
-                       {'path' => CGI_INFO_PATH()},
-                       {'path' => $frame}
-               ) :
-               merge_url (
-                       $viewer_url,
-                       {
-                               'query'=>{
-                               'b' => TEXT_MODE->{'info'}
-                               },
-                               'fragment'=>'insb'
-                       }
-               );
-       my $words_url = merge_url (
-               $viewer_url,
-               {
-                       'query'=>{
-                       'b' => TEXT_MODE->{'words'}
-                       },
-                       'fragment'=>'insw'
-               }
-       );
-       my $frame_file;
-       my $frame_url;
-       my $frame_prev_url;
-       my $frame_next_url;
-       my $frame_normal_url;
-       my $frame_full_url;
-       $frame_file = get_frame_file($frame, $frame_data, $settings);
-       $frame_normal_url = merge_url(
-                       {'path' => CGI_PATH()},
-                       {'path' => $frame_file}
-               );
-       $frame_url = $frame_indirect ?
-               merge_url(
-                       {'path' => CGI_FRAME_PATH()},
-                       {'path' => $frame}
-               ) :
-               $frame_normal_url;
-       $frame_full_url = merge_url(
-               {'scheme' => SCHEME(), 'host' => WEBSITE()},
-               {'path' => $frame_normal_url}
-       );
-       if ($prevframe_indirect) {
-               $frame_prev_url = merge_url(
-                       {'path' => CGI_FRAME_PATH()},
-                       {'path' => $prev_frame}
-               );
-       }
-       else {
-               $frame_prev_url = merge_url(
-                       {'path' => CGI_PATH()},
-                       {'path' => get_frame_file($prev_frame, $prev_frame_data, $settings)}
-               );
-       }
-       if ($nextframe_indirect) {
-               $frame_next_url = merge_url(
-                       {'path' => CGI_FRAME_PATH()},
-                       {'path' => $next_frame}
-               );
-       }
-       else {
-               $frame_next_url = merge_url(
-                       {'path' => CGI_PATH()},
-                       {'path' => get_frame_file($next_frame, $next_frame_data, $settings)}
-               );
-       }
-       
-       if ($password_ok) {
-               $password_query = url_query_encode({'p', $settings->{'password'}});
-               $goto_url        = merge_url($goto_url       , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $info_url        = merge_url($info_url       , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $words_url       = merge_url($words_url      , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $bbcode_url      = merge_url($bbcode_url     , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $viewer_url      = merge_url($viewer_url     , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $viewer_0_url    = merge_url($viewer_0_url   , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $viewer_prev_url = merge_url($viewer_prev_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $viewer_next_url = merge_url($viewer_next_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $viewer_last_url = merge_url($viewer_last_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               if ($frame_indirect) {
-                       $frame_url     = merge_url($frame_url      , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               }
-               if ($prevframe_indirect) {
-                       $frame_prev_url= merge_url($frame_prev_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               }
-               if ($nextframe_indirect) {
-                       $frame_next_url= merge_url($frame_next_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               }
-       }
-       my $_password = $password_ok ? html_entity_encode_dec($settings->{'password'}, 1) : '';
-       my $_action_url      = html_entity_encode_dec(CGI_VIEWER_PATH(), 1);
-       my $_base_url        = html_entity_encode_dec($base_url        , 1);
-       my $_goto_url        = html_entity_encode_dec($goto_url        , 1);
-       my $_info_url        = html_entity_encode_dec($info_url        , 1);
-       my $_words_url       = html_entity_encode_dec($words_url       , 1);
-       my $_bbcode_url      = html_entity_encode_dec($bbcode_url      , 1);
-       my $_timer_url       = html_entity_encode_dec($timer_url       , 1);
-       my $_viewer_full_url = html_entity_encode_dec($viewer_full_url , 1);
-       my $_viewer_url      = html_entity_encode_dec($viewer_url      , 1);
-       my $_viewer_0_url    = html_entity_encode_dec($viewer_0_url    , 1);
-       my $_viewer_prev_url = html_entity_encode_dec($viewer_prev_url , 1);
-       my $_viewer_next_url = html_entity_encode_dec($viewer_next_url , 1);
-       my $_viewer_last_url = html_entity_encode_dec($viewer_last_url , 1);
-       my $_frame_url       = html_entity_encode_dec($frame_url       , 1);
-       my $_frame_prev_url  = html_entity_encode_dec($frame_prev_url  , 1);
-       my $_frame_next_url  = html_entity_encode_dec($frame_next_url  , 1);
-       my $_frame_full_url  = html_entity_encode_dec($frame_full_url  , 1);
-       
-       my $_story      = html_entity_encode_dec($story     , 1);
-       my $_title      = html_entity_encode_dec($title     , 1);
-       my $_command    = html_entity_encode_dec($command   , 1);
-       my $_frame_type = html_entity_encode_dec($frame_type, 1);
-       
-       my $_website_name = html_entity_encode_dec(WEBSITE_NAME(), 1);
-       
-       if ($text_mode == TEXT_MODE->{'info'}) {
-               if ($show_command) {
-                       $frame_data->{'command'} = $command;
-               }
-               if ($access) {
-                       $frame_data->{'frame'} = $frame_file;
-               }
-               if ($frame_data->{'page'} eq '') {
-                       unless (($access) && ($frame < $last_frame)) {
-                               $frame_data->{'page'} = '';
-                       }
-                       else {
-                               $frame_data->{'page'} = get_page_file($frame, $frame_data, $settings);
-                       }
-               }
-       }
-       
-       # everything determined, now start generating
-       
-       if (ref($file)) {
-               $fh=$file;
-               unless (seek($fh, 0, 0)) {
-                       #don't actually fail here
-               }
-       }
-       else {
-               unless (open_encoded($fh, ">:encoding(UTF-8)", $file)) {
-                       return 0;
-               }
-       }
-       
-       print_html_start($fh);
-       print_html_head_start($fh);
-       
-       print $fh '  <title>'.$_title;
-       if ($story ne $title) {
-               print $fh ' &bull; '.$_story;
-       }
-       print $fh ' &bull; '.$_website_name.'</title>'."\n";
-       print $fh '  <link rel="index" href="'.$_goto_url.'">'."\n";
-       print $fh '  <link rel="start" href="'.$_viewer_0_url.'">'."\n";
-       if ($prev_available) {
-               print $fh '  <link rel="prev" href="'.$_viewer_prev_url.'">'."\n";
-               if ($prefetch_prev) {
-                       print $fh '  <link rel="prefetch" href="'.$_viewer_prev_url.'">'."\n";
-                       print $fh '  <link rel="prefetch" href="'.$_frame_prev_url.'">'."\n";
-               }
-       }
-       if ($next_available) {
-               print $fh '  <link rel="next" href="'.$_viewer_next_url.'">'."\n";
-               if ($prefetch_next) {
-                       print $fh '  <link rel="prefetch" href="'.$_viewer_next_url.'">'."\n";
-                       print $fh '  <link rel="prefetch" href="'.$_frame_next_url.'">'."\n";
-               }
-       }
-       if ($show_timer) {
-               print $fh '  <script src="'.$_timer_url.'"></script>'."\n";
-       }
-       
-       print_html_head_end($fh);
-       print_html_body_start($fh);
-       
-       print $fh '   <div id="inst" class="ins">'."\n";
-       
-       print $fh '    <div id="title">'."\n";
-       print $fh '     <h1 id="titletext">'.$_title.'</h1>'."\n";
-       print $fh '    </div>'."\n";
-       
-       print $fh '   </div>'."\n";
-       print $fh '   <div id="framespace">'."\n";
-       
-       print $fh '    <img src="'.$_frame_url.'" id="frame" class="'.$_frame_type.'" alt="'.$frame.'" title="'.$_title.'" width="'.$width.'" height="'.$height.'">'."\n";
-       
-       print $fh '   </div>'."\n";
-       print $fh '   <div id="insb" class="ins">'."\n";
-       
-       if ($text_mode == TEXT_MODE->{'info'}) {
-               print $fh '    <div id="chat">'."\n";
-               
-               print_html_data($fh, $frame_data); 
-               
-               print $fh '    </div>'."\n";
-       }
-       elsif ($text_mode == TEXT_MODE->{'bb'}) {
-               print $fh '    <div id="chat">'."\n";
-               
-               print $fh '[quote][center][size=200]'.$_title.'[/size]<br>'."\n";
-               print $fh '[url='.$_viewer_full_url.'][img]'.$_frame_full_url.'[/img][/url][/center]<br>'."\n";
-               print $fh html_encode_line(
-                       bb_to_bbcode(
-                               eval_bb(
-                                       $frame_data->{'content'},
-                                       1
-                               )
-                       )
-               );
-               print $fh '[/quote]'."\n";
-               
-               print $fh '    </div>'."\n";
-       }
-       elsif ($frame_data->{'content'} ne '') {
-               print $fh '    <div id="undertext">'."\n";
-               print $fh bb_to_html(
-                       eval_bb(
-                               $frame_data->{'content'},
-                               0,
-                               $password_ok ? $settings->{'password'} : ''
-                       )
-               )."\n";
-               print $fh '    </div>'."\n";
-       }
-       
-       print $fh '    <div id="command">'."\n";
-       
-       if ($show_timer) {
-               print $fh '     <span id="timer">';
-               print $fh '[<span id="ongh" class="hv '.$timer_color_h.'">'.$timer_h.'</span>';
-               print $fh ':<span id="ongm" class="hv '.$timer_color_m.'">'.$timer_m.'</span>';
-               print $fh ':<span id="ongs" class="hv '.$timer_color_s.'">'.$timer_s.'</span>]';
-               print $fh '</span><br>'."\n";
-       }
-       print $fh '     &gt;';
-       if ($show_command_link) {
-               print $fh '<a href="'.($access ? $_viewer_next_url : $_viewer_last_url).'">';
-       }
-       if ($show_command) {
-               print $fh $_command;
-       }
-       if ($show_command_cursor) {
-               print $fh '<span class="inp">_</span>';
-       }
-       if ($show_command_link) {
-               print $fh '</a>';
-       }
-       print $fh "<br>\n";
-       print $fh "    </div>\n";
-       
-       print $fh '    <div id="underlinks">'."\n     ";
-       
-       unless (($frame == 0) && $static) {
-               print $fh '<a href="'.$_base_url.'">Once again</a> | ';
-       }
-       if ($prev_available) {
-               print $fh '<a href="'.$_viewer_prev_url.'">Before</a> | ';
-       }
-       unless ($frame == $last_frame) {
-               print $fh '<a href="'.$_viewer_last_url.'">Now</a> | ';
-       }
-       print $fh '<a href="'.$_goto_url.'">GOTO</a>'."\n";
-       print $fh '     <span style="float: right;">'."\n      ";
-       if (
-               ($text_mode == TEXT_MODE->{'normal'}) &&
-               (!$goto)
-       ){
-               if ($show_words) {
-                       print $fh '<a href="'.$_words_url.'">'.$words_link_text.'</a> | ';
-               }
-       }
-       else {
-               print $fh '<a href="'.$_viewer_url.'">Without</a> | ';
-       }
-       print $fh '<a href="'.$_info_url.'">Info</a> | ';
-       print $fh '<a href="'.$_bbcode_url.'">BB</a>';
-       print $fh "\n     </span>\n";
-       
-       print $fh "    </div>\n";
-       
-       if ($goto) {
-               print $fh '    <div class="underlinks" id="goto">'."\n";
-               print $fh '     <form class="goto" method="get" action="'.$_action_url.'">'."\n";
-               print $fh '      GO TO:'."\n";
-               print $fh '      <input class="intx" type="number" size="4" name="f"'.(
-                       ($goto > 1) ?
-                               ('value="'.$frame.'"') :
-                               ''
-                       ).'>'."\n";
-               print $fh '      <input class="inbt" type="submit" value="GO">'."\n";
-               if ($password_ok) {
-                       print $fh '      <input type="hidden" name="p" value="'.$_password.'">'."\n";
-               }
-               print $fh '      <input type="hidden" name="g" value="2">'."\n";
-               print $fh '     </form>'."\n";
-               print $fh "    </div>\n";
-       }
-       
-       print $fh "   </div>\n";
-       
-       if (($text_mode == TEXT_MODE->{'words'}) && $show_words) {
-               print_comments($fh, $context, $settings, $words_data);
-       }
-       
-       print_html_body_end($fh, $ong_state == STATE->{'inactive'});
-       print_html_end($fh);
-       
-       
-       unless (ref($file)) {
-               close ($fh);
-       }
-       else {
-               truncate ($fh , tell($fh));
-       }
-       
-       return 1;
-}
-
-sub print_comments {
-       (my $fh, my $context, my $settings, my $words_data) = @_;
-       
-       my $password_ok = $context->{'password_ok'};
-       my $frame = int($context->{'frame'});
-       my $page = int($context->{'words_page'});
-       my $post_count = int($words_data->{'posts'});
-       my $id_start = $page * COMMENT_PAGE_LENGTH();
-       my $id_stop = $id_start + COMMENT_PAGE_LENGTH();
-       my $older = ($page > 0) ? ($page-1) : '';
-       my $newer;
-       my $password_query;
-       if ($id_stop >= $post_count) {
-                       $id_stop = $post_count;
-       }
-       else {
-               $newer = $page+1;
-       }
-       my $links;
-       
-       my $words_url = merge_url(
-               {'path' => CGI_VIEWER_PATH()},
-               {
-                       'path' => $frame,
-                       'query' => {'b' => TEXT_MODE->{'words'}},
-               }
-       );
-       my $older_url = merge_url(
-               $words_url,
-               {
-                       'query' => {'i' => $page-1},
-                       'fragment' => 'insw',
-                       'append_query' => 1
-               }
-       );
-       my $newer_url = merge_url(
-               $words_url,
-               {
-                       'query' => {'i' => $page+1},
-                       'fragment' => 'insw',
-                       'append_query' => 1
-               }
-       );
-       
-       if ($password_ok) {
-               $password_query = url_query_encode({'p', $settings->{'password'}});
-               $older_url = merge_url($older_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-               $newer_url = merge_url($older_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       }
-       
-       my $_password = $password_ok ? html_entity_encode_dec($settings->{'password'}, 1) : '';
-       my $_post_url = html_entity_encode_dec(CGI_WORDS_PATH(), 1);
-       my $_older_url = html_entity_encode_dec($older_url, 1);
-       my $_newer_url = html_entity_encode_dec($newer_url, 1);
-       
-       if (($older ne '') || ($newer ne '')) {
-               $links .= '    <div class="underlinks">'."\n";
-               $links .= '     ';
-               if ($older ne '') {
-                       $links .= '<a href="'.$_older_url.'">Older</a>'
-               }
-               if (($older ne '') && ($newer ne '')) {
-                       $links .= ' | ';
-               }
-               if ($newer ne '') {
-                       $links .= '<a href="'.$_newer_url.'">Newer</a>';
-               }
-               $links .= "\n";
-               $links .= '    </div>'."\n";
-       }
-       
-       print $fh '   <div class="space"></div>'."\n";
-       print $fh '   <div id="insw" class="ins">'."\n";
-       
-       print $fh '    <div class="title" id="wordstitle">'."\n";
-       print $fh '     <h1 class="titletext" id="wordstitletext">Words</h1>'."\n";
-       print $fh '    </div>'."\n";
-       
-       if ($links ne '') {
-               print $fh $links;
-       }
-       
-       print $fh '    <div class="undertext" id="words">'."\n";
-       
-       if ($post_count > 0) {
-               for (my $i=$id_start; $i<$id_stop; ++$i) {
-                       my $ID = $words_data->{'content'}->[$i];
-                       my %post_data = read_words($ID);
-                       
-                       my $post_time = int($post_data{'posttime'});
-                       my $edit_time = int($post_data{'edittime'});
-                       
-                       my $post_time_text;
-                       my $edit_time_text;
-                       
-                       if ($post_time != 0) {
-                               my @time_tab = gmtime($post_time);
-                               $post_time_text = sprintf(
-                                       '%04d.%02d.%02d %02d:%02d:%02d UTC',
-                                       $time_tab[5]+1900,
-                                       $time_tab[4]+1,
-                                       $time_tab[3],
-                                       $time_tab[2],
-                                       $time_tab[1],
-                                       $time_tab[0]
-                               );
-                       }
-                       if (($edit_time !=0) && ($edit_time != $post_time)) {
-                               my @time_tab = gmtime($edit_time);
-                               $edit_time_text = sprintf(
-                                       '%04d.%02d.%02d %02d:%02d UTC',
-                                       $time_tab[5]+1900,
-                                       $time_tab[4]+1,
-                                       $time_tab[3],
-                                       $time_tab[2],
-                                       $time_tab[1]
-                               );
-                       }
-                       my $quote_url = merge_url(
-                               {'path' => CGI_WORDS_PATH()},
-                               {
-                                       'query' => {
-                                               'f' => $frame,
-                                               'quote' => $ID,
-                                               'p' => ($password_ok ? $settings->{'password'} : '')
-                                       }
-                               }
-                       );
-                       my $edit_url = merge_url(
-                               {'path' => CGI_WORDS_PATH()},
-                               {
-                                       'query' => {
-                                               'f' => $frame,
-                                               'edit' => $ID,
-                                               'key' => $post_data{'key'},
-                                               'username' => $post_data{'name'},
-                                               'p' => ($password_ok ? $settings->{'password'} : '')
-                                       }
-                               }
-                       );
-                       my $remove_url = merge_url(
-                               {'path' => CGI_WORDS_PATH()},
-                               {
-                                       'query' => {
-                                               'f' => $frame,
-                                               'remove' => $ID,
-                                               'key' => $post_data{'key'},
-                                               'username' => $post_data{'name'},
-                                               'p' => ($password_ok ? $settings->{'password'} : '')
-                                       }
-                               }
-                       );
-                       
-                       my $_ID         = html_entity_encode_dec($ID, 1);
-                       my $_name       = html_entity_encode_dec($post_data{'name'}, 1);
-                       my $_quote_url  = html_entity_encode_dec($quote_url, 1);
-                       my $_edit_url   = html_entity_encode_dec($edit_url, 1);
-                       my $_remove_url = html_entity_encode_dec($remove_url, 1);
-                       
-                       print $fh '     <div id="'.$_ID.'"class="opomba">'."\n";
-                       print $fh '      <div class="opomba_info">'."\n";
-                       print $fh '       <a href="#'.$_ID.'" class="bi hu">'.$i.': '.$_name;
-                       if ($post_time_text ne '') {
-                               print $fh ' &bull; '.$post_time_text;
-                       }
-                       if ($edit_time_text ne '') {
-                               print $fh ' &bull; '.$edit_time_text;
-                       }
-                       print $fh '</a>'."\n";
-                       print $fh '       <div class="pr">'."\n";
-                       print $fh '        <a href="'.$_quote_url.'" class="bi hu">quote</a> | <a href="'.$_edit_url.'" class="bi hu">edit</a> | <a href="'.$_remove_url.'" class="bi hu">remove</a>'."\n";
-                       print $fh '       </div>'."\n";
-                       print $fh '      </div>'."\n";
-                       print $fh '      <div class="opomba_text">'."\n";
-                 print $fh bb_to_html(
-                               eval_bb(
-                                       $post_data{'content'},
-                                       0,
-                                       $password_ok ? $settings->{'password'} : ''
-                               )
-                       )."\n";
-                       print $fh '      </div>'."\n";
-                       print $fh '     </div>'."\n";
-                       print $fh '     <br>'."\n";
-               }
-       }
-       
-       print $fh '     <form method="post" action="'.$_post_url.'">'."\n";
-       print $fh '      <b>Your words:</b>'."\n";
-       print $fh '      <textarea class="inta" name="words" rows="4"></textarea>'."\n";
-       print $fh '      <table cellpadding="0" cellspacing="0" border="0"><tr>'."\n";
-       print $fh '       <td><b>Your name: </b></td>'."\n";
-       print $fh '       <td><input class="intx" type="text" name="username" value=""></td>'."\n";
-       print $fh '       <td></td>'."\n";
-       print $fh '      </tr><tr>'."\n";
-       print $fh '       <td><b>Optional password: </b></td>'."\n";
-       print $fh '       <td><input class="intx" type="password" name="password" value=""></td>'."\n";
-       print $fh '       <td>(if you want to edit later)</td>'."\n";
-       print $fh '      </tr><tr>'."\n";
-       print $fh '       <td><b>Leave this empty: </b></td>'."\n";
-       print $fh '       <td><input class="intx" type="text" name="password2" value=""></td>'."\n";
-       print $fh '       <td>'."\n";
-       print $fh '        <input class="inbt" type="submit" name="post" value="Send">'."\n";
-       print $fh '        <input class="inbt" type="submit" name="preview" value="Preview">'."\n";
-       print $fh '       </td>'."\n";
-       print $fh '      </tr></table>'."\n";
-       print $fh '      <input type="hidden" name="f" value="'.$frame.'">'."\n";
-       if ($password_ok) {
-               print $fh '      <input type="hidden" name="p" value="'.$_password.'">'."\n";
-       }
-       print $fh '     </form>'."\n";
-       print $fh '    </div>'."\n";
-       
-       if ($links ne '') {
-               print $fh $links;
-       }
-       
-       print $fh '   </div>'."\n";
-}
-
-sub write_index {
-       (
-               my $state,
-               my $settings,
-               my $pass,
-               my $mode,
-               my $pause
-       ) = @_;
-       my $fh;
-       my $r = 1;
-       my $ong_state = int($state->{'state'});
-       
-       unless (open_encoded($fh, ">:encoding(UTF-8)", WWW_INDEX_PATH())) {
-               return 0;
-       }
-       
-       # normal running story
-       if ($ong_state > STATE->{'inactive'}) {
-               my %default        = read_default();
-               my %frame_data     = read_frame_data(0, \%default);
-               my %next_frame_data= read_frame_data(1, \%default);
-               my %words_data     = read_words_list(
-                       0, # frame ID
-                       1,  # header only
-               );
-               
-               $r = print_viewer_page(
-                       $fh,
-                       {
-                               'launch'         => 0,
-                               'frame'          => 0,
-                               'access'         => 1,
-                               'password_ok'    => 0,
-                               'timer_unlocked' => 3, # not relevant
-                               'timer'          => 0, # not relevant
-                               'static'         => 1,
-                               'show_command'   => 1,
-                               'text_mode'      => TEXT_MODE->{'normal'},
-                               'words_page'     => 0, # not relevant
-                               'goto'           => 0
-                       },
-                       $state,
-                       $settings,
-                       \%frame_data,
-                       \%default, # prev
-                       \%next_frame_data,
-                       \%words_data
-               );
-       }
-       # no conditions met, pretend a normal Apache2 index
-       elsif ($pass != 1) { 
-               my $index_of = CGI_PATH;
-               $index_of =~ s/\/$//g;
-               
-               my $_index_of     = html_entity_encode_dec($index_of  , 1);
-               my $_2words_date  = html_entity_encode_dec(INTF_DATE(), 1);
-               my $_coin_date    = html_entity_encode_dec(COIN_DATE(), 1);
-               my $_website      = html_entity_encode_dec(WEBSITE()  , 1);
-               
-               print_html_start ($fh);
-               print $fh ' <head>'."\n";
-               print $fh '  <meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
-               print $fh '  <title>Index of '.$_index_of.'</title>'."\n";
-               print $fh ' </head>'."\n";
-               print $fh ' <body>'."\n";
-               print $fh '  <h1>Index of '.$_index_of.'</h1>'."\n";
-               print $fh '  <table>'."\n";
-               print $fh '   <tr>'."\n";
-               print $fh '    <th><img src="/icons/blank.gif" alt="[ICO]"></th>'."\n";
-               print $fh '    <th><a href="?C=N;O=D">Name</a></th>'."\n";
-               print $fh '    <th><a href="?C=M;O=A">Last modified</a></th>'."\n";
-               print $fh '    <th><a href="?C=S;O=A">Size</a></th>'."\n";
-               print $fh '    <th><a href="?C=D;O=A">Description</a></th>'."\n";
-               print $fh '   </tr><tr>'."\n";
-               print $fh '    <th colspan="5"><hr></th>'."\n";
-               print $fh '   </tr><tr>'."\n";
-               print $fh '    <td valign="top"><img src="/icons/back.gif" alt="[DIR]"></td>'."\n";
-               print $fh '    <td><a href="/">Parent Directory</a></td>'."\n";
-               print $fh '    <td>&nbsp;</td>'."\n";
-               print $fh '    <td align="right">  - </td>'."\n";
-               print $fh '    <td>&nbsp;</td>'."\n";
-               print $fh '   </tr><tr>'."\n";
-               print $fh '    <td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td>'."\n";
-               print $fh '    <td><a href="2words/">2words/</a></td>'."\n";
-               print $fh '    <td align="right">'.$_2words_date.'  </td>'."\n";
-               print $fh '    <td align="right">  - </td><td>&nbsp;</td>'."\n";
-               print $fh '   </tr><tr>'."\n";
-               print $fh '    <td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td>'."\n";
-               print $fh '    <td><a href="coin/">coin/</a></td>'."\n";
-               print $fh '    <td align="right">'.$_coin_date.'  </td>'."\n";
-               print $fh '    <td align="right">  - </td><td> Coincidence </td>'."\n";
-               print $fh '   </tr><tr>'."\n";
-               print $fh '    <th colspan="5"><hr></th>'."\n";
-               print $fh '   </tr>'."\n";
-               print $fh '  </table>'."\n";
-               print $fh '  <address>Apache/2.2.22 (Debian) Server at '.$_website.' Port 80</address>'."\n";
-               print $fh '  </body>'."\n";
-               print_html_end ($fh);
-       }
-       # the launch index
-       else {
-               my %default        = read_default();
-               my %frame_data     = read_frame_data(0, \%default);
-               my %next_frame_data= read_frame_data(1, \%default);
-               my %coin_data      = read_coincidence();
-               
-               if (($mode == INTF_STATE->{'>'}) && $pause) {
-                       $r = print_viewer_page(
-                               $fh,
-                               {
-                                       'launch'         => 1,
-                                       'frame'          => 0,
-                                       'access'         => 1,
-                                       'password_ok'    => 0,
-                                       'timer_unlocked' => 3,
-                                       'timer'          => 0,
-                                       'static'         => 1,
-                                       'show_command'   => 1,
-                                       'text_mode'      => TEXT_MODE->{'normal'},
-                                       'words_page'     => 0, # not relevant
-                                       'goto'           => 0
-                               },
-                               $state,
-                               $settings,
-                               \%frame_data,
-                               \%default, # prev
-                               \%next_frame_data,
-                               {'posts' => 0} # words_data
-                       );
-                       return $r;
-               }
-               
-               my $index_of = CGI_PATH;
-               $index_of =~ s/\/$//g;
-               my $title;
-               my $frame_file;
-               my $undertext = '';
-               my $show_parent_dir = 0;
-               my $show_yb = 0;
-               my $show_folders = 0;
-               my $timer = '';
-               my $timer_color = 'ni';
-               if ($mode == INTF_STATE->{'>'}) {
-                       $title = $settings->{'story'}; # $frame_data{'title'} ?
-                       $frame_file = 'intf-tr.gif';
-                       $undertext = '...';
-                       $timer = '--';
-               }
-               elsif ($mode == INTF_STATE->{'<<'}) {
-                       $title = 'Index of';
-                       $frame_file = 'intf-ll.gif';
-                       $show_parent_dir = 1;
-                       $show_yb = 1;
-                       $timer = 'EE';
-                       $timer_color = 'br';
-               }
-               elsif ($mode == INTF_STATE->{'>>'}) {
-                       $title = 'Index of';
-                       $frame_file = 'intf-pp.gif';
-                       $show_parent_dir = 1;
-                       $show_yb = 1;
-                       $timer = 'EE';
-               }
-               else
-               {
-                       $title = 'Index of '.$index_of;
-                       $frame_file = 'intf-kw.gif';
-                       $show_parent_dir = 1;
-                       $show_folders = 1;
-               }
-               my $frame_url = merge_url(
-                       {'path' => CGI_PATH()},
-                       {'path' => $frame_file}
-               );
-               my $coin_server = $coin_data{'server'};
-               
-               my $_title        = html_entity_encode_dec($title           , 1);
-               my $_website_name = html_entity_encode_dec(WEBSITE_NAME()   , 1);
-               my $_frame_url    = html_entity_encode_dec($frame_url       , 1);
-               my $_undertext    = html_entity_encode_dec($undertext       , 1);
-               my $_2words_date  = html_entity_encode_dec(INTF_DATE()      , 1);
-               my $_coin_date    = html_entity_encode_dec(COIN_DATE()      , 1);
-               my $_coin_server  = html_entity_encode_dec($coin_server     , 1);
-               my $_2words_url   = html_entity_encode_dec(CGI_2WORDS_PATH(), 1);
-               my $_coin_url     = html_entity_encode_dec(CGI_COIN_PATH()  , 1);
-               
-               print_html_start($fh);
-               print_html_head_start($fh);
-               
-               print $fh '  <title>'.$_title.' &bull; '.$_website_name.'</title>'."\n";
-               
-               print_html_head_end($fh);
-               print_html_body_start($fh);
-               
-               print $fh '   <div id="inst" class="ins">'."\n";
-               
-               print $fh '    <div id="title">'."\n";
-               print $fh '     <h1 id="titletext">'.$_title.'</h1>'."\n";
-               print $fh '    </div>'."\n";
-               
-               print $fh '   </div>'."\n";
-               print $fh '   <div id="framespace">'."\n";
-               
-               print $fh '    <img src="'.$_frame_url.'" id="frame" alt="0">'."\n"; # title="'.$_title.'"
-               
-               print $fh '   </div>'."\n";
-               print $fh '   <div id="insb" class="ins">'."\n";
-               
-               print $fh '    <div id="undertext">'."\n";
-               
-               if ($show_parent_dir) {
-                       print $fh '     <img src="/icons/back.gif" alt="[DIR]"> <a href="..">Parent Directory</a><br>'."\n";
-               }
-               if ($show_folders) {
-                       print $fh '     <img src="/icons/folder.gif" alt="[DIR]"> <a href="'.$_2words_url.'">2words/</a> '.$_2words_date.' - <br>'."\n";
-                       print $fh '     <img src="/icons/folder.gif" alt="[DIR]"> <a href="'.$_coin_url.'">coin/</a> '.$_coin_date.' - '.$_coin_server."\n";
-               }
-               elsif ($show_yb) {
-                       print $fh '     <img src="/icons/folder.gif" alt="[DIR]"> <a href="'.$_2words_url.'">yyyyb/</a>'."\n";
-               }
-               if ($undertext ne '') {
-                       print $fh '     '.$_undertext."\n";
-               }
-               
-               print $fh '    </div>'."\n";
-               
-               if ($timer ne '') {
-                       print $fh '    <div id="command">'."\n";
-                       
-                       print $fh '     [<span id="ongh" class="'.$timer_color.'">'.$timer.'</span>';
-                       print $fh      ':<span id="ongm" class="'.$timer_color.'">'.$timer.'</span>';
-                       print $fh      ':<span id="ongs" class="'.$timer_color.'">'.$timer.'</span>]<br>'."\n";
-                       
-                       if ($undertext ne '') {
-                               print $fh '&gt;<a href="'.$_2words_url.'">'.$_undertext.'</a><span class="inp">_</span>'."\n";
-                       }
-                       print $fh "    </div>\n";
-               }
-               
-               print $fh "   </div>\n";
-               
-               print_html_body_end($fh, $ong_state == STATE->{'inactive'});
-               print_html_end($fh);
-       }
-       close ($fh);
-       return $r
-}
-
-sub write_static_viewer_page {
-       (
-               my $frame,
-               my $state_ref,
-               my $settings_ref,
-               my $default_ref,
-               my $frame_data_ref,
-               my $prev_frame_data_ref,
-               my $next_frame_data_ref,
-               my $words_data_ref
-       ) = @_;
-       
-       my %state;
-       my %settings;
-       my %default;
-       my %frame_data;
-       my %prev_frame_data;
-       my %next_frame_data;
-       my %words_data;
-       
-       my $file;
-       
-       $frame = int($frame);
-       my $prev_frame = $frame -1;
-       my $next_frame = $frame +1;
-       
-       %state = (ref ($state_ref)) ?
-               %$state_ref :
-               read_state();
-       my $ong_state = int($state{'state'});
-       my $last_frame = int($state{'last'});
-       
-       unless ($ong_state > STATE->{'inactive'}) {
-               return 0;
-       }
-       unless (
-               ($frame >= 0) && (
-                       ($frame < $last_frame) || (
-                               ($frame <= $last_frame) &&
-                               ($ong_state >= STATE->{'end'})
-                       )
-               )
-       ) {
-               return 0;
-       }
-       
-       %settings = (ref ($settings_ref)) ?
-               %$settings_ref :
-               read_settings();
-       %default = (ref ($default_ref)) ?
-               %$default_ref :
-               read_default();
-       
-       %frame_data = (ref ($frame_data_ref)) ?
-               %$frame_data_ref :
-               read_frame_data($frame);
-       
-       %prev_frame_data = (ref ($prev_frame_data_ref)) ?
-               %$prev_frame_data_ref : (
-                       ($prev_frame >= 0) ?
-                       read_frame_data($prev_frame) :
-                       %default
-               );
-               
-       %next_frame_data = (ref ($next_frame_data_ref)) ?
-               %$next_frame_data_ref :
-               read_frame_data($next_frame);
-       
-       %words_data = (ref ($words_data_ref)) ?
-               %$words_data_ref :
-               read_words_list(
-                       $frame, # frame ID
-                       1,  # header only
-               );
-       
-       %frame_data      = merge_settings(\%default, \%frame_data);
-       %prev_frame_data = merge_settings(\%default, \%prev_frame_data);
-       %next_frame_data = merge_settings(\%default, \%next_frame_data);
-       
-       $file = get_page_file($frame, \%frame_data, \%settings);
-       $file = join_path(PATH_SEPARATOR(), WWW_PATH(), $file);
-       
-       return print_viewer_page(
-               $file,
-               {
-                       'launch'        => 0,
-                       'frame'         => $frame,
-                       'access'        => 1,
-                       'password_ok'   => 0,
-                       'timer_unlocked'=> 3, # not relevant
-                       'timer'         => 0, # not relevant
-                       'static'        => 1,
-                       'show_command'  => 1,
-                       'text_mode'     => TEXT_MODE->{'normal'},
-                       'words_page'    => 0, # not relevant
-                       'goto'          => 0
-               },
-               \%state,
-               \%settings,
-               \%frame_data,
-               \%prev_frame_data,
-               \%next_frame_data,
-               \%words_data
-       );
-}
-
-sub write_static_goto {
-       (my $state_ref, my $settings_ref, my $goto_ref) = @_;
-       my %state;
-       my %settings;
-       my %goto_list;
-       
-       %state = (ref ($state_ref)) ?
-               %$state_ref :
-               read_state();
-       %settings = (ref ($settings_ref)) ?
-               %$settings_ref :
-               read_settings();
-       %goto_list = (ref ($goto_ref)) ?
-               %$goto_ref :
-               read_goto();
-       
-       return print_goto(
-               WWW_GOTO_PATH(),
-               \%state,
-               \%settings,
-               \%goto_list,
-               0, # password OK
-       );
-}
-
-# ONG the frame + attachment & stuff. NOT update state file.
-sub ong {
-       (
-               my $ID, my $ongtime, my $timer, my $update, my $print,
-               my $settings_ref, my $default_ref, my $data_ref, my $goto_ref
-       ) = @_;
-       my @files;
-       my $cfrt;
-       my $intf;
-       my $frame;
-       my $frame_data_path;
-       my $write_data;
-       my $in_path;
-       my $out_path;
-       my $r;
-       my %settings;
-       my %default;
-       my %frame_data;
-       my %frame_full_data;
-       my %goto_list;
-       
-       if ($ongtime eq '') {
-               $ongtime = time();
-       }
-       
-       if ($ID eq 'i') {
-               $intf = 1;
-       }
-       elsif ($ID eq 'c') {
-               $cfrt = 1;
-       }
-       else {
-               $frame = int($ID);
-       }
-       
-       if ($intf) {
-               @files = (
-                       'intf-00.gif',
-                       'intf-00_04.gif',
-                       'intf-00_08.gif',
-                       'intf-00_10.gif',
-                       'intf-01.gif',
-                       'intf-01_.gif',
-                       'intf-02.gif',
-                       'intf-02_.gif',
-                       'intf-04.gif',
-                       'intf-04_.gif',
-                       'intf-08.gif',
-                       'intf-08_.gif',
-                       'intf-10.gif',
-                       'intf-10_.gif',
-                       'intf-20.gif',
-                       'intf-20_.gif',
-                       'intf-kw.gif',
-                       'intf-ll.gif',
-                       'intf-pp.gif',
-                       'intf-tr.gif',
-               );
-       }
-       else {
-               %settings = (ref ($settings_ref)) ?
-                       %$settings_ref :
-                       read_settings();
-               %default = (ref ($default_ref)) ? %$default_ref : read_default();
-               $frame_data_path = $cfrt ?
-                       DATA_NOACCESS_PATH() :
-                       join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
-               %frame_data = (ref ($data_ref)) ?
-                       %$data_ref :
-                       read_frame_data($frame_data_path);
-               %frame_full_data = merge_settings(\%default, \%frame_data);
-               @files = (get_frame_file($frame, \%frame_full_data, \%settings), );
-               unless ($cfrt) {
-                       %goto_list = (ref ($goto_ref)) ?
-                               %$goto_ref :
-                               read_goto();
-                       for (my $i=0; ;$i+=1) {
-                               my %file_data = read_attachment($i);
-                               if ($file_data{'frame'} eq '') {
-                                       last;
-                               }
-                               if (int($file_data{'frame'}) != $frame) {
-                                       next;
-                               }
-                               if ($file_data{'content'} ne '') {
-                                       next;
-                               }
-                               unshift @files, $file_data{'filename'};
-                       }
-                       if (
-                               (!$update) ||
-                               ($frame_full_data{'ongtime'} eq '')
-                       ) {
-                               $frame_data     {'ongtime'} = $ongtime;
-                               $frame_full_data{'ongtime'} = $ongtime;
-                               $write_data = 1;
-                       }
-                       if (
-                               ($timer ne '') && (
-                                       (!$update) ||
-                                       ($frame_full_data{'timer'} eq '')
-                               )
-                       ) {
-                               $frame_data{'timer'} = int($timer);
-                               $write_data = 1;
-                       }
-                       if ($write_data) {
-                               $r = write_frame_data($frame_data_path, \%frame_data);
-                               unless ($r) {
-                                       print STDERR "fail writing $frame_data_path\n";
-                                       if ($print) {
-                                               print "write frame data fail\n";
-                                       }
-                                       return $r;
-                               }
-                       }
-                       $goto_list{'title-'  .$frame} = $frame_full_data{'title'};
-                       $goto_list{'ongtime-'.$frame} = $frame_full_data{'ongtime'};
-                       $r = write_goto('', \%goto_list);
-                       unless ($r) {
-                               print STDERR "fail writing ".DATA_LIST_PATH()."\n";
-                               if ($print) {
-                                       print "write GOTO list fail\n";
-                               }
-                               return $r;
-                       }
-               }
-       }
-       foreach my $file (@files) {
-               $in_path  = join_path(PATH_SEPARATOR(), DATA_PATH(), $file);
-               $out_path = join_path(PATH_SEPARATOR(), WWW_PATH() , $file);
-               if ($print) {
-                       print $in_path.' -> '.$out_path;
-               }
-               $r = copy_encoded($in_path, $out_path);
-               if ($print) {
-                       print (($r) ? " OK\n" : " FAIL\n");
-               }
-               unless ($r) {
-                       print STDERR "fail copy $in_path $out_path\n";
-                       return $r
-               }
-       }
-       
-       return 1;
-}
-
-
-sub get_frame_file {
-       (my $frame, my $frame_data, my $settings) = @_;
-       my $file;
-       my $pattern;
-       
-       if ($frame_data->{'frame'} ne '') {
-               $file = $frame_data->{'frame'};
-       }
-       else {
-               $pattern = validate_filename($settings->{'frame'}, '%d.%ext');
-               $file = sprintf(
-                       $pattern,
-                       int($frame), $frame_data->{'ext'}
-               );
-       }
-       return validate_filename($file);
-}
-
-sub get_page_file {
-       (my $frame, my $frame_data, my $settings) = @_;
-       my $file;
-       my $pattern;
-       
-       if ($frame == 0) {
-               return 'index.htm';
-       }
-       if ($frame_data->{'page'} ne '') {
-               $file = $frame_data->{'page'};
-       }
-       else {
-               $pattern = validate_filename($settings->{'frame'}, '%d.%ext');
-               $file = sprintf(
-                       $pattern,
-                       int($frame), 'htm'
-               );
-       }
-       return validate_filename($file);
-}
-
-sub validate_filename {
-       (my $filename, my $fallback) = @_;
-       if ($fallback eq '') {
-               $fallback = '';
-       }
-       
-       # TODO: more checks
-       
-       if ($filename =~ /^\./) {
-               return $fallback;
-       }
-       if (index($filename, PATH_SEPARATOR()) >= 0) {
-               return $fallback;
-       }
-       return $filename;
-}
-
-sub validate_frame_data {
-       (my $data_in) = @_;
-       my %data = %$data_in;
-       
-       if ($data{'ongtime'} ne '') {
-               $data{'ongtime'} = int($data{'ongtime'});
-       }
-       if ($data{'timer'} ne '') {
-               $data{'timer'} = int($data{'timer'});
-       }
-       if ($data{'width'} ne '') {
-               $data{'width'} = int($data{'width'});
-       }
-       if ($data{'height'} ne '') {
-               $data{'height'} = int($data{'height'});
-       }
-       if ($data{'page'} ne '') {
-               $data{'page'} = validate_filename($data{'page'});
-       }
-       if ($data{'frame'} ne '') {
-               $data{'frame'} = validate_filename($data{'frame'});
-       }
-       
-       return %data;
-}
-
-sub validate_settings {
-       (my $data_in) = @_;
-       my %data = %$data_in;
-       
-       if ($data{'ongtime'} ne '') {
-               $data{'ongtime'} = int($data{'ongtime'});
-       }
-       if ($data{'dynamicongtime'} ne '') {
-               $data{'dynamicongtime'} = int($data{'dynamicongtime'});
-       }
-       if ($data{'firstongtime'} ne '') {
-               $data{'firstongtime'} = int($data{'firstongtime'});
-       }
-       if ($data{'last'} ne '') {
-               $data{'last'} = int($data{'last'});
-       }
-       $data{'frame'} = validate_filename($data{'frame'}, '%d.%s');
-       
-       return %data;
-}
-
-sub validate_state {
-       (my $data_in) = @_;
-       my %data = %$data_in;
-       
-       if ($data{'state'} ne '') {
-               $data{'state'} = int($data{'state'});
-       }
-       if ($data{'last'} ne '') {
-               $data{'last'} = int($data{'last'});
-       }
-       if ($data{'nextong'} ne '') {
-               $data{'nextong'} = int($data{'nextong'});
-       }
-       
-       return %data;
-}
-
-sub validate_words_list {
-       (my $data_in, my $not_list) = @_;
-       my %data = %$data_in;
-       
-       if ($data{'ongtime'} ne '') {
-               $data{'ongtime'} = int($data{'ongtime'});
-       }
-       
-       if ($not_list) {
-               my $id_list = '';
-               foreach my $ID (split(/\r?\n/, $data{'content'})) {
-                       $ID = validate_filename($ID);
-                       if ($ID ne '') {
-                               $id_list .= $ID."\n";
-                       }
-               }
-               $data{'content'} = $id_list;
-       }
-       else {
-               my @id_list;
-               foreach my $ID (@{$data{'content'}}) {
-                       
-                       $ID = validate_filename($ID);
-                       if ($ID ne '') {
-                               push @id_list, $ID;
-                       }
-               }
-               $data{'content'} = [@id_list];
-       }
-       
-       return %data;
-}
-
-sub validate_words {
-       (my $data_in) = @_;
-       my %data = %$data_in;
-       
-       if ($data{'posttime'} ne '') {
-               $data{'posttime'} = int($data{'posttime'});
-       }
-       if ($data{'edittime'} ne '') {
-               $data{'edittime'} = int($data{'edittime'});
-       }
-       
-       return %data;
-}
-
-sub validate_story {
-       (my $data_in) = @_;
-       my %data = %$data_in;
-       
-       if ($data{'id'} ne '') {
-               $data{'id'} = int($data{'id'});
-       }
-       if ($data{'pass'} ne '') {
-               $data{'pass'} = int($data{'pass'});
-       }
-       if ($data{'state'} ne '') {
-               $data{'state'} = int($data{'state'});
-       }
-       
-       return %data;
-}
-
-sub validate_goto {
-       (my $data_in) = @_;
-       my %data = %$data_in;
-       
-       foreach my $key (keys %data) {
-               if ($key =~ /^ongtime-([0-9]+)$/) {
-                       my $new_key = 'ongtime-'.int($1);
-                       $data{$new_key} = int($data{$key});
-                       if ($new_key != $key) {
-                               delete $data{$key};
-                       }
-               }
-       }
-       
-       return %data;
-}
-
-sub validate_attachment {
-       (my $data_in) = @_;
-       my %data = %$data_in;
-       
-       if ($data{'frame'} ne '') {
-               $data{'frame'} = int($data{'frame'});
-       }
-       $data{'filename'} = validate_filename($data{'filename'});
-       
-       return %data;
-}
-
-sub validate_coincidence {
-       (my $data_in) = @_;
-       my %data = %$data_in;
-       
-       if ($data{'server'} ne '') {
-               $data{'server'} = int($data{'server'});
-       }
-       
-       return %data;
-}
-
-sub read_frame_data {
-       (my $f, my $default) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # frame ID
-               $file = join_path(PATH_SEPARATOR(), DATA_PATH(), int($&));
-       }
-       elsif ($f =~ /^(c(frt)?)|(noaccess)$/) { # CFRT (no access)
-               $file = DATA_NOACCESS_PATH();
-       }
-       elsif ($f =~ /^d(efault)?$/) { # default
-               $file = DATA_DEFAULT_PATH();
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_DEFAULT_PATH();
-       }
-       
-       %data = read_data_file($file);
-       if (ref ($default)) {
-               %data = merge_settings($default, \%data);
-       }
-       elsif ($default ne '') {
-               my %default_data = read_data_file(DATA_DEFAULT_PATH());
-               %data = merge_settings(\%default_data, \%data);
-       }
-       
-       return validate_frame_data(\%data);
-}
-
-sub write_frame_data {
-       (my $f, my $data) = @_;
-       my $file;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # frame ID
-               $file = join_path(PATH_SEPARATOR(), DATA_PATH(), int($&));
-       }
-       elsif ($f =~ /^(c(frt)?)|(noaccess)$/) { # CFRT (no access)
-               return 0; # forbidden
-       }
-       elsif ($f =~ /^d(efault)?$/) { # default
-               return 0; # forbidden
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               return 0; # forbidden
-       }
-       
-       my %_data = validate_frame_data($data);
-       
-       return write_data_file($file, \%_data);
-}
-
-sub read_default {
-       return read_frame_data('default');
-}
-
-sub read_noaccess {
-       (my $default) = @_;
-       return read_frame_data('noaccess', $default);
-}
-
-sub read_settings {
-       (my $f) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_SETTINGS_PATH();
-       }
-       
-       %data = read_data_file($file);
-       
-       return validate_settings(\%data);
-}
-
-sub read_state {
-       (my $f) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_STATE_PATH();
-       }
-       
-       %data = read_data_file($file);
-       
-       return validate_state(\%data);
-}
-
-sub write_state {
-       (my $f, my $data) = @_;
-       my $file;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = PERL_DATA_STATE_PATH();
-       }
-       
-       my %_data = validate_state($data);
-       
-       return write_data_file($file, \%_data);
-}
-
-sub read_words_list {
-       (my $f, my $header_only, my $not_list) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # frame ID
-               $file = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), int($&));
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else { # which frame ???
-               return ('posts' => 0);
-       }
-       
-       %data = read_data_file(
-               $file,
-               '', # encoding
-               0,  # no header
-               $header_only,
-               not $not_list # as list
-       );
-       
-       return validate_words_list(\%data, $not_list);
-}
-
-sub write_words_list {
-       (my $f, my $data) = @_;
-       my $file;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # frame ID
-               $file = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), int($&));
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else { # which frame ???
-               return 0;
-       }
-       
-       my %_data = validate_words_list($data);
-       
-       return write_data_file(
-               $file, # file 
-               \%_data,
-               '',  # encoding
-               0,   # no header
-               0,   # header only
-               1    # as list
-       );
-}
-
-sub read_words {
-       (my $f, my $default) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+\.[0-9\.]+$/) { # post ID
-               $file = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $&);
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else { # which post ???
-               return ();
-       }
-       
-       %data = read_data_file($file);
-       
-       return validate_words(\%data);
-}
-
-sub write_words {
-       (my $f, my $data) = @_;
-       my $file;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9\.]+$/) { # post ID
-               $file = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $&);
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else { # which post ???
-               return 0;
-       }
-       
-       my %_data = validate_words($data);
-       
-       return write_data_file($file, \%_data);
-}
-
-sub read_story {
-       (my $f) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # story ID
-               $file = DATA_STORY_PATH().int($&);
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_STORY_PATH();
-       }
-       
-       %data = read_data_file($file);
-       
-       return validate_story(\%data);
-}
-
-sub write_story {
-       (my $f, my $data) = @_;
-       my $file;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # story ID
-               $file = DATA_STORY_PATH().int($&);
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_STORY_PATH();
-       }
-       
-       my %_data = validate_story($data);
-       
-       return write_data_file($file, \%_data);
-}
-
-sub read_goto {
-       (my $f) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_LIST_PATH();
-       }
-       
-       %data = read_data_file($file);
-       
-       return validate_goto(\%data);
-}
-
-sub write_goto {
-       (my $f, my $data) = @_;
-       my $file;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_LIST_PATH();
-       }
-       
-       my %_data = validate_goto($data);
-       
-       return write_data_file($file, \%_data);
-}
-
-sub read_attachment {
-       (my $f, my $default) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # attachment ID
-               $file = DATA_ATTACH_PATH().int($&);
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               return ();
-       }
-       
-       %data = read_data_file($file);
-       
-       return validate_attachment(\%data);
-}
-
-sub read_coincidence {
-       (my $f) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_COIN_PATH();
-       }
-       
-       %data = read_data_file($file);
-       
-       return validate_coincidence(\%data);
-}
-
-sub read_chat {
-       (my $f) = @_;
-       my $file;
-       my %data;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # chat ID
-               $file = DATA_CHAT_PATH().int($&);
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_CHAT_PATH();
-       }
-       
-       return read_data_file($file);
-       
-       # no validation
-}
-
-sub write_chat {
-       (my $f, my $data) = @_;
-       my $file;
-       
-       if (ref ($f)) { # already open file
-               $file = $f;
-       }
-       elsif ($f =~ /^[0-9]+$/) { # chat ID
-               $file = DATA_CHAT_PATH().int($&);
-       }
-       elsif ($f ne '') { # path
-               $file = $f;
-       }
-       else {
-               $file = DATA_CHAT_PATH();
-       }
-       
-       # no validation
-       
-       return write_data_file($file, $data);
-}
-
-
-1
diff --git a/chat.1.pl b/chat.1.pl
deleted file mode 100644 (file)
index 90ea637..0000000
--- a/chat.1.pl
+++ /dev/null
@@ -1,507 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/coin
-# chat.pl is generated from chat.1.pl.
-#
-# The coincidence interface
-#
-# Copyright (C) 2016, 2017, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-###PERL_LIB: use lib /botm/lib/bsta
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'read_header_env',
-       'url_query_decode', 'url_query_encode',
-       'merge_url',
-       'html_entity_encode_dec',
-       'open_encoded',
-       'http_header_status'
-);
-use bsta_lib (
-       'STATE', 'CHAT_STATE', 'CHAT_ACTION',
-       'fail_method', 'fail_content_type',
-       'get_remote_addr', 'get_id', 'get_password',
-       'print_html_start', 'print_html_end',
-       'print_html_head_start', 'print_html_head_end',
-       'print_html_body_start', 'print_html_body_end',
-       'merge_settings',
-       'read_chat', 'write_chat',
-       'read_coincidence', 'read_settings', 'read_state'
-);
-use  File::Copy;
-
-###PERL_CGI_PATH:           CGI_PATH           = /bsta/
-###PERL_CGI_COIN_PATH:      CGI_COIN_PATH      = /bsta/coin
-
-###PERL_DATA_CHAT_PATH:     DATA_CHAT_PATH     = /botm/data/bsta/chat
-
-###PERL_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my %http;
-my %cgi;
-my %coin;
-my %chat;
-my %settings;
-my %state;
-
-my $time = time();
-srand ($time-$$);
-
-my $method;
-my $IP;
-my $page;
-my $words = '';
-my $username = '';
-my $action = CHAT_ACTION->{'none'};
-my $password;
-my $fh;
-my $state;
-my $password_ok;
-my @chat_lines;
-my $chat_state;
-my $status;
-my $message;
-my $chat_id;
-my $last_id;
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else {
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else{
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-
-$IP       = get_remote_addr();
-$page     = get_id(\%cgi, -1);
-$password = get_password(\%cgi);
-
-%coin      = read_coincidence();
-%settings  = read_settings();
-%state     = read_state();
-
-$password_ok = ($password eq $settings{'password'});
-
-if ($cgi{'words'} ne '') {
-       $words = $cgi{'words'};
-}
-if ($password_ok && ($cgi{'username'} ne '')) {
-       $username = $cgi{'username'};
-}
-foreach my $action_id ('join', 'leave', 'nopost', 'file') {
-       if ($cgi{$action_id} ne '') {
-               $action = CHAT_ACTION->{$action_id};
-               last;
-       }
-}
-
-# ongoing chat
-if ($page < 0) {
-       if (open_encoded($fh, "+<", DATA_CHAT_PATH())) {
-               if (flock($fh, 2)) {
-                       %chat = read_chat($fh);
-                       
-                       $chat_state = int($chat{'state'});
-                       $chat_id    = int($chat{'id'});
-                       $last_id    = $chat_id;
-                       
-                       if ($method ne 'POST') {
-                               #
-                       }
-                       
-                       elsif (
-                               ($action == CHAT_ACTION->{'none'}) &&
-                               ($words ne '')
-                       ) {
-                               if (($chat_state < CHAT_STATE->{'ready'}) && !$password_ok) {
-                                       $status = HTTP_STATUS->{'forbidden'};
-                                       $message = 'Not connected.';
-                               }
-                               else {
-                                       if ($words !~ /[\r\n]/) {
-                                               if ($username =~ /^[A-Za-z]*$/) {
-                                                       $chat{'content'} .= $username.': '.$words."\n";
-                                                       if ($chat_state < CHAT_STATE->{'active'}) {
-                                                               $chat_state = CHAT_STATE->{'active'};
-                                                               $chat{'state'} = $chat_state;
-                                                       }
-                                                       write_chat($fh, \%chat);
-                                               }
-                                               else {
-                                                       $status = HTTP_STATUS->{'bad_request'};
-                                                       $message = 'Invalid username.';
-                                               }
-                                       }
-                                       else {
-                                               $status = HTTP_STATUS->{'bad_request'};
-                                               $message = 'Invalid text.';
-                                       }
-                               }
-                       }
-                       
-                       elsif ($action == CHAT_ACTION->{'join'}) {
-                               if (($chat_state > CHAT_STATE->{'disconnected'}) && !$password_ok) {
-                                       $message = 'Already connected.';
-                               }
-                               else {
-                                       if ($username =~ /^[A-Za-z]*$/) {
-                                               if ($password_ok || $words eq $coin{'server'}) {
-                                                       $chat{'content'} .= 'join@'.$username.': '.$words."\n";
-                                                       if ($chat_state < CHAT_STATE->{'ready'}) {
-                                                               $chat_state = CHAT_STATE->{'ready'};
-                                                               $chat{'state'} = $chat_state;
-                                                       }
-                                                       write_chat($fh, \%chat);
-                                               }
-                                               elsif ($words eq '') {
-                                                       $status = HTTP_STATUS->{'bad_request'};
-                                                       $message = 'Server ID missing.';
-                                               }
-                                               elsif ($words !~ /^[0-9]+$/) {
-                                                       $status = HTTP_STATUS->{'bad_request'};
-                                                       $message = 'Invalid server ID.';
-                                               }
-                                               else {
-                                                       $status = HTTP_STATUS->{'not_found'};
-                                                       $message = 'No active Coincidence server with this ID.';
-                                               }
-                                       }
-                                       else {
-                                               $status = HTTP_STATUS->{'bad_request'};
-                                               $message = 'Invalid username.';
-                                       }
-                               }
-                       }
-                       
-                       elsif ($action == CHAT_ACTION->{'leave'}) {
-                               if (($chat_state < CHAT_STATE->{'ready'}) && !$password_ok) {
-                                       $message = 'Already disconnected.';
-                               }
-                               else {
-                                       if ($username =~ /^[A-Za-z]*$/) {
-                                               $chat{'content'} .= 'leave@'.$username.': '.$words."\n";
-                                               if ($username ne '') {
-                                                       write_chat($fh, \%chat);
-                                               }
-                                               else {
-                                                       my %new_chat;
-                                                       if ($chat_state > 1) {
-                                                               write_chat($chat_id, \%chat);
-                                                               $new_chat{'id'} = $chat_id+1;
-                                                       }
-                                                       else {
-                                                               $new_chat{'id'} = $chat_id;
-                                                       }
-                                                       $new_chat{'state'} = CHAT_STATE->{'disconnected'};
-                                                       $new_chat{'content'} = '';
-                                                       write_chat($fh, \%new_chat);
-                                               }
-                                       }
-                                       else {
-                                               $status = HTTP_STATUS->{'bad_request'};
-                                               $message = 'Invalid username.';
-                                       }
-                               }
-                       }
-                       
-                       elsif (
-                               ($action == CHAT_ACTION->{'file'}) &&
-                               ($cgi{'file'} ne '') &&
-                               ($words ne '') && 
-                               $password_ok
-                       ) {
-                               if ($words !~ /[\r\n]/) {
-                                       if ($username =~ /^[A-Za-z]*$/) {
-                                               $chat{'content'} .= 'file@'.$username.': '.$words."\n";
-                                               if ($chat_state < CHAT_STATE->{'active'}) {
-                                                       $chat_state = CHAT_STATE->{'active'};
-                                                       $chat{'state'} = $chat_state;
-                                               }
-                                               write_chat($fh, \%chat);
-                                       }
-                                       else {
-                                               $status = HTTP_STATUS->{'bad_request'};
-                                               $message = 'Invalid username.';
-                                       }
-                               }
-                               else {
-                                       $status = HTTP_STATUS->{'bad_request'};
-                                       $message = 'Invalid text.';
-                               }
-                       }
-                       
-                       @chat_lines = split(/\r?\n/, $chat{'content'});
-               }
-               else {
-                       $chat_state = CHAT_STATE->{'disconnected'};
-                       $status = HTTP_STATUS->{'internal_server_error'};
-                       $message = 'Can\'t lock data file!';
-               }
-               
-               close($fh);
-       }
-       else {
-               $chat_state = CHAT_STATE->{'disconnected'};
-               $status = HTTP_STATUS->{'internal_server_error'};
-               $message='Can\'t open data file!';
-       }
-}
-# old chat archive
-else {
-       $chat_id = $page;
-       %chat = read_chat();
-       $last_id = int($chat{'id'});
-       if ($chat_id < $last_id) {
-               %chat = read_chat($page);
-               $chat_state = int($chat{'state'});
-               @chat_lines = split(/\r?\n/, $chat{'content'});
-       }
-}
-
-if ($status ne '') {
-       print http_header_status($status);
-}
-print "Content-type: text/html; charset=UTF-8\n\n";
-if($method eq 'HEAD') {
-       exit;
-}
-
-if ($username eq '') {
-       $username = $coin{'name'};
-}
-
-my $base_url = CGI_PATH();
-my $coin_url = CGI_COIN_PATH();
-my $form_url = $coin_url;
-my $oldest_url = merge_url(
-       {'path' => $coin_url},
-       {'path' => 0}
-);
-my $older_url = merge_url(
-       {'path' => $coin_url},
-       {'path' => $chat_id -1}
-);
-my $newer_url = ($chat_id < ($last_id -1)) ?
-       merge_url(
-               {'path' => $coin_url},
-               {'path' => $chat_id +1}
-       ) : $coin_url;
-
-if ($password_ok) {
-       my $password_query = url_query_encode({'p', $settings{'password'}});
-       $coin_url   = merge_url($coin_url  , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $oldest_url = merge_url($oldest_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $older_url  = merge_url($older_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-       $newer_url  = merge_url($newer_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
-}
-
-my $_password = $password_ok ? html_entity_encode_dec($settings{'password'}, 1): '';
-my $abbr = abbr_name($username);
-my $_website_name = html_entity_encode_dec(WEBSITE_NAME() , 1);
-my $_server       = html_entity_encode_dec($coin    {'server'}  , 1);
-my $_key          = html_entity_encode_dec($coin    {'key'}     , 1);
-my $_cgi_username = html_entity_encode_dec($cgi     {'username'}, 1);
-my $_username     = html_entity_encode_dec($username  , 1);
-my $_abbr         = html_entity_encode_dec($abbr      , 1);
-my $_message      = html_entity_encode_dec($message   , 1);
-my $_base_url     = html_entity_encode_dec($base_url  , 1);
-my $_coin_url     = html_entity_encode_dec($coin_url  , 1);
-my $_form_url     = html_entity_encode_dec($form_url  , 1);
-my $_oldest_url   = html_entity_encode_dec($oldest_url, 1);
-my $_older_url    = html_entity_encode_dec($older_url , 1);
-my $_newer_url    = html_entity_encode_dec($newer_url , 1);
-
-print_html_start(\*STDOUT);
-print_html_head_start(\*STDOUT);
-
-print '  <title>Coincidence &bull; '.$_website_name.'</title>'."\n";
-
-print_html_head_end(\*STDOUT);
-print_html_body_start(\*STDOUT);
-
-print '   <div id="inst" class="ins">'."\n";
-
-print '    <div id="title">'."\n";
-print '     <H1 id="titletext">Coincidence</H1>'."\n";
-print '    </div>'."\n";
-
-print '    <div id="storypuzzle">'."\n";
-if ($page >= 0) {
-       print '     Before: '.$chat_id."\n";
-}
-elsif ($chat_state > CHAT_STATE->{'disconnected'}) {
-       print '     Connected to server <span class="br">'.$_server.'</span> as user <span class="ni">'.$_username.'</span> (<span class="ni">'.$_abbr.'</span>), public key <span class="br">'.$_key.'</span>.'."\n";
-}
-else{
-       print '     Not connected.'."\n";
-}
-print '    </div>'."\n";
-
-print '    <div id="command">'."\n";
-if ($message ne '') {
-       print '     <span class="br">'.$_message.'</span>'."\n";
-}
-if ($page < 0) {
-       print '     <form method="post" action="'.$_form_url.'">'."\n";
-       if ($password_ok) {
-               print '      <input class="intxc" type="text" name="words">'."\n";
-               print '      <input class="inbt" type="submit" value="Send">'."\n";
-               print "      |\n";
-               print '      <input class="intx" type="text" name="username" value="'.$_cgi_username.'">'."\n";
-               print '      <input class="inbt" type="submit" name="nopost" value="Refresh">'."\n";
-               print '      <input class="inbt" type="submit" name="join" value="Connect">'."\n";
-               print '      <input class="inbt" type="submit" name="leave" value="Disconnect">'."\n";
-               print '      <input class="inbt" type="submit" name="file" value="Send file">'."\n";
-               print '      <input type="hidden" name="p" value="'.$_password.'">'."\n";
-       }
-       elsif ($chat_state > CHAT_STATE->{'disconnected'}) {
-               print '      <input class="intxc" type="text" name="words">'."\n";
-               print '      <input class="inbt" type="submit" value="Send">'."\n";
-               print "      |\n";
-               print '      <input class="inbt" type="submit" name="nopost" value="Refresh">'."\n";
-               print '      <input class="inbt" type="submit" name="leave" value="Disconnect">'."\n";
-       }
-       else {
-               print '      <input class="intx" type="text" name="words">'."\n";
-               print '      <input class="inbt" type="submit" name="join" value="Connect">'."\n";
-       }
-       print '     </form>'."\n";
-}
-print '    </div>'."\n";
-
-print '   </div>'."\n";
-print '   <div id="insb" class="ins">'."\n";
-
-print '    <div id="chat">'."\n";
-if ($page < 0) {
-       for (my $i = @chat_lines-1; $i>=0; --$i) {
-               print '     '.chat_line($chat_lines[$i])."<br>\n";
-       }
-}
-else {
-       for (my $i = 0; $i<@chat_lines; ++$i) {
-               print '     '.chat_line($chat_lines[$i])."<br>\n";
-       }
-}
-print '    </div>'."\n";
-
-print '    <div id="underlinks">'."\n";
-print '     <a href="'.$_base_url.'">BSTA</a> | <a href="'.$_coin_url.'">Once again</a>';
-if ($chat_id > 0) {
-       print ' | <a href="'.$_older_url.'">Before</a>';
-}
-if ($chat_id < $last_id) {
-       print ' | <a href="'.$_newer_url.'">Unbefore</a>';
-}
-if ($chat_id > 0) {
-       print ' | <a href="'.$_oldest_url.'">Initially</a>';
-}
-print ' | (This interface is only a demo, a proof of concept. It is very limited. No autorefresh, no private chat, etc. For full functionality use the actual Coincidence client.)'."\n";
-print '    </div>'."\n";
-
-print '   </div>'."\n";
-
-print_html_body_end(\*STDOUT, int($state{'state'}) == STATE->{'inactive'});
-print_html_end(\*STDOUT);
-
-
-sub abbr_name {
-       (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 chat_line {
-       (my $line) = @_;
-       
-       if ($line =~ /^([a-z]*@)?([A-Za-z]*): (.*)$/) {
-               my $action = $1;
-               my $name = $2;
-               my $text = $3;
-               my $color;
-               if ($name eq '') {
-                       $name = $coin{'name'};
-                       $color = 'ni';
-               }
-               else {
-                       $color = 'br';
-               }
-               $abbr = abbr_name($name);
-               
-               my $_name   = html_entity_encode_dec($name          , 1);
-               my $_abbr   = html_entity_encode_dec($abbr          , 1);
-               my $_text   = html_entity_encode_dec($text          , 1);
-               my $_server = html_entity_encode_dec($coin{'server'}, 1);
-               
-               if($action ne '') {
-                       if ($action eq 'join@') {
-                               return "$_name ($_abbr) joined the public chat on server $_server.";
-                       }
-                       elsif ($action eq 'leave@') {
-                               return "$_name ($_abbr) left the public chat on server $_server.";
-                       }
-                       elsif ($action eq 'file@') {
-                               return "$_name ($_abbr)  sent the file $_text.";
-                       }
-                       else {
-                               return 'E:E:E';
-                       }
-               }
-               else {
-                       return "<span class=\"$color\">$_abbr: $_text</span>";
-               }
-       }
-       else {
-               return 'E:E:E';
-       }
-}
diff --git a/exec b/exec
deleted file mode 160000 (submodule)
index 92cf35c..0000000
--- a/exec
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 92cf35c0340afcadb39f06248de26e114ad5603c
diff --git a/frame.1.pl b/frame.1.pl
deleted file mode 100644 (file)
index a0a81fd..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/f
-# viewer.pl is generated from viewer.1.pl.
-#
-# The frame interface
-#
-# Copyright (C) 2016, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'read_header_env',
-       'url_query_decode',
-       'join_path',
-       'merge_url',
-       'open_encoded', 'stat_encoded',
-       'http_header_line', 'http_header_content_length', 'http_header_content_disposition'
-);
-use bsta_lib (
-       'STATE', 'INTF_STATE',
-       'fail_method', 'fail_content_type', 'fail_open_file', 'fail_500', 'redirect',
-       'get_frame', 'get_password',
-       'merge_settings',
-       'get_frame_file',
-       'read_frame_data', 'read_default', 'read_noaccess',
-       'read_settings', 'read_state', 'read_story'
-);
-
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_CGI_PATH:           CGI_PATH           = /bsta/
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta
-###PERL_WWW_PATH:           WWW_PATH           = /botm/www/1190/bsta/
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %http;
-my %cgi;
-my %frame_data;
-my %default;
-my %settings;
-my %state;
-
-my $method;
-my $frame;
-my $password;
-my $password_ok;
-my $IP;
-my $access;
-my $try_onged;
-my $frame_path;
-my $frame_file;
-my $fh;
-my $buffer;
-my $ong_state;
-my $last_frame;
-my $r = 0;
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else{
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else{
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-
-$frame    = get_frame(\%cgi);
-$password = get_password(\%cgi);
-
-%settings  = read_settings();
-%default   = read_default();
-%state     = read_state();
-
-$ong_state  = int($state{'state'});
-$last_frame = int($state{'last'});
-
-if ($frame < 0) {
-       $frame = $state{'last'} + $frame +1;
-}
-
-$password_ok = ($password eq $settings{'password'});
-
-$access = 0;
-if (
-               $password_ok || (
-                       ($ong_state >= STATE->{'waiting'}) &&
-                       ($frame <= $last_frame) &&
-                       ($frame >= 0)
-               )
-       ) {
-       $access = 1;
-}
-elsif (
-       ($ong_state == STATE->{'inactive'}) &&
-       ($frame == 0)
-) {
-       my %story = read_story();
-       if (
-               (int($story{'pass'}) == 1) &&
-               (int($story{'state'}) == INTF_STATE->{'>|'})
-       ) {
-               $access = 1;
-       }
-}
-
-$try_onged = (
-       (!$access) || (
-               ($frame <= $last_frame) &&
-               ($ong_state > STATE->{'inactive'})
-       )
-);
-
-if ($access) {
-       %frame_data = read_frame_data($frame, \%default);
-}
-else {
-       %frame_data = read_noaccess(\%default);
-}
-$frame_file = get_frame_file($frame, \%frame_data, \%settings);
-
-if ($try_onged) {
-       $frame_path = join_path(PATH_SEPARATOR(), WWW_PATH(), $frame_file);
-       $r = open_encoded($fh, '<' , $frame_path);
-       if ($r) {
-               close($r);
-               $frame_path = merge_url(
-                       {'path' => CGI_PATH()},
-                       {'path' => $frame_file}
-               );
-               exit redirect ($method, $frame_path, HTTP_STATUS->{'see_other'});
-       }
-}
-unless ($r) {
-       $frame_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame_file);
-       $r = open_encoded($fh, '<' , $frame_path);
-       unless ($r) {
-               exit fail_open_file($method, 'image file', $frame_file);
-       }
-}
-unless (binmode($fh)) {
-       close($fh);
-       exit fail_500("Can't switch file to binary mode.");
-}
-
-if (my @file_info = stat_encoded($frame_path)){
-       print http_header_content_length($file_info[7]);
-}
-if ($frame_data{'content-type'} ne '') {
-       print http_header_line('content-type', $frame_data{'content-type'});
-}
-if ($frame_file ne '') {
-       print http_header_content_disposition('inline', $frame_file);
-}
-unless (binmode STDOUT) {
-       close($fh);
-       exit fail_500("Can't switch output to binary mode.");
-}
-print "\n";
-
-if($method ne 'HEAD'){
-       while (read ($fh, $buffer, 1024)) {
-               print (STDOUT $buffer);
-       }
-}
-close($fh);
diff --git a/goto.1.pl b/goto.1.pl
deleted file mode 100644 (file)
index 37feb23..0000000
--- a/goto.1.pl
+++ /dev/null
@@ -1,123 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/g
-# goto is generated from goto.1.pl.
-#
-# The frame list
-#
-# Copyright (C) 2017, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'read_header_env',
-       'url_query_decode',
-       '_x_encoded'
-);
-use bsta_lib (
-       'STATE',
-       'fail_method', 'fail_content_type',
-       'redirect',
-       'get_password',
-       'print_goto',
-       'merge_settings',
-       'read_settings', 'read_state', 'read_goto'
-);
-
-###PERL_CGI_PATH:           CGI_PATH           = /bsta/
-###PERL_CGI_LIST_PATH:      CGI_LIST_PATH      = /bsta/goto.htm
-###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v
-
-###PERL_WWW_GOTO_PATH:      WWW_GOTO_PATH      = /botm/www/1190/bsta/goto.htm
-
-###PERL_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %http;
-my %cgi;
-my %settings;
-my %state;
-my %goto_list;
-
-my $method;
-my $password;
-my $password_ok;
-my $no_cgi;
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else{
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else{
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-
-$no_cgi = (scalar (keys %cgi) == 0);
-
-if ($no_cgi) {
-       if (_x_encoded('-f', WWW_GOTO_PATH())) {
-               exit redirect($method, CGI_LIST_PATH());
-       }
-}
-
-$password = get_password(\%cgi);
-
-%settings  = read_settings();
-%state     = read_state();
-%goto_list = read_goto();
-
-$password_ok = ($password eq $settings{'password'});
-
-print "Content-type: text/html; charset=UTF-8\n";
-print "\n";
-if($method eq 'HEAD') {
-       exit;
-}
-
-print_goto(
-       \*STDOUT,
-       \%state,
-       \%settings,
-       \%goto_list,
-       $password_ok
-);
diff --git a/info.1.pl b/info.1.pl
deleted file mode 100644 (file)
index 3778092..0000000
--- a/info.1.pl
+++ /dev/null
@@ -1,263 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/i
-# info.pl is generated from info.1.pl.
-#
-# The frame/story info interface
-#
-# Copyright (C) 2017, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'http_header_status',
-       'read_header_env',
-       'write_data_file',
-       'url_query_decode'
-);
-use bsta_lib (
-       'STATE',
-       'fail_method', 'fail_content_type',
-       'get_password',
-       'merge_settings',
-       'get_page_file', 'get_frame_file',
-       'read_frame_data', 'read_default', 'read_noaccess',
-       'read_settings', 'read_default', 'read_state',
-       'read_words_list', 'read_words', 'read_attachment'
-);
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %http;
-my %cgi;
-my %info_data;
-my %next_frame_data;
-my %default;
-my %settings;
-my %state;
-
-my $method;
-my $frame = '';
-my $attachment = '';
-my $words = '';
-my $password;
-my $password_ok;
-my $access;
-my $show_command;
-my $ongtime;
-my $timer;
-my $ong_state;
-my $last_frame;
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else{
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else{
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-
-if ($cgi{'f'} =~ /^.+$/) {
-       $frame = int($&);
-}
-elsif ($cgi{'a'} =~ /^.+$/) {
-       $attachment = int($&);
-}
-elsif ($cgi{'i'} =~ /^.+$/) {
-       $attachment = int($&);
-}
-elsif ($cgi{'w'} =~ /^.+$/) {
-       $words = $&;
-}
-elsif ($ENV{'PATH_INFO'} =~ /^\/a\/?(.+)$/) {
-       $attachment = int($1);
-}
-elsif ($ENV{'PATH_INFO'} =~ /^\/w\/?(.+)$/) {
-       $words = $1;
-}
-elsif ($ENV{'PATH_INFO'} =~ /^\/(f\/?)?(.+)$/) {
-       $frame = int($2);
-}
-
-$password = get_password(\%cgi);
-
-%settings   = read_settings();
-%default    = read_default();
-%state      = read_state(());
-
-$ong_state  = int($state{'state'});
-$last_frame = int($state{'last'});
-
-$password_ok = ($password eq $settings{'password'});
-
-# comment info, not frame
-if ($words ne '') {
-       if ($words =~ /^[0-9]+$/) {
-               %info_data = read_words_list(
-                       int($&), # id
-                       0, # header only
-                       1 # not as list
-               );
-               $frame = int($&);
-               if ($info_data{'posts'} eq '') {
-                       $info_data{'posts'} = 0;
-               }
-       }
-       elsif ($words =~ /^[0-9]+\.[0-9\.]+$/) {
-               %info_data = read_words($&);
-               $frame = ($info_data{'frame'} ne '') ? int($info_data{'frame'}) : -1;
-               unless ($password_ok) {
-                       delete($info_data{'password'});
-                       delete($info_data{'key'});
-               }
-       }
-}
-# attachment info, not frame
-elsif ($attachment ne '') {
-       %info_data = read_attachment($attachment);
-       $frame = ($info_data{'frame'} ne '') ? int($info_data{'frame'}) : -1;
-}
-# frame info
-elsif ($frame ne '') {
-       if ($frame < 0) {
-               $frame = $last_frame + $frame +1;
-       }
-       %info_data       = read_frame_data($frame, \%default);
-       %next_frame_data = read_frame_data($frame+1, \%default);
-       
-       $timer   = int($state{'nextong'}) - $time;
-       $ongtime = int($state{'ongtime'});
-       if($ongtime == 0) {
-               $ongtime = int($settings{'ongtime'})
-       }
-       $show_command = ($timer < ($ongtime * 3600 / 3));
-}
-# state info, not frame
-else {
-       unless ($password_ok) {
-               # just show if IP was saved, not its value
-               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; charset=UTF-8\n\n";
-       if ($method eq 'HEAD') {
-               exit;
-       }
-       write_data_file(
-               \*STDOUT, \%state, '',
-               0, 0, 0,
-               '>>', 1
-       );
-       
-       exit;
-}
-
-if (
-       $password_ok || (
-               ($ong_state >= STATE->{'waiting'}) &&
-               ($frame <= $last_frame) &&
-               ($frame >= 0)
-       )
-) {
-       $access = 1;
-       
-       if (
-               ($words eq '') &&
-               ($attachment eq '') &&
-               ($info_data{'command'} eq '') && (
-                       $password_ok ||
-                       ($frame < $last_frame) || (
-                               ($ong_state >= STATE->{'ready'}) &&
-                               $show_command
-                       )
-               )
-       ) {
-               $info_data{'command'} = $next_frame_data{'title'};
-       }
-}
-else {
-       $access = 0;
-       if (($attachment ne '') || ($words ne '')) {
-               %info_data = ();
-       }
-       else {
-               %info_data = read_noaccess(\%default);
-       }
-}
-if (
-       ($attachment eq '') &&
-       ($words eq '')
-) {
-       if ($info_data{'frame'} eq '') {
-               $info_data{'frame'} = get_frame_file($frame, \%info_data, \%settings)
-       }
-       if ($info_data{'page'} eq '') {
-               unless (($access) && ($frame < $last_frame)) {
-                       $info_data{'page'} = '';
-               }
-               else {
-                       $info_data{'page'} = get_page_file($frame, \%info_data, \%settings);
-               }
-       }
-}
-
-print "Content-type: text/plain; charset=UTF-8\n";
-if (!$access) {
-       print http_header_status(HTTP_STATUS->{'forbidden'});
-}
-print "\n";
-if($method eq 'HEAD') {
-       exit;
-}
-write_data_file(
-       \*STDOUT, \%info_data, '',
-       0, 0, 0,
-       '>>', 1
-);
index 22a4f9e83a5155c8d64041edd50946afa349383b..27f5a309816790c33c3de1baf71a33650c577f8d 100755 (executable)
@@ -1,8 +1,5 @@
 #!/bin/sh
 make clean
-make -B TARGET=bsta makefile
-make install
-make clean
-make -B TARGET=again makefile
+make -B TARGET=release makefile
 make install
 make clean
index 7007b12b9e72c8191b4e8608406fadf92c87e8b8..f702897eedbda526c72af70f4f85266b0bf617b6 100644 (file)
--- a/makefile
+++ b/makefile
@@ -23,26 +23,15 @@ TARGET = debug
 endif
 PERL = perl
 
-CC   =/usr/bin/gcc
-CF   =-g -Wall
-
 CHMOD=/usr/bin/chmod
 CP   =/usr/bin/cp
 MKDIR=/usr/bin/mkdir
 PERL =/usr/bin/perl
 RM   =/usr/bin/rm
-SUDO =/usr/bin/sudo
 
-BIN_PATH        = /botm/bin/test-bsta
-DATA_PATH       = /botm/data/test-bsta
-DATA_WORDS_PATH = /botm/data/test-bsta/words
-LIB_PATH        = /botm/lib/test-bsta
-LOG_PATH        = /botm/log/test-bsta
-TMP_PATH        = /botm/tmp/test-bsta
-WWW_PATH        = /botm/www/1190/bstatest
+BIN_PATH        = /botm/bin/test-oldlogs
+LIB_PATH        = /botm/lib/test-oldlogs
 
-CONF = /botm/etc/www/conf/1190/test-bsta.conf
-CRON = /etc/cron.d/test-bsta
 
 CONFIGFILE = settings-$(TARGET).txt settings.txt
 DEFAULT_CONFIGFILE = settings-$(DEFAULT_TARGET).txt settings.txt
@@ -52,107 +41,31 @@ CONFIGURE_CMD = $(PERL) ./configure.pl $(CONFIGFILE)
 
 # keep these 2 lists in the same order!:
 GENERATE_FROM=\
-2words.1.pl\
-attach.1.pl\
-bbcode.1.pl\
-bsta.1.conf\
-bsta.1.cron\
-bsta_lib.1.pm\
-chat.1.pl\
-frame.1.pl\
-goto.1.pl\
-info.1.pl\
-oldlogs.1.pl\
-opomba.1.pl\
-ong.1.pl\
-reset.1.pl\
-update.1.pl\
-viewer.1.pl
+oldlogs.1.pl
 
 TO_GENERATE=\
-2words.pl\
-attach.pl\
-bbcode.pl\
-bsta.conf\
-bsta.cron\
-bsta_lib.pm\
-chat.pl\
-frame.pl\
-goto.pl\
-info.pl\
-oldlogs.pl\
-opomba.pl\
-ong.pl\
-reset.pl\
-update.pl\
-viewer.pl
+oldlogs.pl
 
 DIR=\
 $(BIN_PATH)\
-$(DATA_PATH)\
-$(DATA_WORDS_PATH)\
-$(LIB_PATH)\
-$(LOG_PATH)\
-$(TMP_PATH)\
-$(WWW_PATH)
-
-HIDDEN_DIR=\
-$(DATA_PATH)\
-$(DATA_WORDS_PATH)\
-$(TMP_PATH)
-
-SETUID=\
-2words\
-bbcode\
-attach\
-chat\
-frame\
-goto\
-info\
-opomba\
-viewer
+$(LIB_PATH)
+
+# HIDDEN_DIR=
+
+# SETUID=
 
 EXEC=\
-2words.pl\
-attach.pl\
-bbcode.pl\
-chat.pl\
-frame.pl\
-goto.pl\
-info.pl\
-oldlogs.pl\
-opomba.pl\
-ong.pl\
-reset.pl\
-update.pl\
-viewer.pl
-
-PERL_WRAP_EXEC=\
-2words\
-attach\
-bbcode\
-chat\
-frame\
-goto\
-info\
-opomba\
-viewer
+oldlogs.pl
+
+# PERL_WRAP_EXEC=
 
 BIN=\
-$(EXEC)\
-$(PERL_WRAP_EXEC)
+$(EXEC)
 
 LIB=\
 botm-common/botm_common.pm\
-bsta_lib.pm
-
-WWW=\
-botmlogo.png\
-bsta.css\
-timer.js
-
 
-all: $(BIN) setuid exec
+all: $(BIN) exec
        
 
 makefile: makefile.1.mak $(CONFIGFILE) configure.pl
@@ -164,25 +77,15 @@ configure.pl: $(CONFIGFILE) config/configure.1.pl
 $(TO_GENERATE): $(GENERATE_FROM) $(CONFIGFILE) configure.pl
        $(CONFIGURE_CMD) --in $(GENERATE_FROM) --out $(TO_GENERATE)
 
-$(PERL_WRAP_EXEC): %: exec/exec.c exec/settings.txt configure.pl
-       $(PERL) configure.pl path=$(BIN_PATH) target=$*.pl io_path=$(LOG_PATH) stderr=$*-stderr.log exec/settings.txt --in exec/exec.c --out $*.c
-       $(CC) $(CF) -o $@ $*.c
-
 exec: $(EXEC)
        $(CHMOD) +x $(EXEC)
 
-wrap_exec: 
-       
-setuid: $(SETUID)
-       $(CHMOD) u+s,g+s $(SETUID)
-
-
 mktree:
        $(MKDIR) -p $(DIR)
-       $(CHMOD) g-r,g-w,g-x,o-r,o-w,o-x $(HIDDEN_DIR)
+#      $(CHMOD) g-r,g-w,g-x,o-r,o-w,o-x $(HIDDEN_DIR)
 
 ifdef BIN_PATH
-cp_bin: $(BIN) setuid exec | mktree
+cp_bin: $(BIN) exec | mktree
        $(RM) -f $(BIN_PATH)/*
        $(CP) -p $(BIN) $(BIN_PATH)
 endif
@@ -193,21 +96,13 @@ cp_lib: $(LIB) | mktree
        $(CP) -p $(LIB) $(LIB_PATH)
 endif
 
-cp_www:
-       $(CP) -p $(WWW) $(WWW_PATH)
-
-cp_conf: bsta.conf
-       $(CP) bsta.conf $(CONF)
-
-cp_cron: bsta.cron
-       $(SUDO) $(CP) bsta.cron $(CRON)
 
-install: all cp_bin cp_lib cp_www cp_conf cp_cron
+install: all cp_bin cp_lib
        
 
 clean:
-       $(RM) -f configure.pl $(TO_GENERATE) $(PERL_WRAP_EXEC) $(PERL_WRAP_EXEC:=.c)
+       $(RM) -f configure.pl $(TO_GENERATE)
        $(PERL) config/configure.1.pl $(DEFAULT_CONFIGFILE) < makefile.1.mak > makefile
 
-PHONY: all clean install setuid exec mktree cp_bin cp_lib cp_www cp_conf cp_cron
+PHONY: all clean install exec mktree cp_bin cp_lib
        
index 7ff6c93cd9b53950ddc0039688ef9217edf62633..496f8cf58cf3e94a99ec76764f8b52907b70f897 100644 (file)
@@ -23,26 +23,15 @@ TARGET = $(DEFAULT_TARGET) ###MAKE_TARGET:
 endif
 PERL = perl
 
-###MAKE_CC:    CC=gcc
-###MAKE_CF:    CF=-g -Wall
-
 ###MAKE_CHMOD: CHMOD = chmod
 ###MAKE_CP:    CP    = cp
 ###MAKE_MKDIR: MKDIR = mkdir
 ###MAKE_PERL:  PERL  = perl
 ###MAKE_RM:    RM    = rm
-###MAKE_SUDO:  SUDO  = sudo
 
 ###MAKE_BIN_PATH:        BIN_PATH        = /botm/bin/bsta
-###MAKE_DATA_PATH:       DATA_PATH       = /botm/data/bsta
-###MAKE_DATA_WORDS_PATH: DATA_WORDS_PATH = /botm/data/bsta/words
 ###MAKE_LIB_PATH:        LIB_PATH        = /botm/lib/bsta
-###MAKE_LOG_PATH:        LOG_PATH        = /botm/log/bsta
-###MAKE_TMP_PATH:        TMP_PATH        = /botm/tmp/bsta
-###MAKE_WWW_PATH:        WWW_PATH        = /botm/www/1190/bsta
 
-###MAKE_CONF: CONF = /botm/etc/www/conf/1190/bsta.conf
-###MAKE_CRON: CRON = /etc/cron.d/bsta
 
 CONFIGFILE = settings-$(TARGET).txt settings.txt
 DEFAULT_CONFIGFILE = settings-$(DEFAULT_TARGET).txt settings.txt
@@ -52,107 +41,31 @@ CONFIGURE_CMD = $(PERL) ./configure.pl $(CONFIGFILE)
 
 # keep these 2 lists in the same order!:
 GENERATE_FROM=\
-2words.1.pl\
-attach.1.pl\
-bbcode.1.pl\
-bsta.1.conf\
-bsta.1.cron\
-bsta_lib.1.pm\
-chat.1.pl\
-frame.1.pl\
-goto.1.pl\
-info.1.pl\
-oldlogs.1.pl\
-opomba.1.pl\
-ong.1.pl\
-reset.1.pl\
-update.1.pl\
-viewer.1.pl
+oldlogs.1.pl
 
 TO_GENERATE=\
-2words.pl\
-attach.pl\
-bbcode.pl\
-bsta.conf\
-bsta.cron\
-bsta_lib.pm\
-chat.pl\
-frame.pl\
-goto.pl\
-info.pl\
-oldlogs.pl\
-opomba.pl\
-ong.pl\
-reset.pl\
-update.pl\
-viewer.pl
+oldlogs.pl
 
 DIR=\
 $(BIN_PATH)\
-$(DATA_PATH)\
-$(DATA_WORDS_PATH)\
-$(LIB_PATH)\
-$(LOG_PATH)\
-$(TMP_PATH)\
-$(WWW_PATH)
-
-HIDDEN_DIR=\
-$(DATA_PATH)\
-$(DATA_WORDS_PATH)\
-$(TMP_PATH)
-
-SETUID=\
-2words\
-bbcode\
-attach\
-chat\
-frame\
-goto\
-info\
-opomba\
-viewer
+$(LIB_PATH)
+
+# HIDDEN_DIR=
+
+# SETUID=
 
 EXEC=\
-2words.pl\
-attach.pl\
-bbcode.pl\
-chat.pl\
-frame.pl\
-goto.pl\
-info.pl\
-oldlogs.pl\
-opomba.pl\
-ong.pl\
-reset.pl\
-update.pl\
-viewer.pl
-
-PERL_WRAP_EXEC=\
-2words\
-attach\
-bbcode\
-chat\
-frame\
-goto\
-info\
-opomba\
-viewer
+oldlogs.pl
+
+# PERL_WRAP_EXEC=
 
 BIN=\
-$(EXEC)\
-$(PERL_WRAP_EXEC)
+$(EXEC)
 
 LIB=\
 botm-common/botm_common.pm\
-bsta_lib.pm
-
-WWW=\
-botmlogo.png\
-bsta.css\
-timer.js
-
 
-all: $(BIN) setuid exec
+all: $(BIN) exec
        
 
 makefile: makefile.1.mak $(CONFIGFILE) configure.pl
@@ -164,25 +77,15 @@ configure.pl: $(CONFIGFILE) config/configure.1.pl
 $(TO_GENERATE): $(GENERATE_FROM) $(CONFIGFILE) configure.pl
        $(CONFIGURE_CMD) --in $(GENERATE_FROM) --out $(TO_GENERATE)
 
-$(PERL_WRAP_EXEC): %: exec/exec.c exec/settings.txt configure.pl
-       $(PERL) configure.pl path=$(BIN_PATH) target=$*.pl io_path=$(LOG_PATH) stderr=$*-stderr.log exec/settings.txt --in exec/exec.c --out $*.c
-       $(CC) $(CF) -o $@ $*.c
-
 exec: $(EXEC)
        $(CHMOD) +x $(EXEC)
 
-wrap_exec: 
-       
-setuid: $(SETUID)
-       $(CHMOD) u+s,g+s $(SETUID)
-
-
 mktree:
        $(MKDIR) -p $(DIR)
-       $(CHMOD) g-r,g-w,g-x,o-r,o-w,o-x $(HIDDEN_DIR)
+#      $(CHMOD) g-r,g-w,g-x,o-r,o-w,o-x $(HIDDEN_DIR)
 
 ifdef BIN_PATH
-cp_bin: $(BIN) setuid exec | mktree
+cp_bin: $(BIN) exec | mktree
        $(RM) -f $(BIN_PATH)/*
        $(CP) -p $(BIN) $(BIN_PATH)
 endif
@@ -193,21 +96,13 @@ cp_lib: $(LIB) | mktree
        $(CP) -p $(LIB) $(LIB_PATH)
 endif
 
-cp_www:
-       $(CP) -p $(WWW) $(WWW_PATH)
-
-cp_conf: bsta.conf
-       $(CP) bsta.conf $(CONF)
-
-cp_cron: bsta.cron
-       $(SUDO) $(CP) bsta.cron $(CRON)
 
-install: all cp_bin cp_lib cp_www cp_conf cp_cron
+install: all cp_bin cp_lib
        
 
 clean:
-       $(RM) -f configure.pl $(TO_GENERATE) $(PERL_WRAP_EXEC) $(PERL_WRAP_EXEC:=.c)
+       $(RM) -f configure.pl $(TO_GENERATE)
        $(PERL) config/configure.1.pl $(DEFAULT_CONFIGFILE) < makefile.1.mak > makefile
 
-PHONY: all clean install setuid exec mktree cp_bin cp_lib cp_www cp_conf cp_cron
+PHONY: all clean install exec mktree cp_bin cp_lib
        
index dbb44211990620cd92b3dbcef1448169997acd76..9a52809b80ebc13049dfe3d1349378c29e001d98 100644 (file)
@@ -33,13 +33,12 @@ use botm_common (
        'system_encoded',
        'opendir_encoded', 'readdir_decoded',
        '_x_encoded', 'stat_encoded',
-       'unlink_encoded', 'rename_encoded'
+       'unlink_encoded', 'rename_encoded', 'env_pwd_decoded'
 );
 
 ###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
 
 ###PERL_GZIP:              GZIP              = gzip
-###PERL_LOG_PATH:          LOG_PATH          = /botm/log/bsta/
 ###PERL_LOG_SIZE_LIMIT:    LOG_SIZE_LIMIT    = 65536
 ###PERL_LOGS_UNCOMPRESSED: LOGS_UNCOMPRESSED = 2
 ###PERL_LOGS_TOTAL:        LOGS_TOTAL        = 10
@@ -49,7 +48,7 @@ binmode STDOUT, ':encoding(UTF-8)';
 binmode STDERR, ':encoding(UTF-8)';
 decode_argv();
 
-my $log_path          = ($ARGV[0] ne ''        ) ? $ARGV[0]: LOG_PATH();
+my $log_path          = ($ARGV[0] ne ''        ) ? $ARGV[0]: env_pwd_decoded;
 my $log_size_limit    = ($ARGV[1] =~ /^[0-9]+$/) ? int($&) : LOG_SIZE_LIMIT();
 my $logs_total        = ($ARGV[2] =~ /^[0-9]+$/) ? int($&) : LOGS_TOTAL();
 my $logs_uncompressed = ($ARGV[3] =~ /^[0-9]+$/) ? int($&) : LOGS_UNCOMPRESSED();
diff --git a/ong.1.pl b/ong.1.pl
deleted file mode 100644 (file)
index df5eab0..0000000
--- a/ong.1.pl
+++ /dev/null
@@ -1,213 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# ong.pl is generated from ong.1.pl.
-#
-# The ONG bot
-#
-# Copyright (C) 2016, 2017, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'open_encoded',
-);
-use bsta_lib (
-       'STATE',
-       'ong',
-       'write_static_viewer_page', 'write_index', 'write_static_goto',
-       'read_default', 'read_frame_data', 'read_settings', 'read_goto',
-       'read_state', 'write_state'
-);
-
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %settings;
-my %state;
-my %new_state;
-# my %goto_list;
-my %default;
-my %frame_data;
-my %frame_1_data;
-my %frame_2_data;
-my %frame_3_data;
-
-my $fh;
-my $ongstate;
-my $frame;
-my $next_ong;
-my $ongtime;
-my $static_timer;
-my $timer;
-my $last;
-my $r = 0;
-
-$ongtime = int($time / 3600) * 3600; # check time as if it was last full hour!
-
-print $time.' - '.$ongtime."\n";
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-unless (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STATE_PATH())) {
-       print "NO STATEFILE\n\n";
-       exit;
-}
-unless (flock($fh, 2)) {
-       print "NO STATELOCK\n\n";
-       close ($fh);
-       exit;
-}
-%state = read_state($fh);
-$ongstate = int($state{'state'});
-print 'state: '.$ongstate."\n";
-unless ($ongstate > STATE->{'inactive'}) {
-       print "INACTIVE\n\n";
-       close ($fh);
-       exit;
-}
-$next_ong = int($state{'nextong'});
-print 'ongtime: '.$next_ong."\n";
-
-unless ($ongtime >= $next_ong) {
-       print "WAIT\n\n";
-       close ($fh);
-       exit;
-}
-
-%settings = read_settings();
-$static_timer = int($settings{'ongtime'});
-$timer        = int($settings{'dynamicongtime'});
-$last         = int($settings{'last'});
-$frame        = int($state   {'last'})+1;
-
-if (($timer > 0) && ($frame < $last)) {
-       $timer = int($timer / ($last - $frame));
-}
-else {
-       $timer=0;
-}
-
-if ($static_timer > $timer) {
-       $timer = $static_timer;
-}
-$next_ong = $ongtime + ($timer*3600);
-$state{'nextong'} = $next_ong;
-print 'next ongtime: '.$next_ong.' (+'.$timer.")\n";
-$state{'ongtime'}=$timer;
-
-if ($ongstate == STATE->{'ready'}) {
-       print 'next frame: '.$frame."\n";
-       
-       %default = read_default();
-       %frame_data = read_frame_data($frame);
-       # %goto_list = read_goto());
-       
-       %new_state = %state;
-       $new_state{'last'}   = $frame;
-       $new_state{'state'}  = 1;
-       $new_state{'ip1'}    = '';
-       $new_state{'ip2'}    = '';
-       $new_state{'ip3'}    = '';
-       $new_state{'ongtime'}= $timer;
-       
-       if ($frame >= 1) {
-               %frame_1_data = read_frame_data($frame-1);
-       }
-       if ($frame >= 2) {
-               %frame_2_data = read_frame_data($frame-2);
-       }
-       if ($frame >= 3) {
-               %frame_3_data = read_frame_data($frame-3);
-       }
-       
-       $r = ong (
-               $frame, # frame ID
-               $time,  # ONG time
-               $timer, # timer to next ONG
-               0,      # update
-               1,      # print
-               \%settings,
-               \%default,
-               \%frame_data,
-               '' # \%goto_list
-       );
-       if ($r && ($frame >= 2)) {
-               print 'static page '.($frame-1);
-               $r = write_static_viewer_page(
-                       $frame-1, # frame ID
-                       \%new_state,
-                       \%settings,
-                       \%default,
-                       \%frame_1_data, # frame data
-                       \%frame_2_data, # prev frame data
-                       \%frame_data,   # next frame data
-                       '' # words data
-               );
-               print (($r) ? " OK\n" : " FAIL\n");
-       }
-       if ($r && ($frame >= 3)) {
-               print 'static page '.($frame-2);
-               $r = write_static_viewer_page(
-                       $frame-2, # frame ID
-                       \%new_state,
-                       \%settings,
-                       \%default,
-                       \%frame_2_data, # frame data
-                       \%frame_3_data, # prev frame data
-                       \%frame_1_data, # next frame data
-                       '' # words data
-               );
-               print (($r) ? " OK\n" : " FAIL\n");
-       }
-       if ($r && ($frame <= 2)) {
-               print 'index';
-               $r = write_index(
-                       \%new_state,
-                       \%settings
-               );
-               print (($r) ? " OK\n" : " FAIL\n");
-       }
-       if ($r) {
-               print 'static GOTO';
-               $r = write_static_goto(
-                       \%new_state,
-                       \%settings,
-                       '' # \%goto_list
-               );
-               print (($r) ? " OK\n" : " FAIL\n");
-       }
-       if ($r) {
-               %state = %new_state;
-               print "ONG\n\n";
-       }
-       else {
-               print "NO ONG\n\n";
-       }
-}
-write_state($fh, \%state);
-close ($fh);
diff --git a/opomba.1.pl b/opomba.1.pl
deleted file mode 100644 (file)
index 639097a..0000000
+++ /dev/null
@@ -1,591 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/w
-# opomba is generated from opomba.1.pl.
-#
-# The comment posting interface
-#
-# Copyright (C) 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'read_header_env', 'url_query_decode',
-       'write_data_file',
-       'html_entity_encode_dec',
-       'open_encoded',
-       'join_path',
-       'merge_url',
-       'make_id',
-       'http_header_status'
-);
-use bsta_lib (
-       'TEXT_MODE', 'STATE',
-       'get_password',
-       'fail_method', 'fail_content_type',
-       'redirect',
-       'print_html_start', 'print_html_end',
-       'print_html_head_start', 'print_html_head_end',
-       'print_html_body_start', 'print_html_body_end',
-       'bb_to_html', 'eval_bb',
-       'merge_settings',
-       'write_index', 'write_static_viewer_page',
-       'read_settings', 'read_state',
-       'read_words', 'write_words',
-       'read_words_list', 'write_words_list'
-       
-);
-
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v
-###PERL_CGI_WORDS_PATH:     CGI_WORDS_PATH     = /bsta/w
-
-###PERL_DATA_WORDS_PATH:    DATA_WORDS_PATH    = /botm/data/bsta/words/
-
-###PERL_LOG_SPAM_PATH:      LOG_SPAM_PATH      = /botm/log/bsta/words_spam.log
-###PERL_LOG_WORDS_PATH:     LOG_WORDS_PATH     = /botm/log/bsta/words.log
-
-###PERL_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
-
-###PERL_COMMENT_PAGE_LENGTH:COMMENT_PAGE_LENGTH= 16
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %http;
-my %cgi;
-my %state;
-my %settings;
-my %words_data;
-my %post_data;
-my %last_post_data;
-
-my @post_list;
-
-my $method;
-my $frame;
-my $ID;
-my $last_ID;
-my $password;
-my $password_ok;
-my $access;
-my $edit = 0;
-my $remove = 0;
-my $post = 0;
-my $quote;
-my $words_data_path;
-my $index;
-my $page;
-my $ong_state;
-my $last_frame;
-my $fh;
-my $r;
-
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else {
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else {
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-
-if ($ENV{'PATH_INFO'} =~ /^\/([0-9]+)$/) {
-       $frame = int($1);
-}
-elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) {
-       $ID = $1;
-}
-if ($cgi{'f'} =~ /^.+$/) {
-       $frame = int($&);
-}
-if ($cgi{'i'} =~ /^.+$/) {
-       $ID = $&;
-}
-$password = get_password(\%cgi);
-
-%settings = read_settings();
-%state    = read_state();
-$ong_state = int($state{'state'});
-$last_frame = int($state{'last'});
-
-$password_ok = ($password eq $settings{'password'});
-
-if ($cgi{'post'} ne '') {
-       $post = 1;
-}
-elsif ($cgi{'edit'} ne '') {
-       $edit = 1;
-       if ($ID eq '') {
-               $ID = $cgi{'edit'};
-       }
-}
-elsif ($cgi{'remove'} ne '') {
-       $remove = 1;
-       if ($ID eq '') {
-               $ID = $cgi{'remove'};
-       }
-}
-else {
-       $edit = 1;
-       if ($cgi{'quote'} ne '') {
-               $quote = $cgi{'quote'};
-       }
-}
-
-if ($ID ne '') {
-       %post_data = read_words($ID);
-       if ($post_data{'frame'} ne '') {
-               $frame = int($post_data{'frame'});
-       }
-}
-
-unless ($frame ne '') {
-       exit output(0, HTTP_STATUS->{'bad_request'}, 'Frame ID not specified.');
-}
-$access = (
-       $password_ok || (
-               ($ong_state >= STATE->{'waiting'}) &&
-               ($frame <= $last_frame)
-       )
-);
-unless ($access) {
-       exit output(0, HTTP_STATUS->{'forbidden'}, 'Not allowed to post this here now');
-}
-
-$words_data_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $frame);
-
-unless (open_encoded($fh, "+<:encoding(UTF-8)", $words_data_path)) {
-       unless (open_encoded($fh, "+>:encoding(UTF-8)", $words_data_path)) {
-               exit output(0, '500 Internal Server Error', 'Failed opening data file.', 1);
-       }
-}
-unless (flock($fh, 2)) {
-       exit output(0, HTTP_STATUS->{'internal_server_error'}, 'Failed locking data file.', 1);
-}
-
-%words_data = read_words_list(
-       $fh, # file
-       0,   # header only
-);
-
-@post_list = @{$words_data{'content'}};
-
-for (my $i=0; $i< scalar(@post_list); $i +=1) {
-       if ($post_list[$i] eq $ID) {
-               $index = $i;
-               $page = int($index / COMMENT_PAGE_LENGTH());
-               last;
-       }
-}
-
-if ($remove || ($ID ne '')) {
-       unless ($index ne '') {
-               close($fh);
-               exit output(0, HTTP_STATUS->{'not_found'}, $remove ? 'Nothing to remove.' : 'No such message.');
-       }
-       unless ($cgi{'key'} eq $post_data{'key'}) {
-               close($fh);
-               exit output(0, HTTP_STATUS->{'bad_request'}, 'Invalid request.');
-       }
-}
-if ($remove) {
-       unless (($method eq 'POST') && ($cgi{'i'} ne '')) { # followed a link, not confirmed yet
-               close($fh);
-               exit output(0, '', '', 1);
-       }
-}
-else {
-       unless (($method eq 'POST') && $post) { # followed a link, not confirmed yet
-               close($fh);
-               exit output(0, '', '', 1);
-       }
-}
-if (!$remove) {
-       unless ($cgi{'words'} ne '') {
-               exit output(0, HTTP_STATUS->{'bad_request'}, 'Where are your words?', 1);
-       }
-}
-unless ($cgi{'username'} ne '') {
-       close($fh);
-       exit output(0, HTTP_STATUS->{'bad_request'}, 'Missing user name.', 1);
-}
-if ($remove || ($ID ne '')) {
-       unless ($cgi{'username'} eq $post_data{'name'}) {
-               close($fh);
-               exit output(0, HTTP_STATUS->{'forbidden'}, 'Wrong user name.', 1);
-       }
-}
-if ($remove || ($ID ne '')) {
-               unless ($cgi{'password'} ne '') {
-               close($fh);
-               exit output(0, HTTP_STATUS->{'bad_request'}, 'Missing password.', 1);
-       }
-       unless (
-               ($cgi{'password'} eq $post_data{'password'}) || (
-                       ($cgi{'password'} eq $settings{'password'}) &&
-                       $password_ok
-               )
-       ) {
-               close($fh);
-               exit output(0, HTTP_STATUS->{'forbidden'}, 'Wrong password.', 1);
-       }
-       if ($password_ok) {
-               $cgi{'password'} = $post_data{'password'};
-       }
-}
-unless ($cgi{'password2'} eq '') {
-       close($fh);
-       # no error code to confuse spambot :)
-       output(0, '', 'Please don\'t write anything in the place which should remain empty.', 1);
-       if (open_encoded($fh, ">>:encoding(UTF-8)", LOG_SPAM_PATH())) {
-               $cgi{'content'} = $cgi{'words'};
-               $cgi{'empty'} = $cgi{'password2'};
-               delete($cgi{'words'});
-               delete ($cgi{'password'});
-               delete ($cgi{'password2'});
-               print $fh "$time SPAM $ID\n";
-               write_data_file(
-                       $fh, \%cgi, '',
-                       0, 0, 0,
-                       '>>', 1
-               );
-               print $fh "\n\n";
-               close ($fh);
-       }
-       exit;
-}
-
-# all conditions fulfilled
-
-if ($remove) {
-       splice @post_list, $index, 1;
-       $words_data{'posts'} = scalar(@post_list);
-       $words_data{'content'} = \@post_list;
-       
-       $r = write_words_list($fh, \%words_data);
-       unless ($r) {
-               close($fh);
-               exit output(0, HTTP_STATUS->{'internal_server_error'}, 'Failed writing data file.');
-       }
-       
-       close ($fh);
-       
-       if (open_encoded($fh, ">>:encoding(UTF-8)", LOG_WORDS_PATH())) {
-               delete ($post_data{'password'});
-               print $fh "$time REMOVE $ID\n";
-               write_data_file(
-                       $fh, \%post_data, '',
-                       0, 0, 0,
-                       '>>', 1
-               );
-               print $fh "\n\n";
-               close ($fh);
-       }
-       
-       $ID = 'insw';
-       exit output(1);
-}
-
-if ($ID eq '') {
-       $ID = make_id($frame, 1);
-}
-if ($index eq '') {
-       $index = scalar(@post_list);
-       $page = int($index / COMMENT_PAGE_LENGTH());
-       if ($index > 0) {
-               $last_ID = $post_list[-1];
-               %last_post_data = read_words($last_ID);
-               if (
-                       ($cgi{'username'} eq $last_post_data{'name'   }) &&
-                       ($cgi{'words'   } eq $last_post_data{'content'})
-               ) { # duplicate post
-                       $index -= 1;
-                       $page = int($index / COMMENT_PAGE_LENGTH());
-                       $ID = $last_ID;
-                       close ($fh);
-                       exit output(1);
-               }
-       }
-       push @post_list, $ID;
-}
-$words_data{'posts'} = scalar(@post_list);
-$words_data{'content'} = \@post_list;
-
-$post_data{'frame'} = $frame;
-$post_data{'name'} = $cgi{'username'};
-$post_data{'password'} = $cgi{'password'};
-if ($post_data{'posttime'} eq '') {
-       $post_data{'posttime'} = $time;
-}
-else {
-       $post_data{'edittime'} = $time;
-}
-if ($post_data{'key'} eq '') {
-       my $new_key = '';
-       for (my $i=1; $i<16; $i+=1) {
-               $new_key .= sprintf('%02X', int(rand(0x100)));
-       }
-       $post_data{'key'} = $new_key;
-}
-$post_data{'content'} = $cgi{'words'};
-
-$r = write_words($ID, \%post_data);
-unless ($r) {
-       close($fh);
-       exit output(0, HTTP_STATUS->{'internal_server_error'}, 'Failed writing post file.', 1, 0);
-}
-
-$r = write_words_list($fh, \%words_data);
-unless ($r) {
-       close($fh);
-       exit output(0, HTTP_STATUS->{'internal_server_error'}, 'Failed writing data file.', 1, 0);
-}
-
-close($fh);
-
-if (($frame == 0) && ($ong_state > STATE->{'inactive'})) {
-       write_index(\%state, \%settings);
-}
-elsif ($frame >= 1) {
-       write_static_viewer_page(
-               $frame,
-               \%state,
-               \%settings,
-               '', # default
-               '', # frame data
-               '', # prev frame data
-               '', # next frame data
-               \%words_data
-       );
-}
-
-if (open_encoded($fh, ">>:encoding(UTF-8)", LOG_WORDS_PATH())) {
-       delete ($post_data{'password'});
-       print $fh "$time POST $ID\n";
-       write_data_file(
-               $fh, \%post_data, '',
-               0, 0, 0,
-               '>>', 1
-       );
-       print $fh "\n\n";
-       close ($fh);
-}
-
-exit output(1);
-
-
-sub output {
-       (my $done, my $status, my $message, my $show_content) = @_;
-       
-       my $return_url = merge_url(
-               {'path' => CGI_VIEWER_PATH()},
-               {
-                       'path' => $frame,
-                       'query' => {
-                               'b' => TEXT_MODE->{'words'},
-                               'i' => $page,
-                               'p' => ($password_ok ? $settings{'password'} : '')
-                       },
-                       'fragment' => $ID
-               }
-       );
-       if ($done) {
-               return redirect($method, $return_url, HTTP_STATUS->{'see_other'});
-       }
-       
-       if ($status ne '') {
-               print http_header_status($status);
-       }
-       print "Content-type: text/html; charset=UTF-8\n\n";
-       if ($method eq 'HEAD') {
-               return;
-       }
-       
-       my $title;
-       my $name;
-       my $content;
-       
-       if ($remove) {
-               $title = 'Remove message "'.$ID.'"';
-       }
-       elsif ($ID ne '') {
-               $title = 'Edit message "'.$ID.'"';
-       }
-       else {
-               $title = 'Words';
-       }
-       if ($frame ne '') {
-               $title = $frame.'. '.$title;
-       }
-       
-       if ($cgi{'username'} ne '') {
-               $name = $cgi{'username'}
-       }
-       elsif ($post_data{'name'} ne '') {
-               $name = $post_data{'name'}
-       }
-       else {
-               $name = '';
-       }
-       
-       if ($cgi{'words'} ne '') {
-               $content = $cgi{'words'};
-       }
-       elsif ($quote ne '') {
-               my %quote_data = read_words($quote);
-               $content = '[quote="'.$quote_data{'name'}.'"]'.$quote_data{'content'}.'[/quote]';
-       }
-       elsif (($cgi{'edit'} ne '') || $remove) {
-               $content = $post_data{'content'};
-       }
-       else {
-               $content = '';
-       }
-       
-       my $_password = $password_ok ? html_entity_encode_dec($settings{'password'}, 1) : '';
-       my $_key = html_entity_encode_dec($post_data{'key'}, 1);
-       my $_ID = html_entity_encode_dec($ID, 1);
-       my $_title = html_entity_encode_dec($title, 1);
-       my $_message = html_entity_encode_dec($message, 1);
-       my $_story = html_entity_encode_dec($settings{'story'}, 1);
-       my $_name = html_entity_encode_dec($name, 1);
-       my $_content = html_entity_encode_dec($content, 1);
-       my $_empty = html_entity_encode_dec($cgi{'password2'}, 1);
-       my $_website_name = html_entity_encode_dec(WEBSITE_NAME(), 1);
-       my $_post_url = html_entity_encode_dec(CGI_WORDS_PATH(), 1);
-       my $_return_url = html_entity_encode_dec($return_url, 1);
-               
-       print_html_start(\*STDOUT);
-       print_html_head_start(\*STDOUT);
-       
-       print '  <title>'.$_title.' &bull; '.$_story.' &bull; '.$_website_name.'</title>';
-       
-       print_html_head_end(\*STDOUT);
-       print_html_body_start(\*STDOUT);
-       
-       print '   <div id="inst" class="ins">'."\n";
-       
-       print '    <div id="title">'."\n";
-       print '     <h1 id="titletext">'.$_title.'</h1>'."\n";
-       print '    </div>'."\n";
-       
-       print '   </div>'."\n";
-       
-       if ($message ne '') {
-               print '   <div id="insb" class="ins">'."\n";
-               
-               print '    <div id="command">'."\n";
-               print '     <span class="br">'.$_message.'</span>'."\n";
-               print '    </div>'."\n";
-               
-               print '   </div>'."\n";
-       }
-       
-       print '   <div id="insw" class="ins">'."\n";
-       
-       if ($show_content) {
-               print '    <div class="undertext" id="words">'."\n";
-               print '     <form method="post" action="'.$_post_url.'">'."\n";
-               unless ($remove) {
-                       print '      <b>Your words:</b>'."\n";
-                       print '      <textarea class="inta" name="words" rows="4">'.$_content.'</textarea>'."\n";
-               }
-               print '      <table cellpadding="0" cellspacing="0" border="0"><tr>'."\n";
-               print '       <td><b>Your name: </b></td>'."\n";
-               print '       <td><input class="intx" type="text" name="username" value="'.$_name.'"></td>'."\n";
-               print '       <td></td>'."\n";
-               print '      </tr><tr>'."\n";
-               print '       <td><b>'.(($ID ne '') ? 'Password' : 'Optional password').': </b></td>'."\n";
-               print '       <td><input class="intx" type="password" name="password" value=""></td>'."\n";
-               print '       <td>'.(($ID ne '') ? '' : '(if you want to edit later)').'</td>'."\n";
-               print '      </tr><tr>'."\n";
-               print '       <td><b>Leave this empty: </b></td>'."\n";
-               print '       <td><input class="intx" type="text" name="password2" value="'.$_empty.'"></td>'."\n";
-               if ($remove) {
-                       print '       <td><input class="inbt" type="submit" name="remove" value="Remove"></td>'."\n";
-               }
-               else {
-                       print '       <td>'."\n";
-                       print '        <input class="inbt" type="submit" name="post" value="'.(($ID ne '') ? 'Update' : 'Send').'">'."\n";
-                       print '        <input class="inbt" type="submit" name="preview" value="Preview">'."\n";
-                       print '       </td>'."\n";
-               }
-               print '      </tr></table>'."\n";
-               print '      <input type="hidden" name="f" value="'.$frame.'">'."\n";
-               if ($ID ne '') {
-                       print '      <input type="hidden" name="i" value="'.$_ID.'">'."\n";
-               }
-               print '      <input type="hidden" name="key" value="'.$_key.'">'."\n";
-               if ($password_ok) {
-                       print '      <input type="hidden" name="p" value="'.$_password.'">'."\n";
-               }
-               print '     </form>'."\n";
-               if ($content ne ''){
-                       print '     <br>'."\n";
-                       print '     <div id="preview"class="opomba">'."\n";
-                       print '      <div class="opomba_info">'."\n";
-                       print '       Preview:'."\n";
-                       print '      </div>'."\n";
-                       print '      <div class="opomba_text">'."\n";
-                 print bb_to_html(
-                               eval_bb(
-                                       $content,
-                                       0,
-                                       $password_ok ? $settings{'password'} : ''
-                               )
-                       )."\n";
-                       print '      </div>'."\n";
-                       print '     </div>'."\n";
-               }
-               print '    </div>'."\n";
-       }
-       print '    <div id="underlinks">'."\n";
-       print '     <a href="'.$_return_url.'">Return</a>'."\n";
-       print '    </div>'."\n";
-       
-       print '   </div>'."\n";
-       
-       print_html_body_end(\*STDOUT, $ong_state == STATE->{'inactive'});
-       print_html_end(\*STDOUT);
-}
diff --git a/reset.1.pl b/reset.1.pl
deleted file mode 100644 (file)
index 9aa9541..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# reset is generated from reset.1.pl.
-#
-# Reset BSTA state
-#
-# Copyright (C) 2016, 2017, 2018, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'write_data_file',
-       'opendir_encoded', 'readdir_decoded', 'unlink_encoded',
-       'join_path'
-);
-use bsta_lib (
-       'STATE', 'INTF_STATE', 'CHAT_STATE',
-       'write_index',
-       'merge_settings',
-       'get_page_file', 'get_frame_file',
-       'read_settings', 'read_default', 'read_frame_data', 'read_attachment', 'read_state'
-);
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-decode_argv();
-
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_DATA_CHAT_PATH:     DATA_CHAT_PATH     = /botm/data/bsta/chat
-###PERL_DATA_DEFAULT_PATH:  DATA_DEFAULT_PATH  = /botm/data/bsta/default
-###PERL_DATA_LIST_PATH:     DATA_LIST_PATH     = /botm/data/bsta/list
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
-###PERL_DATA_STORY_PATH:    DATA_STORY_PATH    = /botm/data/bsta/story
-###PERL_DATA_WORDS_PATH:    DATA_WORDS_PATH    = /botm/data/bsta/words/
-
-###PERL_WWW_PATH:           WWW_PATH           = /botm/www/
-
-###PERL_RESET_PASSWORD:     RESET_PASSWORD     = ''
-
-my %story;
-my %state;
-my %chat;
-my %settings;
-my %goto_list;
-my %default;
-my $last_frame;
-my @remove_list;
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-%settings = read_settings();
-%state    = read_state();
-unless (
-       ($ARGV[0] ne '') && (
-               ($ARGV[0] eq $settings{'password'}) ||
-               ($ARGV[0] eq RESET_PASSWORD())
-       )
-) {
-       print STDERR "Wrong password; no reset.\n";
-       exit 1;
-}
-
-$last_frame = (int($settings{'last'}) > int($state{'last'})) ? 
-       int($settings{'last'}) : int($state{'last'});
-%default = read_default();
-
-for (my $frame=0; $frame<=$last_frame; $frame+=1) {
-       my %frame_data = read_frame_data($frame, \%default);
-       unless ($frame == 0) {
-               push @remove_list, get_page_file($frame, \%frame_data, \%settings);
-       }
-       push @remove_list, get_frame_file($frame, \%frame_data, \%settings);
-}
-push @remove_list, 'goto.htm';
-for (my $i=0; ;$i+=1) {
-       my %file_data;
-       
-       %file_data = read_attachment($i);
-       if ($file_data{'frame'} eq '') {
-               last;
-       }
-       if ($file_data{'content'} ne '') {
-               next;
-       }
-       push @remove_list, $file_data{'filename'};
-}
-
-%state = (
-       'state' => STATE->{'inactive'},
-       'last'  => 0,
-       'ongtime' => '',
-       'nextong' => '',
-       'ip1' => '',
-       'ip2' => '',
-       'ip3' => ''
-);
-%story = (
-       'id'      => 0,
-       'letter'  => '',
-       'lastip'  => '0.0.0.0',
-       'content' => '',
-       'pass'    => 0,
-       'state'   => INTF_STATE->{'X'}
-);
-%chat = (
-       'id'      => 0,
-       'state'   => CHAT_STATE->{'disconnected'},
-       'content' => ''
-);
-%goto_list = (
-);
-
-write_data_file(DATA_STATE_PATH(), \%state);
-write_data_file(DATA_STORY_PATH(), \%story);
-write_data_file(DATA_CHAT_PATH() , \%chat);
-write_data_file(DATA_LIST_PATH() , \%goto_list);
-
-write_index(
-       \%state,
-       \%settings,
-       $story{'pass'},
-       $story{'state'},
-       0 # pause
-);
-
-if (opendir_encoded(my $dir, DATA_WORDS_PATH())) {
-       while (defined (my $file_name = readdir_decoded($dir))) {
-               if ($file_name !~ /^[0-9]+$/) {
-                       next;
-               }
-               my $full_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $file_name);
-               # print "RM $full_path\n";
-               unlink_encoded ($full_path);
-       }
-}
-foreach my $file_name (@remove_list) {
-       my $full_path = join_path(PATH_SEPARATOR(), WWW_PATH(), $file_name);
-       # print "RM $full_path\n";
-       unlink_encoded ($full_path);
-}
diff --git a/settings-again.txt b/settings-again.txt
deleted file mode 100644 (file)
index 8f13d1c..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-# In this file are defined values specific for the user's system
-
-
-# target name. settings file (THIS FILE) is "settings-TARGET_NAME.txt"
-# where TARGET_NAME is the value
-target: again
-
-name: bstagain
-
-
-# Where the software will be located
-bin_path: /botm/bin/bstagain
-
-# where the libraries will be located
-lib_path: /botm/lib/bstagain
-
-# where the software  will remember data
-data_path: /botm/data/bstagain
-
-#where the software will record logs
-log_path: /botm/log/bstagain
-
-#for temporary fies
-tmp_path: /botm/tmp/bstagain
-
-#for the www server
-www_path : /botm/www/1190/bstagain
-cgi_path : /bstagain
-conf_path: /botm/etc/www/conf/1190
-
-#cron files directory
-cron_path: /etc/cron.d
-
-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
-
-chmod: /usr/bin/chmod
-cp   : /usr/bin/cp
-gzip : /usr/bin/gzip
-mkdir: /usr/bin/mkdir
-mv   : /usr/bin/mv
-perl : /usr/bin/perl
-rm   : /usr/bin/rm
-sudo : /usr/bin/sudo
-
-CC: /usr/bin/gcc
-CF: -g -Wall
-
-
-# How big can a log file be
-log_size_limit: 65536
-
-# How many uncompressed old logs to keep
-logs_uncompressed: 2
-
-# How many old logs to keep 
-logs_total: 10
-
-# When to deal with old logs
-oldlogs_schedule: 1 4 * * *
-
-# When to run the  ONG bot
-ong_schedule: 0 * * * *
-
-# When to RESET EVERYTHING
-reset_schedule: 33 4 * * *
-reset_password: again
-
-cron_user: b
-
-
-scheme      : http
-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
-
-comment_page_length: 40
-
-story_credits: "BSTA" by Balthasar Szczepański
-intf_credits: Online interface v$_version © Balthasar Szczepański; AGPL 3 license
-source_url: http://bicyclesonthemoon.info/git-projects/?p=ott/bsta
diff --git a/settings-bsta.txt b/settings-bsta.txt
deleted file mode 100644 (file)
index a02554d..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-# In this file are defined values specific for the user's system
-
-
-# target name. settings file (THIS FILE) is "settings-TARGET_NAME.txt"
-# where TARGET_NAME is the value
-target: bsta
-
-name: bsta
-
-
-# Where the software will be located
-bin_path: /botm/bin/bsta
-
-# where the libraries will be located
-lib_path: /botm/lib/bsta
-
-# where the software  will remember data
-data_path: /botm/data/bsta
-
-#where the software will record logs
-log_path: /botm/log/bsta
-
-#for temporary fies
-tmp_path: /botm/tmp/bsta
-
-#for the www server
-www_path : /botm/www/1190/bsta
-cgi_path : /bsta
-conf_path: /botm/etc/www/conf/1190
-
-#cron files directory
-cron_path: /etc/cron.d
-
-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
-
-chmod: /usr/bin/chmod
-cp   : /usr/bin/cp
-gzip : /usr/bin/gzip
-mkdir: /usr/bin/mkdir
-mv   : /usr/bin/mv
-perl : /usr/bin/perl
-rm   : /usr/bin/rm
-sudo : /usr/bin/sudo
-
-CC: /usr/bin/gcc
-CF: -g -Wall
-
-
-# How big can a log file be
-log_size_limit: 65536
-
-# How many uncompressed old logs to keep
-logs_uncompressed: 2
-
-# How many old logs to keep 
-logs_total: 10
-
-# When to deal with old logs
-oldlogs_schedule: 0 4 * * *
-
-# When to run the  ONG bot
-ong_schedule: 0 * * * *
-
-# When to RESET EVERYTHING
-reset_schedule: #33 4 * * *
-reset_password: 
-
-cron_user: b
-
-
-scheme      : http
-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
-
-comment_page_length: 40
-
-story_credits: "BSTA" by Balthasar Szczepański
-intf_credits: Online interface v$_version © Balthasar Szczepański; AGPL 3 license
-source_url: http://bicyclesonthemoon.info/git-projects/?p=ott/bsta
index 40e8d9b614aac5b74151075345563c3a3bfe9a9c..88eac5d5fee8e49bb4534d463a7d9f5d12cad58f 100644 (file)
@@ -5,37 +5,14 @@
 # where TARGET_NAME is the value
 target: debug
 
-name: test-bsta
+name: test-oldlogs
 
 
 # Where the software will be located
-bin_path: /botm/bin/test-bsta
+bin_path: /botm/bin/test-oldlogs
 
 # where the libraries will be located
-lib_path: /botm/lib/test-bsta
-
-# where the software  will remember data
-data_path: /botm/data/test-bsta
-
-#where the software will record logs
-log_path: /botm/log/test-bsta
-
-#for temporary fies
-tmp_path: /botm/tmp/test-bsta
-
-#for the www server
-www_path : /botm/www/1190/bstatest
-cgi_path : /bstatest
-conf_path: /botm/etc/www/conf/1190
-
-#cron files directory
-cron_path: /etc/cron.d
-
-path: /usr/local/bin:/usr/bin:/bin
-# The path environment variable. Must be overwritten if SETUID.
-# Otherwise launching programs may fail.
-# (Perl security...)
-
+lib_path: /botm/lib/test-oldlogs
 
 #paths to software
 
@@ -46,10 +23,6 @@ mkdir: /usr/bin/mkdir
 mv   : /usr/bin/mv
 perl : /usr/bin/perl
 rm   : /usr/bin/rm
-sudo : /usr/bin/sudo
-
-CC: /usr/bin/gcc
-CF: -g -Wall
 
 
 # How big can a log file be
@@ -61,32 +34,3 @@ logs_uncompressed: 2
 # How many old logs to keep 
 logs_total: 10
 
-# When to deal with old logs
-oldlogs_schedule: #0 4 * * *
-
-# When to run the  ONG bot
-ong_schedule: #0 * * * *
-
-# When to RESET EVERYTHING
-reset_schedule: #33 4 * * *
-reset_password: bstreset
-
-cron_user: b
-
-
-scheme      : http
-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
-
-comment_page_length: 4
-
-story_credits: "BSTA" by Balthasar Szczepański
-intf_credits: Online interface v$_version © Balthasar Szczepański; AGPL 3 license
-source_url: http://bicyclesonthemoon.info/git-projects/?p=ott/bsta
diff --git a/settings-release.txt b/settings-release.txt
new file mode 100644 (file)
index 0000000..05e72ea
--- /dev/null
@@ -0,0 +1,36 @@
+# In this file are defined values specific for the user's system
+
+
+# target name. settings file (THIS FILE) is "settings-TARGET_NAME.txt"
+# where TARGET_NAME is the value
+target: release
+
+name: oldlogs
+
+
+# Where the software will be located
+bin_path: /botm/bin/oldlogs
+
+# where the libraries will be located
+lib_path: /botm/lib/oldlogs
+
+#paths to software
+
+chmod: /usr/bin/chmod
+cp   : /usr/bin/cp
+gzip : /usr/bin/gzip
+mkdir: /usr/bin/mkdir
+mv   : /usr/bin/mv
+perl : /usr/bin/perl
+rm   : /usr/bin/rm
+
+
+# How big can a log file be
+log_size_limit: 65536
+
+# How many uncompressed old logs to keep
+logs_uncompressed: 2
+
+# How many old logs to keep 
+logs_total: 10
+
index 7d809c5eed413224fd69db6d2cb4b3f20d9500f8..2760223a8fc68d439e39d557085402075cfcebc9 100644 (file)
@@ -15,7 +15,7 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-_version: 1.2.6
+_version: 1.0.0y
 
 _SHEBANG: #!$0
 
@@ -27,101 +27,6 @@ _PERL_OUR: our $0 = $1;
 _PERL_OUR_STR: @_PERL_OUR(\$$0,@_PERL_STR($1))
 
 
-_bin_path           = @_PATH( $bin_path,           )
-_bin_2words_path    = @_PATH( $bin_path, 2words    )
-_bin_attach_path    = @_PATH( $bin_path, attach    )
-_bin_bbcode_path    = @_PATH( $bin_path, bbcode    )
-_bin_coin_path      = @_PATH( $bin_path, chat      )
-_bin_frame_path     = @_PATH( $bin_path, frame     )
-_bin_goto_path      = @_PATH( $bin_path, goto      )
-_bin_info_path      = @_PATH( $bin_path, info      )
-_bin_oldlogs_path   = @_PATH( $bin_path, oldlogs.pl)
-_bin_ong_path       = @_PATH( $bin_path, ong.pl    )
-_bin_reset_path     = @_PATH( $bin_path, reset.pl  )
-_bin_viewer_path    = @_PATH( $bin_path, viewer    )
-_bin_words_path     = @_PATH( $bin_path, opomba    )
-
-_cgi_path           = @_PATH( $cgi_path,             )
-_cgi_2words_path    = @_PATH( $cgi_path, 2words      )
-_cgi_attach_path    = @_PATH( $cgi_path, a           )
-_cgi_bbcode_path    = @_PATH( $cgi_path, b           )
-_cgi_coin_path      = @_PATH( $cgi_path, coin        )
-_cgi_css_path       = @_PATH( $cgi_path, bsta.css    )
-_cgi_frame_path     = @_PATH( $cgi_path, f           )
-_cgi_goto_path      = @_PATH( $cgi_path, g           )
-_cgi_info_path      = @_PATH( $cgi_path, i           )
-_cgi_list_path      = @_PATH( $cgi_path, goto.htm    )
-_cgi_logo_path      = @_PATH( $cgi_path, botmlogo.png)
-_cgi_timer_path     = @_PATH( $cgi_path, timer.js    )
-_cgi_viewer_path    = @_PATH( $cgi_path, v           )
-_cgi_words_path     = @_PATH( $cgi_path, w           )
-
-_data_path          = @_PATH( $data_path,            )
-_data_attach_path   = @_PATH( $data_path, a          )
-_data_chat_path     = @_PATH( $data_path, chat       )
-_data_coin_path     = @_PATH( $data_path, coincidence)
-_data_default_path  = @_PATH( $data_path, default    )
-_data_list_path     = @_PATH( $data_path, list       )
-_data_noaccess_path = @_PATH( $data_path, noaccess   )
-_data_settings_path = @_PATH( $data_path, settings   )
-_data_state_path    = @_PATH( $data_path, state      )
-_data_story_path    = @_PATH( $data_path, story      )
-_data_words_path    = @_PATH( $data_path, words      )
-
-_log_path           = @_PATH( $log_path,               )
-_log_ong_path       = @_PATH( $log_path, ong.log       )
-_log_spam_path      = @_PATH( $log_path, words_spam.log)
-_log_words_path     = @_PATH( $log_path, words.log     )
-
-_www_path           = @_PATH( $www_path,          )
-_www_goto_path      = @_PATH( $www_path, goto.htm )
-_www_index_path     = @_PATH( $www_path, index.htm)
-
-_conf_path = @_PATH($conf_path, $name\.conf)
-_cron_path = @_PATH($cron_path, $name)
-
-
-CONF_BIN        = $_bin_path
-CONF_BIN_2WORDS = $_bin_2words_path
-CONF_BIN_ATTACH = $_bin_attach_path
-CONF_BIN_BBCODE = $_bin_bbcode_path
-CONF_BIN_COIN   = $_bin_coin_path
-CONF_BIN_FRAME  = $_bin_frame_path
-CONF_BIN_GOTO   = $_bin_goto_path
-CONF_BIN_INFO   = $_bin_info_path
-CONF_BIN_VIEWER = $_bin_viewer_path
-CONF_BIN_WORDS  = $_bin_words_path
-
-CONF_CGI_2WORDS = $_cgi_2words_path
-CONF_CGI_ATTACH = $_cgi_attach_path
-CONF_CGI_BBCODE = $_cgi_bbcode_path
-CONF_CGI_COIN   = $_cgi_coin_path
-CONF_CGI_FRAME  = $_cgi_frame_path
-CONF_CGI_GOTO   = $_cgi_goto_path
-CONF_CGI_INFO   = $_cgi_info_path
-CONF_CGI_VIEWER = $_cgi_viewer_path
-CONF_CGI_WORDS  = $_cgi_words_path
-
-
-CRON_ONG     = $_bin_ong_path
-CRON_OLDLOGS = $_bin_oldlogs_path
-CRON_RESET   = $_bin_reset_path
-
-CRON_USER    = $cron_user
-
-CRON_OLDLOGS_SCHEDULE = $oldlogs_schedule
-CRON_ONG_SCHEDULE     = $ong_schedule
-CRON_RESET_SCHEDULE   = $reset_schedule
-CRON_RESET_PASSWORD   = $reset_password
-
-CRON_LOG_SIZE_LIMIT    = $log_size_limit
-CRON_LOGS_UNCOMPRESSED = $logs_uncompressed
-CRON_LOGS_TOTAL        = $logs_total
-
-CRON_LOG      = $_log_path
-CRON_ONG_LOG = $_log_ong_path
-
-
 MAKE_TARGET = TARGET = $target
 
 MAKE_CHMOD  = CHMOD=$chmod
@@ -129,90 +34,21 @@ MAKE_CP     = CP   =$cp
 MAKE_MKDIR  = MKDIR=$mkdir
 MAKE_PERL   = PERL =$perl
 MAKE_RM     = RM   =$rm
-MAKE_SUDO   = SUDO =$sudo
-
-MAKE_CC    = CC   =$CC
-MAKE_CF    = CF   =$CF
-
-MAKE_CONF = CONF = $_conf_path
-MAKE_CRON = CRON = $_cron_path
 
 MAKE_BIN_PATH        = BIN_PATH        = $bin_path
-MAKE_DATA_PATH       = DATA_PATH       = $data_path
-MAKE_DATA_WORDS_PATH = DATA_WORDS_PATH = $_data_words_path
 MAKE_LIB_PATH        = LIB_PATH        = $lib_path
-MAKE_LOG_PATH        = LOG_PATH        = $log_path
-MAKE_TMP_PATH        = TMP_PATH        = $tmp_path
-MAKE_WWW_PATH        = WWW_PATH        = $www_path
 
 
 PERL_LIB = @_PERL_USE_2(lib, @_PERL_STR($lib_path))
 
-PERL_SET_PATH = \$ENV{'PATH'} = @_PERL_STR($path);
-
 PERL_EXPORT_VERSION    = @_PERL_OUR_STR( VERSION, $_version)
 
 PERL_PATH_SEPARATOR     = @_PERL_CONSTANT_STR( PATH_SEPARATOR, $_PATH_SEPARATOR)
 
-PERL_CGI_PATH           = @_PERL_CONSTANT_STR( CGI_PATH       , $_cgi_path       )
-PERL_CGI_2WORDS_PATH    = @_PERL_CONSTANT_STR( CGI_2WORDS_PATH, $_cgi_2words_path)
-PERL_CGI_ATTACH_PATH    = @_PERL_CONSTANT_STR( CGI_ATTACH_PATH, $_cgi_attach_path)
-PERL_CGI_BBCODE_PATH    = @_PERL_CONSTANT_STR( CGI_BBCODE_PATH, $_cgi_bbcode_path)
-PERL_CGI_COIN_PATH      = @_PERL_CONSTANT_STR( CGI_COIN_PATH  , $_cgi_coin_path  )
-PERL_CGI_CSS_PATH       = @_PERL_CONSTANT_STR( CGI_CSS_PATH   , $_cgi_css_path   )
-PERL_CGI_FRAME_PATH     = @_PERL_CONSTANT_STR( CGI_FRAME_PATH , $_cgi_frame_path )
-PERL_CGI_GOTO_PATH      = @_PERL_CONSTANT_STR( CGI_GOTO_PATH  , $_cgi_goto_path  )
-PERL_CGI_INFO_PATH      = @_PERL_CONSTANT_STR( CGI_INFO_PATH  , $_cgi_info_path  )
-PERL_CGI_LIST_PATH      = @_PERL_CONSTANT_STR( CGI_LIST_PATH  , $_cgi_list_path  )
-PERL_CGI_LOGO_PATH      = @_PERL_CONSTANT_STR( CGI_LOGO_PATH  , $_cgi_logo_path  )
-PERL_CGI_TIMER_PATH     = @_PERL_CONSTANT_STR( CGI_TIMER_PATH , $_cgi_timer_path )
-PERL_CGI_VIEWER_PATH    = @_PERL_CONSTANT_STR( CGI_VIEWER_PATH, $_cgi_viewer_path)
-PERL_CGI_WORDS_PATH     = @_PERL_CONSTANT_STR( CGI_WORDS_PATH , $_cgi_words_path )
-
-PERL_DATA_PATH          = @_PERL_CONSTANT_STR( DATA_PATH         , $_data_path         )
-PERL_DATA_ATTACH_PATH   = @_PERL_CONSTANT_STR( DATA_ATTACH_PATH  , $_data_attach_path  )
-PERL_DATA_CHAT_PATH     = @_PERL_CONSTANT_STR( DATA_CHAT_PATH    , $_data_chat_path    )
-PERL_DATA_COIN_PATH     = @_PERL_CONSTANT_STR( DATA_COIN_PATH    , $_data_coin_path    )
-PERL_DATA_DEFAULT_PATH  = @_PERL_CONSTANT_STR( DATA_DEFAULT_PATH , $_data_default_path )
-PERL_DATA_LIST_PATH     = @_PERL_CONSTANT_STR( DATA_LIST_PATH    , $_data_list_path    )
-PERL_DATA_NOACCESS_PATH = @_PERL_CONSTANT_STR( DATA_NOACCESS_PATH, $_data_noaccess_path)
-PERL_DATA_SETTINGS_PATH = @_PERL_CONSTANT_STR( DATA_SETTINGS_PATH, $_data_settings_path)
-PERL_DATA_STATE_PATH    = @_PERL_CONSTANT_STR( DATA_STATE_PATH   , $_data_state_path   )
-PERL_DATA_STORY_PATH    = @_PERL_CONSTANT_STR( DATA_STORY_PATH   , $_data_story_path   )
-PERL_DATA_WORDS_PATH    = @_PERL_CONSTANT_STR( DATA_WORDS_PATH   , $_data_words_path   )
-
-PERL_LOG_PATH           = @_PERL_CONSTANT_STR( LOG_PATH      , $_log_path      )
-PERL_LOG_SPAM_PATH      = @_PERL_CONSTANT_STR( LOG_SPAM_PATH , $_log_spam_path )
-PERL_LOG_WORDS_PATH     = @_PERL_CONSTANT_STR( LOG_WORDS_PATH, $_log_words_path)
-
-PERL_WWW_PATH           = @_PERL_CONSTANT_STR( WWW_PATH      , $_www_path      )
-PERL_WWW_GOTO_PATH      = @_PERL_CONSTANT_STR( WWW_GOTO_PATH , $_www_goto_path )
-PERL_WWW_INDEX_PATH     = @_PERL_CONSTANT_STR( WWW_INDEX_PATH, $_www_index_path)
-
-PERL_SCHEME             = @_PERL_CONSTANT_STR( SCHEME      , $scheme      )
-PERL_WEBSITE            = @_PERL_CONSTANT_STR( WEBSITE     , $website     )
-PERL_WEBSITE_NAME       = @_PERL_CONSTANT_STR( WEBSITE_NAME, $website_name)
-PERL_FAVICON_PATH       = @_PERL_CONSTANT_STR( FAVICON_PATH, $favicon_path)
-
-PERL_COIN_DATE          = @_PERL_CONSTANT_STR( COIN_DATE, $coin_date)
-PERL_INTF_DATE          = @_PERL_CONSTANT_STR( INTF_DATE, $intf_date)
-
-PERL_STORY_CREDITS      = @_PERL_CONSTANT_STR( STORY_CREDITS, $story_credits)
-PERL_INTF_CREDITS       = @_PERL_CONSTANT_STR( INTF_CREDITS , @intf_credits)
-PERL_SOURCE_URL         = @_PERL_CONSTANT_STR( SOURCE_URL   , $source_url)
-
 PERL_GZIP               = @_PERL_CONSTANT_STR( GZIP, $gzip)
 
-PERL_RESET_PASSWORD     = @_PERL_CONSTANT_STR( RESET_PASSWORD, $reset_password)
-
 PERL_LOG_SIZE_LIMIT     = @_PERL_CONSTANT(     LOG_SIZE_LIMIT   , $log_size_limit)
 PERL_LOGS_UNCOMPRESSED  = @_PERL_CONSTANT(     LOGS_UNCOMPRESSED, $logs_uncompressed)
 PERL_LOGS_TOTAL         = @_PERL_CONSTANT(     LOGS_TOTAL       , $logs_total)
 
-PERL_STORY_LENGTH       = @_PERL_CONSTANT(     STORY_LENGTH    , $story_length)
-PERL_PAGE_LENGTH        = @_PERL_CONSTANT(     PAGE_LENGTH     , $page_length)
-PERL_FIRSTPAGE_LENGTH   = @_PERL_CONSTANT(     FIRSTPAGE_LENGTH, $firstpage_length)
-
-PERL_COMMENT_PAGE_LENGTH= @_PERL_CONSTANT(     COMMENT_PAGE_LENGTH, $comment_page_length)
-
 RUN_PERL = @_SHEBANG($perl)
diff --git a/timer.js b/timer.js
deleted file mode 100644 (file)
index 964763f..0000000
--- a/timer.js
+++ /dev/null
@@ -1,95 +0,0 @@
-// timer.js
-// 
-// The countdown script.
-//
-// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
-//    Copyright (C) 2017, 2024  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 <http://www.gnu.org/licenses/>.
-// @license-end
-
-var enabled = false;
-
-window.onload = function () {
-       var e_h;
-       var e_m;
-       var e_s;
-       var h;
-       var m;
-       var s;
-       var countdown;
-       var timer;
-       
-       e_h = document.getElementById("ongh");
-       e_m = document.getElementById("ongm");
-       e_s = document.getElementById("ongs");
-       
-       h = +(e_h.innerHTML);
-       m = +(e_m.innerHTML);
-       s = +(e_s.innerHTML);
-       
-       timer = document.getElementById("timer");
-       timer.onclick = function () {
-               enabled = !enabled;
-       }
-       
-       if (e_h == null || e_m == null || e_s == null) {
-               // window.alert("NUL");
-       }
-       else {
-               countdown = setInterval (function() {
-                       if(isNaN(h) || isNaN(m) || isNaN(s)) {
-                               // window.alert("NAN");
-                               clearInterval(countdown);
-                               return;
-                       }
-                       
-                       if (s > 0) {
-                               s -= 1;
-                       }
-                       else {
-                               s = 59;
-                               if (m > 0) {
-                                       m -= 1;
-                               }
-                               else {
-                                       m == 59;
-                                       if (h > 0) {
-                                               h -= 1;
-                                       }
-                                       else {
-                                               m = 0;
-                                               s = 0;
-                                       }
-                               }
-                       }
-                       
-                       if (enabled) {
-                               if (h == 0 && m == 0 && s == 0) {
-                                       e_h.innerHTML = "00";
-                                       e_m.innerHTML = "00";
-                                       e_s.innerHTML = "NG";
-                                       // window.alert("ONG");
-                                       clearInterval(countdown);
-                                       return;
-                               }
-                               else {
-                                       e_h.innerHTML = ((h < 10) ? "0" : "") + h;
-                                       e_m.innerHTML = ((m < 10) ? "0" : "") + m;
-                                       e_s.innerHTML = ((s < 10) ? "0" : "") + s;
-                               }
-                       }
-               }, 1000);
-       }
-};
diff --git a/update.1.pl b/update.1.pl
deleted file mode 100644 (file)
index 8cfba90..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-#!/usr/bin/perl
-
-# update.pl is generated from update.1.pl.
-#
-# update already ONGed frames & stuff
-#
-# Copyright (C) 2016, 2017, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-);
-use bsta_lib (
-       'STATE',
-       'ong',
-       'write_index', 'write_static_viewer_page', 'write_static_goto',
-       'read_frame_data', 'read_default', 'read_words_list',
-       'read_settings', 'read_state'
-);
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %settings  = read_settings();
-my %default   = read_default();
-my %state     = read_state();
-my %all_frame_data = ();
-my %all_words_data = ();
-
-my $update_goto = 0;
-
-my $ong_state  = int($state{'state'});
-my $last_frame = ($ong_state > STATE->{'inactive'}) ? 
-       int($state{'last'}) :
-       0;
-
-my @list;
-
-my $fail = 0;
-
-print $time."\n";
-
-foreach my $id (@ARGV) {
-       if ($id eq 'all') {
-               $update_goto = 1;
-               push @list, 'i';
-               push @list, 'c';
-               for (my $f=0; $f<=$last_frame; $f+=1) {
-                       push @list, $f;
-               }
-       }
-       elsif ($id =~ /^[0-9]+$/) {
-               $update_goto = 1;
-               my $f = int($&);
-               if ($f <= $last_frame) {
-                       push @list, $f
-               }
-               else {
-                       print "$f > $last_frame\n";
-                       $fail += 1;
-               }
-       }
-       elsif ($id =~ /^[ic]$/) {
-               push @list, $&;
-       }
-       else {
-               print "$id ???\n";
-               $fail += 1;
-       }
-}
-
-# duplicated - before AND after normal pages!
-if ($update_goto) {
-       print 'static GOTO';
-       my $r = write_static_goto(
-               \%state,
-               \%settings,
-               '' # \%goto_list
-       );
-       if ($r) {
-               print " OK\n";
-       }
-       else {
-               print " FAIL\n";
-               $fail += 1;
-       }
-}
-
-foreach my $id (@list) {
-       print "ONG $id\n";
-       my $r = ong(
-               $id,   # frame ID
-               $time, # ONG time
-               '',    # timer value; not relevant
-               1,     # update
-               1,     # print
-               \%settings,
-               \%default,
-               get_frame_data($id),
-               ''    # %goto_list
-       );
-       unless ($r) {
-               $fail += 1;
-               print "ONG FAIL!\n";
-       }
-       make_static_pages($id);
-}
-
-# duplicated - before AND after normal pages!
-if ($update_goto) {
-       print 'static GOTO';
-       my $r = write_static_goto(
-               \%state,
-               \%settings,
-               '' # \%goto_list
-       );
-       if ($r) {
-               print " OK\n";
-       }
-       else {
-               print " FAIL\n";
-               $fail += 1;
-       }
-}
-
-print "\n";
-
-
-sub get_frame_data {
-       (my $id) = @_;
-       
-       unless ($id =~ /^[0-9]+$/) {
-               return '';
-       }
-       my $f = int($id);
-       
-       unless (($f >= 0) && ($f <= $last_frame)) {
-               return '';
-       }
-       
-       my $r = $all_frame_data{$f};
-       if (ref ($r)) {
-               return $r;
-       }
-       
-       my %frame_data = read_frame_data($f);
-       $all_frame_data{$f} = \%frame_data;
-       return \%frame_data;
-}
-
-sub get_words_data {
-       (my $id) = @_;
-       
-       unless ($id =~ /^[0-9]+$/) {
-               return '';
-       }
-       my $f = int($id);
-       
-       unless (($f >= 0) && ($f <= $last_frame)) {
-               return '';
-       }
-       
-       my $r = $all_words_data{$f};
-       if (ref ($r)) {
-               return $r;
-       }
-       
-       my %words_data = read_words_list($f, 1);
-       $all_words_data{$f} = \%words_data;
-       return \%words_data;
-}
-
-sub make_static_page {
-       (my $id) = @_;
-       unless ($id =~ /^[0-9]+$/) {
-               return;
-       }
-       my $f = int($id);
-       unless (
-               ($f >= 0) && (
-                       ($f < $last_frame) || (
-                               ($ong_state >= STATE->{'end'}) &&
-                               ($f <= $last_frame)
-                       )
-               )
-       ) {
-               return;
-       }
-       my $r;
-       
-       if (($f == 0) && ($ong_state > STATE->{'inactive'})) {
-               print 'index';
-               $r = write_index(
-                       \%state,
-                       \%settings,
-               );
-               print (($r) ? " OK\n" : " FAIL\n");
-       }
-       elsif ($f > 0) {
-               print 'static page '.$f;
-               $r = write_static_viewer_page (
-                       $f,
-                       \%state,
-                       \%settings,
-                       \%default,
-                       get_frame_data($f),
-                       get_frame_data($f-1),
-                       get_frame_data($f+1),
-                       get_words_data($f)
-               );
-               print (($r) ? " OK\n" : " FAIL\n");
-       }
-}
-
-sub make_static_pages {
-       (my $id) = @_;
-       unless ($id =~ /^[0-9]+$/) {
-               return;
-       }
-       my $f = int($id);
-       unless (($f >= 0) && ($f <= $last_frame)) {
-               return '';
-       }
-       
-       make_static_page($f);
-       make_static_page($f-1);
-       make_static_page($f+1);
-       make_static_page($f);
-}
-
-exit $fail;
diff --git a/viewer.1.pl b/viewer.1.pl
deleted file mode 100644 (file)
index c7d74d9..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-###RUN_PERL: #!/usr/bin/perl
-
-# /bsta/v
-# viewer is generated from viewer.1.pl.
-#
-# The viewer interface
-#
-# Copyright (C) 2016, 2017, 2019, 2020, 2023, 2024  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 <http://www.gnu.org/licenses/>.
-
-use strict;
-use utf8;
-# use Encode::Locale ('decode_argv');
-use Encode ('encode', 'decode');
-
-###PERL_LIB: use lib /botm/lib/bsta
-use botm_common (
-       'HTTP_STATUS',
-       'read_header_env',
-       'url_query_decode',
-       'join_path',
-       'open_encoded', '_x_encoded',
-       'http_header_status',
-       'merge_url'
-);
-use bsta_lib (
-       'STATE', 'TEXT_MODE', 'INTF_STATE',
-       'fail_method', 'fail_content_type', 'redirect',
-       'get_remote_addr', 'get_frame', 'get_password',
-       'merge_settings',
-       'print_viewer_page',
-       'write_index', 'write_static_goto', 'write_static_viewer_page',
-       'ong',
-       'read_frame_data', 'read_default', 'read_noaccess',
-       'read_words_list', 'read_settings', 'read_story', 'read_goto',
-       'read_state', 'write_state',
-       'get_page_file'
-);
-
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_CGI_PATH:           CGI_PATH           = /bsta/
-###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v
-
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
-
-###PERL_WWW_PATH:           WWW_PATH           = /botm/www/
-
-binmode STDIN,  ':encoding(UTF-8)';
-binmode STDOUT, ':encoding(UTF-8)';
-binmode STDERR, ':encoding(UTF-8)';
-# decode_argv();
-
-my $time = time();
-srand ($time-$$);
-
-my %http;
-my %cgi;
-my %frame_data;
-my %prev_frame_data;
-my %next_frame_data;
-my %default;
-my %settings;
-my %state;
-my %new_state;
-my %goto_list;
-my %words_data;
-
-my $method;
-my $frame;
-my $prev_frame_data_path;
-my $next_frame_data_path;
-my $password;
-my $password_ok;
-my $IP;
-my $access;
-my $timer;
-my $timer_unlocked;
-my $fh;
-my $show_command;
-my $ongtime;
-my $goto;
-my $text_mode;
-my $words_page;
-my $words_data_path;
-my $no_cgi;
-my $force_redirect;
-
-delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
-###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
-
-if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
-       $method = $1;
-}
-else{
-       exit fail_method($ENV{'REQUEST_METHOD'}, ['GET', 'POST', 'HEAD']);
-}
-
-%http = read_header_env(\%ENV);
-%cgi = url_query_decode($ENV{'QUERY_STRING'});
-
-if ($method eq 'POST') {
-       if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
-               my %cgi_post = url_query_decode( <STDIN> );
-               %cgi = merge_settings(\%cgi, \%cgi_post);
-       }
-       # multipart not supported
-       else{
-               exit fail_content_type($method, $http{'content-type'});
-       }
-}
-$no_cgi = (scalar (keys %cgi) == 0);
-
-$IP = get_remote_addr();
-$frame = get_frame(\%cgi);
-$password = get_password(\%cgi);
-
-%settings  = read_settings();
-%default   = read_default();
-
-if ($frame >= 0) {
-       %frame_data= read_frame_data($frame);
-}
-
-$password_ok = ($password eq $settings{'password'});
-
-# state & activation logic
-if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STATE_PATH())) {
-       if (flock($fh, 2)) {
-               
-               %state = read_state($fh);
-               
-               if ($frame < 0) {
-                       $frame = int($state{'last'}) + $frame +1;
-                       if ($frame >= 0) {
-                               $force_redirect = 1;
-                               %frame_data = read_frame_data($frame);
-                       }
-               }
-               
-               if (
-                       (int($state{'state'}) == STATE->{'waiting'}) &&
-                       ($frame == int($state{'last'})) &&
-                       ($method ne 'HEAD') &&
-                       (!$password_ok)
-               ) {
-                       # register IP for progress
-                       my %new_state = %state;
-                       unless (
-                               ($state{'ip1'} eq $IP) ||
-                               ($state{'ip2'} eq $IP) ||
-                               ($state{'ip3'} eq $IP)
-                       )
-                       {
-                               if ($state{'ip1'} eq '') {
-                                       $new_state{'ip1'} = $IP;
-                               }
-                               elsif ($state{'ip2'} eq '') {
-                                       $new_state{'ip2'} = $IP;
-                               }
-                               elsif ($state{'ip3'} eq '') {
-                                       $new_state{'ip3'} = $IP;
-                                       $new_state{'state'} = STATE->{'ready'};
-                               }
-                               else {
-                                       $new_state{'state'} = STATE->{'ready'};
-                               }
-                               if ($new_state{'state'} == STATE->{'ready'}) {
-                                       write_static_goto(\%new_state, \%settings, '');
-                                       write_static_viewer_page(
-                                               $frame-1,
-                                               \%new_state,
-                                               \%settings,
-                                               \%default,
-                                               '', # frame data
-                                               '', # prev frame data
-                                               \%frame_data, # next frame data,
-                                               '' # words data
-                                       );
-                               }
-                               write_state($fh, \%new_state);
-                       }
-               }
-               elsif (
-                       (int($state{'state'}) == STATE->{'inactive'}) &&
-                       ($frame == 1) &&
-                       (!$password_ok)
-               ) {
-                       # ready to activate?
-                       # NOTE: at this point frame 0 is already ONGed.
-                       my %story;
-                       my $ong_time = int($settings{'firstongtime'});
-                       my $r;
-                       
-                       %story     = read_story();
-                       %goto_list = read_goto();
-                       
-                       if (
-                               (int($story{'state'}) == INTF_STATE->{'>|'} ) &&
-                               (int($story{'pass'}) == 1)
-                       ) {
-                               # conditions met; ACTIVATE!
-                               
-                               # set initial state
-                               $state{'state'} = STATE->{'waiting'};
-                               $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'} = $ong_time;
-                               
-                               # prepare to ONG frame 1
-                               
-                               $r = ong(
-                                       1,         # frame ID
-                                       $time,     # ONG time,
-                                       $ong_time, # timer
-                                       0,         # update
-                                       0,         # print
-                                       \%settings,
-                                       \%default,
-                                       \%frame_data,
-                                       \%goto_list
-                               );
-                               if ($r) {
-                                       $r = write_index(\%state, \%settings);
-                               }
-                               if ($r) {
-                                       $r = write_static_goto(\%state, \%settings, \%goto_list);
-                               }
-                               if ($r) {
-                                       $r = write_state($fh, \%state);
-                               }
-                               unless ($r) {
-                                       # FAILED ONG! Story as if it was inactive!
-                                       $state{'state'} = STATE->{'inactive'};
-                               }
-                       }
-               }
-       }
-       else {
-               # FAILED GET STATE! Story as if it was inactive!
-               $state{'state'} = STATE->{'inactive'};
-       }
-       close ($fh);
-}
-else {
-       $state{'state'} = STATE->{'inactive'};
-}
-
-$access = (
-       $password_ok || (
-               (int($state{'state'}) >= STATE->{'waiting'}) &&
-               ($frame <= int($state{'last'})) &&
-               ($frame >= 0)
-       )
-);
-
-if ($access) {
-       if ($no_cgi) {
-               # no CGI - static page is OK
-               if ($frame == 0) {
-                       exit redirect($method, CGI_PATH(), HTTP_STATUS->{'see_other'});
-               }
-               elsif ($frame < int($state{'last'})) {
-                       my $page_file = get_page_file($frame, \%frame_data, \%settings);
-                       if (_x_encoded('-f',
-                               join_path(PATH_SEPARATOR(), WWW_PATH() , $page_file)
-                       )) {
-                               my $static_url = merge_url(
-                                       {'path' => CGI_PATH()},
-                                       {'path' => $page_file}
-                               );
-                               exit redirect($method, $static_url, HTTP_STATUS->{'see_other'});
-                       }
-               }
-       }
-       if ($force_redirect) {
-               my $redirect_url = merge_url(
-                       {'path' => CGI_VIEWER_PATH()},
-                       {'path' => $frame}
-               );
-               unless ($no_cgi) {
-                       delete $cgi{'f'}; # to avoid infinite loop
-                       $redirect_url = merge_url(
-                               {'path' => $redirect_url},
-                               {'query' => \%cgi}
-                       );
-               }
-               exit redirect($method, $redirect_url, HTTP_STATUS->{'see_other'});
-       }
-       
-       if ($frame > 0) {
-               %prev_frame_data = read_frame_data($frame-1, \%default);
-       }
-       else {
-               %prev_frame_data = %default;
-       }
-       %next_frame_data = read_frame_data($frame+1, \%default);
-       %frame_data      = merge_settings(\%default, \%frame_data);
-}
-else {
-       # replace frame data with fail state replacement
-       %frame_data = read_noaccess(\%default);
-}
-
-$timer   = int($state{'nextong'}) - $time;
-$ongtime = int($state{'ongtime'});
-if($ongtime == 0) {
-       $ongtime = int($settings{'ongtime'})
-}
-
-$show_command = ($timer < ($ongtime*3600/3));
-if ($state{'state'} >= STATE->{'ready'}) {
-       $timer_unlocked = 3;
-}
-elsif ($state{'ip3'} ne '') {
-       $timer_unlocked = 3;
-}
-elsif ($state{'ip2'} ne '') {
-       $timer_unlocked = 2;
-}
-elsif ($state{'ip1'} ne '') {
-       $timer_unlocked = 1;
-}
-else {
-       $timer_unlocked = 0;
-}
-
-$text_mode = int($cgi{'b'});
-if($text_mode > TEXT_MODE->{'words'}) {
-       $text_mode = TEXT_MODE->{'normal'};
-}
-$words_page = int($cgi{'i'});
-$goto = int($cgi{'g'});
-
-%words_data = read_words_list(
-       $frame,
-       ($text_mode != TEXT_MODE->{'words'})
-);
-
-if (!$access) {
-       print http_header_status(HTTP_STATUS->{'forbidden'});
-}
-print "Content-type: text/html; charset=UTF-8\n\n";
-if($method eq 'HEAD') {
-       exit;
-}
-
-print_viewer_page (
-       \*STDOUT,
-       {
-               'launch'        => 0,
-               'frame'         => $frame,
-               'access'        => $access,
-               'password_ok'   => $password_ok,
-               'timer_unlocked'=> $timer_unlocked,
-               'timer'         => $timer,
-               'static'        => 0,
-               'show_command'  => $show_command,
-               'text_mode'     => $text_mode,
-               'words_page'    => $words_page,
-               'goto'          => $goto
-       },
-       \%state,
-       \%settings,
-       \%frame_data,
-       $access ? \%prev_frame_data : \%frame_data,
-       $access ? \%next_frame_data : \%frame_data,
-       \%words_data,
-);