###RUN_PERL: #!/usr/bin/perl

# /bsta/v
# viewer is generated from viewer.1.pl.
#
# The viewer interface
#
# Copyright (C) 2016-2017, 2019-2020, 2023  Balthasar Szczepański
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

use strict;
#use warnings;
###PERL_LIB: use lib /botm/lib/bsta
use bsta_lib qw(failpage gethttpheader getcgi entityencode readdatafile writedatafile printdatafileht urlencode bb2ht bb2bb linehtml);
use File::Copy;

###PERL_CGI_PATH:           CGI_PATH           = /bsta/
###PERL_CGI_ATTACH_PATH:    CGI_ATTACH_PATH    = /bsta/a
###PERL_CGI_BBCODE_PATH:    CGI_BBCODE_PATH    = /bsta/b
###PERL_CGI_CSS_PATH:       CGI_CSS_PATH       = /bsta/bsta.css
###PERL_CGI_FRAME_PATH:     CGI_FRAME_PATH     = /bsta/f
###PERL_CGI_GOTO_PATH:      CGI_GOTO_PATH      = /bsta/g
###PERL_CGI_INFO_PATH:      CGI_INFO_PATH      = /bsta/i
###PERL_CGI_LOGO_PATH:      CGI_LOGO_PATH      = /bsta/botmlogo.png
###PERL_CGI_TIMER_PATH:     CGI_TIMER_PATH     = /bsta/timer.js
###PERL_CGI_VIEWER_PATH:    CGI_VIEWER_PATH    = /bsta/v

###PERL_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_WWW_PATH:           WWW_PATH           = /botm/www/1190/bsta/
###PERL_WWW_INDEX_PATH:     WWW_INDEX_PATH     = /botm/www/1190/bsta/index.htm

###PERL_WEBSITE:            WEBSITE            = 1190.bicyclesonthemoon.info
###PERL_WEBSITE_NAME:       WEBSITE_NAME       = Bicycles on the Moon
###PERL_FAVICON_PATH:       FAVICON_PATH       = /img/favicon.png

my %http;
my %cgi;
my %framedata;
my %nextframedata;
my %default;
my %settings;
my %state;
my %newstate;
my %gotolist;

my $time = time();
srand ($time-$$);

my $method;
my $frame;
my $password;
my $passwordOK;
my $IP;
my $access;
my $seconds;
my $minutes;
my $hours;
my $statefile;
my $showcommand;
my $ongtime;
my $textmode;

delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
###PERL_SET_PATH: $ENV{'PATH'} = /usr/local/bin:/usr/bin:/bin;

if ($ENV{'REQUEST_METHOD'} =~ /^(HEAD|GET|POST)$/) {
	$method=$1;
}
else{
	exit failpage("Status: 405 Method Not Allowed\nAllow: GET, POST, HEAD\n","405 Method Not Allowed","The interface does not support the $ENV{'REQUEST_METHOD'} method.",$method);
}

%http = gethttpheader (\%ENV);
%cgi = getcgi($ENV{'QUERY_STRING'});

if ($method eq 'POST') {
	if ($http{'content-type'} eq 'application/x-www-form-urlencoded') {
		my %cgipost=getcgi( <STDIN> );
		foreach my $ind (keys %cgipost) {
			$cgi{$ind}=$cgipost{$ind};
		}
	}
	# multipart not supported
	else{
		exit failpage("Status: 415 Unsupported Media Type\n","415 Unsupported Media Type","Unsupported Content-type: $http{'content-type'}.");
	}
}

