#!/usr/bin/perl

#┌─────────────────────────────────
#│ TOPICS BOARD : topics.cgi - 2012/12/31
#│ Copyright (c) KentWeb
#│ http://www.kent-web.com/
#└─────────────────────────────────

# モジュール宣言
#use strict;
use CGI::Carp qw(fatalsToBrowser);
use lib "./lib";
use CGI::Minimal;
use Jcode;

# 設定ファイル認識
require "./init.cgi";
my %cf = &init;

# データ受理
CGI::Minimal::max_read_size($cf{maxdata});
my $cgi = CGI::Minimal->new;
&error('容量オーバー') if ($cgi->truncated);
my %in = &parse_form($cgi);
my $message="";

# 処理分岐
if ($in{mode} eq 'find') { &find_log; }
if ($in{mode} eq 'find') { &find_log; }
if ($in{mode} eq 'new') { &add_data; }
if ($in{poptag}) { &poptag; }
&bbs_list;

#-----------------------------------------------------------
#  記事表示
#-----------------------------------------------------------
sub bbs_list {
	# ページ数
	my $pg = $in{pg} || 0;

	# データ認識
	my ($i,@log);
	open(IN,"$cf{logfile}") or &error("open err: $cf{logfile}");
	while(<IN>) {
		my ($no,$date,$name,$sub,$com,$e1,$w1,$h1,$e2,$w2,$h2,$e3,$w3,$h3,$tag,$clip,$tube,$permission) = split(/<>/);
		if($permission ne "checked"){next;}
		$i++;
		next if ($i < $pg + 1);
		next if ($i > $pg + $cf{pg_max});

		push(@log,$_);
	}
	close(IN);

	#投稿フォーム作成
	$ENV{TZ} = "JST-9";
	my ($min,$hur,$mday,$mon,$year) = (localtime(time))[1..5];
	my $date = sprintf("%04d. %02d. %02d", $year+1900,$mon+1,$mday,$hur,$min);
	
	my $bbs_form =  <<"EOM";
	<br>
<div class="sub">
■投稿フォーム
</div>
<div style="text-align:left; margin-left:60px;">
<ul>
<li>HTMLタグを有効にする場合改行は無効となるため、改行する部分で &lt;br&gt; と記述すること。
<li>画像またはYouTubeタグ（ニコ動画等も可）を添付することができます（任意）。
</ul>
</div>
	<br>
<form action="$cf{bbs_cgi}" method="post" enctype="multipart/form-data">
<input type="hidden" name="mode" value="new">
<input type="hidden" name="date" value="$date">
<div  align="center">
<table border="1" cellpadding="10" cellspacing="0" class="form"  width="680">
<tr>
	<th style="padding:10px;" width="100">件名</th>
	<td style="padding:10px;"><input type="text" name="sub" value="" size="40"></td>
</tr><tr>
	<th style="padding:10px;" width="100">名前</th>
	<td style="padding:10px;"><input type="text" name="name" value="" size="40"></td>
</tr><tr>
	<th style="padding:10px;" width="100">本文</th>
	<td style="padding:10px;"><input type="checkbox" name="tag" value="1" >HTMLタグ有効 (但し改行は無効)<br>
		<textarea name="comment" cols="50" rows="6"></textarea>
	</td>
</tr><tr>
	<th style="padding:10px;" width="100">添付</th>
	<td style="padding:10px;">
		<input type="radio" name="clip" value="i" onclick="entryChange1();" checked>画像
		<input type="radio" name="clip" value="t" onclick="entryChange1();" >YouTube
	</td>
</tr><tr id="ibox">
	<th style="padding:10px;" width="100">画像</th>
	<td style="padding:10px;" nowrap>
EOM

	foreach my $i (1 .. 1) {
		$bbs_form .=  qq|画像$i : <input type="file" name="upfile$i" size="35">\n|;
		$bbs_form .= "<br>\n";
	}

	$bbs_form .= <<EOM;
	</td>
</tr><tr id="ybox">
	<th style="padding:10px;" width="100">YouTube<br>タグ</th>
	<td style="padding:10px;"><textarea name="tube" cols="50" rows="4"></textarea></td>
</tr>
</table>
</div>
<br>
<input type="submit" value="送信する">
</form>
EOM

	# 繰越ボタン作成
	my $pg_btn = &make_pgbtn($i,$pg);

	# テンプレート読み込み
	open(IN,"$cf{tmpldir}/bbs.html") or &error("open err: bbs.html");
	my $tmpl = join('', <IN>);
	close(IN);
	
	use Encode qw/ from_to /;
	use Encode::Guess qw/ shiftjis 7bit-jis euc-jp /;
	
	open(IN,"../admin/skin/dir.txt");
	flock(IN, LOCK_EX);
	$dir = <IN>;
	close(IN);
	
	
	open(IN,"../admin/skin/head.html");
	flock(IN, LOCK_EX);
	my @head = <IN>;
	close(IN);
	foreach $line (@head) {
		$line =~ s/\[dir\]/$dir/ig;
		$head .= $line;
	}
	
	open(IN,"../admin/skin/navi.html");
	flock(IN, LOCK_EX);
	my @navi = <IN>;
	close(IN);
	foreach $line (@navi) {
		$line =~ s/\[dir\]/$dir/ig;
		$navi .= $line;
	}
	
	open(IN,"../admin/skin/foot.html");
	flock(IN, LOCK_EX);
	my @foot = <IN>;
	close(IN);
	foreach $line (@foot) {
		$line =~ s/\[dir\]/$dir/ig;
		$foot .= $line;
	}
	
	from_to ( $head , 'utf8' , 'shiftjis' );
	from_to ( $navi , 'utf8' , 'shiftjis' );
	from_to ( $foot , 'utf8' , 'shiftjis' );
	
	$tmpl =~ s/\<\!\-\-head\-\-\>/$head/ig;
	$tmpl =~ s/\<\!\-\-navi\-\-\>/$navi/ig;
	$tmpl =~ s/\<\!\-\-foot\-\-\>/$foot/ig;
		
	# テンプレート分割
	my ($head,$loop,$foot) = $tmpl =~ /(.+)<!-- loop_begin -->(.+)<!-- loop_end -->(.+)/s
			? ($1,$2,$3) : &error("テンプレートが不正です");

	# 文字置換
	for ($head, $foot) {
		s/!bbs_title!/$cf{bbs_title}/g;
		s/!([a-z]+_cgi)!/$cf{$1}/g;
		s/!page_btn!/$pg_btn/g;
		s/!homepage!/$cf{homepage}/g;
		s/!bbs_form!/$bbs_form/g;
	}

	# ヘッダ表示
	print "Content-type: text/html; charset=shift_jis\n\n";
	print $head;
	
	print '<div><strong>'.$message.'</strong></div>' if($message);

	# 記事展開
	foreach (@log) {
		my ($no,$date,$name,$sub,$com,$e1,$w1,$h1,$e2,$w2,$h2,$e3,$w3,$h3,$tag,$clip,$tube,$permission) = split(/<>/);
		if ($tag == 1) {
			$com = &tag($com);
		} elsif ($cf{autolink}) {
			$com = &autolink($com);
		}

		# YouTube
		my $att;
		if ($clip eq 't') {
			$att = &tag($tube) if ($tube);

		# 画像
		} else {
			if ($e1) { $att .= &image(1,$no,$e1,$w1,$h1); }
			if ($e2) { $att .= &image(2,$no,$e2,$w2,$h2); }
			if ($e3) { $att .= &image(3,$no,$e3,$w3,$h3); }
		}

		# 文字置換
		my $tmp = $loop;
		$tmp =~ s/!date!/$date/g;
		$tmp =~ s/!name!/$name/g;
		$tmp =~ s/!subject!/$sub/g;
		$tmp =~ s/!comment!/$com/g;
		$tmp =~ s/<!-- clip -->/$att/g;
		print $tmp;
	}


	# フッタ（著作権表記は削除・改変を禁止）
	my $copy = &copyright;
	if ($foot =~ /(.+)(<\/body[^>]*>.*)/si) {
		print "$1$copy$2\n";
	} else {
		print "$foot$copy\n";
		print "</body></html>\n";
	}
	exit;
}

