]> bicyclesonthemoon.info Git - ott/bsta/commitdiff
input validation; goto form; show version; 2 words password v1.2.6
authorb <rowerynaksiezycu@gmail.com>
Mon, 5 Feb 2024 23:24:17 +0000 (23:24 +0000)
committerb <rowerynaksiezycu@gmail.com>
Mon, 5 Feb 2024 23:24:17 +0000 (23:24 +0000)
18 files changed:
2words.1.pl
attach.1.pl
bbcode.1.pl
bsta.css
bsta_lib.1.pm
chat.1.pl
frame.1.pl
goto.1.pl
info.1.pl
ong.1.pl
opomba.1.pl
reset.1.pl
settings-again.txt
settings-bsta.txt
settings-debug.txt
settings.txt
update.1.pl
viewer.1.pl

index 3b8bdfa3b17d3c7ed5fa5384d30c6da881b03b51..1bc2d74be5eef2d5c7ea48caa6b2960aaa8061d2 100644 (file)
@@ -29,11 +29,10 @@ use Encode ('encode', 'decode');
 use botm_common (
        'HTTP_STATUS',
        'http_header_status', 'http_header_allow',
-       'read_data_file', 'write_data_file',
        'merge_url',
        'read_header_env',
        'html_entity_encode_dec',
-       'url_query_decode',
+       'url_query_decode', 'url_query_encode',
        'open_encoded'
 );
 use bsta_lib (
@@ -44,16 +43,16 @@ use bsta_lib (
        'print_html_head_start', 'print_html_head_end',
        'print_html_body_start', 'print_html_body_end',
        'write_index',
-       'get_remote_addr',
+       'get_remote_addr', 'get_password',
        'merge_settings',
-       'ong'
+       '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_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_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
@@ -94,14 +93,13 @@ my $intf_state;
 my $intf_pass;
 my $intf_pause;
 my $intf_mode;
-my $story_i_path;
 my $fh;
 my $story_lock;
 my @story_lines;
 my $ong_state;
 my $page;
-my $cmd_clear;
-my $cmd_clear_all;
+my $password;
+my $password_ok;
 
 
 delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
@@ -130,15 +128,19 @@ if ($method eq 'POST') {
 
 $IP = get_remote_addr();
 $page = get_id(\%cgi);
+$password = get_password(\%cgi);
 if ($cgi{'words'} ne '') {
        $words = $cgi{'words'};
 }
 
-%settings = read_data_file(DATA_SETTINGS_PATH());
-%state    = read_data_file(DATA_STATE_PATH());
+%settings = read_settings();
+%state    = read_state();
 $ong_state = int($state{'state'});
-$cmd_clear     = $settings{'password'}.' clear';
-$cmd_clear_all = $settings{'password'}.' clearall';
+
+$password_ok = ($password eq $settings{'password'});
+if ($password_ok) {
+       $IP .= ' OK';
+}
 
 $story_lock=0;
 if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
@@ -146,7 +148,7 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
        if (flock($fh,2)) {
                $story_lock=2;
        }
-       %story = read_data_file($fh);
+       %story = read_story($fh);
        
        if ($story{'lastip'} =~ /^.+$/) {
                $last_IP=$&;
@@ -172,13 +174,13 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
        if (
                ($intf_state < 0) || (
                        ($method eq 'POST') && (
-                               ($words eq $cmd_clear) ||
-                               ($words eq $cmd_clear_all)
+                               ($cgi{'clear'} ne '') || 
+                               ($cgi{'clear_all'} ne '')
                        )
                )
        ) {
                if (
-                       ($words eq $cmd_clear_all) ||
+                       ($cgi{'clear_all'} ne '') ||
                        ($intf_state < -1)
                ) {
                        $story{'id'} = 0;
@@ -198,28 +200,38 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
                                0 # pause
                        );
                }
-               write_data_file($fh, \%story);
+               write_story($fh, \%story);
        }
        
        if (($words ne '') && ($method eq 'POST')) {
-               if (!$turn) {
+               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]*)$/) {
+               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 '')
+                               ($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) {
+                       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).'.';
                        }
@@ -233,10 +245,12 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
                                
                                if ($cgi{'next'} ne '') {
                                        # start next game
-                                       if (split(/\r?\n/,$story{'content'}) >= (STORY_LENGTH-1)) {
+                                       if (
+                                               $password_ok ||
+                                               (split(/\r?\n/,$story{'content'}) >= (STORY_LENGTH-1))
+                                       ) {
                                                # store finished game
-                                               $story_i_path = DATA_STORY_PATH.$story_id;
-                                               write_data_file($story_i_path, \%story);
+                                               write_story($story_id, \%story);
                                                # init new game
                                                $new_story{'id'     } = $story_id + 1;
                                                $new_story{'letter' } = '';
@@ -260,11 +274,11 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
                                                        );
                                                }
                                                # save new game
-                                               write_data_file($fh, \%new_story);
+                                               write_story($fh, \%new_story);
                                        }
                                        else {
                                                $message = 'To early to finish this wordgame.';
-                                               write_data_file($fh, \%story);
+                                               write_story($fh, \%story);
                                        }
                                }
                                else {
@@ -354,7 +368,7 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
                                                        }
                                                }
                                        }
-                                       write_data_file($fh, \%story);
+                                       write_story($fh, \%story);
                                }
                        }
                }
@@ -379,7 +393,7 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STORY_PATH())) {
                        $intf_mode,
                        $intf_pause
                );
