1 # bsta_lib.pm is generated from bsta_lib.1.pm
5 # Copyright (C) 2016, 2017, 2019, 2020, 2022, 2023, 2024 Balthasar Szczepański
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 # TODO: BB & INFO indent
31 use Encode ('encode', 'decode');
33 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
35 ###PERL_EXPORT_VERSION: our $VERSION = 'x.x.x';
36 our @ISA = qw(Exporter);
39 'STATE', 'TEXT_MODE', 'INTF_STATE', 'CHAT_STATE', 'CHAT_ACTION',
41 'fail_method', 'fail_content_type', 'fail_open_file', 'fail_attachment', 'fail_500',
43 'get_remote_addr', 'get_id', 'get_frame', 'get_password',
45 'print_html_start', 'print_html_end',
46 'print_html_head_start', 'print_html_head_end',
47 'print_html_body_start', 'print_html_body_end',
51 'eval_bb', 'bb_to_bbcode', 'bb_to_html'
54 ###PERL_LIB: use lib /botm/lib/bsta
56 'url_query_decode', 'url_query_encode',
57 'url_decode', 'url_encode',
58 'html_entity_encode_dec',
61 'read_data_file', 'write_data_file',
63 'copy_encoded', 'open_encoded'
66 ###PERL_PATH_SEPARATOR: PATH_SEPARATOR = /
68 ###PERL_CGI_PATH: CGI_PATH = /bsta/
69 ###PERL_CGI_ATTACH_PATH: CGI_ATTACH_PATH = /bsta/a
70 ###PERL_CGI_2WORDS_PATH: CGI_2WORDS_PATH = /bsta/2words
71 ###PERL_CGI_BBCODE_PATH: CGI_BBCODE_PATH = /bsta/b
72 ###PERL_CGI_COIN_PATH: CGI_COIN_PATH = /bsta/coin
73 ###PERL_CGI_CSS_PATH: CGI_CSS_PATH = /bsta/bsta.css
74 ###PERL_CGI_FRAME_PATH: CGI_FRAME_PATH = /bsta/f
75 ###PERL_CGI_GOTO_PATH: CGI_GOTO_PATH = /bsta/g
76 ###PERL_CGI_INFO_PATH: CGI_INFO_PATH = /bsta/i
77 ###PERL_CGI_LOGO_PATH: CGI_LOGO_PATH = /bsta/botmlogo.png
78 ###PERL_CGI_TIMER_PATH: CGI_TIMER_PATH = /bsta/timer.js
79 ###PERL_CGI_VIEWER_PATH: CGI_VIEWER_PATH = /bsta/v
80 ###PERL_CGI_WORDS_PATH: CGI_WORDS_PATH = /bsta/w
82 ###PERL_DATA_PATH: DATA_PATH = /botm/data/bsta/
83 ###PERL_DATA_ATTACH_PATH: DATA_ATTACH_PATH = /botm/data/bsta/a
84 ###PERL_DATA_COIN_PATH: DATA_COIN_PATH = /botm/data/bsta/coincidence
85 ###PERL_DATA_DEFAULT_PATH: DATA_DEFAULT_PATH = /botm/data/bsta/default
86 ###PERL_DATA_LIST_PATH: DATA_LIST_PATH = /botm/data/bsta/list
87 ###PERL_DATA_NOACCESS_PATH: DATA_NOACCESS_PATH = /botm/data/bsta/noaccess
88 ###PERL_DATA_WORDS_PATH: DATA_WORDS_PATH = /botm/data/bsta/words/
90 ###PERL_WWW_PATH: WWW_PATH = /botm/www/
91 ###PERL_WWW_INDEX_PATH: WWW_INDEX_PATH = /botm/www/1190/bsta/index.htm
93 ###PERL_SCHEME: SCHEME = http
94 ###PERL_WEBSITE: WEBSITE = 1190.bicyclesonthemoon.info
95 ###PERL_WEBSITE_NAME: WEBSITE_NAME = Bicycles on the Moon
96 ###PERL_FAVICON_PATH: FAVICON_PATH = /img/favicon.png
98 ###PERL_COIN_DATE: COIN_DATE = 13-Nov-2016 22:15
99 ###PERL_INTF_DATE: INTF_DATE = 28-Sep-2016 20:34
101 ###PERL_STORY_CREDITS: STORY_CREDITS = "BSTA" by Balthasar Szczepański
102 ###PERL_INTF_CREDITS: INTF_CREDITS = Online interface © Balthasar Szczepański; AGPL 3 license
103 ###PERL_SOURCE_URL: SOURCE_URL = http://bicyclesonthemoon.info/git-projects/?p=ott/bsta
105 ###PERL_COMMENT_PAGE_LENGTH:COMMENT_PAGE_LENGTH= 16
107 use constant STATE => {
113 use constant INTF_STATE => {
126 use constant TEXT_MODE => {
132 use constant CHAT_STATE => {
137 use constant CHAT_ACTION => {
145 use constant tags_bbcode => {
152 'quote' => '[quote]',
153 'quote=' => '[quote="',
155 '/quote' => '[/quote]',
156 'ni' => '[color=#0057AF]',
158 'br' => '[color=#BB6622]',
160 'po' => '[color=#FF8800]',
171 '/list' => '[/list]',
175 '/?' => '[/unknown!]',
177 use constant tags_html => {
180 'fq' => '<div class="fq">',
182 'tq' => '<div class="tq">',
184 'quote' => '<div class="opomba"><div class="opomba_text">',
185 'quote=' => '<div class="opomba"><div class="opomba_info"><b>',
186 'quote/='=> '</b> wrote:</div><div class="opomba_text">',
187 '/quote' => '</div></div>',
188 'ni' => '<span class="ni">',
190 'br' => '<span class="br">',
192 'po' => '<span class="po">',
194 'url' => '<a href="#">',#think: how to add selfincluding?
195 'url=' => '<a href="',
201 'list=' => '<ol style="list-style-type: ',
202 'list=1' => 'decimal',
203 'list=A' => 'upper-alpha',
204 'list=a' => 'lower-alpha',
205 'list=I' => 'upper-roman',
206 'list=i' => 'lower-roman',
213 '/?' => '[/unknown!]',
217 # Function to return an error page
218 # arguments: 1 - header fields, 2 - page title, 3 - error message, 4 method
220 (my $header, my $title, my $message, my $method, my $hyperlink) = @_;
224 if($method eq 'HEAD') {
228 my $_title = html_entity_encode_dec($title , 1);
229 my $_message = html_entity_encode_dec($message , 1);
230 my $_hyperlink = html_entity_encode_dec($hyperlink, 1);
232 print "Content-type: text/html; charset=UTF-8\n\n";
234 print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
235 print ' <html lang="en">'."\n";
236 print ' <head>'."\n";
237 print ' <meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
239 print ' <title>'.$_title.'</title>'."\n";
241 print ' </head>'."\n";
242 print ' <body>'."\n";
244 print ' <h1>'.$_title.'</h1>'."\n";
246 if (($message ne '') || ($hyperlink ne '')) {
248 if ($message ne '') {
249 print ' '.$_message.($hyperlink ne '' ? '<br>' : '')."\n";
251 if ($hyperlink ne '') {
252 print ' <a href="'.$_hyperlink.'">'.$_hyperlink."</a>\n";
256 print ' </body>'."\n";
257 print '</html>'."\n";
261 (my $method, my $allowed) = @_;
263 my $header = "Status: 405 Method Not Allowed\n";
264 if ($allowed ne '') {
265 $header .= "Allow: $allowed\n";
269 "405 Method Not Allowed",
270 "The interface does not support the $method method.",
275 sub fail_content_type
277 (my $method, my $content_type) = @_;
280 "Status: 415 Unsupported Media Type\n",
281 "415 Unsupported Media Type",
282 "Unsupported Content-type: $content_type.",
289 (my $method, my $type, my $path) = @_;
292 "Status: 404 Not Found\n",
295 ($type ne '' ? $type : 'file').
296 ($path ne '' ? ': "'.$path.'"' : '').
304 (my $method, my $ID) = @_;
307 "Status: 404 Not Found\n",
309 "Attachment $ID not found.",
316 (my $method, my $text) = @_;
318 "Status: 500 Internal Server Error\n",
319 "500 Internal Server Error",
327 (my $method, my $uri, my $code) = @_;
334 $status = '301 Moved Permanently';
336 elsif ($code == 302) {
337 $status = '302 Found';
339 elsif ($code == 303) {
340 $status = '303 See Other';
342 elsif ($code == 307) {
343 $status = '307 Temporary Redirect';
345 elsif ($code == 308) {
346 $status = '308 Permanent Redirect';
349 $status = "$code Redirect";
352 "Status: $status\nLocation: $uri\n",
361 # function to obtain address of remote agent
362 sub get_remote_addr {
363 if ($ENV{'HTTP_X_FORWARDED_FOR'} =~ /^.+$/) {
366 elsif ($ENV{'REMOTE_ADDR'} =~ /^.+$/) {
374 # functions to get ID/number etc.
376 (my $cgi, my $default, my $cgi_name) = @_;
377 if ($default eq '') {
380 if ($cgi_name eq '') {
384 if ($cgi->{$cgi_name} =~ /^.+$/) {
387 elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) {
391 return int($default);
395 # function to obtain frame number
397 (my $cgi, my $default) = @_;
398 return get_id($cgi, $default, 'f');
401 # function to obtain password
405 if ($cgi->{'p'} =~ /^.+$/) {
417 foreach my $settings (@_) {
418 foreach my $ind (keys %$settings) {
419 $final_settings{$ind} = $settings->{$ind};
422 return %final_settings;
427 # different & simpler implementation than in post library
431 #analyse bbcode text to build tag tree
432 #TODO make [/*] optional!
434 (my $bb, my $printdebug) = @_;
447 $bbtree{"_.name" } = "ht";
448 $bbtree{"_.value" } = '';
449 $bbtree{"_.type" } = "tag";
450 $bbtree{"_.count" } = 0;
451 $bbtree{"_.closed"} = 0;
452 $debug .= debug($printdebug,
454 "<!--GENERATING BBCODE TREE:\n".
455 '[_]automatic tag: [ht]'."\n"
459 my $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
461 if($bb =~ m/\[(\/?)([A-Za-z]+|\*)(=([^\[\]]*))?\]/g) {
468 if ($tag_value =~ /^"(.*)"$/) {
472 if ($pre_text ne '') {
473 $debug .= debug($printdebug, "[$new_ind]text: $pre_text\n");
474 $bbtree{$new_ind.'.type' } = 'text';
475 $bbtree{$new_ind.'.value'} = $pre_text;
476 $bbtree{ $ind.'.count'}+= 1;
477 $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
480 if($tag_name =~ /^(fq|tq|quote|br|ni|po|url|i|list|\*)$/) {
481 if ($tag_end ne '') {
483 ($tag_name ne $bbtree{$ind.'.name'}) ||
486 $debug .= debug($printdebug, "[$new_ind]text: $tag\n");
487 $bbtree{$new_ind.'.type' } = 'text';
488 $bbtree{$new_ind.'.value'} = $tag;
489 $bbtree{ $ind.'.count'}+= 1;
490 # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
493 $debug .= debug($printdebug, "[$new_ind]tag: $tag\n");
494 $bbtree{$new_ind.'.type' } = 'tag';
495 $bbtree{$new_ind.'.name' } = '/'.$tag_name;
496 $bbtree{$new_ind.'.value' } = $tag_value;
497 $bbtree{ $ind.'.count' }+= 1;
498 $bbtree{ $ind.'.closed'} = 1;
500 $ind =~ s/\.[0-9]+$//;
501 # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
506 $debug .= debug($printdebug, "[$new_ind]tag: $tag\n");
507 $bbtree{$new_ind.'.type' } = 'tag';
508 $bbtree{$new_ind.'.name' } = $tag_name;
509 $bbtree{$new_ind.'.value' } = $tag_value;
510 $bbtree{$new_ind.'.count' } = 0;
511 $bbtree{$new_ind.'.closed'} = 0;
512 $bbtree{ $ind.'.count' }+= 1;
515 # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
519 $debug .= debug($printdebug, "[$new_ind]text: $tag\n");
520 $bbtree{$new_ind.'.type' } = 'text';
521 $bbtree{$new_ind.'.value'} = $tag;
522 $bbtree{ $ind.'.count'}+= 1;
523 # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
527 $debug .= debug($printdebug, "[$new_ind]text: $bb\n");
528 $bbtree{$new_ind.'.type' } = 'text';
529 $bbtree{$new_ind.'.value'} = $bb;
530 $bbtree{ $ind.'.count'}+= 1;
531 # $new_ind = $ind.'.'.$bbtree{$ind.'.count'};
535 my $final_ind = '_.'.$bbtree{"_.count"};
536 $debug .= debug($printdebug, "[$final_ind]automatic tag: [/ht]\n -->\n");
537 $bbtree{$final_ind.'.type' } = "tag";
538 $bbtree{$final_ind.'.name' } = '/ht';
539 $bbtree{ '_.count' }+= 1;
540 $bbtree{ '_.closed'} = 1;
542 return ($debug, %bbtree);
545 #convert tag tree to final text
547 (my $printdebug, my $debug, my $lang, my $bbtree) = @_;
552 my $tags = ($lang eq 'html') ? tags_html : tags_bbcode;
553 my $escape = ($lang eq 'html');
555 # $debug .= debug($printdebug, "\n****\n");
556 # foreach my $iiii (keys %tags) {
557 # $debug .= debug($printdebug, $iiii.'='.$tags->{$iiii}."\n");
559 # $debug .= debug($printdebug, "****\n");
564 $debug .= debug($printdebug, "\n<!--PROCESSING BBCODE TREE:\n");
566 while ($level >= 0) {
568 $debug .= debug($printdebug, "[$level:$ind:".int($bbtree->{$ind.'.count'})."]");
570 if ($bbtree->{$ind.'.type'} eq 'text') {
571 my $text = $bbtree->{$ind.'.value'};
572 $debug .= debug($printdebug, "text: ".$text);
573 $out .= $escape ? html_encode_line($text) : $text;
578 elsif ($bbtree->{$ind.'.type'} eq 'tag') {
579 my $name = $bbtree->{$ind.'.name'};
581 if ($name =~ /^\//) {
582 $debug .= debug($printdebug, "tag: [$name]");
584 $indd =~ s/\.([0-9]+)$//;
585 if (exists($tags->{$name.'='}) && ($bbtree->{$indd.'.value'} ne '')) {
586 $out .= $tags->{$name.'='};
588 elsif (exists($tags->{$name})) {
589 $out .= $tags->{$name};
592 $out .= $tags->{'/?'};
593 $debug .= debug($printdebug, "[unknown!]");
596 $ind =~ s/\.([0-9]+)$//;
598 $debug .= debug($printdebug, "[<]");
609 my $value = $bbtree->{$ind.'.value'};
610 if($bbtree->{$ind.'.closed'} ne '') {
611 $debug .= debug($printdebug, "tag: [$name]");
613 if (exists($tags->{$name.'='}) && ($value ne '')) {
614 if (exists($tags->{$name.'='.$value})) {
617 $tags->{$name.'='.$value} .
623 ($escape ? html_entity_encode_dec($value, 1) : $value) .
627 elsif (exists($tags->{$name})) {
628 $out .= $tags->{$name};
631 $out .= $out.$tags->{'?'};
632 $debug .= debug($printdebug, "[unknown!]");
636 $debug .= debug($printdebug, "unclosed tag: [$name]");
637 my $text = $name . (($value ne '') ? ('='.$value) : '');
638 $out .= '['.($escape ? html_encode_line($text) : $text).']';
640 if ($bbtree->{$ind.'.count'} > 0) {
643 $debug .= debug($printdebug, "[>]");
652 $debug .= debug($printdebug, "unknown thing: ".$bbtree->{$ind.'.type'});
653 #should not occur with a correct bbtree
654 #unless unimplemented
655 $ind =~ s/\.([0-9]+)$//;
657 $debug .= debug($printdebug, "[<ui]");
666 if ($goto_next ne '') {
668 $ind =~ s/\.([0-9]+)$//;
670 if (($i < $bbtree->{$ind.'.count'}) and ($1 ne '')){
677 # should not occur with a correct bbtree
678 $debug .= debug($printdebug, "[<$goto_next]");
681 } while ($level >= 0);}
684 $debug .= debug($printdebug, "[>$level:$ind]\n");
687 $debug .= debug($printdebug, "-->\n");
688 return ($debug, $out);
693 (my $bb, my $printdebug) = @_;
698 ($debug, %bbtree) = bbtree($bb, $printdebug);
699 ($debug, $ht) = convtree ($printdebug, $debug, 'html', \%bbtree);
706 (my $bb, my $printdebug) = @_;
711 ($debug, %bbtree) = bbtree($bb, $printdebug);
712 ($debug, $ht) = convtree ($printdebug, $debug, 'bb', \%bbtree);
718 (my $bb, my $full_url) = @_;
723 my $base_url = $full_url ?
724 {'scheme' => SCHEME(), 'host' => WEBSITE()} :
727 while ($bb =~ m/###([^#;]*);/g) {
732 if ($value =~ /^att&([0-9]+)$/) {
735 {'path' => CGI_ATTACH_PATH()},
739 elsif ($value =~ /^vw&([0-9]+)$/) {
742 {'path' => CGI_VIEWER_PATH()},
746 elsif ($value =~ /^fr&([0-9]+)$/) {
749 {'path' => CGI_FRAME_PATH()},
756 $bb = $before . $value . $after;
762 sub html_encode_line {
763 (my $text, my $non_ascii, my $all) = @_;
767 $text =~ s/\r\n/\n/gs;
770 while ($text ne '') {
771 $ind = index($text, "\n");
773 $html .= html_entity_encode_dec(substr($text, 0, $ind), $non_ascii, $all)."<br>\n";
774 $text = substr($text, $ind+1);
778 $html .= html_entity_encode_dec($text, 1);
786 (my $print, my $text) = @_;
796 sub print_html_start {
798 print $fh '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
799 print $fh '<html lang="en">'."\n";
804 print $fh '</html>'."\n";
807 sub print_html_head_start {
809 print $fh ' <head>'."\n";
810 print $fh ' <meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
811 print $fh ' <link rel="icon" type="image/png" href="'.html_entity_encode_dec(FAVICON_PATH(),1).'">'."\n";
812 print $fh ' <link rel="stylesheet" href="'.html_entity_encode_dec(CGI_CSS_PATH(),1).'">'."\n";
815 sub print_html_head_end {
817 print $fh ' </head>'."\n";
820 sub print_html_body_start {
822 print $fh ' <body>'."\n";
823 print $fh ' <a href="/"><img id="botmlogo" src="'.html_entity_encode_dec(CGI_LOGO_PATH(),1).'" alt="'.html_entity_encode_dec(WEBSITE(),1).'"></a>'."\n";
824 print $fh ' <div id="all">'."\n";
827 sub print_html_body_end {
828 (my $fh, my $hide_credits) = @_;
829 print $fh ' </div>'."\n";
830 unless ($hide_credits) {
831 print $fh ' <p>'."\n";
832 print $fh ' '.html_entity_encode_dec(STORY_CREDITS(),1).'<br>'."\n";
833 print $fh ' '.html_entity_encode_dec(INTF_CREDITS(),1).'<br>'."\n";
834 print $fh ' <a href="'.html_entity_encode_dec(SOURCE_URL(),1).'" class="cz">source code</a>'."\n";
835 print $fh ' </p>'."\n";
837 print $fh ' <a href="/" class="cz">'.html_entity_encode_dec(WEBSITE(),1).'</a>'."\n";
838 print $fh ' </body>'."\n";
841 sub print_html_data {
842 (my $fh, my $data) = @_;
844 foreach my $key (keys %$data) {
845 unless ($key eq 'content') {
846 my $val = $data->{$key};
847 $val =~ s/(\r)?\n/\n /gs; # does the space make sense in HTML anyway?
848 print $fh html_encode_line("$key: $val\n", 1);
851 print $fh html_encode_line("\n".$data->{'content'});
854 # TODO: previous page preload?
855 sub print_viewer_page {
867 my $launch = $context->{'launch'};
868 my $access = $context->{'access'};
869 my $password_ok = $context->{'password_ok'};
870 my $static = $context->{'static'};
872 my $frame = int($context->{'frame'});
873 my $text_mode = int($context->{'text_mode'});
874 my $timer_unlocked = int($context->{'timer_unlocked'});
875 my $timer = int($context->{'timer'});
876 # my $words_page = int($context->{'words_page'});
878 # my $prev_frame = $frame - 1;
879 my $next_frame = $frame + 1;
881 my $story = $settings->{'story'};
882 my $title = $frame_data->{'title'};
883 my $command = ($frame_data->{'command'} ne '') ?
884 $frame_data->{'command'} :
885 $next_frame_data->{'title'};
887 my $last_frame = int($state->{'last'});
888 my $ong_state = int($state->{'state'});
890 my $width = int($frame_data->{'width'});
891 my $height = int($frame_data->{'height'});
892 my $frame_type = $frame_data->{'frametype'};
894 my $timer_color_h = (($timer_unlocked >= 1) || ($ong_state >= STATE->{'ready'})) ? 'br' : 'ni';
895 my $timer_color_m = (($timer_unlocked >= 2) || ($ong_state >= STATE->{'ready'})) ? 'br' : 'ni';
896 my $timer_color_s = (($timer_unlocked >= 3) || ($ong_state >= STATE->{'ready'})) ? 'br' : 'ni';
903 (($timer >= 0) && ($frame == 0))
905 $timer_s = sprintf('%02d', $timer % 60);
906 $timer_h = int($timer / 60);
907 $timer_m = sprintf('%02d', $timer_h % 60);
908 $timer_h = sprintf('%02d', $timer_h / 60);
910 elsif (($timer >= -15) && ($ong_state >= STATE->{'ready'})) {
921 my $words_posts = int($words_data->{'posts'});
922 my $words_link_text = 'Words'.(($words_posts > 0) ? "[$words_posts]" : '');
924 my $prev_available = (($frame > 0) && $access);
925 my $next_available = ($launch || $password_ok || ($next_frame <= $last_frame));
926 my $prefetch_next = (
928 ($next_frame < $last_frame) || ( # avoid unseen trigger!
929 ($next_frame <= $last_frame) &&
930 ($ong_state >= STATE->{'ready'})
937 ($frame == $last_frame) && (
938 ($ong_state == STATE->{'waiting'}) ||
939 ($ong_state == STATE->{'ready'})
947 ($frame < $last_frame) || (
948 ($ong_state >= STATE->{'ready'}) &&
949 $context->{'show_command'}
952 my $show_command_link = ($next_available || (!$access));
953 my $show_command_cursor = ((!$next_available) || ($command eq ''));
954 my $show_words = ($password_ok || ($access && !$launch));
956 my $frame_indirect = !(
958 ($frame <= $last_frame) &&
959 ($ong_state > STATE->{'inactive'})
962 my $nextframe_indirect = !($next_frame <= $last_frame);
966 my $base_url = CGI_PATH();
967 my $goto_url = CGI_GOTO_PATH();
968 my $timer_url = CGI_TIMER_PATH();
969 my $viewer_full_url = merge_url(
970 {'scheme' => SCHEME(), 'host' => WEBSITE()},
971 {'path' => CGI_VIEWER_PATH()},
974 my $viewer_url = merge_url(
975 {'path' => CGI_VIEWER_PATH()},
978 my $viewer_0_url = merge_url(
979 {'path' => CGI_VIEWER_PATH()},
982 my $viewer_prev_url = merge_url(
983 {'path' => CGI_VIEWER_PATH()},
986 my $viewer_next_url = merge_url(
987 {'path' => CGI_VIEWER_PATH()},
988 {'path' => $next_frame}
990 my $viewer_last_url = merge_url(
991 {'path' => CGI_VIEWER_PATH()},
992 {'path' => ($static ? -1 : $last_frame)}
994 my $bbcode_url = ($text_mode == TEXT_MODE->{'bb'}) ?
996 {'path' => CGI_BBCODE_PATH()},
1003 'b' => TEXT_MODE->{'bb'}
1008 my $info_url = ($text_mode == TEXT_MODE->{'info'}) ?
1010 {'path' => CGI_INFO_PATH()},
1017 'b' => TEXT_MODE->{'info'}
1022 my $words_url = merge_url (
1026 'b' => TEXT_MODE->{'words'}
1034 my $frame_normal_url;
1036 if ($frame_data->{'frame'} ne '') {
1037 $frame_file = $frame_data->{'frame'};
1040 $frame_file = sprintf(
1041 $settings->{'frame'},
1042 $frame, $frame_data->{'ext'}
1045 $frame_normal_url = merge_url(
1046 {'path' => CGI_PATH()},
1047 {'path' => $frame_file}
1049 $frame_url = $frame_indirect ?
1051 {'path' => CGI_FRAME_PATH()},
1055 $frame_full_url = merge_url(
1056 {'scheme' => SCHEME(), 'host' => WEBSITE()},
1057 {'path' => $frame_normal_url}
1059 if ($nextframe_indirect) {
1060 $frame_next_url = merge_url(
1061 {'path' => CGI_FRAME_PATH()},
1062 {'path' => $next_frame}
1065 elsif ($next_frame_data->{'frame'} ne '') {
1066 $frame_next_url = merge_url(
1067 {'path' => CGI_PATH()},
1068 {'path' => $next_frame_data->{'frame'}}
1072 $frame_next_url = merge_url(CGI_PATH(), sprintf(
1073 $settings->{'frame'}, $next_frame, $next_frame_data->{'ext'}
1078 $password_query = url_query_encode({'p', $settings->{'password'}});
1079 $goto_url = merge_url($goto_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1080 $info_url = merge_url($info_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1081 $words_url = merge_url($words_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1082 $bbcode_url = merge_url($bbcode_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1083 $viewer_url = merge_url($viewer_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1084 $viewer_0_url = merge_url($viewer_0_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1085 $viewer_prev_url = merge_url($viewer_prev_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1086 $viewer_next_url = merge_url($viewer_next_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1087 $viewer_last_url = merge_url($viewer_last_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1088 if ($frame_indirect) {
1089 $frame_url = merge_url($frame_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1091 if ($nextframe_indirect) {
1092 $frame_next_url= merge_url($frame_next_url , {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1095 my $_base_url = html_entity_encode_dec($base_url , 1);
1096 my $_goto_url = html_entity_encode_dec($goto_url , 1);
1097 my $_info_url = html_entity_encode_dec($info_url , 1);
1098 my $_words_url = html_entity_encode_dec($words_url , 1);
1099 my $_bbcode_url = html_entity_encode_dec($bbcode_url , 1);
1100 my $_timer_url = html_entity_encode_dec($timer_url , 1);
1101 my $_viewer_full_url = html_entity_encode_dec($viewer_full_url, 1);
1102 my $_viewer_url = html_entity_encode_dec($viewer_url , 1);
1103 my $_viewer_0_url = html_entity_encode_dec($viewer_0_url , 1);
1104 my $_viewer_prev_url = html_entity_encode_dec($viewer_prev_url, 1);
1105 my $_viewer_next_url = html_entity_encode_dec($viewer_next_url, 1);
1106 my $_viewer_last_url = html_entity_encode_dec($viewer_last_url, 1);
1107 my $_frame_url = html_entity_encode_dec($frame_url , 1);
1108 my $_frame_next_url = html_entity_encode_dec($frame_next_url , 1);
1109 my $_frame_full_url = html_entity_encode_dec($frame_full_url , 1);
1111 my $_story = html_entity_encode_dec($story , 1);
1112 my $_title = html_entity_encode_dec($title , 1);
1113 my $_command = html_entity_encode_dec($command , 1);
1114 my $_frame_type = html_entity_encode_dec($frame_type, 1);
1116 my $_website_name = html_entity_encode_dec(WEBSITE_NAME(), 1);
1118 if ($text_mode == TEXT_MODE->{'info'}) {
1119 if ($show_command) {
1120 $frame_data->{'command'} = $command;
1122 if ($context->{'access'}) {
1123 $frame_data->{'frame'} = $frame_file;
1127 # everything determined, now start generating
1131 unless (seek($fh, 0, 0)) {
1132 #don't actually fail here
1136 unless (open_encoded($fh, ">:encoding(UTF-8)", $file)) {
1141 print_html_start($fh);
1142 print_html_head_start($fh);
1144 print $fh ' <title>'.$_title;
1145 if ($story ne $title) {
1146 print $fh ' • '.$_story;
1148 print $fh ' • '.$_website_name.'</title>'."\n";
1149 print $fh ' <link rel="index" href="'.$_goto_url.'">'."\n";
1150 print $fh ' <link rel="start" href="'.$_viewer_0_url.'">'."\n";
1151 if ($prev_available) {
1152 print $fh ' <link rel="prev" href="'.$_viewer_prev_url.'">'."\n";
1154 if ($next_available) {
1155 print $fh ' <link rel="next" href="'.$_viewer_next_url.'">'."\n";
1156 if ($prefetch_next) {
1157 print $fh ' <link rel="prefetch" href="'.$_viewer_next_url.'">'."\n";
1158 print $fh ' <link rel="prefetch" href="'.$_frame_next_url.'">'."\n";
1162 print $fh ' <script src="'.$_timer_url.'"></script>'."\n";
1165 print_html_head_end($fh);
1166 print_html_body_start($fh);
1168 print $fh ' <div id="inst" class="ins">'."\n";
1170 print $fh ' <div id="title">'."\n";
1171 print $fh ' <h1 id="titletext">'.$_title.'</h1>'."\n";
1172 print $fh ' </div>'."\n";
1174 print $fh ' </div>'."\n";
1175 print $fh ' <div id="framespace">'."\n";
1177 print $fh ' <img src="'.$_frame_url.'" id="frame" class="'.$_frame_type.'" alt="'.$frame.'" title="'.$_title.'" width="'.$width.'" height="'.$height.'">'."\n";
1179 print $fh ' </div>'."\n";
1180 print $fh ' <div id="insb" class="ins">'."\n";
1182 if ($text_mode == TEXT_MODE->{'info'}) {
1183 print $fh ' <div id="chat">'."\n";
1185 print_html_data($fh, $frame_data);
1187 print $fh ' </div>'."\n";
1189 elsif ($text_mode == TEXT_MODE->{'bb'}) {
1190 print $fh ' <div id="chat">'."\n";
1192 print $fh '[quote][center][size=200]'.$_title.'[/size]<br>'."\n";
1193 print $fh '[url='.$_viewer_full_url.'][img]'.$_frame_full_url.'[/img][/url][/center]<br>'."\n";
1194 print $fh html_encode_line(bb_to_bbcode(eval_bb($frame_data->{'content'}, 1)));
1195 print $fh '[/quote]'."\n";
1197 print $fh ' </div>'."\n";
1199 elsif ($frame_data->{'content'} ne '') {
1200 print $fh ' <div id="undertext">'."\n";
1201 print $fh bb_to_html(eval_bb($frame_data->{'content'}), 0)."\n";
1202 print $fh ' </div>'."\n";
1205 print $fh ' <div id="command">'."\n";
1208 print $fh ' <span id="timer">';
1209 print $fh '[<span id="ongh" class="hv '.$timer_color_h.'">'.$timer_h.'</span>';
1210 print $fh ':<span id="ongm" class="hv '.$timer_color_m.'">'.$timer_m.'</span>';
1211 print $fh ':<span id="ongs" class="hv '.$timer_color_s.'">'.$timer_s.'</span>]';
1212 print $fh '</span><br>'."\n";
1215 if ($show_command_link) {
1216 print $fh '<a href="'.($access ? $_viewer_next_url : $_viewer_last_url).'">';
1218 if ($show_command) {
1219 print $fh $_command;
1221 if ($show_command_cursor) {
1222 print $fh '<span class="inp">_</span>';
1224 if ($show_command_link) {
1228 print $fh " </div>\n";
1230 print $fh ' <div id="underlinks">'."\n ";
1232 unless (($frame == 0) && $static) {
1233 print $fh '<a href="'.$_base_url.'">Once again</a> | ';
1235 if ($prev_available) {
1236 print $fh '<a href="'.$_viewer_prev_url.'">Before</a> | ';
1238 unless ($frame == $last_frame) {
1239 print $fh '<a href="'.$_viewer_last_url.'">Now</a> | ';
1241 print $fh '<a href="'.$_goto_url.'">GOTO</a>'."\n";
1242 print $fh ' <span style="float: right;">'."\n ";
1243 if ($text_mode == TEXT_MODE->{'normal'}) {
1245 print $fh '<a href="'.$_words_url.'">'.$words_link_text.'</a> | ';
1249 print $fh '<a href="'.$_viewer_url.'">Without</a> | ';
1251 print $fh '<a href="'.$_info_url.'">Info</a> | ';
1252 print $fh '<a href="'.$_bbcode_url.'">BB</a>';
1253 print $fh "\n </span>\n";
1255 print $fh " </div>\n";
1256 print $fh " </div>\n";
1258 if (($text_mode == TEXT_MODE->{'words'}) && $show_words) {
1259 print_comments($fh, $context, $settings, $words_data);
1262 print_html_body_end($fh, $ong_state == STATE->{'inactive'});
1263 print_html_end($fh);
1266 unless (ref($file)) {
1270 truncate ($fh , tell($fh));
1276 sub print_comments {
1277 (my $fh, my $context, my $settings, my $words_data) = @_;
1279 my $password_ok = $context->{'password_ok'};
1280 my $frame = int($context->{'frame'});
1281 my $page = int($context->{'words_page'});
1282 my $post_count = int($words_data->{'posts'});
1283 my $id_start = $page * COMMENT_PAGE_LENGTH();
1284 my $id_stop = $id_start + COMMENT_PAGE_LENGTH();
1285 my $older = ($page > 0) ? ($page-1) : '';
1288 if ($id_stop >= $post_count) {
1289 $id_stop = $post_count;
1296 my $words_url = merge_url(
1297 {'path' => CGI_VIEWER_PATH()},
1300 'query' => {'b' => TEXT_MODE->{'words'}},
1303 my $older_url = merge_url(
1306 'query' => {'i' => $page-1},
1307 'fragment' => 'insw',
1311 my $newer_url = merge_url(
1314 'query' => {'i' => $page+1},
1315 'fragment' => 'insw',
1321 $password_query = url_query_encode({'p', $settings->{'password'}});
1322 $older_url = merge_url($older_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1323 $newer_url = merge_url($older_url, {'query' => $password_query, 'append_query' => 1, 'preserve_fragment' => 1});
1326 my $_post_url = html_entity_encode_dec(CGI_WORDS_PATH(), 1);
1327 my $_password = html_entity_encode_dec($settings->{'password'}, 1);
1328 my $_older_url = html_entity_encode_dec($older_url, 1);
1329 my $_newer_url = html_entity_encode_dec($newer_url, 1);
1331 if (($older ne '') || ($newer ne '')) {
1332 $links .= ' <div class="underlinks">'."\n";
1335 $links .= '<a href="'.$_older_url.'">Older</a>'
1337 if (($older ne '') && ($newer ne '')) {
1341 $links .= '<a href="'.$_newer_url.'">Newer</a>';
1344 $links .= ' </div>'."\n";
1347 print $fh ' <div class="space"></div>'."\n";
1348 print $fh ' <div id="insw" class="ins">'."\n";
1350 print $fh ' <div class="title" id="wordstitle">'."\n";
1351 print $fh ' <h1 class="titletext" id="wordstitletext">Words</h1>'."\n";
1352 print $fh ' </div>'."\n";
1358 print $fh ' <div class="undertext" id="words">'."\n";
1360 if ($post_count > 0) {
1361 for (my $i=$id_start; $i<$id_stop; ++$i) {
1362 my $ID = $words_data->{'content'}->[$i];
1363 my $post_path = join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), $ID);
1364 my %post_data = read_data_file($post_path);
1366 my $post_time = int($post_data{'posttime'});
1367 my $edit_time = int($post_data{'edittime'});
1372 if ($post_time != 0) {
1373 my @time_tab = gmtime($post_time);
1374 $post_time_text = sprintf(
1375 '%04d.%02d.%02d %02d:%02d UTC',
1383 if (($edit_time !=0) && ($edit_time != $post_time)) {
1384 my @time_tab = gmtime($edit_time);
1385 $edit_time_text = sprintf(
1386 '%04d.%02d.%02d %02d:%02d UTC',
1394 my $quote_url = merge_url(
1395 {'path' => CGI_WORDS_PATH()},
1400 'p' => ($password_ok ? $settings->{'password'} : '')
1404 my $edit_url = merge_url(
1405 {'path' => CGI_WORDS_PATH()},
1410 'key' => $post_data{'key'},
1411 'username' => $post_data{'name'},
1412 'p' => ($password_ok ? $settings->{'password'} : '')
1416 my $remove_url = merge_url(
1417 {'path' => CGI_WORDS_PATH()},
1422 'key' => $post_data{'key'},
1423 'username' => $post_data{'name'},
1424 'p' => ($password_ok ? $settings->{'password'} : '')
1429 my $_ID = html_entity_encode_dec($ID, 1);
1430 my $_name = html_entity_encode_dec($post_data{'name'}, 1);
1431 my $_quote_url = html_entity_encode_dec($quote_url, 1);
1432 my $_edit_url = html_entity_encode_dec($edit_url, 1);
1433 my $_remove_url = html_entity_encode_dec($remove_url, 1);
1435 print $fh ' <div id="'.$_ID.'"class="opomba">'."\n";
1436 print $fh ' <div class="opomba_info">'."\n";
1437 print $fh ' <a href="#'.$_ID.'" class="bi hu">'.$i.': '.$_name;
1438 if ($post_time_text ne '') {
1439 print $fh ' • '.$post_time_text;
1441 if ($edit_time_text ne '') {
1442 print $fh ' • '.$edit_time_text;
1444 print $fh '</a>'."\n";
1445 print $fh ' <div class="pr">'."\n";
1446 print $fh ' <a href="'.$_quote_url.'" class="bi hu">quote</a> | <a href="'.$_edit_url.'" class="bi hu">edit</a> | <a href="'.$_remove_url.'" class="bi hu">remove</a>'."\n";
1447 print $fh ' </div>'."\n";
1448 print $fh ' </div>'."\n";
1449 print $fh ' <div class="opomba_text">'."\n";
1450 print $fh bb_to_html(eval_bb($post_data{'content'}), 0)."\n";
1451 print $fh ' </div>'."\n";
1452 print $fh ' </div>'."\n";
1453 print $fh ' <br>'."\n";
1457 print $fh ' <form method="post" action="'.$_post_url.'">'."\n";
1458 print $fh ' <b>Your words:</b>'."\n";
1459 print $fh ' <textarea class="inta" name="words" rows="4"></textarea>'."\n";
1460 print $fh ' <table cellpadding="0" cellspacing="0" border="0"><tr>'."\n";
1461 print $fh ' <td><b>Your name: </b></td>'."\n";
1462 print $fh ' <td><input class="intx" type="text" name="username" value=""></td>'."\n";
1463 print $fh ' <td></td>'."\n";
1464 print $fh ' </tr><tr>'."\n";
1465 print $fh ' <td><b>Optional password: </b></td>'."\n";
1466 print $fh ' <td><input class="intx" type="password" name="password" value=""></td>'."\n";
1467 print $fh ' <td>(if you want to edit later)</td>'."\n";
1468 print $fh ' </tr><tr>'."\n";
1469 print $fh ' <td><b>Leave this empty: </b></td>'."\n";
1470 print $fh ' <td><input class="intx" type="text" name="password2" value=""></td>'."\n";
1471 print $fh ' <td>'."\n";
1472 print $fh ' <input class="inbt" type="submit" name="post" value="Send">'."\n";
1473 print $fh ' <input class="inbt" type="submit" name="preview" value="Preview">'."\n";
1474 print $fh ' </td>'."\n";
1475 print $fh ' </tr></table>'."\n";
1476 print $fh ' <input type="hidden" name="f" value="'.$frame.'">'."\n";
1478 print $fh ' <input type="hidden" name="p" value="'.$_password.'">'."\n";
1480 print $fh ' </form>'."\n";
1481 print $fh ' </div>'."\n";
1487 print $fh ' </div>'."\n";
1500 my $ong_state = int($state->{'state'});
1502 unless (open_encoded($fh, ">:encoding(UTF-8)", WWW_INDEX_PATH())) {
1506 # normal running story
1507 if ($ong_state > STATE->{'inactive'}) {
1508 my %frame_data = read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), 0));
1509 my %next_frame_data= read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), 1));
1510 my %default = read_data_file(DATA_DEFAULT_PATH());
1511 my %words_data = read_data_file(
1512 join_path(PATH_SEPARATOR(), DATA_WORDS_PATH(), 0),
1519 %frame_data = merge_settings(\%default, \%frame_data);
1520 %next_frame_data= merge_settings(\%default, \%next_frame_data);
1522 $r = print_viewer_page(
1529 'timer_unlocked' => 3, # not relevant
1530 'timer' => 0, # not relevant
1532 'show_command' => 1,
1533 'text_mode' => TEXT_MODE->{'normal'},
1534 'words_page' => 0 # not relevant
1543 # no conditions met, pretend a normal Apache2 index
1544 elsif ($pass != 1) {
1545 my $index_of = CGI_PATH;
1546 $index_of =~ s/\/$//g;
1548 my $_index_of = html_entity_encode_dec($index_of , 1);
1549 my $_2words_date = html_entity_encode_dec(INTF_DATE(), 1);
1550 my $_coin_date = html_entity_encode_dec(COIN_DATE(), 1);
1551 my $_website = html_entity_encode_dec(WEBSITE() , 1);
1553 print_html_start ($fh);
1554 print $fh ' <head>'."\n";
1555 print $fh ' <meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
1556 print $fh ' <title>Index of '.$_index_of.'</title>'."\n";
1557 print $fh ' </head>'."\n";
1558 print $fh ' <body>'."\n";
1559 print $fh ' <h1>Index of '.$_index_of.'</h1>'."\n";
1560 print $fh ' <table>'."\n";
1561 print $fh ' <tr>'."\n";
1562 print $fh ' <th><img src="/icons/blank.gif" alt="[ICO]"></th>'."\n";
1563 print $fh ' <th><a href="?C=N;O=D">Name</a></th>'."\n";
1564 print $fh ' <th><a href="?C=M;O=A">Last modified</a></th>'."\n";
1565 print $fh ' <th><a href="?C=S;O=A">Size</a></th>'."\n";
1566 print $fh ' <th><a href="?C=D;O=A">Description</a></th>'."\n";
1567 print $fh ' </tr><tr>'."\n";
1568 print $fh ' <th colspan="5"><hr></th>'."\n";
1569 print $fh ' </tr><tr>'."\n";
1570 print $fh ' <td valign="top"><img src="/icons/back.gif" alt="[DIR]"></td>'."\n";
1571 print $fh ' <td><a href="/">Parent Directory</a></td>'."\n";
1572 print $fh ' <td> </td>'."\n";
1573 print $fh ' <td align="right"> - </td>'."\n";
1574 print $fh ' <td> </td>'."\n";
1575 print $fh ' </tr><tr>'."\n";
1576 print $fh ' <td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td>'."\n";
1577 print $fh ' <td><a href="2words/">2words/</a></td>'."\n";
1578 print $fh ' <td align="right">'.$_2words_date.' </td>'."\n";
1579 print $fh ' <td align="right"> - </td><td> </td>'."\n";
1580 print $fh ' </tr><tr>'."\n";
1581 print $fh ' <td valign="top"><img src="/icons/folder.gif" alt="[DIR]"></td>'."\n";
1582 print $fh ' <td><a href="coin/">coin/</a></td>'."\n";
1583 print $fh ' <td align="right">'.$_coin_date.' </td>'."\n";
1584 print $fh ' <td align="right"> - </td><td> Coincidence </td>'."\n";
1585 print $fh ' </tr><tr>'."\n";
1586 print $fh ' <th colspan="5"><hr></th>'."\n";
1587 print $fh ' </tr>'."\n";
1588 print $fh ' </table>'."\n";
1589 print $fh ' <address>Apache/2.2.22 (Debian) Server at '.$_website.' Port 80</address>'."\n";
1590 print $fh ' </body>'."\n";
1591 print_html_end ($fh);
1595 my %frame_data = read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), 0));
1596 my %next_frame_data= read_data_file(join_path(PATH_SEPARATOR(), DATA_PATH(), 1));
1597 my %default = read_data_file(DATA_DEFAULT_PATH());
1598 my %coin_data = read_data_file(DATA_COIN_PATH());
1600 %frame_data = merge_settings(\%default, \%frame_data);
1601 %next_frame_data= merge_settings(\%default, \%next_frame_data);
1603 if (($mode == INTF_STATE->{'>'}) && $pause) {
1604 $r = print_viewer_page(
1611 'timer_unlocked' => 3,
1614 'show_command' => 1,
1615 'text_mode' => TEXT_MODE->{'normal'},
1616 'words_page' => 0 # not relevant
1622 {'posts' => 0} # words_data
1627 my $index_of = CGI_PATH;
1628 $index_of =~ s/\/$//g;
1632 my $show_parent_dir = 0;
1634 my $show_folders = 0;
1636 my $timer_color = 'ni';
1637 if ($mode == INTF_STATE->{'>'}) {
1638 $title = $settings->{'story'}; # $frame_data{'title'} ?
1639 $frame_file = 'intf-tr.gif';
1643 elsif ($mode == INTF_STATE->{'<<'}) {
1644 $title = 'Index of';
1645 $frame_file = 'intf-ll.gif';
1646 $show_parent_dir = 1;
1649 $timer_color = 'br';
1651 elsif ($mode == INTF_STATE->{'>>'}) {
1652 $title = 'Index of';
1653 $frame_file = 'intf-pp.gif';
1654 $show_parent_dir = 1;
1660 $title = 'Index of '.$index_of;
1661 $frame_file = 'intf-kw.gif';
1662 $show_parent_dir = 1;
1665 my $frame_url = merge_url(
1666 {'path' => CGI_PATH()},
1667 {'path' => $frame_file}
1669 my $coin_server = $coin_data{'server'};
1671 my $_title = html_entity_encode_dec($title , 1);
1672 my $_website_name = html_entity_encode_dec(WEBSITE_NAME() , 1);
1673 my $_frame_url = html_entity_encode_dec($frame_url , 1);
1674 my $_undertext = html_entity_encode_dec($undertext , 1);
1675 my $_2words_date = html_entity_encode_dec(INTF_DATE() , 1);
1676 my $_coin_date = html_entity_encode_dec(COIN_DATE() , 1);
1677 my $_coin_server = html_entity_encode_dec($coin_server , 1);
1678 my $_2words_url = html_entity_encode_dec(CGI_2WORDS_PATH(), 1);
1679 my $_coin_url = html_entity_encode_dec(CGI_COIN_PATH() , 1);
1681 print_html_start($fh);
1682 print_html_head_start($fh);
1684 print $fh ' <title>'.$_title.' • '.$_website_name.'</title>'."\n";
1686 print_html_head_end($fh);
1687 print_html_body_start($fh);
1689 print $fh ' <div id="inst" class="ins">'."\n";
1691 print $fh ' <div id="title">'."\n";
1692 print $fh ' <h1 id="titletext">'.$_title.'</h1>'."\n";
1693 print $fh ' </div>'."\n";
1695 print $fh ' </div>'."\n";
1696 print $fh ' <div id="framespace">'."\n";
1698 print $fh ' <img src="'.$_frame_url.'" id="frame" alt="0">'."\n"; # title="'.$_title.'"
1700 print $fh ' </div>'."\n";
1701 print $fh ' <div id="insb" class="ins">'."\n";
1703 print $fh ' <div id="undertext">'."\n";
1705 if ($show_parent_dir) {
1706 print $fh ' <img src="/icons/back.gif" alt="[DIR]"> <a href="..">Parent Directory</a><br>'."\n";
1708 if ($show_folders) {
1709 print $fh ' <img src="/icons/folder.gif" alt="[DIR]"> <a href="'.$_2words_url.'">2words/</a> '.$_2words_date.' - <br>'."\n";
1710 print $fh ' <img src="/icons/folder.gif" alt="[DIR]"> <a href="'.$_coin_url.'">coin/</a> '.$_coin_date.' - '.$_coin_server."\n";
1713 print $fh ' <img src="/icons/folder.gif" alt="[DIR]"> <a href="'.$_2words_url.'">yyyyb/</a>'."\n";
1715 if ($undertext ne '') {
1716 print $fh ' '.$_undertext."\n";
1719 print $fh ' </div>'."\n";
1722 print $fh ' <div id="command">'."\n";
1724 print $fh ' [<span id="ongh" class="'.$timer_color.'">'.$timer.'</span>';
1725 print $fh ':<span id="ongm" class="'.$timer_color.'">'.$timer.'</span>';
1726 print $fh ':<span id="ongs" class="'.$timer_color.'">'.$timer.'</span>]<br>'."\n";
1728 if ($undertext ne '') {
1729 print $fh '><a href="'.$_2words_url.'">'.$_undertext.'</a><span class="inp">_</span>'."\n";
1731 print $fh " </div>\n";
1734 print $fh " </div>\n";
1736 print_html_body_end($fh, $ong_state == STATE->{'inactive'});
1737 print_html_end($fh);
1744 # ONG the frame + attachment & stiff. NOT update state file.
1747 my $ID, my $ongtime, my $timer, my $update, my $print,
1748 my $settings_ref, my $default_ref, my $data_ref, my $goto_ref
1754 my $frame_data_path;
1762 my %frame_full_data;
1765 if ($ongtime eq '') {
1772 elsif ($ID eq 'c') {
1804 %settings = (ref ($settings_ref)) ?
1806 read_data_file(DATA_SETTINGS_PATH());
1807 %default = (ref ($default_ref)) ?
1809 read_data_file(DATA_DEFAULT_PATH());
1810 $frame_data_path = $cfrt ?
1811 DATA_NOACCESS_PATH() :
1812 join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
1813 %frame_data = (ref ($data_ref)) ?
1815 read_data_file($frame_data_path);
1816 %frame_full_data = merge_settings(\%default, \%frame_data);
1818 ($frame_full_data{'frame'} ne '') ?
1819 $frame_full_data{'frame'} :
1822 $frame, $frame_full_data{'ext'}
1827 %goto_list = (ref ($goto_ref)) ?
1829 read_data_file(DATA_LIST_PATH());
1830 for (my $i=0; ;$i+=1) {
1831 my %file_data = read_data_file(DATA_ATTACH_PATH().$i);
1832 if ($file_data{'frame'} eq '') {
1835 if (int($file_data{'frame'}) != $frame) {
1838 if ($file_data{'content'} ne '') {
1841 unshift @files, $file_data{'filename'};
1845 ($frame_full_data{'ongtime'} eq '')
1847 $frame_data {'ongtime'} = $ongtime;
1848 $frame_full_data{'ongtime'} = $ongtime;
1854 ($frame_full_data{'timer'} eq '')
1857 $frame_data{'timer'} = int($timer);
1861 $r = write_data_file($frame_data_path, \%frame_data);
1863 print STDERR "fail writing $frame_data_path\n";
1865 print "write frame data fail\n";
1870 $goto_list{'title-' .$frame} = $frame_full_data{'title'};
1871 $goto_list{'ongtime-'.$frame} = $frame_full_data{'ongtime'};
1872 $r = write_data_file(DATA_LIST_PATH(), \%goto_list);
1874 print STDERR "fail writing ".DATA_LIST_PATH()."\n";
1876 print "write GOTO list fail\n";
1882 foreach my $file (@files) {
1883 $in_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $file);
1884 $out_path = join_path(PATH_SEPARATOR(), WWW_PATH() , $file);
1886 print $in_path.' -> '.$out_path;
1888 $r = copy_encoded($in_path, $out_path);
1890 print (($r) ? " OK\n" : " FAIL\n");
1893 print STDERR "fail copy $in_path $out_path\n";