if ($ENV{'HTTP_X_FORWARDED_FOR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) {
	$IP=$1;
}
elsif ($ENV{'REMOTE_ADDR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) {
	$IP=$1;
}
else {
	$IP='0.0.0.0';
}

if ($cgi{'f'} =~ /^(.+)$/) {
	$frame=int($1);
}
elsif ($ENV{'PATH_INFO'} =~ /^\/(.+)$/) {
	$frame=int($1);
}
else {
	$frame = 0;
}

if ($cgi{'p'} =~ /^(.+)$/) {
	$password=$1;
}
else {
	$password='';
}
# print "Content-type: text/plain\n\n";

%settings=readdatafile(DATA_SETTINGS_PATH);
%default=readdatafile(DATA_DEFAULT_PATH);
%framedata=readdatafile(DATA_PATH.$frame);
if($password eq $settings{'password'}){
	$passwordOK = 1;
}
else{
	$passwordOK = 0;
}

if (open ($statefile,"+<",DATA_STATE_PATH)){
	if (flock($statefile,2)) {
		
		%state=readdatafile($statefile);
		
		if($frame<0) {
			$frame = int($state{'last'}) + $frame +1;
			%framedata=readdatafile(DATA_PATH.$frame);
		}
		
		if(int($state{'state'})==1 && $frame == int($state{'last'}) && $method ne 'HEAD' && !$passwordOK){
			my %newstate=%state;
			if($state{'ip1'} ne $IP) {
				if ($state{'ip1'} eq '') {
					$newstate{'ip1'} = $IP;
					writedatafile($statefile,%newstate);
				}
				elsif($state{'ip2'} ne $IP) {
					if ($state{'ip2'} eq '') {
						$newstate{'ip2'} = $IP;
						writedatafile($statefile,%newstate);
					}
					else {
						$newstate{'state'}=2;
						$newstate{'ip3'} = $IP;
						writedatafile($statefile,%newstate);
					}
				}
			}
		}
		elsif(int($state{'state'})==0 && $frame == 1) {
			my %story;
			my $inpath;
			my $outpath;
			
			%story = readdatafile(DATA_STORY_PATH);
			%gotolist=readdatafile(DATA_LIST_PATH);
			if(int($story{'state'}) == 17 && int($story{'pass'}) == 1) {
				#ACTIVATE!
				
				$framedata{'ongtime'} = $time;
				writedatafile(DATA_PATH.$frame,%framedata);
				$state{'state'} = 1;
				$state{'last'} = 1;
				$state {'ip1'} = '0.0.0.0';
				$state {'ip2'} = '0.0.0.0';
				$state {'ip3'} = '';
				$state {'nextong'} = (int($time / 3600) + int($settings{'firstongtime'})) * 3600 ;
				$state{'ongtime'} = int($settings{'firstongtime'});
				
				unless(defined($framedata{'ext'})){
					$framedata{'ext'}=$default{'ext'};
				}
				
				$inpath = DATA_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
				$outpath = WWW_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
				
				$gotolist{'title-1'}=$framedata{'title'};
				$gotolist{'ongtime-1'}=$framedata{'ongtime'};
				
				if(copy ($inpath, $outpath)) {
					writeindex(WWW_INDEX_PATH);
					writedatafile($statefile,%state);
					writedatafile(DATA_LIST_PATH,%gotolist);
				}
				else {
					$state{'state'} = 0;
				}
			}
		}
	}
	else {
		$state{'state'} = 0;
	}
	close ($statefile);
}
else {
	$state{'state'} = 0;
}

%nextframedata=readdatafile(DATA_PATH.($frame+1));
foreach my $ind (keys %default) {
	unless(defined($framedata{$ind})){
		$framedata{$ind}=$default{$ind};
	}
	unless(defined($nextframedata{$ind})){
		$nextframedata{$ind}=$default{$ind};
	}
}

$hours=int($state{'nextong'})-$time;
$ongtime=int($state{'ongtime'});
if($ongtime == 0) {
	$ongtime=int($settings{'ongtime'})
}

$showcommand = ($hours < ($ongtime*3600/3));
if($hours>0){
	$seconds = sprintf('%02d',$hours % 60);
	$hours = int($hours/60);
	$minutes = sprintf('%02d',$hours % 60);
	$hours = sprintf('%02d',int($hours/60));
}
elsif(($hours>=-15) && (int($state{'state'}) == 2)){
	$seconds='NG';
	$minutes='00';
	$hours='00';
}
else{
	$seconds='EE';
	$minutes='EE';
	$hours='EE';
}


if ($passwordOK || (int($state{'state'}) >= 1 && $frame <= int($state{'last'}) && $frame >= 0)) {
	$access=1;
}
else {
	$access=0;
	%framedata = readdatafile(DATA_NOACCESS_PATH);
	foreach my $ind (keys %default) {
		unless(defined($framedata{$ind})){
			$framedata{$ind}=$default{$ind};
		}
	}
}

$textmode = int($cgi{'b'});
if($textmode > 2) {
	$textmode = 0;
}

# print "Content-type: text/plain\n\n";
# print 'frame='.$frame."\n";
# print 'password='.$password."\n";
# print 'passwordOK='.$passwordOK."\n";
# print 'access='.$access."\n";
# print "\n>>>ENV<<<\n\n";
# foreach my $ind (keys %ENV) {
	# print $ind.'='.$ENV{$ind}."\n";
# }
# print "\n>>>HTTP<<<\n\n";
# foreach my $ind (keys %http) {
	# print $ind.': '.$http{$ind}."\n";
# }
# print "\n>>>CGI<<<\n\n";
# foreach my $ind (keys %cgi) {
	# print $ind.'='.$cgi{$ind}."\n";
# }
# print "\n>>>FRAMEDATA<<<\n\n";
# foreach my $ind (keys %framedata) {
	# print $ind.': '.$framedata{$ind}."\n";
# }
# print "\n>>>NEXTFRAMEDATA<<<\n\n";
# foreach my $ind (keys %nextframedata) {
	# print $ind.': '.$nextframedata{$ind}."\n";
# }
# print "\n>>>SETTINGS<<<\n\n";
# foreach my $ind (keys %settings) {
	# print $ind.': '.$settings{$ind}."\n";
# }
# print "\n>>>STATE<<<\n\n";
# foreach my $ind (keys %state) {
	# print $ind.': '.$state{$ind}."\n";
# }

print "Content-type: text/html\n";
if(!$access) {
	print "Status: 403 Forbidden\n";
}
print "\n";
if($method eq 'HEAD') {
	exit;
}

print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
print '<html lang="en"><head>'."\n";
print '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
print '<title>';
unless($framedata{'title'} eq '' || $framedata{'title'} eq $settings{'story'}) {
	print entityencode($framedata{'title'}).' &bull; ';
}
print entityencode($settings{'story'}).' &bull; '.WEBSITE_NAME.'</title>'."\n";
print '<link rel="icon" type="image/png" href="'.FAVICON_PATH.'">'."\n";
print '<link rel="stylesheet" href="'.CGI_CSS_PATH.'">'."\n";
print '<link rel="index" href="'.CGI_GOTO_PATH.($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
print '<link rel="start" href="'.CGI_VIEWER_PATH.'/0'.($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
if($frame>0 && $access) {
	print '<link rel="prev" href="'.CGI_VIEWER_PATH.'/'.($frame - 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
}
if ($passwordOK || $frame<int($state{'last'})) {
	print '<link rel="next" href="'.CGI_VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
	print '<link rel="prefetch" href="'.CGI_VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">'."\n";
}
if($frame==int($state{'last'}) && int($state{'state'}) >= 1 && int($state{'state'}) < 3) {
	print '<!-- <script src="'.CGI_TIMER_PATH.'"></script> -->'."\n";
}
print '</head><body>'."\n";
print '<a href="/"><img id="botmlogo" src="'.CGI_LOGO_PATH.'" alt="'.WEBSITE.'"></a>'."\n";
print '<div id="all">'."\n";

print '<div id="inst" class="ins">'."\n";

print '<div id="title">'."\n";
print '<H1 id="titletext">'.entityencode($framedata{'title'}).'</H1>'."\n";
print '</div>'."\n";

print '</div><div id="framespace">'."\n";
if(!$access) {
	print '<img src="'.CGI_PATH.$framedata{'frame'}.'" id ="frame" alt="'.$frame.'" title="'.entityencode($framedata{'title'}).'">'."\n";
}
else {
	print'<img src="';
	if($frame<=int($state{'last'}) && int($state{'state'}) >= 1) {
		print CGI_PATH.sprintf($settings{'frame'},$frame,$framedata{'ext'});
	}
	else {
		print CGI_FRAME_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'');
	}
	print '" id="frame" alt="'.$frame.'" title="'.entityencode($framedata{'title'}).'">'."\n";
}
print '</div><div id="insb" class="ins">'."\n";

if($textmode==2){
	print '<div id="chat">'."\n";
	
	if ($passwordOK || $frame<int($state{'last'}) || (int($state{'state'}) >= 2 && $showcommand)) {
		$framedata{'command'}=$nextframedata{'title'};
	}
	if ($access) {
		$framedata{'frame'}=sprintf($settings{'frame'},$frame,$framedata{'ext'});
	}
	
	printdatafileht(%framedata);
	print '</div>'."\n";
}
elsif($textmode==1){
	print '<div id="chat">'."\n";
	print '[quote][center][size=200]'.entityencode($framedata{'title'}).'[/size]<br>'."\n";
	print '[url=http://'.WEBSITE.CGI_VIEWER_PATH.'/'.$frame.'][img]http://'.WEBSITE.CGI_PATH.($access?sprintf($settings{'frame'},$frame,$framedata{'ext'}):$framedata{'frame'}).'[/img][/url][/center]<br>'."\n";
	print bb2bbf($framedata{'content'}).'[/quote]</div>'."\n";
}
elsif($framedata{'content'} ne ''){
	print '<div id="undertext">'."\n";
	print bb2htf($framedata{'content'})."\n";
	print '</div>'."\n";
}

print '<div id="command">'."\n";
if($frame==int($state{'last'}) && int($state{'state'}) >= 1 && int($state{'state'}) < 3) {
	print '[<span id="ongh" class="';
	if(int($state{'state'}) >= 2 || $state{'ip1'} ne '') {
		print 'br';
	}
	else {
		print 'ni';
	}
	print '">'.$hours.'</span>:<span id="ongm" class="';
	if(int($state{'state'}) >= 2 || $state{'ip2'} ne '') {
		print 'br';
	}
	else {
		print 'ni';
	}
	print '">'.$minutes.'</span>:<span id="ongs" class="';
	if(int($state{'state'}) >= 2 || $state{'ip3'} ne '') {
		print 'br';
	}
	else {
		print 'ni';
	}
	print '">'.$seconds.'</span>]<br>';
}
print '&gt;';
if (!$access){
	print '<a href="'.CGI_VIEWER_PATH.'/-1">'.entityencode($framedata{'command'}).'</a><br>'."\n";
}
else {
	if ($passwordOK || $frame<int($state{'last'}) || (int($state{'state'}) >= 2 && $showcommand)) {
		if ($passwordOK || $frame<int($state{'last'})) {
			print '<a href="'.CGI_VIEWER_PATH.'/'.($frame + 1).($passwordOK?('?p='.urlencode($password)):'').'">';
		}
		if($nextframedata{'title'} ne '') {
			print entityencode($nextframedata{'title'});
		}
		elsif ($passwordOK || $frame<int($state{'last'})) {
			print'<span class="inp">_</span>';
		}
		if ($passwordOK || $frame<int($state{'last'})) {
			print '</a>';
		}
		else {
			print'<span class="inp">_</span>';
		}
	}
	else {
		print'<span class="inp">_</span>';
	}
	print '<br>'."\n";
}
print '</div>'."\n";

print '<div id="underlinks">'."\n";
print '<a href="'.CGI_PATH.'">Once again</a>';
if($frame>0 && $access) {
	print ' | <a href="'.CGI_VIEWER_PATH.'/'.($frame-1).($passwordOK?('?p='.urlencode($password)):'').'">Before</a>';
}
if($frame != int($state{'last'})) {
	print ' | <a href="'.CGI_VIEWER_PATH.'/'.int($state{'last'}).($passwordOK?('?p='.urlencode($password)):'').'">Now</a>';
}
print ' | <a href="'.CGI_GOTO_PATH.($passwordOK?('?p='.urlencode($password)):'').'">GOTO</a>'."\n";
print '<span style="float: right;">'."\n";

if ($textmode!=0) {
	print '<a href="'.CGI_VIEWER_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'').'">Without</a> | ';
}

print '<a href="'.(($textmode==2)?(CGI_INFO_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'')):(CGI_VIEWER_PATH.'/'.$frame.'?b=2'.($passwordOK?('&amp;p='.urlencode($password)):''))).'">Info</a>';
print ' | <a href="'.(($textmode==1)?(CGI_BBCODE_PATH.'/'.$frame.($passwordOK?('?p='.urlencode($password)):'')):(CGI_VIEWER_PATH.'/'.$frame.'?b=1'.($passwordOK?('&amp;p='.urlencode($password)):''))).'">BB</a>';
print "\n</span>\n";

print '</div>'."\n";

print '</div>'."\n";

print '</div>'."\n";
print '<a href="/" class="cz">'.WEBSITE.'</a>'."\n";

print '</body></html>'."\n";

sub writeindex {
	(my $indexpath) = @_;
	my $indexfile;
	my %framedata;
	my %nextframedata;
	my %default;
	
	if(ref($indexpath)) {
		$indexfile=$indexpath;
		unless (seek($indexfile, 0, 0)) {
			return 0;
		}
	}
	else {
		unless (open ($indexfile, ">", $indexpath)) {
			return 0;
		}
	}
	
	%framedata = readdatafile(DATA_PATH.0);
	%nextframedata = readdatafile(DATA_PATH.1);
	%default=readdatafile(DATA_DEFAULT_PATH);
	
	foreach my $ind (keys %default) {
		unless(defined($framedata{$ind})){
			$framedata{$ind}=$default{$ind};
		}
		unless(defined($nextframedata{$ind})){
			$nextframedata{$ind}=$default{$ind};
		}
	}
	
	print $indexfile '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "">'."\n";
	print $indexfile '<html lang="en"><head>'."\n";
	print $indexfile '<meta http-equiv="Content-type" content="text/html; charset=UTF-8">'."\n";
	print $indexfile '<title>'.entityencode($settings{'story'}).' &bull; '.WEBSITE_NAME.'</title>'."\n";
	print $indexfile '<link rel="icon" type="image/png" href="'.FAVICON_PATH.'">'."\n";
	print $indexfile '<link rel="stylesheet" href="'.CGI_CSS_PATH.'">'."\n";
	print $indexfile '<link rel="index" href="'.CGI_GOTO_PATH.'">'."\n";
	print $indexfile '<link rel="start" href="'.CGI_VIEWER_PATH.'/0">'."\n";
	print $indexfile '<link rel="next" href="'.CGI_VIEWER_PATH.'/1">'."\n";
	print $indexfile '<link rel="prefetch" href="'.CGI_VIEWER_PATH.'/1">'."\n";
	print $indexfile '</head><body>'."\n";
	print $indexfile '<a href="/"><img id="botmlogo" src="'.CGI_LOGO_PATH.'" alt="'.WEBSITE.'"></a>'."\n";
	print $indexfile '<div id="all">'."\n";
	
	print $indexfile '<div id="inst" class="ins">'."\n";
	
	print $indexfile '<div id="title">'."\n";
	print $indexfile '<H1 id="titletext">'.entityencode($settings{'story'}).'</H1>'."\n";
	print $indexfile '</div>'."\n";
	
	print $indexfile '</div><div id="framespace">'."\n";
	print $indexfile '<img src="'.CGI_PATH.sprintf($settings{'frame'},0,$framedata{'ext'}).'" title="'.entityencode($framedata{'title'}).'" alt="0" id="frame">'."\n";
	
	print $indexfile '</div><div id="insb" class="ins">'."\n";
	print $indexfile '<div id="undertext">'."\n";
	print $indexfile bb2htf($framedata{'content'})."\n";
	print $indexfile '</div>'."\n";
	
	print $indexfile '<div id="command">'."\n";
	print $indexfile '&gt;<a href="'.CGI_VIEWER_PATH.'/1">'.entityencode($nextframedata{'title'}).'</a>'."\n";
	print $indexfile '</div>'."\n";
	
	print $indexfile '<div id="underlinks">'."\n";

	
	# <span style="float: right;"><a href="/bsta/v/0?b=2">Info</a> | <a href="/bsta/v/0?b=1">BB</a></span>
	
	print $indexfile '<a href="'.CGI_VIEWER_PATH.'/-1">Now</a> | <a href="'.CGI_GOTO_PATH.'">GOTO</a>';
	print $indexfile '<span style="float: right;"><a href="'.CGI_INFO_PATH.'/0?b=2">Info</a> | <a href="'.CGI_VIEWER_PATH.'/0?b=1">BB</a></span>'."\n";
	print $indexfile '</div>'."\n";
	
	print $indexfile '</div>'."\n";
	
	print $indexfile '</div>'."\n";
	print $indexfile '<a href="/" class="cz">'.WEBSITE.'</a>'."\n";
	
	print $indexfile '</body></html>'."\n";
	
	unless (ref($indexpath)) {
		close ($indexfile);
	}
	else {
		truncate ($indexfile , tell($indexfile));
	}
	
	return 1;
}

sub bb2htf {
	(my $bb) = @_;
	my $tag;
	my $tagvalue;
	my $pretext;
	my $posttext;
	
	while($bb =~ m/(###([^#;]*);)/g) {
		$tag = $1;
		$tagvalue = $2;
		$pretext = substr($bb,0,pos ($bb)-length($tag));
		$posttext = substr ($bb,pos ($bb));
		
		if ($tagvalue =~ /^att&([0-9]+)$/) {
			$tagvalue = CGI_ATTACH_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
		}
		elsif ($tagvalue =~ /^vw&([0-9]+)$/) {
			$tagvalue = CGI_VIEWER_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
		}
		elsif ($tagvalue =~ /^fr&([0-9]+)$/) {
			$tagvalue = CGI_FRAME_PATH.'/'.int($1).($passwordOK?('?p='.urlencode($password)):'');
		}
		else {
			$tagvalue = '';
		}
		
		$bb = $pretext.$tagvalue.$posttext;
	}
	
	return bb2ht ($bb);
}

sub bb2bbf {
	(my $bb) = @_;
	my $tag;
	my $tagvalue;
	my $pretext;
	my $posttext;
	
	while($bb =~ m/(###([^#;]*);)/g) {
		$tag = $1;
		$tagvalue = $2;
		$pretext = substr($bb,0,pos ($bb)-length($tag));
		$posttext = substr ($bb,pos ($bb));
		
		if ($tagvalue =~ /^att&([0-9]+)$/) {
			$tagvalue = 'http://'.WEBSITE.CGI_ATTACH_PATH.'/'.int($1);
		}
		elsif ($tagvalue =~ /^vw&([0-9]+)$/) {
			$tagvalue = 'http://'.WEBSITE.CGI_VIEWER_PATH.'/'.int($1);
		}
		elsif ($tagvalue =~ /^fr&([0-9]+)$/) {
			$tagvalue = 'http://'.WEBSITE.CGI_FRAME_PATH.'/'.int($1);
		}
		else {
			$tagvalue = '';
		}
		
		$bb = $pretext.$tagvalue.$posttext;
	}
	
	return linehtml(bb2bb ($bb));
}