-               write_data_file($fh, \%story);
+               write_story($fh, \%story);
        }
        @story_lines = split(/\r?\n/, $story{'content'});
        if(@story_lines & 1) {
@@ -401,7 +415,7 @@ if($method eq 'HEAD') {
        exit;
 }
 
-my $max_page = int(($story_id - FIRSTPAGE_LENGTH - 1) / PAGE_LENGTH) + 1;
+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'});
@@ -500,6 +514,20 @@ my $intf_img = merge_url(
        {'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);
@@ -556,7 +584,7 @@ if ($page == 0) {
                print '     <span class="br">'.$_message.'</span>'."\n";
        }
        
-       if ($turn) {
+       if ($turn || $password_ok) {
                print '     <form method="post" action="'.$_twowords_url.'">'."\n";
                if ($message eq '') {
                        if ($story{"content"} eq '') {
@@ -568,9 +596,14 @@ if ($page == 0) {
                }
                print '      <input class="intx" type="text" name="words">'."\n";
                print '      <input class="inbt" type="submit" value="enter">'."\n";
-               if (@story_lines >= (STORY_LENGTH-1)) {
+               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 {
@@ -610,8 +643,7 @@ print '   <div id="insb" class="ins">'."\n";
 
 print '    <div id="undertext">'."\n";
 for (my $i = $id_start; $i > $id_stop; --$i) {
-       $story_i_path = DATA_STORY_PATH.$i;
-       %new_story = read_data_file($story_i_path);
+       %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";
index 151dddcf5dcd8104a3873153e286a71531105de8..cb34f63e996a200797fb9361189e94278e1e8286 100644 (file)
@@ -30,7 +30,6 @@ use botm_common (
        'HTTP_STATUS',
        'read_header_env',
        'url_query_decode',
-       'read_data_file',
        'join_path',
        'merge_url',
        'open_encoded', 'stat_encoded',
@@ -41,18 +40,14 @@ use bsta_lib (
        'merge_settings',
        'get_id', 'get_password',
        'fail_method', 'fail_content_type', 'fail_attachment', 'fail_500',
-       'redirect'
+       '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_DATA_ATTACH_PATH:   DATA_ATTACH_PATH   = /botm/data/bsta/a
-###PERL_DATA_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/settings
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
-
 ###PERL_WWW_PATH:           WWW_PATH           = /botm/www/1190/bsta/
 
 binmode STDIN,  ':encoding(UTF-8)';
@@ -112,9 +107,9 @@ if ($method eq 'POST') {
 $ID       = get_id(      \%cgi);
 $password = get_password(\%cgi);
 
-%settings  = read_data_file(DATA_SETTINGS_PATH());
-%state     = read_data_file(DATA_STATE_PATH());
-%file_data = read_data_file(DATA_ATTACH_PATH().$ID);
+%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'});
index ee88ab11ed22efcf07af55f7b1715b6d368e13f6..28e5e6d4bf612801dbc83270bbafc5b7a40b50cc 100644 (file)
@@ -29,9 +29,7 @@ use Encode ('encode', 'decode');
 use botm_common (
        'HTTP_STATUS',
        'read_header_env',
-       'read_data_file',
        'url_query_decode',
-       'join_path',
        'merge_url',
        'http_header_status'
 );
@@ -40,19 +38,16 @@ use bsta_lib (
        'fail_method', 'fail_content_type',
        'get_frame', 'get_password',
        'merge_settings',
-       'eval_bb', 'bb_to_bbcode'
+       'eval_bb', 'bb_to_bbcode',
+       'get_frame_file',
+       'read_frame_data', 'read_default', 'read_noaccess',
+       'read_settings', 'read_state'
 );
 
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
 ###PERL_CGI_PATH:           CGI_PATH           = /bsta/
 ###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v
 
 ###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta/
-###PERL_DATA_DEFAULT_PATH:  DATA_DEFAULT_PATH  = /botm/data/bsta/default
-###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_SCHEME:             SCHEME             = http
 ###PERL_WEBSITE:            WEBSITE            = 1190.bicyclesonthemoon.info
@@ -110,9 +105,9 @@ if ($method eq 'POST') {
 $frame  = get_frame(\%cgi);
 $password = get_password(\%cgi);
 
-%settings   = read_data_file(DATA_SETTINGS_PATH());
-%default    = read_data_file(DATA_DEFAULT_PATH());
-%state      = read_data_file(DATA_STATE_PATH());
+%settings   = read_settings();
+%default    = read_default();
+%state      = read_state();
 
 $ong_state  = int($state{'state'});
 $last_frame = int($state{'last'});
@@ -122,9 +117,7 @@ $password_ok = ($password eq $settings{'password'});
 if ($frame < 0) {
        $frame = $last_frame + $frame +1;
 }
-$frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
-%frame_data = read_data_file($frame_data_path);
-%frame_data = merge_settings(\%default, \%frame_data);
+%frame_data = read_frame_data($frame, \%default);
 
 if (
        $password_ok || (
@@ -137,18 +130,9 @@ if (
 }
 else {
        $access=0;
-       %frame_data = read_data_file(DATA_NOACCESS_PATH());
-       %frame_data = merge_settings(\%default, \%frame_data);
-}
-if ($frame_data{'frame'} ne '') {
-       $frame_file = $frame_data{'frame'};
-}
-else {
-       $frame_file = sprintf(
-               $settings{'frame'},
-               $frame, $frame_data{'ext'}
-       );
+       %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) {
index b1ae221aa4e6b0970c64740837936db05e39b4b5..da52470caba218dc2234612e00f98c72d4d74d72 100644 (file)
--- a/bsta.css
+++ b/bsta.css
@@ -6,6 +6,7 @@ html
        color: #000000;
        text-align: center;
 }
+
 a
 {
        border-color: #0057af;
@@ -92,7 +93,6 @@ div#title
        border: 0px;
        margin: 0px;
 }
-
 div.title
 {
        text-align: center;
@@ -110,7 +110,6 @@ h1#titletext
        border: 0px;
        padding: 0px;
 }
-
 h1.titletext
 {
        margin: 0px;
@@ -146,17 +145,23 @@ img#frame
        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;
@@ -166,32 +171,24 @@ img#frame.bftf
        background-color: #d9ecff;
 }
 
-img#frame:hover
-{
-       border-color: #bb6622;
-}
-
 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;
@@ -210,7 +207,6 @@ div#undertext
        margin: 0px;
        border: 0px;
 }
-
 div.undertext
 {
        text-align: left;
@@ -235,19 +231,16 @@ div.fq
        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;
@@ -259,31 +252,26 @@ div.opomba
        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;
@@ -319,7 +307,6 @@ div#underlinks
        border: 0px;
        font-family: monospace;
 }
-
 div.underlinks
 {
        text-align: left;
@@ -333,7 +320,6 @@ span.inp
 {
        animation: inp 2380ms step-start infinite;
 }
-
 @keyframes inp
 {
        50% { opacity: 0.0;}
@@ -350,11 +336,14 @@ input.intx
        font-family: monospace;
        /* font-size: 150%; */
 }
-
 input.intx:focus
 {
        border-color: #bb6622;
 }
+input.intx:hover
+{
+       border-color: #bb6622;
+}
 
 input.intxc
 {
@@ -368,11 +357,14 @@ input.intxc
        width: 100%;
        /* font-size: 150%; */
 }
-
 input.intxc:focus
 {
        border-color: #bb6622;
 }
+input.intxc:hover
+{
+       border-color: #bb6622;
+}
 
 /* table.intxc
 {
@@ -390,11 +382,14 @@ textarea.inta
        margin: 2px;
        resize: none;
 }
-
 textarea.inta:focus
 {
        border-color: #bb6622;
 }
+textarea.inta:hover
+{
+       border-color: #bb6622;
+}
 
 input.inbt
 {
@@ -407,11 +402,14 @@ input.inbt
        font-family: monospace;
        /* font-size: 150%; */
 }
-
 input.inbt:focus
 {
        border-color: #bb6622;
 }
+input.inbt:hover
+{
+       border-color: #bb6622;
+}
 
 input.hl {
        background:none!important;
@@ -428,6 +426,14 @@ input.hl:hover {
        border-color: #bb6622;
        color: #bb6622;
 }
+form.hl {
+       display: inline
+}
+
+form.goto {
+       clear: both;
+       display: inline
+}
 
 .br
 {
index 7b8c37d5c45dee09ec0db16061a8bf4af51fe7e1..7545a90440d9e89b3cd94603a63f1ae2c2189fcc 100644 (file)
@@ -19,7 +19,6 @@
 
 # TODO: FQ NBSP ?
 # TODO: DEBUG
-# TODO: timer JS
 # TODO: BB & INFO indent
 
 package bsta_lib;
@@ -47,6 +46,14 @@ our @EXPORT_OK   = (
        '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'
 );
@@ -72,6 +79,7 @@ use botm_common (
 ###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
@@ -91,6 +99,7 @@ use botm_common (
 ###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/
@@ -949,8 +958,7 @@ sub print_goto {
                $ongtime = $goto_list->{'ongtime-'.$frame};
                $title   = $goto_list->{'title-'  .$frame};
                if (($ongtime eq '') && ($title eq '')) {
-                       my $frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
-                       my %frame_data = read_data_file($frame_data_path);
+                       my %frame_data = read_frame_data($frame);
                        $ongtime = $frame_data{'ongtime'};
                        $title   = $frame_data{'title'};
                        unless (keys %frame_data) {
@@ -1034,6 +1042,7 @@ sub print_viewer_page {
        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'});
@@ -1137,7 +1146,6 @@ sub print_viewer_page {
        my $password_query;
        
        my $base_url   = CGI_PATH();
-       my $goto_url   = CGI_GOTO_PATH();
        my $timer_url  = CGI_TIMER_PATH();
        my $viewer_full_url = merge_url(
                {'scheme' => SCHEME(), 'host' => WEBSITE()},
@@ -1164,6 +1172,16 @@ sub print_viewer_page {
                {'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;
@@ -1171,15 +1189,7 @@ sub print_viewer_page {
                        $viewer_prev_url = $viewer_0_url;
                }
                else {
-                       if ($prev_frame_data->{'page'} ne '') {
-                               $page_file = $prev_frame_data->{'page'};
-                       }
-                       else {
-                               $page_file = sprintf(
-                                       $settings->{'frame'},
-                                       $prev_frame, 'htm'
-                               );
-                       }
+                       $page_file = get_page_file($prev_frame, $prev_frame_data, $settings);
                        if (_x_encoded('-f',
                                join_path(PATH_SEPARATOR(), WWW_PATH() , $page_file)
                        )) {
@@ -1190,15 +1200,7 @@ sub print_viewer_page {
                        }
                }
                if ($next_frame < $last_frame) {
-                       if ($next_frame_data->{'page'} ne '') {
-                               $page_file = $next_frame_data->{'page'};
-                       }
-                       else {
-                               $page_file = sprintf(
-                                       $settings->{'frame'},
-                                       $next_frame, 'htm'
-                               );
-                       }
+                       $page_file = get_page_file($next_frame, $next_frame_data, $settings);
                        if (_x_encoded('-f',
                                join_path(PATH_SEPARATOR(), WWW_PATH() , $page_file)
                        )) {
@@ -1208,7 +1210,10 @@ sub print_viewer_page {
                                );
                        }
                }
-               if (_x_encoded('-f',WWW_GOTO_PATH())) {
+               if (
+                       $goto &&
+                       (_x_encoded('-f',WWW_GOTO_PATH()))
+               ) {
                        $goto_url = CGI_LIST_PATH();
                }
        }
@@ -1255,15 +1260,7 @@ sub print_viewer_page {
        my $frame_next_url;
        my $frame_normal_url;
        my $frame_full_url;
-       if ($frame_data->{'frame'} ne '') {
-               $frame_file = $frame_data->{'frame'};
-       }
-       else {
-               $frame_file = sprintf(
-                       $settings->{'frame'},
-                       $frame, $frame_data->{'ext'}
-               );
-       }
+       $frame_file = get_frame_file($frame, $frame_data, $settings);
        $frame_normal_url = merge_url(
                        {'path' => CGI_PATH()},
                        {'path' => $frame_file}
@@ -1284,34 +1281,24 @@ sub print_viewer_page {
                        {'path' => $prev_frame}
                );
        }
-       elsif ($prev_frame_data->{'frame'} ne '') {
+       else {
                $frame_prev_url = merge_url(
                        {'path' => CGI_PATH()},
-                       {'path' => $prev_frame_data->{'frame'}}
+                       {'path' => get_frame_file($prev_frame, $prev_frame_data, $settings)}
                );
        }
-       else {
-               $frame_prev_url = merge_url(CGI_PATH(), sprintf(
-                       $settings->{'frame'}, $prev_frame, $prev_frame_data->{'ext'}
-               ));
-       }
        if ($nextframe_indirect) {
                $frame_next_url = merge_url(
                        {'path' => CGI_FRAME_PATH()},
                        {'path' => $next_frame}
                );
        }
-       elsif ($next_frame_data->{'frame'} ne '') {
+       else {
                $frame_next_url = merge_url(
                        {'path' => CGI_PATH()},
-                       {'path' => $next_frame_data->{'frame'}}
+                       {'path' => get_frame_file($next_frame, $next_frame_data, $settings)}
                );
        }
-       else {
-               $frame_next_url = merge_url(CGI_PATH(), sprintf(
-                       $settings->{'frame'}, $next_frame, $next_frame_data->{'ext'}
-               ));
-       }
        
        if ($password_ok) {
                $password_query = url_query_encode({'p', $settings->{'password'}});
@@ -1334,22 +1321,24 @@ sub print_viewer_page {
                        $frame_next_url= merge_url($frame_next_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 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 $_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);
@@ -1369,14 +1358,8 @@ sub print_viewer_page {
                        unless (($access) && ($frame < $last_frame)) {
                                $frame_data->{'page'} = '';
                        }
-                       elsif ($frame == 0) {
-                               $frame_data->{'page'} = 'index.htm';
-                       }
                        else {
-                               $frame_data->{'page'} = sprintf(
-                                       $settings->{'frame'},
-                                       $frame, 'htm'
-                               );
+                               $frame_data->{'page'} = get_page_file($frame, $frame_data, $settings);
                        }
                }
        }
@@ -1514,7 +1497,10 @@ sub print_viewer_page {
        }
        print $fh '<a href="'.$_goto_url.'">GOTO</a>'."\n";
        print $fh '     <span style="float: right;">'."\n      ";
-       if ($text_mode == TEXT_MODE->{'normal'}) {
+       if (
+               ($text_mode == TEXT_MODE->{'normal'}) &&
+               (!$goto)
+       ){
                if ($show_words) {
                        print $fh '<a href="'.$_words_url.'">'.$words_link_text.'</a> | ';
                }
@@ -1527,6 +1513,25 @@ sub print_viewer_page {
        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) {
@@ -1597,8 +1602,8 @@ sub print_comments {
                $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 $_password = html_entity_encode_dec($settings->{'password'}, 1);
        my $_older_url = html_entity_encode_dec($older_url, 1);
        my $_newer_url = html_entity_encode_dec($newer_url, 1);
        
@@ -1634,8 +1639,7 @@ sub print_comments {
        if ($post_count > 0) {
                for (my $i=$id_start; $i<$id_stop; ++$i) {
                        my $ID = $words_data->{'content'}->[$i];
-                       my $post_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $ID);
-                       my %post_data = read_data_file($post_path);
+                       my %post_data = read_words($ID);
                        
                        my $post_time = int($post_data{'posttime'});
                        my $edit_time = int($post_data{'edittime'});
@@ -1786,20 +1790,14 @@ sub write_index {
        
        # normal running story
        if ($ong_state > STATE->{'inactive'}) {
-               my %frame_data     = read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), 0));
-               my %next_frame_data= read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), 1));
-               my %default        = read_data_file(DATA_DEFAULT_PATH());
-               my %words_data     = read_data_file(
-                       join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), 0),
-                       '', # encoding
-                       0,  # no header
+               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
-                       1,  # as list
                );
                
-               %frame_data     = merge_settings(\%default,      \%frame_data);
-               %next_frame_data= merge_settings(\%default, \%next_frame_data);
-               
                $r = print_viewer_page(
                        $fh,
                        {
@@ -1812,7 +1810,8 @@ sub write_index {
                                'static'         => 1,
                                'show_command'   => 1,
                                'text_mode'      => TEXT_MODE->{'normal'},
-                               'words_page'     => 0 # not relevant
+                               'words_page'     => 0, # not relevant
+                               'goto'           => 0
                        },
                        $state,
                        $settings,
@@ -1874,13 +1873,10 @@ sub write_index {
        }
        # the launch index
        else {
-               my %frame_data     = read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), 0));
-               my %next_frame_data= read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), 1));
-               my %default        = read_data_file(DATA_DEFAULT_PATH());
-               my %coin_data      = read_data_file(DATA_COIN_PATH());
-               
-               %frame_data     = merge_settings(\%default,      \%frame_data);
-               %next_frame_data= merge_settings(\%default, \%next_frame_data);
+               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(
@@ -1895,7 +1891,8 @@ sub write_index {
                                        'static'         => 1,
                                        'show_command'   => 1,
                                        'text_mode'      => TEXT_MODE->{'normal'},
-                                       'words_page'     => 0 # not relevant
+                                       'words_page'     => 0, # not relevant
+                                       'goto'           => 0
                                },
                                $state,
                                $settings,
@@ -2051,7 +2048,7 @@ sub write_static_viewer_page {
        
        %state = (ref ($state_ref)) ?
                %$state_ref :
-               read_data_file(DATA_STATE_PATH());
+               read_state();
        my $ong_state = int($state{'state'});
        my $last_frame = int($state{'last'});
        
@@ -2071,55 +2068,38 @@ sub write_static_viewer_page {
        
        %settings = (ref ($settings_ref)) ?
                %$settings_ref :
-               read_data_file(DATA_SETTINGS_PATH());
+               read_settings();
        %default = (ref ($default_ref)) ?
                %$default_ref :
-               read_data_file(DATA_DEFAULT_PATH());
+               read_default();
        
        %frame_data = (ref ($frame_data_ref)) ?
                %$frame_data_ref :
-               read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), $frame));
+               read_frame_data($frame);
        
        %prev_frame_data = (ref ($prev_frame_data_ref)) ?
                %$prev_frame_data_ref : (
                        ($prev_frame >= 0) ?
-                       read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), $prev_frame)) :
+                       read_frame_data($prev_frame) :
                        %default
                );
                
        %next_frame_data = (ref ($next_frame_data_ref)) ?
-               %$next_frame_data_ref : (
-                       (($next_frame < $last_frame) || (
-                               ($next_frame <= $last_frame) &&
-                               ($next_frame >= STATE->{'end'})
-                       )) ?
-                       read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), $next_frame)) :
-                       %default
-               );
-       
-       %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);
+               %$next_frame_data_ref :
+               read_frame_data($next_frame);
        
        %words_data = (ref ($words_data_ref)) ?
                %$words_data_ref :
-               read_data_file(
-                       join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $frame), # file
-                       '', # encoding
-                       0,  # no header
+               read_words_list(
+                       $frame, # frame ID
                        1,  # header only
-                       1,  # as list; not relevant
                );
        
-       if ($frame_data{'page'} ne '') {
-               $file = $frame_data{'page'}
-       }
-       else {
-               $file = sprintf(
-                       $settings{'frame'},
-                       $frame, 'htm'
-               );
-       }
+       %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(
@@ -2135,6 +2115,7 @@ sub write_static_viewer_page {
                        'show_command'  => 1,
                        'text_mode'     => TEXT_MODE->{'normal'},
                        'words_page'    => 0, # not relevant
+                       'goto'          => 0
                },
                \%state,
                \%settings,
@@ -2153,13 +2134,13 @@ sub write_static_goto {
        
        %state = (ref ($state_ref)) ?
                %$state_ref :
-               read_data_file(DATA_STATE_PATH());
+               read_state();
        %settings = (ref ($settings_ref)) ?
                %$settings_ref :
-               read_data_file(DATA_SETTINGS_PATH());
+               read_settings();
        %goto_list = (ref ($goto_ref)) ?
                %$goto_ref :
-               read_data_file(DATA_SETTINGS_PATH());
+               read_goto();
        
        return print_goto(
                WWW_GOTO_PATH(),
@@ -2232,32 +2213,22 @@ sub ong {
        else {
                %settings = (ref ($settings_ref)) ?
                        %$settings_ref :
-                       read_data_file(DATA_SETTINGS_PATH());
-               %default = (ref ($default_ref)) ?
-                       %$default_ref :
-                       read_data_file(DATA_DEFAULT_PATH());
+                       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_data_file($frame_data_path);
+                       read_frame_data($frame_data_path);
                %frame_full_data = merge_settings(\%default, \%frame_data);
-               @files = (
-                       ($frame_full_data{'frame'} ne '') ?
-                               $frame_full_data{'frame'} :
-                               sprintf(
-                                       $settings{'frame'},
-                                       $frame, $frame_full_data{'ext'}
-                               )
-                       ,
-               );
+               @files = (get_frame_file($frame, \%frame_full_data, \%settings), );
                unless ($cfrt) {
                        %goto_list = (ref ($goto_ref)) ?
                                %$goto_ref :
-                               read_data_file(DATA_LIST_PATH());
+                               read_goto();
                        for (my $i=0; ;$i+=1) {
-                               my %file_data = read_data_file(DATA_ATTACH_PATH().$i);
+                               my %file_data = read_attachment($i);
                                if ($file_data{'frame'} eq '') {
                                        last;
                                }
@@ -2287,7 +2258,7 @@ sub ong {
                                $write_data = 1;
                        }
                        if ($write_data) {
-                               $r = write_data_file($frame_data_path, \%frame_data);
+                               $r = write_frame_data($frame_data_path, \%frame_data);
                                unless ($r) {
                                        print STDERR "fail writing $frame_data_path\n";
                                        if ($print) {
@@ -2298,7 +2269,7 @@ sub ong {
                        }
                        $goto_list{'title-'  .$frame} = $frame_full_data{'title'};
                        $goto_list{'ongtime-'.$frame} = $frame_full_data{'ongtime'};
-                       $r = write_data_file(DATA_LIST_PATH(), \%goto_list);
+                       $r = write_goto('', \%goto_list);
                        unless ($r) {
                                print STDERR "fail writing ".DATA_LIST_PATH()."\n";
                                if ($print) {
@@ -2327,4 +2298,637 @@ sub ong {
        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
index 1fd807361bac9c4281b462fbba1560fba1c4f277..90ea637323a58d57d762aa154bc5db3e71bdadc0 100644 (file)
--- a/chat.1.pl
+++ b/chat.1.pl
@@ -29,7 +29,6 @@ use Encode ('encode', 'decode');
 ###PERL_LIB: use lib /botm/lib/bsta
 use botm_common (
        'HTTP_STATUS',
-       'read_data_file', 'write_data_file',
        'read_header_env',
        'url_query_decode', 'url_query_encode',
        'merge_url',
@@ -44,7 +43,9 @@ use bsta_lib (
        'print_html_start', 'print_html_end',
        'print_html_head_start', 'print_html_head_end',
        'print_html_body_start', 'print_html_body_end',
-       'merge_settings'
+       'merge_settings',
+       'read_chat', 'write_chat',
+       'read_coincidence', 'read_settings', 'read_state'
 );
 use  File::Copy;
 
@@ -52,9 +53,6 @@ use  File::Copy;
 ###PERL_CGI_COIN_PATH:      CGI_COIN_PATH      = /bsta/coin
 
 ###PERL_DATA_CHAT_PATH:     DATA_CHAT_PATH     = /botm/data/bsta/chat
-###PERL_DATA_COIN_PATH:     DATA_COIN_PATH     = /botm/data/bsta/coincidence
-###PERL_DATA_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/settings
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
 
 ###PERL_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
 
@@ -118,9 +116,9 @@ $IP       = get_remote_addr();
 $page     = get_id(\%cgi, -1);
 $password = get_password(\%cgi);
 
-%coin      = read_data_file(DATA_COIN_PATH());
-%settings  = read_data_file(DATA_SETTINGS_PATH());
-%state     = read_data_file(DATA_STATE_PATH());
+%coin      = read_coincidence();
+%settings  = read_settings();
+%state     = read_state();
 
 $password_ok = ($password eq $settings{'password'});
 
@@ -141,7 +139,7 @@ foreach my $action_id ('join', 'leave', 'nopost', 'file') {
 if ($page < 0) {
        if (open_encoded($fh, "+<", DATA_CHAT_PATH())) {
                if (flock($fh, 2)) {
-                       %chat = read_data_file($fh);
+                       %chat = read_chat($fh);
                        
                        $chat_state = int($chat{'state'});
                        $chat_id    = int($chat{'id'});
@@ -167,7 +165,7 @@ if ($page < 0) {
                                                                $chat_state = CHAT_STATE->{'active'};
                                                                $chat{'state'} = $chat_state;
                                                        }
-                                                       write_data_file($fh, \%chat);
+                                                       write_chat($fh, \%chat);
                                                }
                                                else {
                                                        $status = HTTP_STATUS->{'bad_request'};
@@ -193,7 +191,7 @@ if ($page < 0) {
                                                                $chat_state = CHAT_STATE->{'ready'};
                                                                $chat{'state'} = $chat_state;
                                                        }
-                                                       write_data_file($fh, \%chat);
+                                                       write_chat($fh, \%chat);
                                                }
                                                elsif ($words eq '') {
                                                        $status = HTTP_STATUS->{'bad_request'};
@@ -223,12 +221,12 @@ if ($page < 0) {
                                        if ($username =~ /^[A-Za-z]*$/) {
                                                $chat{'content'} .= 'leave@'.$username.': '.$words."\n";
                                                if ($username ne '') {
-                                                       write_data_file($fh, \%chat);
+                                                       write_chat($fh, \%chat);
                                                }
                                                else {
                                                        my %new_chat;
                                                        if ($chat_state > 1) {
-                                                               write_data_file(DATA_CHAT_PATH.$chat_id, \%chat);
+                                                               write_chat($chat_id, \%chat);
                                                                $new_chat{'id'} = $chat_id+1;
                                                        }
                                                        else {
@@ -236,7 +234,7 @@ if ($page < 0) {
                                                        }
                                                        $new_chat{'state'} = CHAT_STATE->{'disconnected'};
                                                        $new_chat{'content'} = '';
-                                                       write_data_file($fh, \%new_chat);
+                                                       write_chat($fh, \%new_chat);
                                                }
                                        }
                                        else {
@@ -259,7 +257,7 @@ if ($page < 0) {
                                                        $chat_state = CHAT_STATE->{'active'};
                                                        $chat{'state'} = $chat_state;
                                                }
-                                               write_data_file($fh, \%chat);
+                                               write_chat($fh, \%chat);
                                        }
                                        else {
                                                $status = HTTP_STATUS->{'bad_request'};
@@ -291,10 +289,10 @@ if ($page < 0) {
 # old chat archive
 else {
        $chat_id = $page;
-       %chat = read_data_file(DATA_CHAT_PATH());
+       %chat = read_chat();
        $last_id = int($chat{'id'});
        if ($chat_id < $last_id) {
-               %chat = read_data_file(DATA_CHAT_PATH.$page);
+               %chat = read_chat($page);
                $chat_state = int($chat{'state'});
                @chat_lines = split(/\r?\n/, $chat{'content'});
        }
@@ -337,11 +335,11 @@ if ($password_ok) {
        $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 $_password     = html_entity_encode_dec($settings{'password'}, 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);
index 9bea1c2a91c5ef12152886e14be93afbfcee84e0..a0a81fd8acb11d352a285d193cd23a4cb312bec4 100644 (file)
@@ -30,7 +30,6 @@ use botm_common (
        'HTTP_STATUS',
        'read_header_env',
        'url_query_decode',
-       'read_data_file',
        'join_path',
        'merge_url',
        'open_encoded', 'stat_encoded',
@@ -40,20 +39,16 @@ use bsta_lib (
        'STATE', 'INTF_STATE',
        'fail_method', 'fail_content_type', 'fail_open_file', 'fail_500', 'redirect',
        'get_frame', 'get_password',
-       'merge_settings'
+       '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_DATA_DEFAULT_PATH:  DATA_DEFAULT_PATH  = /botm/data/bsta/default
-###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_WWW_PATH:           WWW_PATH           = /botm/www/1190/bsta/
 
 binmode STDIN,  ':encoding(UTF-8)';
@@ -79,7 +74,6 @@ my $IP;
 my $access;
 my $try_onged;
 my $frame_path;
-my $frame_data_path;
 my $frame_file;
 my $fh;
 my $buffer;
@@ -114,9 +108,9 @@ if ($method eq 'POST') {
 $frame    = get_frame(\%cgi);
 $password = get_password(\%cgi);
 
-%settings  = read_data_file(DATA_SETTINGS_PATH());
-%default   = read_data_file(DATA_DEFAULT_PATH());
-%state     = read_data_file(DATA_STATE_PATH());
+%settings  = read_settings();
+%default   = read_default();
+%state     = read_state();
 
 $ong_state  = int($state{'state'});
 $last_frame = int($state{'last'});
@@ -141,7 +135,7 @@ elsif (
        ($ong_state == STATE->{'inactive'}) &&
        ($frame == 0)
 ) {
-       my %story = read_data_file(DATA_STORY_PATH());
+       my %story = read_story();
        if (
                (int($story{'pass'}) == 1) &&
                (int($story{'state'}) == INTF_STATE->{'>|'})
@@ -158,23 +152,12 @@ $try_onged = (
 );
 
 if ($access) {
-       $frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
-       %frame_data = read_data_file($frame_data_path);
-       %frame_data = merge_settings(\%default, \%frame_data);
-}
-else {
-       %frame_data = read_data_file(DATA_NOACCESS_PATH());
-       %frame_data = merge_settings(\%default, \%frame_data);
-}
-if ($frame_data{'frame'} ne '') {
-       $frame_file = $frame_data{'frame'};
+       %frame_data = read_frame_data($frame, \%default);
 }
 else {
-       $frame_file = sprintf(
-               $settings{'frame'},
-               $frame, $frame_data{'ext'}
-       );
+       %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);
index 80dcf16c92bcd15a8acf6297b26bca81826b7591..37feb2391c8998200426ea87d32912269da2daf2 100644 (file)
--- a/goto.1.pl
+++ b/goto.1.pl
@@ -28,7 +28,6 @@ use Encode ('encode', 'decode');
 ###PERL_LIB: use lib /botm/lib/bsta
 use botm_common (
        'read_header_env',
-       'read_data_file',
        'url_query_decode',
        '_x_encoded'
 );
@@ -38,20 +37,14 @@ use bsta_lib (
        'redirect',
        'get_password',
        'print_goto',
-       'merge_settings'
+       'merge_settings',
+       'read_settings', 'read_state', 'read_goto'
 );
 
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
 ###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_DATA_PATH:          DATA_PATH          = /botm/data/bsta/
-###PERL_DATA_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/settings
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
-###PERL_DATA_LIST_PATH:     DATA_LIST_PATH     = /botm/data/bsta/list
-
 ###PERL_WWW_GOTO_PATH:      WWW_GOTO_PATH      = /botm/www/1190/bsta/goto.htm
 
 ###PERL_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
@@ -109,9 +102,9 @@ if ($no_cgi) {
 
 $password = get_password(\%cgi);
 
-%settings  = read_data_file(DATA_SETTINGS_PATH());
-%state     = read_data_file(DATA_STATE_PATH());
-%goto_list = read_data_file(DATA_LIST_PATH());
+%settings  = read_settings();
+%state     = read_state();
+%goto_list = read_goto();
 
 $password_ok = ($password eq $settings{'password'});
 
index d5c0ec8b85e26e84055c736e595f69a758303f4d..377809261ca7a24846e1cf8470f1242e0bff4aea 100644 (file)
--- a/info.1.pl
+++ b/info.1.pl
@@ -30,27 +30,20 @@ use botm_common (
        'HTTP_STATUS',
        'http_header_status',
        'read_header_env',
-       'read_data_file', 'write_data_file',
-       'url_query_decode',
-       'join_path'
+       'write_data_file',
+       'url_query_decode'
 );
 use bsta_lib (
        'STATE',
        'fail_method', 'fail_content_type',
        'get_password',
-       'merge_settings'
+       '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'
 );
 
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta
-###PERL_DATA_ATTACH_PATH:   DATA_ATTACH_PATH   = /botm/data/bsta/a
-###PERL_DATA_DEFAULT_PATH:  DATA_DEFAULT_PATH  = /botm/data/bsta/default
-###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_WORDS_PATH:    DATA_WORDS_PATH    = /botm/data/bsta/words/
-
 binmode STDIN,  ':encoding(UTF-8)';
 binmode STDOUT, ':encoding(UTF-8)';
 binmode STDERR, ':encoding(UTF-8)';
@@ -77,8 +70,6 @@ my $access;
 my $show_command;
 my $ongtime;
 my $timer;
-my $info_data_path;
-my $next_frame_data_path;
 my $ong_state;
 my $last_frame;
 
@@ -118,21 +109,21 @@ elsif ($cgi{'i'} =~ /^.+$/) {
 elsif ($cgi{'w'} =~ /^.+$/) {
        $words = $&;
 }
-elsif ($ENV{'PATH_INFO'} =~ /^\/a(.+)$/) {
+elsif ($ENV{'PATH_INFO'} =~ /^\/a\/?(.+)$/) {
        $attachment = int($1);
 }
-elsif ($ENV{'PATH_INFO'} =~ /^\/w(.+)$/) {
+elsif ($ENV{'PATH_INFO'} =~ /^\/w\/?(.+)$/) {
        $words = $1;
 }
-elsif ($ENV{'PATH_INFO'} =~ /^\/f?(.+)$/) {
-       $frame = int($1);
+elsif ($ENV{'PATH_INFO'} =~ /^\/(f\/?)?(.+)$/) {
+       $frame = int($2);
 }
 
 $password = get_password(\%cgi);
 
-%settings   = read_data_file(DATA_SETTINGS_PATH());
-%default    = read_data_file(DATA_DEFAULT_PATH());
-%state      = read_data_file(DATA_STATE_PATH());
+%settings   = read_settings();
+%default    = read_default();
+%state      = read_state(());
 
 $ong_state  = int($state{'state'});
 $last_frame = int($state{'last'});
@@ -141,15 +132,19 @@ $password_ok = ($password eq $settings{'password'});
 
 # comment info, not frame
 if ($words ne '') {
-       $info_data_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $words);
-       %info_data      = read_data_file($info_data_path);
        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;
                }
        }
-       else {
+       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'});
@@ -159,7 +154,7 @@ if ($words ne '') {
 }
 # attachment info, not frame
 elsif ($attachment ne '') {
-       %info_data = read_data_file(DATA_ATTACH_PATH().$attachment);
+       %info_data = read_attachment($attachment);
        $frame = ($info_data{'frame'} ne '') ? int($info_data{'frame'}) : -1;
 }
 # frame info
@@ -167,12 +162,8 @@ elsif ($frame ne '') {
        if ($frame < 0) {
                $frame = $last_frame + $frame +1;
        }
-       $info_data_path       = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
-       $next_frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame+1);
-       %info_data       = read_data_file($info_data_path);
-       %next_frame_data = read_data_file($next_frame_data_path);
-       %info_data       = merge_settings(\%default,      \%info_data);
-       %next_frame_data = merge_settings(\%default, \%next_frame_data);
+       %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'});
@@ -237,8 +228,7 @@ else {
                %info_data = ();
        }
        else {
-               %info_data = read_data_file(DATA_NOACCESS_PATH());
-               %info_data = merge_settings(\%default, \%info_data);
+               %info_data = read_noaccess(\%default);
        }
 }
 if (
@@ -246,17 +236,14 @@ if (
        ($words eq '')
 ) {
        if ($info_data{'frame'} eq '') {
-               $info_data{'frame'} = sprintf($settings{'frame'}, $frame, $info_data{'ext'});
+               $info_data{'frame'} = get_frame_file($frame, \%info_data, \%settings)
        }
        if ($info_data{'page'} eq '') {
                unless (($access) && ($frame < $last_frame)) {
                        $info_data{'page'} = '';
                }
-               elsif ($frame == 0) {
-                       $info_data{'page'} = 'index.htm';
-               }
                else {
-                       $info_data{'page'} = sprintf($settings{'frame'}, $frame, 'htm');
+                       $info_data{'page'} = get_page_file($frame, \%info_data, \%settings);
                }
        }
 }
index 6c3ecf33c2c975868ac96dd1e72011d125fd7156..df5eab07d05965a158c421c77b0e7ede8a435921 100644 (file)
--- a/ong.1.pl
+++ b/ong.1.pl
@@ -26,22 +26,16 @@ use Encode ('encode', 'decode');
 
 ###PERL_LIB: use lib /botm/lib/bsta
 use botm_common (
-       'read_data_file', 'write_data_file',
        'open_encoded',
-       'join_path'
 );
 use bsta_lib (
        'STATE',
        'ong',
-       'write_static_viewer_page', 'write_index', 'write_static_goto'
+       'write_static_viewer_page', 'write_index', 'write_static_goto',
+       'read_default', 'read_frame_data', 'read_settings', 'read_goto',
+       'read_state', 'write_state'
 );
 
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta/
-###PERL_DATA_DEFAULT_PATH:  DATA_DEFAULT_PATH  = /botm/data/bsta/default
-###PERL_DATA_LIST_PATH:     DATA_LIST_PATH     = /botm/data/bsta/list
-###PERL_DATA_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/settings
 ###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
 
 binmode STDIN,  ':encoding(UTF-8)';
@@ -88,7 +82,7 @@ unless (flock($fh, 2)) {
        close ($fh);
        exit;
 }
-%state = read_data_file($fh);
+%state = read_state($fh);
 $ongstate = int($state{'state'});
 print 'state: '.$ongstate."\n";
 unless ($ongstate > STATE->{'inactive'}) {
@@ -105,7 +99,7 @@ unless ($ongtime >= $next_ong) {
        exit;
 }
 
-%settings = read_data_file(DATA_SETTINGS_PATH());
+%settings = read_settings();
 $static_timer = int($settings{'ongtime'});
 $timer        = int($settings{'dynamicongtime'});
 $last         = int($settings{'last'});
@@ -129,11 +123,9 @@ $state{'ongtime'}=$timer;
 if ($ongstate == STATE->{'ready'}) {
        print 'next frame: '.$frame."\n";
        
-       %default = read_data_file(DATA_DEFAULT_PATH());
-       %frame_data = read_data_file(
-               join_path(PATH_SEPARATOR(), DATA_PATH(), $frame)
-       );
-       # %goto_list = read_data_file(DATA_LIST_PATH());
+       %default = read_default();
+       %frame_data = read_frame_data($frame);
+       # %goto_list = read_goto());
        
        %new_state = %state;
        $new_state{'last'}   = $frame;
@@ -144,19 +136,13 @@ if ($ongstate == STATE->{'ready'}) {
        $new_state{'ongtime'}= $timer;
        
        if ($frame >= 1) {
-               %frame_1_data = read_data_file(
-                       join_path(PATH_SEPARATOR(), DATA_PATH(), $frame-1)
-               );
+               %frame_1_data = read_frame_data($frame-1);
        }
        if ($frame >= 2) {
-               %frame_2_data = read_data_file(
-                       join_path(PATH_SEPARATOR(), DATA_PATH(), $frame-2)
-               );
+               %frame_2_data = read_frame_data($frame-2);
        }
        if ($frame >= 3) {
-               %frame_3_data = read_data_file(
-                       join_path(PATH_SEPARATOR(), DATA_PATH(), $frame-3)
-               );
+               %frame_3_data = read_frame_data($frame-3);
        }
        
        $r = ong (
@@ -223,5 +209,5 @@ if ($ongstate == STATE->{'ready'}) {
                print "NO ONG\n\n";
        }
 }
-write_data_file($fh, \%state);
+write_state($fh, \%state);
 close ($fh);
index 4e29a569a81a6d99f76414906ee7a5eeef1f2b74..639097a9774708b42f646d866ccc3a58fe016bd0 100644 (file)
@@ -29,7 +29,7 @@ use Encode ('encode', 'decode');
 use botm_common (
        'HTTP_STATUS',
        'read_header_env', 'url_query_decode',
-       'read_data_file', 'write_data_file',
+       'write_data_file',
        'html_entity_encode_dec',
        'open_encoded',
        'join_path',
@@ -47,7 +47,11 @@ use bsta_lib (
        'print_html_body_start', 'print_html_body_end',
        'bb_to_html', 'eval_bb',
        'merge_settings',
-       'write_index', 'write_static_viewer_page'
+       '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     = /
@@ -55,8 +59,6 @@ use bsta_lib (
 ###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v
 ###PERL_CGI_WORDS_PATH:     CGI_WORDS_PATH     = /bsta/w
 
-###PERL_DATA_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/settings
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
 ###PERL_DATA_WORDS_PATH:    DATA_WORDS_PATH    = /botm/data/bsta/words/
 
 ###PERL_LOG_SPAM_PATH:      LOG_SPAM_PATH      = /botm/log/bsta/words_spam.log
@@ -96,8 +98,6 @@ my $remove = 0;
 my $post = 0;
 my $quote;
 my $words_data_path;
-my $post_data_path;
-my $last_post_data_path;
 my $index;
 my $page;
 my $ong_state;
@@ -144,8 +144,8 @@ if ($cgi{'i'} =~ /^.+$/) {
 }
 $password = get_password(\%cgi);
 
-%settings = read_data_file(DATA_SETTINGS_PATH());
-%state    = read_data_file(DATA_STATE_PATH());
+%settings = read_settings();
+%state    = read_state();
 $ong_state = int($state{'state'});
 $last_frame = int($state{'last'});
 
@@ -174,8 +174,7 @@ else {
 }
 
 if ($ID ne '') {
-       $post_data_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $ID);
-       %post_data = read_data_file($post_data_path);
+       %post_data = read_words($ID);
        if ($post_data{'frame'} ne '') {
                $frame = int($post_data{'frame'});
        }
@@ -205,12 +204,9 @@ unless (flock($fh, 2)) {
        exit output(0, HTTP_STATUS->{'internal_server_error'}, 'Failed locking data file.', 1);
 }
 
-%words_data = read_data_file(
+%words_data = read_words_list(
        $fh, # file
-       '',  # encoding
-       0,   # no header
        0,   # header only
-       1    # as list
 );
 
 @post_list = @{$words_data{'content'}};
@@ -307,14 +303,7 @@ if ($remove) {
        $words_data{'posts'} = scalar(@post_list);
        $words_data{'content'} = \@post_list;
        
-       $r = write_data_file(
-               $fh, # file 
-               \%words_data,
-               '',  # encoding
-               0,   # no header
-               0,   # header only
-               1    # as list
-       );
+       $r = write_words_list($fh, \%words_data);
        unless ($r) {
                close($fh);
                exit output(0, HTTP_STATUS->{'internal_server_error'}, 'Failed writing data file.');
@@ -346,8 +335,7 @@ if ($index eq '') {
        $page = int($index / COMMENT_PAGE_LENGTH());
        if ($index > 0) {
                $last_ID = $post_list[-1];
-               $last_post_data_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $last_ID);
-               %last_post_data = read_data_file($last_post_data_path);
+               %last_post_data = read_words($last_ID);
                if (
                        ($cgi{'username'} eq $last_post_data{'name'   }) &&
                        ($cgi{'words'   } eq $last_post_data{'content'})
@@ -364,8 +352,6 @@ if ($index eq '') {
 $words_data{'posts'} = scalar(@post_list);
 $words_data{'content'} = \@post_list;
 
-$post_data_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $ID);
-
 $post_data{'frame'} = $frame;
 $post_data{'name'} = $cgi{'username'};
 $post_data{'password'} = $cgi{'password'};
@@ -384,20 +370,13 @@ if ($post_data{'key'} eq '') {
 }
 $post_data{'content'} = $cgi{'words'};
 
-$r = write_data_file($post_data_path, \%post_data);
+$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_data_file(
-       $fh, # file 
-       \%words_data,
-       '',  # encoding
-       0,   # no header
-       0,   # header only
-       1    # as list
-);
+$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);
@@ -494,8 +473,7 @@ sub output {
                $content = $cgi{'words'};
        }
        elsif ($quote ne '') {
-               my $quote_data_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $quote);
-               my %quote_data = read_data_file($quote_data_path);
+               my %quote_data = read_words($quote);
                $content = '[quote="'.$quote_data{'name'}.'"]'.$quote_data{'content'}.'[/quote]';
        }
        elsif (($cgi{'edit'} ne '') || $remove) {
@@ -505,11 +483,11 @@ sub output {
                $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 $_password = html_entity_encode_dec($settings{'password'}, 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);
index a7ee374f33ac81e4d4eabe88778fcde40f384968..9aa95418b656d4ea255f9f5f1a9c0a324c495f65 100644 (file)
@@ -26,14 +26,16 @@ use Encode ('encode', 'decode');
 
 ###PERL_LIB: use lib /botm/lib/bsta
 use botm_common (
-       'read_data_file', 'write_data_file',
+       'write_data_file',
        'opendir_encoded', 'readdir_decoded', 'unlink_encoded',
        'join_path'
 );
 use bsta_lib (
        'STATE', 'INTF_STATE', 'CHAT_STATE',
        'write_index',
-       'merge_settings'
+       'merge_settings',
+       'get_page_file', 'get_frame_file',
+       'read_settings', 'read_default', 'read_frame_data', 'read_attachment', 'read_state'
 );
 
 binmode STDIN,  ':encoding(UTF-8)';
@@ -43,12 +45,9 @@ decode_argv();
 
 ###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
 
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta/
-###PERL_DATA_ATTACH_PATH:   DATA_ATTACH_PATH   = /botm/data/bsta/a
 ###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_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/state
 ###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/
@@ -69,7 +68,8 @@ my @remove_list;
 delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
 ###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
 
-%settings = read_data_file(DATA_SETTINGS_PATH());
+%settings = read_settings();
+%state    = read_state();
 unless (
        ($ARGV[0] ne '') && (
                ($ARGV[0] eq $settings{'password'}) ||
@@ -80,38 +80,22 @@ unless (
        exit 1;
 }
 
-$last_frame = int($settings{'last'});
-%default = read_data_file(DATA_DEFAULT_PATH());
+$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_data_file(
-               join_path(PATH_SEPARATOR(), DATA_PATH(), $frame)
-       );
-       %frame_data = merge_settings(\%default, \%frame_data);
+       my %frame_data = read_frame_data($frame, \%default);
        unless ($frame == 0) {
-               push @remove_list, (
-                       ($frame_data{'page'} ne '') ?
-                               $frame_data{'page'} :
-                               sprintf(
-                                       $settings{'frame'},
-                                       $frame, 'htm'
-                               )
-               );
+               push @remove_list, get_page_file($frame, \%frame_data, \%settings);
        }
-       push @remove_list, (
-               ($frame_data{'frame'} ne '') ?
-                       $frame_data{'frame'} :
-                       sprintf(
-                               $settings{'frame'},
-                               $frame, $frame_data{'ext'}
-                       )
-       );
+       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_data_file(DATA_ATTACH_PATH().$i);
+       %file_data = read_attachment($i);
        if ($file_data{'frame'} eq '') {
                last;
        }
index e9f74424f67cd1ac1f38588fc8f61786caaa1d51..8f13d1c479cddffd990816e7eff88ad924c91207 100644 (file)
@@ -88,5 +88,5 @@ page_length     : 16
 comment_page_length: 40
 
 story_credits: "BSTA" by Balthasar Szczepański
-intf_credits: Online interface © Balthasar Szczepański; AGPL 3 license
+intf_credits: Online interface v$_version © Balthasar Szczepański; AGPL 3 license
 source_url: http://bicyclesonthemoon.info/git-projects/?p=ott/bsta
index 67cbc4a5d38852110783cc763c1e6d71821fb034..a02554d98959dfe3f365996acc35b878782e8b7d 100644 (file)
@@ -88,5 +88,5 @@ page_length     : 16
 comment_page_length: 40
 
 story_credits: "BSTA" by Balthasar Szczepański
-intf_credits: Online interface © Balthasar Szczepański; AGPL 3 license
+intf_credits: Online interface v$_version © Balthasar Szczepański; AGPL 3 license
 source_url: http://bicyclesonthemoon.info/git-projects/?p=ott/bsta
index 5ee085f4b99b64783dbe31e9a6309bf3918d1a5d..40e8d9b614aac5b74151075345563c3a3bfe9a9c 100644 (file)
@@ -88,5 +88,5 @@ page_length     : 16
 comment_page_length: 4
 
 story_credits: "BSTA" by Balthasar Szczepański
-intf_credits: Online interface © Balthasar Szczepański; AGPL 3 license
+intf_credits: Online interface v$_version © Balthasar Szczepański; AGPL 3 license
 source_url: http://bicyclesonthemoon.info/git-projects/?p=ott/bsta
index fb52921332910f5b6305b6e37e8b9a90dec6f307..7d809c5eed413224fd69db6d2cb4b3f20d9500f8 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.0.0
+_version: 1.2.6
 
 _SHEBANG: #!$0
 
@@ -198,7 +198,7 @@ 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_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)
index a5f0c5efbd4e3f231efcc024d5390cc3a9aa4e00..8cfba90fa447128fd0229b08e492037186888b16 100644 (file)
@@ -26,23 +26,15 @@ use Encode ('encode', 'decode');
 
 ###PERL_LIB: use lib /botm/lib/bsta
 use botm_common (
-       'read_data_file',
-       'join_path'
 );
 use bsta_lib (
        'STATE',
        'ong',
-       'write_index', 'write_static_viewer_page', 'write_static_goto'
+       'write_index', 'write_static_viewer_page', 'write_static_goto',
+       'read_frame_data', 'read_default', 'read_words_list',
+       'read_settings', 'read_state'
 );
 
-###PERL_PATH_SEPARATOR:     PATH_SEPARATOR     = /
-
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta/
-###PERL_DATA_DEFAULT_PATH:  DATA_DEFAULT_PATH  = /botm/data/bsta/default
-###PERL_DATA_SETTINGS_PATH: DATA_SETTINGS_PATH = /botm/data/bsta/settings
-###PERL_DATA_STATE_PATH:    DATA_STATE_PATH    = /botm/data/bsta/state
-###PERL_DATA_WORDS_PATH:    DATA_WORDS_PATH    = /botm/data/bsta/words/
-
 binmode STDIN,  ':encoding(UTF-8)';
 binmode STDOUT, ':encoding(UTF-8)';
 binmode STDERR, ':encoding(UTF-8)';
@@ -51,9 +43,9 @@ decode_argv();
 my $time = time();
 srand ($time-$$);
 
-my %settings  = read_data_file(DATA_SETTINGS_PATH());
-my %default   = read_data_file(DATA_DEFAULT_PATH());
-my %state     = read_data_file(DATA_STATE_PATH());
+my %settings  = read_settings();
+my %default   = read_default();
+my %state     = read_state();
 my %all_frame_data = ();
 my %all_words_data = ();
 
@@ -173,9 +165,7 @@ sub get_frame_data {
                return $r;
        }
        
-       my %frame_data = read_data_file(
-               join_path(PATH_SEPARATOR(), DATA_PATH(), $f)
-       );
+       my %frame_data = read_frame_data($f);
        $all_frame_data{$f} = \%frame_data;
        return \%frame_data;
 }
@@ -197,15 +187,9 @@ sub get_words_data {
                return $r;
        }
        
-       my %frame_data = read_data_file(
-               join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $f),
-               '', # encoding,
-               0,  # no header
-               1,  # header only
-               1,  # as list; not relevant
-       );
-       $all_words_data{$f} = \%frame_data;
-       return \%frame_data;
+       my %words_data = read_words_list($f, 1);
+       $all_words_data{$f} = \%words_data;
+       return \%words_data;
 }
 
 sub make_static_page {
@@ -216,10 +200,7 @@ sub make_static_page {
        my $f = int($id);
        unless (
                ($f >= 0) && (
-                       ($f < $last_frame-1) || (
-                               ($ong_state >= STATE->{'ready'}) &&
-                               ($f <= $last_frame-1)
-                       ) || (
+                       ($f < $last_frame) || (
                                ($ong_state >= STATE->{'end'}) &&
                                ($f <= $last_frame)
                        )
index 280a0f9423057468cb4d6f455284bc4661103bcb..c7d74d9d4edb1401940671026c30cab5fe9a085f 100644 (file)
@@ -29,7 +29,6 @@ use Encode ('encode', 'decode');
 use botm_common (
        'HTTP_STATUS',
        'read_header_env',
-       'read_data_file', 'write_data_file',
        'url_query_decode',
        'join_path',
        'open_encoded', '_x_encoded',
@@ -41,8 +40,13 @@ use bsta_lib (
        'fail_method', 'fail_content_type', 'redirect',
        'get_remote_addr', 'get_frame', 'get_password',
        'merge_settings',
-       'print_viewer_page', 'write_index', 'write_static_goto',
-       'ong'
+       '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     = /
@@ -50,14 +54,7 @@ use bsta_lib (
 ###PERL_CGI_PATH:           CGI_PATH           = /bsta/
 ###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v
 
-###PERL_DATA_PATH:          DATA_PATH          = /botm/data/bsta/
-###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/
 
@@ -83,7 +80,6 @@ my %words_data;
 
 my $method;
 my $frame;
-my $frame_data_path;
 my $prev_frame_data_path;
 my $next_frame_data_path;
 my $password;
@@ -95,6 +91,7 @@ my $timer_unlocked;
 my $fh;
 my $show_command;
 my $ongtime;
+my $goto;
 my $text_mode;
 my $words_page;
 my $words_data_path;
@@ -130,12 +127,11 @@ $IP = get_remote_addr();
 $frame = get_frame(\%cgi);
 $password = get_password(\%cgi);
 
-%settings  = read_data_file(DATA_SETTINGS_PATH());
-%default   = read_data_file(DATA_DEFAULT_PATH());
+%settings  = read_settings();
+%default   = read_default();
 
 if ($frame >= 0) {
-       $frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
-       %frame_data= read_data_file($frame_data_path);
+       %frame_data= read_frame_data($frame);
 }
 
 $password_ok = ($password eq $settings{'password'});
@@ -144,14 +140,13 @@ $password_ok = ($password eq $settings{'password'});
 if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STATE_PATH())) {
        if (flock($fh, 2)) {
                
-               %state = read_data_file($fh);
+               %state = read_state($fh);
                
                if ($frame < 0) {
                        $frame = int($state{'last'}) + $frame +1;
                        if ($frame >= 0) {
                                $force_redirect = 1;
-                               $frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
-                               %frame_data = read_data_file($frame_data_path);
+                               %frame_data = read_frame_data($frame);
                        }
                }
                
@@ -178,18 +173,30 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STATE_PATH())) {
                                elsif ($state{'ip3'} eq '') {
                                        $new_state{'ip3'} = $IP;
                                        $new_state{'state'} = STATE->{'ready'};
-                                       write_static_goto(\%new_state, \%settings, '');
                                }
                                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_data_file($fh, \%new_state);
+                               write_state($fh, \%new_state);
                        }
                }
                elsif (
                        (int($state{'state'}) == STATE->{'inactive'}) &&
-                       ($frame == 1)
+                       ($frame == 1) &&
+                       (!$password_ok)
                ) {
                        # ready to activate?
                        # NOTE: at this point frame 0 is already ONGed.
@@ -197,8 +204,8 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STATE_PATH())) {
                        my $ong_time = int($settings{'firstongtime'});
                        my $r;
                        
-                       %story     = read_data_file(DATA_STORY_PATH());
-                       %goto_list = read_data_file(DATA_LIST_PATH());
+                       %story     = read_story();
+                       %goto_list = read_goto();
                        
                        if (
                                (int($story{'state'}) == INTF_STATE->{'>|'} ) &&
@@ -235,7 +242,7 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STATE_PATH())) {
                                        $r = write_static_goto(\%state, \%settings, \%goto_list);
                                }
                                if ($r) {
-                                       $r = write_data_file($fh, \%state);
+                                       $r = write_state($fh, \%state);
                                }
                                unless ($r) {
                                        # FAILED ONG! Story as if it was inactive!
@@ -269,16 +276,7 @@ if ($access) {
                        exit redirect($method, CGI_PATH(), HTTP_STATUS->{'see_other'});
                }
                elsif ($frame < int($state{'last'})) {
-                       my $page_file;
-                       if ($frame_data{'page'} ne '') {
-                               $page_file = $frame_data{'page'};
-                       }
-                       else {
-                               $page_file = sprintf(
-                                       $settings{'frame'},
-                                       $frame, 'htm'
-                               );
-                       }
+                       my $page_file = get_page_file($frame, \%frame_data, \%settings);
                        if (_x_encoded('-f',
                                join_path(PATH_SEPARATOR(), WWW_PATH() , $page_file)
                        )) {
@@ -296,6 +294,7 @@ if ($access) {
                        {'path' => $frame}
                );
                unless ($no_cgi) {
+                       delete $cgi{'f'}; # to avoid infinite loop
                        $redirect_url = merge_url(
                                {'path' => $redirect_url},
                                {'query' => \%cgi}
@@ -305,20 +304,17 @@ if ($access) {
        }
        
        if ($frame > 0) {
-               $prev_frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame-1);
-               %prev_frame_data = read_data_file($prev_frame_data_path);
+               %prev_frame_data = read_frame_data($frame-1, \%default);
        }
-       $next_frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame+1);
-       %next_frame_data = read_data_file($next_frame_data_path);
-       
-       %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);
+       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_data_file(DATA_NOACCESS_PATH());
-       %frame_data = merge_settings(\%default, \%frame_data);
+       %frame_data = read_noaccess(\%default);
 }
 
 $timer   = int($state{'nextong'}) - $time;
@@ -349,14 +345,11 @@ if($text_mode > TEXT_MODE->{'words'}) {
        $text_mode = TEXT_MODE->{'normal'};
 }
 $words_page = int($cgi{'i'});
+$goto = int($cgi{'g'});
 
-$words_data_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $frame);
-%words_data = read_data_file(
-       $words_data_path, # file
-       '', # encoding
-       0,  # no header
-       ($text_mode != TEXT_MODE->{'words'}), # header only
-       1,  # as list
+%words_data = read_words_list(
+       $frame,
+       ($text_mode != TEXT_MODE->{'words'})
 );
 
 if (!$access) {
@@ -379,7 +372,8 @@ print_viewer_page (
                'static'        => 0,
                'show_command'  => $show_command,
                'text_mode'     => $text_mode,
-               'words_page'    => $words_page
+               'words_page'    => $words_page,
+               'goto'          => $goto
        },
        \%state,
        \%settings,