#-----------------------------------------------------------
#  ワード検索
#-----------------------------------------------------------
sub find_log {
	# 条件
	$in{cond} =~ s/\D//g;

	# 検索条件プルダウン
	my %op = (1 => 'AND', 0 => 'OR');
	my $op_cond;
	foreach (1,0) {
		if ($in{cond} eq $_) {
			$op_cond .= qq|<option value="$_" selected>$op{$_}\n|;
		} else {
			$op_cond .= qq|<option value="$_">$op{$_}\n|;
		}
	}

	# 検索実行
	my @log = &search($in{word},$in{cond}) if ($in{word} ne '');

	# テンプレート
	open(IN,"$cf{tmpldir}/find.html") or &error("open err: find.html");
	my $tmpl = join('', <IN>);
	close(IN);

	# 分割
	my ($head,$loop,$foot) = $tmpl =~ /(.+)<!-- loop_begin -->(.+)<!-- loop_end -->(.+)/s
			? ($1,$2,$3) : &error("テンプレートが不正です");

	for ($head, $foot) {
		s/!bbs_cgi!/$cf{bbs_cgi}/g;
		s/<!-- op_cond -->/$op_cond/;
		s/!word!/$in{word}/;
	}

	# ヘッダ部
	print "Content-type: text/html; charset=shift_jis\n\n";
	print $head;

	# ループ部
	foreach (@log) {
		my ($no,$date,$name,$sub,$com,$e1,$w1,$h1,$e2,$w2,$h2,$e3,$w3,$h3,$tag,$clip,$tube,$permission) = split(/<>/);
		if ($tag == 1) {
			$com = &tag($com);
		} elsif ($cf{autolink}) {
			$com = &autolink($com);
		}

		# YouTube
		my $att;
		if ($clip eq 't') {
			if ($tube) {
				$att = qq|[<a href="$cf{bbs_cgi}?poptag=$no" target="pop" onclick="popup('!bbs_cgi!?poptag=$no')">埋込タグ</a>]|;
			}

		# 画像
		} else {
			if ($e1) {
				$att .= qq|[<a href="$cf{imgurl}/$no-1$e1" target="_blank">画像1</a>]\n|;
			}
			if ($e2) {
				$att .= qq|[<a href="$cf{imgurl}/$no-2$e2" target="_blank">画像2</a>]\n|;
			}
			if ($e3) {
				$att .= qq|[<a href="$cf{imgurl}/$no-3$e3" target="_blank">画像3</a>]\n|;
			}
		}
		if ($att) { $com .= "<p>$att</p>"; }

		my $tmp = $loop;
		$tmp =~ s/!name!/$name/g;
		$tmp =~ s/!sub!/$sub/g;
		$tmp =~ s/!date!/$date/g;
		$tmp =~ s/!comment!/$com/g;
		print $tmp;
	}

	# フッタ部
	if ($foot =~ /(.+)(<\/body[^>]*>.*)/si) {
		print "$1$cf{copyright}$2";
	} else {
		print "$foot$cf{copyright}";
		print "</body></html>\n";
	}
	exit;
}

