#!/usr/bin/perl


# --------------------------------------------------------------
# T.M.BBS ver.1.04(2001.03.24)
#     Programed by Tsukasa Minazuki(tmcr@din.or.jp)
#                  ホームページ(http://www.din.or.jp/~tmcr/)
# --------------------------------------------------------------
# T.M.Web Wizard対応バージョン
# ※このファイル(tmbbs.cg_)自体は配布せず、T.M.CGI Generatorに
#   よって変換されたファイルのみが配布されることになります。
# --------------------------------------------------------------
#
# --------------------------------------------------------------
# ■ Wizard Paramaters
# --------------------------------------------------------------
#$cookiePath = '/cgi-bin';
$cookiePath = '/BBS';
$cookieDomain = 'www.is.sci.yamaguchi-u.ac.jp';
$libdir = './';

# --------------------------------------------------------------
# ■ プログラム
# --------------------------------------------------------------
$prgname = "T.M.BBS ver.1.04";


$df = './tmbbs.dat';
$wf = './words.dat';
$lockfile = './lock/lock.dat';
$html_ok = 1;
$res_indent = 1;
$article_num = 10;
$data_num = 256;
$time_plus = 0;
$edit_top = 1;
$res_top = 1;
$admin_only = 0;
$cookie = 'tmbbs';
$AdminPassword = 'hogeboge';
$ctrlStr = '';

