# TODO: FQ NBSP ?
# TODO: DEBUG
-# TODO: timer JS
# TODO: BB & INFO indent
package bsta_lib;
'print_html_body_start', 'print_html_body_end',
'print_viewer_page', 'print_goto',
'write_index', 'write_static_viewer_page', 'write_static_goto',
+ 'get_frame_file', 'get_page_file',
+ 'read_frame_data', 'write_frame_data', 'read_default', 'read_noaccess',
+ 'read_state', 'write_state',
+ 'read_words_list', 'write_words_list', 'read_words', 'write_words',
+ 'read_story', 'write_story',
+ 'read_goto', 'write_goto',
+ 'read_chat', 'write_chat',
+ 'read_settings', 'read_attachment', 'read_coincidence',
'ong',
'eval_bb', 'bb_to_bbcode', 'bb_to_html'
);
###PERL_CGI_ATTACH_PATH: CGI_ATTACH_PATH = /bsta/a
###PERL_CGI_2WORDS_PATH: CGI_2WORDS_PATH = /bsta/2words
###PERL_CGI_BBCODE_PATH: CGI_BBCODE_PATH = /bsta/b
+###PERL_DATA_CHAT_PATH: DATA_CHAT_PATH = /botm/data/bsta/chat
###PERL_CGI_COIN_PATH: CGI_COIN_PATH = /bsta/coin
###PERL_CGI_CSS_PATH: CGI_CSS_PATH = /bsta/bsta.css
###PERL_CGI_FRAME_PATH: CGI_FRAME_PATH = /bsta/f
###PERL_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/
$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) {
my $password_ok = $context->{'password_ok'};
my $static = $context->{'static'};
+ my $goto = int($context->{'goto'});
my $frame = int($context->{'frame'});
my $text_mode = int($context->{'text_mode'});
my $timer_unlocked = int($context->{'timer_unlocked'});
my $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()},
{'path' => CGI_VIEWER_PATH()},
{'path' => ($static ? -1 : $last_frame)}
);
+ my $goto_url = ($goto) ?
+ CGI_GOTO_PATH() :
+ merge_url(
+ {'path' => $viewer_url},
+ {
+ 'query' => {
+ 'g' => 1,
+ 'b' => $text_mode
+ },
+ 'fragment' => 'goto'
+ }
+ );
+
unless ($password_ok) {
my $page_file;
$viewer_0_url = $base_url;
$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)
)) {
}
}
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)
)) {
);
}
}
- if (_x_encoded('-f',WWW_GOTO_PATH())) {
+ if (
+ $goto &&
+ (_x_encoded('-f',WWW_GOTO_PATH()))
+ ) {
$goto_url = CGI_LIST_PATH();
}
}
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}
{'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'}});
$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);
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);
}
}
}
}
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> | ';
}
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) {
$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);
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'});
# 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,
{
'static' => 1,
'show_command' => 1,
'text_mode' => TEXT_MODE->{'normal'},
- 'words_page' => 0 # not relevant
+ 'words_page' => 0, # not relevant
+ 'goto' => 0
},
$state,
$settings,
}
# 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(
'static' => 1,
'show_command' => 1,
'text_mode' => TEXT_MODE->{'normal'},
- 'words_page' => 0 # not relevant
+ 'words_page' => 0, # not relevant
+ 'goto' => 0
},
$state,
$settings,
%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'});
%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(
'show_command' => 1,
'text_mode' => TEXT_MODE->{'normal'},
'words_page' => 0, # not relevant
+ 'goto' => 0
},
\%state,
\%settings,
%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(),
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;
}
$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) {
}
$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) {
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