#-----------------------------------------------------------
#  検索実行
#-----------------------------------------------------------
sub search {
	my ($word,$cond) = @_;

	# コード変換
	if ($cf{conv_code} == 1) {
		$in{word} = Jcode->new($in{word})->sjis;
	}

	# キーワードを配列化
	$word =~ s/　/ /g;
	my @wd = split(/\s+/, $word);

	# キーワード検索準備（Shift-JIS定義）
	my $ascii = '[\x00-\x7F]';
	my $hanka = '[\xA1-\xDF]';
	my $kanji = '[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]';

	# 検索処理
	my @log;
	open(IN,"$cf{logfile}") or &error("open err: $cf{logfile}");
	while (<IN>) {
		#my ($no,$date,$nam,$eml,$name,$sub,$com,$url,$hos,$pw,$tim) = split(/<>/);
		my ($no,$date,$nam,$eml,$name,$sub,$com,$url,$hos,$pw,$tim, $e3,$w3,$h3,$tag,$clip,$tube,$permission) = split(/<>/);
		if($permission ne "checked"){next;}
		
		my $flg;
		foreach my $wd (@wd) {
			if ("$nam $eml $name $sub $com $url" =~ /^(?:$ascii|$hanka|$kanji)*?\Q$wd\E/i) {
				$flg++;
				if ($cond == 0) { last; }
			} else {
				if ($cond == 1) { $flg = 0; last; }
			}
		}
		next if (!$flg);

		push(@log,$_);
	}
	close(IN);

	# 検索結果
	return @log;
}

