From e73eca24ab14104b4184ae9949ab9a24af3ca551 Mon Sep 17 00:00:00 2001
From: b <rowerynaksiezycu@gmail.com>
Date: Sat, 27 Jan 2024 21:26:56 +0000
Subject: [PATCH] viewer redirects to static page; info includes static page;
 fixed directory scanning for comment reset & old logs

---
 bsta_lib.1.pm |  17 +++++++-
 info.1.pl     |  16 ++++++-
 oldlogs.1.pl  |   2 +-
 ong.1.pl      |   2 +-
 reset.1.pl    |   2 +-
 viewer.1.pl   | 113 ++++++++++++++++++++++++++++++++++++--------------
 6 files changed, 116 insertions(+), 36 deletions(-)

diff --git a/bsta_lib.1.pm b/bsta_lib.1.pm
index 5629795..262d852 100644
--- a/bsta_lib.1.pm
+++ b/bsta_lib.1.pm
@@ -354,6 +354,7 @@ sub redirect
 	if ($code eq '') {
 		$code = HTTP_STATUS->{'found'};
 	}
+	# https://insanecoding.blogspot.com/2014/02/http-308-incompetence-expected.html
 	# 301 Moved Permanently
 	# 302 Found
 	# 303 See Other
@@ -1215,9 +1216,23 @@ sub print_viewer_page {
 		if ($show_command) {
 			$frame_data->{'command'} = $command;
 		}
-		if ($context->{'access'}) {
+		if ($access) {
 			$frame_data->{'frame'} = $frame_file;
 		}
+		if ($frame_data->{'page'} eq '') {
+			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'
+				);
+			}
+		}
 	}
 	
 	# everything determined, now start generating
diff --git a/info.1.pl b/info.1.pl
index fc23668..d5c0ec8 100644
--- a/info.1.pl
+++ b/info.1.pl
@@ -242,11 +242,23 @@ else {
 	}
 }
 if (
-	($info_data{'frame'} eq '') &&
 	($attachment eq '') &&
 	($words eq '')
 ) {
-	$info_data{'frame'} = sprintf($settings{'frame'}, $frame, $info_data{'ext'});
+	if ($info_data{'frame'} eq '') {
+		$info_data{'frame'} = sprintf($settings{'frame'}, $frame, $info_data{'ext'});
+	}
+	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');
+		}
+	}
 }
 
 print "Content-type: text/plain; charset=UTF-8\n";