@wday_name = ("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
@wday_name_e = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
@wday_name_j = ('日','月','火','水','木','金','土');
@month_name = ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
@ckey = ( 'name', 'mail', 'url', 'pw', 'n', 'ex1', 'ex2', 'ex3', 'ex4', 'ex5', 'subject','article','ex6','ex7','ex8','ex9','ex10' );
@wkey = ( 'name', 'mail', 'subject', 'article', 'url', 'pw', 'time', 'domain', 'index', 'ex1', 'ex2', 'ex3', 'ex4', 'ex5', 'ex6', 'ex7', 'ex8', 'ex9', 'ex10' );

print "Content-type: text/html\n";

&InstallCheck;

&ReadParse;

$df = $in{ 'data' }		if( defined $in{ 'data' } && $in{ 'data' } =~ /^[A-Za-z0-9_\.\/\-]+\.[dD][aA][tT]$/ );

if( defined $ENV{'HTTP_COOKIE'} ){
	@cookie = &cookieCutter;
	$#cookie = 9;
}

if( defined $in{'responseto'} ){
	$act = 'response';
	$in{ 'target' } = $in{ 'responseto' };
}elsif( defined $in{'act'} ){
	$act = $in{'act'};
	
	if( $act =~ m/^write;(.*)$/i ){
		
		$in{ 'subject' } = $1.':'.$in{ 'subject' };
		$act = 'write';
		
	}else{
		
		$btn_delete = '削除';
		$btn_delete = $in{'bdelete'}		if( defined $in{'bdelete'} );
		
		$act = 'delete'	if( $act eq 'edit' && $in{'act2'} eq $btn_delete );
		
	}
}elsif( defined $in{'article'} ){
	$act = 'write';
}else{
	$act = 'read';
}

$pw = '';
$pw = $in{'pw'}	if( defined $in{ 'pw' } );


$bRefuse = 0;

&LoadData;

if( $adminpw eq '' ){
	&require2( './admin.pl');
	$pw1 = $in{'pw1'};
	$pw2 = $in{'pw2'};
	if( $AdminPassword ne '' ){
		$adminpw = 'Invalid';
		&InitData;
	}elsif( $act eq 'write' ){
		&Error( "2つの欄に入力されたパスワードが一致しません。" )	unless( $pw1 eq $pw2 );
		&Error( "パスワードは2文字以上で設定してください。" )	unless( length($pw1) >= 2 );
		$adminpw = &encode0( $pw1 );
		&InitData;
	}else{
		&adregist;
	}
}

if( $act =~ /^admin/ )
{
	&require2('./admin.pl');
	&adlogin		if( $act eq 'admin' );
	
	&Error( '管理者用パスワードが正しくありません。' )	unless( &isad );
	
	&adopen( $act );
	
}elsif( $act eq 'write' )
{
	
	&Error( '管理者にしか書き込みは許可されていません。<BR>正しい管理者パスワードを入力してください。<BR>' )	if( $admin_only && &isad == 0 );
	
	&Error( 'タイトルが入力されていません。' )			if( $in{'subject'} eq '' );
	&Error( '記事内容が入力されていません。' )			if( $in{'article'} eq '' );
	&Error( '名前が入力されていません。' )				if( $in{'name'} eq '' );
	&Error( '削除用パスワードが入力されていません。' )	if( $in{'pw'} eq '' );
	
	&require2($libdir.'jcode.pl');
	
	$iIndex = ++$max_article_index;
	$Target = '';
	$status = '1';
	if( $in{'subject'} =~ /^Edit\(([0-9]+)\.([0-9.]+)\):(.*)$/ ){
		$Target = "$1.$2";
		$in{'subject'} = $3;
		$iIndex = $1;
		$string = &Get_Article( $iIndex );
		&Error( "編集対象の記事が見つかりません" )	if( $string eq '' );
		@elem = split( /,/, $string );
		$originalStatus = $elem[1];
		
		if( $originalStatus =~ /R[0-9]+/ ){
			$status = 'E'.$originalStatus;
		}else{
			$status = 'E';
		}
		
	}elsif( $in{'subject'} =~ /^Re\(([0-9]+)\):(.*)$/ ){
		$in{'subject'} = $2;
		$Target = $1;
		$status = 'R'.$1;
	}
	
	undef @p;
	
	$p[ 0 ] = "0;lst;";
	$p[ 1 ] = $status;
	
	$i = 2;
	&LoadWords;
	foreach $key( @wkey ){
		$string = $in{ $key };
		if( $key eq 'pw' ){
			$string = &encode0( $string )	if( $string ne 'not_used' );
			$string =~ s/,/，/g;
		}elsif( $key eq 'time' ){
			$string = &LocalTime;
		}elsif( $key eq 'domain' ){
			$string = $ENV{ 'REMOTE_HOST' };
			$string =~ s/,/&sbquo;/g;
		}elsif( $key eq 'index' ){
			$string = $iIndex;
		}else{
			&jcode'convert( *string, 'euc' );
			&Error( "許可されていない文字が入力されました。<br>投稿規定をよくお読みのうえ、やり直してください。" )		unless( &CheckWords($string) );
			
			$string = &ReplaceWords( $string );
			$string =~ s/\r\n/<br>/g;
			$string =~ s/\n/<br>/g;
			$string =~ s/,/&sbquo;/g;
		}
			
		$p[ $i++ ] = $string;
	}
	
	$string = join(',', ( @p, ';led;'));
	
	if( $status =~ /^R[0-9]+$/ ){
		&modify_article( $status, $string, '' );
	}else{
		if( $edit_top ){
			&modify_article( $Target, $string, '' );
		}else{
			&modify_article( '', $string, $Target );
		}
	}
	
}elsif( $act eq 'delete'  ){
	
	&inputpw( 'delete' )	if( $pw eq '' );
	
	&modify_article( $in{'target'}, '', '' );
	
}elsif( $act eq 'edit' || $act eq 'response' ){
	
	if( $act eq 'edit' ){
		&Error( '記事編集ができない動作モードです。' )	if( $AdminPassword ne '' );
		&inputpw( 'edit' )	if( $pw eq '' );
	}
	
	$string = &Get_Article( $in{ 'target' } );
	&Error( "指定された記事が見つかりません" )	if( $string eq '' );
	@p = split( /,/, $string );
	$dnum = &get_dnum($string);
	if( $act eq 'edit' ){
		&Error( '更新不可能な書き込みです。' )	if( $p[7] eq 'not_used' );
		$p[7] =~ s/，/,/g;
		&Error( 'パスワードが一致しません。' )	unless( &pwcheck0( $in{ 'pw' }, $p[7] ) == 1 );
		
		$ctrlStr = ';Edit('.$dnum.')';
		
	}elsif( $act eq 'response' ){
		
		$ctrlStr = ';Re('.$p[10].')';
		
	}
	
	$i = 2;
	ldivide: foreach $key( @wkey ){
		
		if( $key eq 'pw' ){
			$i++, next ldivide		if( $act eq 'response' );
			$p[$i] = $in{ 'pw' };
		}elsif( $key eq 'article' ){
			if( $act eq 'edit' ){
				$p[$i] =~ s/<br>/\n/g;
			}else{
				$p[$i] =~ s/<br>/\n>/g;
				$p[$i] = ">".$p[ $i ];
				$p[$i] =~ s/>$//g;
			}
		}elsif( $key eq 'subject' ){
			
			$p[$i] = 'Re:'.$p[$i]	if( $act eq 'response' );
			
		}else{
			$i++, next ldivide		if( $act eq 'response' );
		}
		
		$p[$i] =~ s/&sbquo;/,/g;
		$cookiestr{ $key } = $p[ $i ];
		$i++;
		
	}
	
	$i = 0;
	
	foreach( @ckey ){
		if( $act eq 'response' ){
			$cookie[ $i ] = $cookiestr{ $_ }	if( $i >= 10 );
		}else{
			$cookie[ $i ] = $cookiestr{ $_ };
		}
		$i++;
	}
}

if( $act eq 'write' && $in{ 'cookie' } ne 'nosave' ){
	@p = ('');
	for( $i = 0; $i < 10; $i++ ){
		$cookie[ $i ] = $in{ $ckey[ $i ] };
		$p[ $i ] = $cookie[ $i ];
	}
	&SetCookie( @p );
}

@p = split( /,/, $msgBuffer[ $#msgBuffer ] );
$from = $p[10];
$dfrom = $p[8];
@p = split( /,/, $msgBuffer[0] );
$to = $p[10];
$dto = $p[8];
$nmsg = $#msgBuffer + 1;

&PrintHTML;

exit;


sub InstallCheck
{
	&Error( "ディレクトリ'lock'が見つかりません。もう一度転送手順を確認してください。" )	unless( -e './lock' );
}

sub require2
{
	require( $_[0] ), return	if( -e $_[0] );
	
	local( $dir, $title ) = ($_[0] =~ /^(.*)\/([a-zA-Z0-9]+\.pl)$/);
	
	
	&Error( "'$title'のオープンに失敗しました。" );
}

sub Get_Article
{
	local( $target ) = @_;
	local( $bNewTarget, $ret, $dnum, @p, $bValidHead );
	
	$bNewTarget = 0;
	$bNewTarget = 1	if( $target =~ /^[0-9]+$/ );
	
	&Error( 'データファイル'.$df.'がオープンできません。' )	unless( open( FIN, $df ) );
	
	$string = <FIN>;
	$string = '';
	$ret = '';
	
	line_read: while( <FIN> ){
		$string = "$string$_";
		@p = split( /,/, $string );
		$bValidHead = 0;
		$bValidHead = 1		if( $string =~ m/^[0-9]+;lst;/ );
		
		if( ($bValidHead == 1 && $string =~ m/;led;$/) || ($bValidHead == 0 && $p[7] ne '') ){
			if( $bNewTarget == 0 ){
				$dnum = &get_dnum($string);
				$ret = $string, last line_read	if( $target eq $dnum );
			}else{
				$ret = $string, last line_read	if( $target == $p[10] );
			}
			$string = "";
		}
	}
	close( FIN );
	
	return $ret;
}

sub Get_Responses
{
	local( $parent ) = @_;
	local( @elem, @ret );
	
	foreach( @msgBuffer ){
		@elem = split( /,/ );
		
		push( @ret, $_ )	if( $parent >= 0 && ($elem[1] =~ /R$parent$/ || $elem[1] =~ /R$parent[A-Z]/) );
		push( @ret, $_ )	if( $parent < 0 && !($elem[1] =~ /R/) );
	}
	return @ret;
}
sub Get_RLength
{
	local( $parent ) = @_;
	local( @elem, @ret );
	local( $i );
	
	$i = 0;
	foreach( @msgBuffer ){
		@elem = split( /,/ );
		
		$i++	if( $parent >= 0 && ($elem[1] =~ /R$parent$/ || $elem[1] =~ /R$parent[A-Z]/) );
		$i++	if( $parent < 0 && !($elem[1] =~ /^R/) );
	}
	return $i;
}

sub LoadData
{
	local( $bTo, $bFrom, $pg, $ex, $nBuffer, $bShow, $bPg, $bCut, $iBuffer, $string, $NumFrom, $NumTo, $NumDFrom, $NumDTo );
	
	local( $bEnd );
	
	$adminpw = '';
	$string = '';
	undef @msgBuffer;
	$nBuffer = 0;
	$iBuffer = 0;
	$max_article_index = 0;
	
	$bEnd = 0;
	$bFileTop = 1;
	
	&Error( $df."のオープンに失敗しました。サーバーが混んでいる可能性があります。" )	unless( open( FIN, $df ) );
	
	line: while( <FIN> ){
		$bEnd = 0;
		if( $adminpw eq '' && $_ =~ /^tmbbs0\/(.*)\n$/  ){
			@p = split( '/', $1 );
			
			($number, $html_ok, $res_indent, $article_num, $banner_num, $data_num, $edit_top, $time_plus, $admin_only, $res_top) = split( ',', shift( @p ) );
			$adminpw = join( '/', @p );
			
			$data_num = 32	if( $data_num < 32 );
			
			$nRead = $article_num;
			$nRead = $in{'n'}	if( defined $in{'n'} );
			
			if( $in{'act'} =~ /^admin/ ){
				last line;
			}elsif( defined $in{'pg'} ){
				( $pg, $ex ) = split( /,/, $in{'pg'} );
				$bCut = 0;
				$iStart = $pg;
				$iStart += $nRead	if( $ex eq 'next' );
				$iStart -= $nRead	if( $ex eq 'before' );
				$iStart = 0			if( $iStart < 0 );
				$bPg = 1;
			}elsif( defined $in{'to'} || defined $in{'from'} ){
				$bPg = 3;
				$bCut = 2;
				if( defined $in{'to'} ){
					$NumTo = $in{ 'to' };
					$NumDTo = $in{ 'to' };
					$bPg = 2	if( $in{'to'} =~ /^[0-9]+$/ );
				}else{
					$NumDTo = "9999/12/31 23:59:59";
					$NumTo = 30000;
					$bCut = 1;
				}
				if( defined $in{'from'} ){
					$NumDFrom = $in{ 'from' };
					$NumFrom = $in{ 'from' };
					$bPg = 2	if( $in{'from'} =~ /^[0-9]+$/ );
				}else{
					$NumFrom = 0;
					$NumDFrom = "0000/01/01 00:00:00";
					$bCut = 0;
				}
			}else{
				$iStart = 0;
				$bPg = 1;
				$bCut = 0;
			}
			next line;
		}
		
		$string = "$string$_"	if( $string ne '' || $_ =~ m/^([0-9]+);lst;/ );
		
		if( $string =~ m/;led;$/ ){
			
			@p = split( /,/, $string );
			$max_article_index = $p[10]		if( $p[10] > $max_article_index );
			
			
			$bShow = 0;
			
			if( $bPg == 1 ){
				
				$bShow = 1	if( $iStart <= $iBuffer );
				
			}elsif( $bPg == 2 ){
				
				$bShow = 1	if( $NumFrom <= $p[10] && $p[10] <= $NumTo );
				$iStart = $iBuffer	if( $nBuffer == 0 );
				
			}elsif( $bPg == 3 ){
				
				$bShow = 1	if( &dcmp( $NumDFrom, $p[8] ) && &dcmp( $p[8], $NumDTo ) );
				$iStart = $iBuffer	if( $nBuffer == 0 );
				
			}
			
			$iBuffer++	unless( $p[1] =~ /R/ );
			
			if( $bShow ){
				push( @msgBuffer, $string );
				$nBuffer++	unless( $p[1] =~ /R/ );
			}else{
				$bFileTop = 0	if( $nBuffer == 0 );
				last line	if( $nBuffer > 0 );
			}
			
			$string = '';
			
			last line	if( $bCut == 0 && $nBuffer >= $nRead );
		}
		$bEnd = 1;
	}
	
	
	close( FIN );
	
	if( $bCut ){
		
		local( $j, $k );
		
		for( $j = 0, $k = 0; $j <= $#msgBuffer; $j++ ){
			
			$string = $msgBuffer[ $#msgBuffer - $j ];
			@p = split( /,/, $string );
			
			unless( $p[1] =~ /R/ ){
				$k++;
			}
			
			if( $k > $nRead ){
				$bFileTop = 0;
				
				last;
			}
			
		}
		
		splice( @msgBuffer, 0, $#msgBuffer - $j + 1 );
	}
	
	$bFileBottom = $bEnd;
	
}

sub GetList
{
	local( $bTo, $bFrom, $pg, $ex, $nBuffer, $bShow, $bPg, $bCut, $iBuffer, $string, $NumFrom, $NumTo, $NumDFrom, $NumDTo, @r );
	
	&Error( $df."のオープンに失敗しました。サーバーが混んでいる可能性があります。" )	unless( open( FIN, $df ) );
	
	line: while( <FIN> ){
		
		if( $_ =~ /^tmbbs0\/(.*)\n$/ ){
			next line;
		}
		
		$string = "$string$_"	if( $string ne '' || $_ =~ m/^([0-9]+);lst;/ );
		
		if( $string =~ m/;led;\n$/ ){
			
			push( @r, $string );
			
			$string = '';
		}
	}
	close( FIN );
	
	return @r;
}

sub dcmp
{
	local( $a, $b ) = @_;
	local( @da, @db, $i );
	
	@da = ( $a =~ /^([0-9]+)\/([0-9]+)\/([0-9]+) +([0-9]+):([0-9]+):([0-9]+)/ );
	@db = ( $b =~ /^([0-9]+)\/([0-9]+)\/([0-9]+) +([0-9]+):([0-9]+):([0-9]+)/ );
	
	$da[ 0 ] += 1900	if( $da[ 0 ] < 1900 );
	$db[ 0 ] += 1900	if( $db[ 0 ] < 1900 );
	
	for( $i = 0; $i < 6; $i++ ){
		if( $da[$i] < $db[$i] ){
			return 1;
		}elsif( $da[$i] > $db[$i] ){
			return 0;
		}
	}
	
	return 1;
}

sub MainCfg
{
	return join( ',', (0, $html_ok, $res_indent, $article_num, $banner_num, $data_num, $edit_top, $time_plus, $admin_only, $res_top) );
}

sub InitData
{
	&Error( "'".&get_fn($df)."'が開けません。転送方法またはパーミッションが正しいかどうか確認してください。" )
		unless( open( FOUT, ">$df" ) );
	&LockStart;
	
	print FOUT "tmbbs0/".&MainCfg."/$adminpw\n";
	
	&LockEnd;
	close( FOUT );
	
	&adregistOK;
}

sub get_fn
{
	$_[0] =~ /^(.*)\/([A-Za-z0-9_]+\.[A-Za-z0-9_]+)$/;
	return $2;
}

sub ReadParse
{
	local( @pairs, $pair, $buffer );
	
	if ($ENV{'REQUEST_METHOD'} eq "POST") { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); }
	else { $buffer = $ENV{'QUERY_STRING'}; }
	
	@pairs = split(/&/,$buffer);
	foreach $pair (@pairs)
	{
		($name, $value) = split(/=/, $pair);
		$value =~ s/\+/ /g;
		$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
		$in{$name} = $value;
	}
}

sub Indent
{
	local( $string, $value, $onres, @line );
	local( $headers ) = '&gt;|>|＞|★&gt;|★>|to|ｔｏ';
	
	return $_[0]	if( !($_[0] =~ /<br>/) && !($_[0] =~ /^($headers)/) );
	
	@line = split( /<br>/, $_[0] );
	$value = '';
	$onres = -1;
	
	foreach $string(@line){
		if( $string =~ /^($headers)/ ){
			$value = $value."</BLOCKQUOTE>\n"	if( $onres == 1 );
			$onres = 0;
			$value = "$value<CITE>$string</CITE><br>";
		}else{
			if( $onres == 0 ){
				$value = "$value<BLOCKQUOTE>\n";
				$value = "$value$string<br>"	if( $string ne '' );
			}else{
				$value = "$value$string<br>";
			}
			$onres = 1	if( $onres != -1 );
		}
	}
	
	$value = "$value<br>";
	$value = "$value</BLOCKQUOTE>\n"	if( $onres == 1 );
	
	return $value;

}

sub isad
{
	if( $AdminPassword eq '' ){
		return 1		if( &pwcheck0( $in{ 'pw' }, $adminpw ) );
	}else{
		return 1		if( $in{ 'pw' } eq $AdminPassword );
	}
	
	return 0;
}

sub Error
{
	print "\n";

print <<EOM;
	<HTML>
	<HEAD>
		<TITLE>エラー - T.M.BBS</TITLE>
	</HEAD>
	<BODY>
		<H1>■エラー</H1>
		
		$_[0]<BR>
		(ブラウザの「戻る」ボタンを押して前画面に戻って下さい)
	</BODY>
	</HTML>
EOM
	
	exit;
}

sub inputpw
{
	local( $func ) = @_;
	local( $tt, $target );
	
	$tt = '記事の削除'	if( $func eq 'delete' );
	$tt = '記事の編集'	if( $func eq 'edit' );
	$target = $in{'target'};
	
	print "\n";
	print <<EOM;
	<HTML>
	<HEAD>
		<TITLE>パスワードの入力 - T.M.BBS</TITLE>
	</HEAD>
	<BODY>
		<H1>■パスワードの入力</H1>
		
		$ttにはパスワードが必要です。<BR>
		書き込み時に入力した<B>削除キー</B>を入力して、「$tt」を押して下さい。<BR>
		(やめる場合は、ブラウザの「戻る」ボタンを押して元の画面に戻って下さい。)<BR>
		<BR>
		<FORM action="tmbbs.cgi" method="post">
		削除キー: <INPUT type="password" name="pw" size="12">
		<INPUT type="hidden" name="target" value="$target">
		<INPUT type="hidden" name="data" value="$df">
		<INPUT type="hidden" name="act" value="$func">
		<INPUT type="hidden" name="chtml" value="$in{'chtml'}">
		<INPUT type="submit" value="  $tt  ">
		</FORM>
	</BODY>
	</HTML>
EOM
	
	exit;
}

sub get_dnum{
	local(@d) = split( /,/, $_[0] );
	local(@p) = ($d[8] =~ /^(\d+)\/(\d+)\/(\d+)\s(\d+):+(\d+):+(\d+)\(\w+\)/);
	return join( '.', ($d[10], @p) );
}

sub LoadWords
{
	local( $section, %CW );
	
	$CW{ 'he' } = "[A-Za-z]";
	$CW{ 'hn' } = "[0-9]";
	$CW{ 'hk' } = "[ア-ン]";
	$CW{ 'hm' } = "[!.,;:\\[\\]\\(\\)'\"\\-]";
	$msg = '';
	
	$CRefuse = -1;
	
	return	unless( open( IN, $wf ) );
	
	while( <IN> )
	{
		if( $_ =~ /^\.approval\n$/ ){
			$CRefuse = 0;
			$section = 1;
			push( @CWords, "[<>;&\\n\\r \\t]" );
		}elsif( $_ =~ /^\.refuse\n$/ ){
			$CRefuse = 1;
			$section = 1;
		}elsif( !($_ =~ /^#/) ){
			push( @CWords, $CW{ $1 } )		if( $section == 1 );
		}
	}
	
	close( IN );
	
}

sub CheckWords
{
	local( $f, $c, @p );
	
	if( $CRefuse == 0 ){
		@c = split( //, $_[0] );
		foreach $c(@p){
			apcheck: foreach (@CWords){
				last apcheck		if( $c =~ /^$_/ );
			}
			return 0	if( $c =~ /^$_/ );
		}
		return 1;
	}elsif( $CRefuse == 1 ){
		foreach (@CWords){
			return 0	if( $_[0] =~ /^$_/ );
		}
		return 1;
	}else{
		return 1;
	}
}

sub ReplaceWords
{
	return $_[0];
}

sub modify_article{
	local( $delTerget, $addData, $editTarget ) = @_;
	local( $bRes, $ResTarget );
	local( $errmsg ) = '';
	
	$i = 0;
	$string = '';
	
	local( @data, @wk, @top, $bTop );
	
	undef @msgBuffer;
	
	
	if( $delTerget =~ /^R([0-9]+)$/ ){
		$bRes = 1;
		$ResTarget = $1;
		
	}else{
		$bRes = 0;
		$delTerget =~ s/[\0,]/ /g;
		$delTerget = ' '.$delTerget;
		
		if( $addData ne '' && $editTarget eq '' ){
			@data = ("$addData\n");
			$i = 1;
		}else{
			$i = 0;
		}
	}
	
	&LockStart;
	
	&LockEnd, &Error( $df."のオープンに失敗しました。サーバーが混んでいる可能性があります。" )	unless( open( FIN, $df ) );
	$string = <FIN>;
	$string = '';
	local( $bOK ) = 0;
	while( ($_ = <FIN>) && ($i < $data_num) ){
		$string = "$string$_";
		@p = split( /,/, $string );
		if( $string =~ m/^[0-9]+;lst;/ && $string =~ m/;led;$/ ){
			$bOK = 1;
		}elsif( !($string =~ m/^[0-9]+;lst;/) && $p[7] ne '' ){
			$bOK = 1;
		}else{
			$bOK = 0
		}
		
		$bTop = 0;
		
		if( $bOK ){
			$dnum = &get_dnum( $string );
			if( $bRes ){
				push( @data, $string ), $string = "$addData\n", $bTop = 1	if( $p[10] == $ResTarget );
				
				
			}else{
				$p[ 7 ] =~ s/，/,/g;
				
				if( $editTarget eq $dnum ){
					if( &pwcheck0( $pw, $p[7] ) != 0 ){
						$string = "$addData\n";
					}else{
						$errmsg = '編集時のパスワードが正しくありません。';
					}
				}elsif( $delTerget =~ m/ $dnum/ ){
					if( (&isad) || (&pwcheck0($pw,$p[7])!=0) ){
						$string = '';
					}elsif( $AdminPassword ne '' ){
						$errmsg = '管理者パスワードでのみ削除可能です。';
					}else{
						$errmsg = '削除用のパスワードが正しくありません。';
					}
				}
			}
			
			if( $string ne '' ){
				if( $bTop ){
					push( @top, $string );
				}else{
					push( @data, $string );
				}
				$string = '';
				$i++;
			}
		}
	}
	close( FIN );
	
	if( $#top + 1 > 0 ){
		@wk = ( @top, @data );
		@data = @wk;
		undef @wk;
		undef @top;
	}
	
	@data = &moveArticle( $ResTarget, @data )	if( $bRes && $res_top );
	
	$i = 0;
	if( open( FOUT, ">$df" ) ){
		print FOUT "tmbbs0/".&MainCfg."/$adminpw\n";
		foreach ( &arrangeArticle( @data ) ){
			print FOUT $_;
			push( @msgBuffer, $_ )		if( $i < $nRead );
			$i++						unless( $_ =~ /^[0-9]+;lst;,R/ );
		}
		close( FOUT );
	}
	
	&LockEnd;
	
	undef @data;
	
	&Error( $errmsg )	if( $errmsg ne '' );
}

sub getParent
{
	local( $target, @data ) = @_;
	local( @elem, $r, $val );
	
	$r = 0;
	
	foreach $val( @data ){
		
		@elem = split( /,/, $val );
		
		if( $target eq $elem[ 10 ] ){
			
			$r = $1		if( $elem[1] =~ /R([0-9]+)/ );
			
		}
	}
	return $r;
}

sub moveArticle
{
	local( $target, @data ) = @_;
	local( @hist, $parent, $mynum, $val, @r );
	
	$mynum = $target;
	$i = 0;
	
	while( $i < 10 && $mynum > 0 )
	{
		$parent = &getParent( $mynum, @data );
		
		unshift( @hist, $mynum );
		
		$mynum = $parent;
		$i++;
	}
	
	foreach $val( @data ){
		
		@elem = split( /,/, $val );
		
		if( $elem[10] eq $hist[0] ){
			unshift( @r, $val );
		}else{
			push( @r, $val );
		}
	}
	return @r;
}

sub arrangeArticle
{
	@srcArData = @_;
	local( @elem, @destData, $i, $j, $val );
	local( $deloffset, $dellength, @addlist );
	
	for( $i = 0; $i <= $#srcArData; $i++ ){
		$val = $srcArData[ $i ];
		next	if( $val eq '' );
		
		@elem = split( /,/, $val );
		
		if( !($elem[1] =~ /R/) )
		{
			$srcArData[ $i ] = '';
			push( @destData, &arrangeArticle_Res( $elem[10] ) );
			push( @destData, $val );
		}
	}
	return @destData;
}

sub arrangeArticle_Res
{
	local( $parent ) = @_;
	local( @elem, @ret, $val, $i );
	
	for( $i = 0; $i <= $#srcArData; $i++ ){
		$val = $srcArData[ $i ];
		
		next	if( $val eq '' );
		
		@elem = split( /,/, $val );
		
		if( $elem[1] =~ /R$parent$/ || $elem[1] =~ /R$parent[A-Z]/ )
		{
			$srcArData[ $i ] = '';
			push( @ret, &arrangeArticle_Res( $elem[10] ) );
			push( @ret, $val );
		}
		
	}
	
	return @ret;
}


sub encode0
{	
	local($plain) = @_;
	local(@char,$f,$now,@saltset,$pert1,$pert2,$nsalt,$salt, @p, $v);
	
	return 'Invalid'	if( $AdminPassword ne '' );
	

	@saltset = ('a'..'z','A'..'Z','0'..'9','.','/');
	$now = time;
	srand(time|$$);
	$f = splice(@saltset,rand(@saltset),1) . splice(@saltset,rand(@saltset),1);
	($pert1,$pert2) = unpack("C2",$f);
	$week = $now / (60*60*24*7) + $pert1 + $pert2 - length($plain);
	$nsalt = $saltset[$week % 64] . $saltset[$now % 64];

	$result = crypt($plain,$nsalt);
	if ($result =~ /^\$1\$/) { $salt = 3; } else { $salt = 0; }
	&Error( '暗号処理に失敗しました。偶然の可能性があるので、もう一度試してみて下さい。' )	if (crypt($plain,substr($result,$salt,2)) ne $result || $result eq '');
	
	return $result;
}

sub pwcheck0
{	
	return 0	if( $AdminPassword ne '' );
	
	local( $pw1, $pw2 ) = @_;
	local( $salt );
	
	if ($pw2 =~ /^\$1\$/) { $salt = 3; } else { $salt = 0; }
	return 1	if (crypt($pw1,substr($pw2,$salt,2)) eq $pw2);
	
	return 0;
}

sub SetCookie
{
	local($secg,$ming,$hourg,$mdayg,$mong,$yearg,$wdayg,$ydayg,$isdstg) = gmtime(time + 30*24*60*60);
	local($cookieExpires) = sprintf("%s\, %02d\-%s\-%04d %02d:%02d:%02d GMT",$wday_name[$wdayg],$mdayg,$month_name[$mong],$yearg +1900,$hourg,$ming,$secg);
	print "Set-Cookie: ";
	print "$cookie=".join( ',', @_ )."; ";
	print "expires=$cookieExpires; ";
	print "path=$cookiePath; ";
	print "domain=$cookieDomain\n";
}

sub cookieCutter
{
	local($key, $value, @cookie_data);
	foreach( split(/; /, $ENV{'HTTP_COOKIE'}) ){
		($key,$value) = split(/=/);
		@cookie_data = split( /,/, $value )	if( $key eq $cookie );
	}
	return @cookie_data;
}

sub LocalTime
{
	local($sec,$min, $hour,$mday,$mon,$year,$wday) = localtime(time + $time_plus*60);
	
	$mon++;
	
	return sprintf( "%04d/%02d/%02d %02d:%02d:%02d(%s)", $year + 1900, $mon, $mday, $hour, $min, $sec, $wday_name_e[ $wday ] );
}

sub GetVarMember
{
	local( $i, $j, @elem ) = ( 0, 0, 'year', 'mon', 'day', 'hour', 'min', 'sec', 'weekday', 'weekdayj' );
	
	local(@p) = ($_[0] =~ /^(\S+)\/+(\S+)\/+(\S+)\s(\S+):+(\S+):+(\S+)\((\w+)\)/);
	
	foreach( @elem )
	{
		if( $_ eq $_[1] ){
			if( $_ eq 'weekdayj' ){
				$j = 0;
				foreach( @wday_name_e ){
					$p[ $i ] = $wday_name_j[$j]		if( $p[ $i - 1 ] eq $_ );
					$j++;
				}
			}
			return $p[ $i ];
		}
		$i++;
	}
	
	return '(Member Error)';
}

sub PrintHTML
{
	local( $include );
	
	if( defined $in{ 'chtml' } && $in{'chtml'} ne '' ){
		$include = $in{ 'chtml' };
		
		$include =~ s/\.(pl|html|htm)//;
	}else{
		$include = 'html';
	}
	
	$chtml = $include;
	
	&require2( './'.$include.'.pl' );
	
	&print_template;
}

sub LockStart
{
	local( $retry, $msg ) = (0, "ファイルがロックされています。しばらくお待ちください");
	local( $symlink_enabled ) = 0;
	$symlink_enabled = ( eval{ symlink("",""); 1; }, $@ eq "" );
	
	if( $symlink_enabled ){
		while( !symlink( ".", $lockfile ) ){
			$retry++;
			&Error( $msg.'(symlink)' )	if( $retry >= 3 );
			sleep( 2 );
		}
	}else{
		while( -f "$lockfile" ){
			$retry++;
			&Error( $msg )	if( $retry >= 3 );
			sleep( 2 );
		}
		open( LOCK, ">$lockfile" );
		close( LOCK );
	}
}
sub LockEnd
{
	unlink $lockfile	if( -e $lockfile );
}