#-----------------------------------------------------------
#  ポップアップ埋込タグ
#-----------------------------------------------------------
sub poptag {
	$in{poptag} =~ s/\D//g;

	my $tube_tag;
	open(IN,"$cf{logfile}") or &error("open err: $cf{logfile}");
	while(<IN>) {
		my ($no,$date,$name,$sub,$com,$e1,$w1,$h1,$e2,$w2,$h2,$e3,$w3,$h3,$tag,$clip,$tube,$permission) = split(/<>/);
		if(!$permission){next;}

		if ($in{poptag} == $no) {
			$tube_tag = $tube;
			last;
		}
	}
	close(IN);

	open(IN,"$cf{tmpldir}/poptag.html") or &error("open err: poptag.html");
	my $tmpl = join('', <IN>);
	close(IN);

	$tmpl =~ s/!tag!/&tag($tube_tag)/eg;

	print "Content-type: text/html; charset=shift_jis\n\n";
	print $tmpl;
	exit;
}

#-----------------------------------------------------------
#  繰越ボタン作成
#-----------------------------------------------------------
sub make_pgbtn {
	my ($i,$pg) = @_;

	# ページ繰越定義
	my $next = $pg + $cf{pg_max};
	my $back = $pg - $cf{pg_max};

	# ページ繰越ボタン作成
	my $pg_btn;
	if ($back >= 0 || $next < $i) {
		$pg_btn .= "Page: ";

		my ($x, $y) = (1, 0);
		while ($i > 0) {
			if ($pg == $y) {
				$pg_btn .= qq(| <b>$x</b> );
			} else {
				$pg_btn .= qq(| <a href="$cf{bbs_cgi}?pg=$y">$x</a> );
			}
			$x++;
			$y += $cf{pg_max};
			$i -= $cf{pg_max};
		}
		$pg_btn .= "|";
	}
	return $pg_btn;
}

#-----------------------------------------------------------
#  著作権表記（削除・改変を禁ず）
#-----------------------------------------------------------
sub copyright {
	my $copy = <<EOM;
<p style="margin-top:3em;text-align:center;font-family:Verdana,Helvetica,Arial;font-size:10px;">
<a href="http://www.kent-web.com/" target="_top"></a>
</p>
EOM
	return $copy;
}