diff --git a/oldlogs.1.pl b/oldlogs.1.pl
index 7a0959f..dbb4421 100644
--- a/oldlogs.1.pl
+++ b/oldlogs.1.pl
@@ -55,7 +55,7 @@ my $logs_total        = ($ARGV[2] =~ /^[0-9]+$/) ? int($&) : LOGS_TOTAL();
 my $logs_uncompressed = ($ARGV[3] =~ /^[0-9]+$/) ? int($&) : LOGS_UNCOMPRESSED();
 
 if (opendir_encoded(my $dir, $log_path)) {
-	while (my $file_name = readdir_decoded($dir)) {
+	while (defined (my $file_name = readdir_decoded($dir))) {
 		if ($file_name !~ /\.log$/) {
 			next;
 		}
diff --git a/ong.1.pl b/ong.1.pl
index aec693a..8c243c0 100644
--- a/ong.1.pl
+++ b/ong.1.pl
@@ -182,7 +182,7 @@ else {
 						{
 							print 'static page '.($frame-2);
 							$r = write_static_viewer_page(
-								$frame-1, # frame ID
+								$frame-2, # frame ID
 								\%state,
 								\%settings,
 								\%default,
diff --git a/reset.1.pl b/reset.1.pl
index 9e2dfcc..c43e368 100644
--- a/reset.1.pl
+++ b/reset.1.pl
@@ -110,7 +110,7 @@ write_index(
 );
 
 if (opendir_encoded(my $dir, DATA_WORDS_PATH())) {
-	while (my $file_name = readdir_decoded($dir)) {
+	while (defined (my $file_name = readdir_decoded($dir))) {
 		if ($file_name !~ /^[0-9]+$/) {
 			next;
 		}
diff --git a/viewer.1.pl b/viewer.1.pl
index 33c90ed..4e8cc0e 100644
--- a/viewer.1.pl
+++ b/viewer.1.pl
@@ -32,12 +32,13 @@ use botm_common (
 	'read_data_file', 'write_data_file',
 	'url_query_decode',
 	'join_path',
-	'open_encoded',
+	'open_encoded', '_x_encoded',
 	'http_header_status',
+	'merge_url'
 );
 use bsta_lib (
 	'STATE', 'TEXT_MODE', 'INTF_STATE',
-	'fail_method', 'fail_content_type',
+	'fail_method', 'fail_content_type', 'redirect',
 	'get_remote_addr', 'get_frame', 'get_password',
 	'merge_settings',
 	'print_viewer_page', 'write_index',
@@ -46,6 +47,9 @@ use bsta_lib (
 
 ###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
@@ -54,6 +58,8 @@ use bsta_lib (
 ###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/
+
 binmode STDIN,  ':encoding(UTF-8)';
 binmode STDOUT, ':encoding(UTF-8)';
 binmode STDERR, ':encoding(UTF-8)';
@@ -91,6 +97,8 @@ my $ongtime;
 my $text_mode;
 my $words_page;
 my $words_data_path;
+my $no_cgi;
+my $force_redirect;
 
 delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
 ###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;
@@ -115,6 +123,7 @@ if ($method eq 'POST') {
 		exit fail_content_type($method, $http{'content-type'});
 	}
 }
+$no_cgi = (scalar (keys %cgi) == 0);
 
 $IP = get_remote_addr();
 $frame = get_frame(\%cgi);
@@ -138,8 +147,11 @@ if (open_encoded($fh, "+<:encoding(UTF-8)", DATA_STATE_PATH())) {
 		
 		if ($frame < 0) {
 			$frame = int($state{'last'}) + $frame +1;
-			$frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
-			%frame_data = read_data_file($frame_data_path);
+			if ($frame >= 0) {
+				$force_redirect = 1;
+				$frame_data_path = join_path(PATH_SEPARATOR(), DATA_PATH(), $frame);
+				%frame_data = read_data_file($frame_data_path);
+			}
 		}
 		
 		if (
@@ -235,6 +247,73 @@ else {
 	$state{'state'} = STATE->{'inactive'};
 }
 
+$access = (
+	$password_ok || (
+		(int($state{'state'}) >= STATE->{'waiting'}) &&
+		($frame <= int($state{'last'})) &&
+		($frame >= 0)
+	)
+);
+
+if ($access) {
+	if ($no_cgi) {
+		# no CGI - static page is OK
+		if ($frame == 0) {
+			exit redirect($method, CGI_PATH(), HTTP_STATUS->{'see_other'});
+		}
+		elsif ($frame < int($state{'last'})) {
+			my $page_file;
+			if ($frame_data{'page'} ne '') {
+				$page_file = $frame_data{'page'};
+			}
+			else {
+				$page_file = sprintf(
+					$settings{'frame'},
+					$frame, 'htm'
+				);
+			}
+			if (_x_encoded('-f',
+				join_path(PATH_SEPARATOR(), WWW_PATH() , $page_file)
+			)) {
+				my $static_url = merge_url(
+					{'path' => CGI_PATH()},
+					{'path' => $page_file}
+				);
+				exit redirect($method, $static_url, HTTP_STATUS->{'see_other'});
+			}
+		}
+	}
+	if ($force_redirect) {
+		my $redirect_url = merge_url(
+			{'path' => CGI_VIEWER_PATH()},
+			{'path' => $frame}
+		);
+		unless ($no_cgi) {
+			$redirect_url = merge_url(
+				{'path' => $redirect_url},
+				{'query' => \%cgi}
+			);
+		}
+		exit redirect($method, $redirect_url, HTTP_STATUS->{'see_other'});
+	}
+	
+	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);
+	}
+	$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 {
+	# replace frame data with fail state replacement
+	%frame_data = read_data_file(DATA_NOACCESS_PATH());
+	%frame_data = merge_settings(\%default, \%frame_data);
+}
+
 $timer   = int($state{'nextong'}) - $time;
 $ongtime = int($state{'ongtime'});
 if($ongtime == 0) {
@@ -258,32 +337,6 @@ else {
 	$timer_unlocked = 0;
 }
 
-if (
-		$password_ok || (
-			(int($state{'state'}) >= STATE->{'waiting'}) &&
-			($frame <= int($state{'last'})) &&
-			($frame >= 0)
-		)
-	) {
-	$access = 1;
-	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);
-	}
-	$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 {
-	$access = 0;
-	# replace frame data with fail state replacement
-	%frame_data = read_data_file(DATA_NOACCESS_PATH());
-	%frame_data = merge_settings(\%default, \%frame_data);
-}
-
 $text_mode = int($cgi{'b'});
 if($text_mode > TEXT_MODE->{'words'}) {
 	$text_mode = TEXT_MODE->{'normal'};
-- 
2.30.2