#-----------------------------------------------------------
#  自動リンク
#-----------------------------------------------------------
sub autolink {
	my $text = shift;

	$text =~ s/(s?https?:\/\/([\w-.!~*'();\/?:\@=+\$,%#]|&amp;)+)/<a href="$1" target="_blank">$1<\/a>/g;
	return $text;
}

#-----------------------------------------------------------
#  タグ復元
#-----------------------------------------------------------
sub tag {
	local($_) = @_;

	s/&lt;/</g;
	s/&gt;/>/g;
	s/&amp;/&/g;
	s/&quot;/"/g;
	$_;
}

#-----------------------------------------------------------
#  画像表示
#-----------------------------------------------------------
sub image {
	my ($i,$no,$ex,$w,$h) = @_;

	my $image;
	if (-f "$cf{imgdir}/$no-s-$i$ex") {
		$image = qq|<img src="$cf{imgurl}/$no-s-$i$ex" class="img">|;

	} else {
		($w,$h) = &resize($w,$h);
		$image = qq|<img src="$cf{imgurl}/$no-$i$ex" width="$w" height="$h" class="img">|;
	}
	#return qq|<a href="$cf{imgurl}/$no-$i$ex" target="_blank">$image</a>\n|;
	return qq|$image\n|;
}


#-----------------------------------------------------------
#  記事追加
#-----------------------------------------------------------
sub add_data {
	# 入力チェック
	&input_check;
	$in{tube} =~ s/<br>//g;

	# コード変換
	if ($cf{conv_code} == 1) {
		$in{name} = Jcode->new($in{name})->sjis;
		$in{sub} = Jcode->new($in{sub})->sjis;
		$in{comment} = Jcode->new($in{comment})->sjis;
	}

	# データオープン
	my ($num,@file);
	open(DAT,"+< $cf{logfile}") or &error("open err: $cf{logfile}");
	while (<DAT>) {
		my ($no) = (split(/<>/))[0];

		if ($num < $no) { $num = $no; }
		push(@file,$_);
	}

	# 採番
	$num++;

	# 画像アップ
	my ($e1,$w1,$h1,$e2,$w2,$h2,$e3,$w3,$h3);
	if ($in{upfile1} || $in{upfile2} || $in{upfile3}) {
		($e1,$w1,$h1,$e2,$w2,$h2,$e3,$w3,$h3) = &upload($num);
	}

	# 最大記事数調整
	while ( $cf{max} - 1 <= @file ) {
		my $del = pop(@file);
		my ($no,$date,$name,$sub,$com,$e1,$w1,$h1,$e2,$w2,$h2,$e3,$w3,$h3,$tag,$clip,$tube,$permission) = split(/<>/, $del);
		if ($e1) {
			unlink("$cf{imgdir}/$no-1$e1");
			unlink("$cf{imgdir}/$no-s-1$e1") if (-f "$cf{imgdir}/$no-s-1$e1");
		}
		if ($e2) {
			unlink("$cf{imgdir}/$no-2$e2");
			unlink("$cf{imgdir}/$no-s-2$e2") if (-f "$cf{imgdir}/$no-s-2$e2");
		}
		if ($e3) {
			unlink("$cf{imgdir}/$no-3$e3");
			unlink("$cf{imgdir}/$no-s-3$e3") if (-f "$cf{imgdir}/$no-s-3$e3");
		}
	}

	# 更新
	unshift(@file,"$num<>$in{date}<>$in{name}<>$in{sub}<>$in{comment}<>$e1<>$w1<>$h1<>$e2<>$w2<>$h2<>$e3<>$w3<>$h3<>$in{tag}<>$in{clip}<>$in{tube}<><>\n");
	seek(DAT, 0, 0);
	print DAT @file;
	truncate(DAT, tell(DAT));
	close(DAT);
	
	
	if($to_mail){
		my $mailmes  = $cf{bbs_title}."に投稿がありました。\n";
		my $comment = $in{comment};
		$comment =~ s/<br>/\n/ig;
		
		$mailmes .= "\n";
		$mailmes .= "------------------\n";
		$mailmes .= "タイトル：$in{sub}\n";
		$mailmes .= "名前：$in{name}\n";
		$mailmes .= "\n";
		$mailmes .= "$comment\n";
		$mailmes .= "\n";
		$mailmes .= "投稿日時：$in{date}\n";
		$mailmes .= "------------------\n";
		
		&sendmail($to_mail,$from_mail,$subject_mail,$mailmes);
	}
				
	$message = "新規投稿を受け付けました。<br>確認後掲載されます。";
}


#-----------------------------------------------------------
#  メールの送信
#-----------------------------------------------------------
sub sendmail {

	local ($tomail,$frommail,$mail_title,$mail_msg) = @_;
	
	require "./jcode.pl";
	require "./mimew.pl";
	
	# JISコードへ変換
	&jcode'convert(*mail_title,'jis');
	&jcode'convert(*mail_msg,'jis');
	
	#MIMEエンコード
	$mail_title = &mimeencode($mail_title);	
	
	if (open(MAIL,"| /usr/sbin/sendmail -t ")) {
		print MAIL "To: $tomail\n";
		print MAIL "From: $frommail\n";
		print MAIL "MIME-Version: 1.0\n";
		print MAIL "Content-type: text/plain; charset=ISO-2022-JP\n";
		print MAIL "Content-Transfer-Encoding: 7bit\n";
		print MAIL "Subject: $mail_title\n";
		print MAIL "X-Mailer: BBS-Mail-system\n\n";
		print MAIL "$mail_msg\n";
		close(MAIL);
	}
	
}


#-----------------------------------------------------------
#  画像アップロード
#-----------------------------------------------------------
sub upload {
	my $no = shift;

	# サムネイル機能
	require './lib/thumb.pl' if ($cf{thumbnail});

	my @ret;
	foreach my $i (1 .. 3) {
		# 拡張子取得
		my $ext;
		if ($cgi->param_filename("upfile$i") =~ /(\.jpe?g|\.png|\.gif)$/i) {
			$ext = $1;
		} else {
			push(@ret,('','',''));
			next;
		}
		$ext =~ tr/A-Z/a-z/;
		if ($ext eq '.jpeg') { $ext = '.jpg'; }

		# 添付ファイル定義
		my $upfile = "$cf{imgdir}/$no-$i$ext";

		# アップロード書き込み
		open(UP,"+> $upfile") or &error("up err: $upfile");
		binmode(UP);
		print UP $in{"upfile$i"};
		close(UP);

		chmod(0666,$upfile);

		# 画像サイズ取得
		my ($w,$h);
		if ($ext eq ".jpg") { ($w,$h) = &j_size($upfile); }
		elsif ($ext eq ".gif") { ($w,$h) = &g_size($upfile); }
		elsif ($ext eq ".png") { ($w,$h) = &p_size($upfile); }

		# サムネイル作成
		if ($cf{thumbnail}) {
			($w,$h) = &resize($w,$h);
			my $thumb = "$cf{imgdir}/$no-s-$i$ext";
			&make_thumb($upfile,$thumb,$w,$h);
		}

		push(@ret,($ext,$w,$h));
	}

	return @ret;
}

#-----------------------------------------------------------
#  JPEGサイズ認識
#-----------------------------------------------------------
sub j_size {
	my $jpg = shift;

	my ($h, $w, $t);
	open(IMG,"$jpg");
	binmode(IMG);
	read(IMG, $t, 2);
	while (1) {
		read(IMG, $t, 4);
		my ($m, $c, $l) = unpack("a a n", $t);

		if ($m ne "\xFF") {
			$w = $h = 0;
			last;
		} elsif ((ord($c) >= 0xC0) && (ord($c) <= 0xC3)) {
			read(IMG, $t, 5);
			($h, $w) = unpack("xnn", $t);
			last;
		} else {
			read(IMG, $t, ($l - 2));
		}
	}
	close(IMG);

	return ($w, $h);
}

#-----------------------------------------------------------
#  GIFサイズ認識
#-----------------------------------------------------------
sub g_size {
	my $gif = shift;

	my $data;
	open(IMG,"$gif");
	binmode(IMG);
	sysread(IMG, $data, 10);
	close(IMG);

	if ($data =~ /^GIF/) { $data = substr($data, -4); }
	my $w = unpack("v", substr($data, 0, 2));
	my $h = unpack("v", substr($data, 2, 2));

	return ($w, $h);
}

#-----------------------------------------------------------
#  PNGサイズ認識
#-----------------------------------------------------------
sub p_size {
	my $png = shift;

	my $data;
	open(IMG,"$png");
	binmode(IMG);
	read(IMG, $data, 24);
	close(IMG);

	my $w = unpack("N", substr($data, 16, 20));
	my $h = unpack("N", substr($data, 20, 24));

	return ($w, $h);
}



#-----------------------------------------------------------
#  入力チェック
#-----------------------------------------------------------
sub input_check {
	my $err;
	if (!$in{date}) { $err .= "日付が未入力です<br>"; }
	if (!$in{name}) { $err .= "名前が未入力です<br>"; }
	if (!$in{sub}) { $err .= "タイトルが未入力です<br>"; }
	if (!$in{comment}) { $err .= "メッセージが未入力です<br>"; }
	&error($err) if ($err);

	# タグ復元
	if ($in{tag} == 1) {
		$in{comment} =~ s/<br>//g;
	}
}




