#!/usr/bin/perl
#
# index.cgi
#
# Version 1.0.5
#
# Copyright (C) 1997 by Hiroshi Yuki.
# All rights reserved.
# 結城浩 <hyuki@st.rim.or.jp>
# http://www.st.rim.or.jp/~hyuki/
#
#『Perlで作るCGI入門　基礎編』　結城浩著　ソフトバンク(株)刊　ISBN 4-7973-0507-X
#
##########
# 設定部分
# ↓実行テストを単独で行うとき 1 にする。
$testing    = 0;
# ↓漢字ライブラリ jcode.pl のファイル名
$jcodelib   = 'jcode.pl';
# ↓クッキーライブラリのファイル名
$cookielib  = 'cookie.lib';
# ↓保存されるファイルの漢字コード（'sjis' 'euc' 'jis' のいずれか）
$kanjicode  = 'euc';
# ↓（必ず修正）あなたの名前（画面の最下部に表示）
$modifier  = '小出哲也';
# ↓（必ず修正）あなたのホームページのURL（「ホームページへ戻る」のリンク先）
$homepage   = 'http://joker.gs.human.nagoya-u.ac.jp/~koide/index.html';
# ↓（必ず修正）あなたのメールアドレス（エラー時に表示）
$admin      = 'koide@view.human.nagoya-u.ac.jp';
# ↓保存される掲示板のファイル名
$txtfile    = 'bbs.txt';
# ↓この掲示板の名前（クッキーで使用、複数掲示板を持つときには別の名前にする）
$boardname  = 'bbs';
# ↓表示される最大のメッセージの数
$maxmsg     = 1000;
# ↓このスクリプトのURL
$bbsurl   = 'index.cgi';
# ↓日付
$dateofsite = system("date &");
# ↓表示されるページの <BODY> タグ（背景色や背景イメージ指定で利用）
$bodytag    = '<BODY BGCOLOR="#e0ffdd" vlink="green" link="red">';
##########
# ロック関連
$uselock    = 1; # ロックを使うなら1。うまく動かないとき0にする。
$LOCK_NBEX  = 6; # ブロックしない排他的ロック
$LOCK_UN    = 8; # アンロック
$unlockwait = 0; # ロックテスト用。ロックはずす前に待つ秒数指定。

# 漢字ライブラリの読み込み
require "$jcodelib";

# クッキーライブラリの読み込み
require "$cookielib";

# 初期化
&init_form($kanjicode);

# ヘッダの送出(クッキー用に改行は一個だけ)
print "Content-type: text/html\n";

&SetCookieExpDate('Fri, 31-Dec-1999 00:00:00 GMT');
&GetCompressedCookies($boardname);

# フォームの表示用
$c_myname   = $Cookies{'myname'};
$c_mymail   = $Cookies{'mymail'};
$c_myhttp   = $Cookies{'myhttp'};
#if ($c_myhttp eq '') {
#    $c_myhttp = 'http://';
#}

# 情報の取得
if ($testing) {
    # 動作テスト用
    $myname     = '佐藤花子';
    $mymail     = 'hanako@abc.ac.jp';
    $mycomment  = '楽しいページですね。これからもよろしく。';
    $myhttp     = 'http://www.abc.ac.jp/~hanako/';
    $mycookie   = 'on';
    $myaction   = 'write';
} else {
    $myname     = $form{'myname'};
    $mymail     = $form{'mymail'};
    $myhttp     = $form{'myhttp'};
    $mycomment  = $form{'mycomment'};
    $mycookie   = $form{'mycookie'};
    $myaction   = $form{'myaction'};
}

# タグの入力を禁止する
$myname =~ s/</&lt;/g;
$mymail =~ s/</&lt;/g;
$myhttp =~ s/</&lt;/g;
$mycomment =~ s/</&lt;/g;

# 書き込みの場合
if ($myaction eq "write") {

    # 名前が入力されているかどうかの確認
    if ($myname eq '') {
        &print_error("名前を書いてね。");
    }

    # 内容が入力されているかどうかの確認（メッセージなしでも入力可能に改良。by小出）
    #if ($mycomment eq '') {
    #    &print_error("何かメッセージを書いてね。");
    #}

    if ($mycookie eq 'on') {
        # この時点での値をクッキーとして設定する。
        &SetCompressedCookies($boardname, 'myname', $myname, 'mymail', $mymail, 'myhttp', $myhttp);
        # フォームの表示用
        $c_myname   = $myname;
        $c_mymail   = $mymail;
        $c_myhttp   = $myhttp;
    }

    # 日付文字列
    $datestr = &get_date_string;

    # Emailからタグを作成
    if ($mymail ne '') {
        $mymail = "&lt;<A HREF=mailto:$mymail>$mymail</A>&gt;";
    }

    # http からタグを作成
    if ($myhttp ne 'http://') {
        $myhttp = "<A HREF=$myhttp>$myhttp</A>";
    }

    # 一行に変換する
    $mycomment =~ s/\r\n/<BR>/g;
    $mycomment =~ s/\n/<BR>/g;
    $mycomment =~ s/<BR><BR>/<BR> <BR>/g;

    # 書き込みメッセージ構成
    $message = "<font color=orange><B>$myname </B></font><BR>$myhttp<PRE>$mycomment</PRE><HR>";

    # データファイルのオープン
    if (!open(TXT, "+<$txtfile")) {
        &print_error("データファイルに書き込みができません。");
    }

    # ファイルのロック
    if (!&lock_file(TXT)) {
        close(TXT);
        &print_error("誰かが今書き込んでいるので、時間を置いて書き込みましょう。");
    }

    # 読み込む
    seek(TXT, 0, 0);
    @lines = <TXT>;

    # 書き込むため先頭に戻す
    seek(TXT, 0, 0);

    # メッセージを一行で書くこと
    print TXT "$message";
    print TXT "\n";

    # これまでのメッセージをコピー
    for ($i = 0; $i < $maxmsg - 1 && $i <= $#lines; $i++) {
        print TXT "$lines[$i]";
    }

    # 現在までの大きさでファイルを切りつめる
    $filesize = tell(TXT);
    truncate(TXT, $filesize);
    &unlock_file(TXT);
    close(TXT);
}

# この空行は重要(！)
# HTTPヘッダの終わり
print "\n";

&show_head;              # 上の部分の表示
&show_file($txtfile);   # データファイルの表示
&show_foot;              # 下の部分の表示

exit(0);

##########

# はじめの部分の表示
sub show_head {
print <<"end_of_show_head";
<HTML>
<HEAD>
<TITLE>マイメモTips</TITLE>

<!-- アンカーのアンダーバーを非表示にする処理 -->
<STYLE>
	<--A{text-decoration:none;}-->
	<!--A:hover{background-color:#ffffaa;}-->
</STYLE>

<script language="JavaScript1.2">
<!--
function FIN(i){
	if(window.find(i, true)){
		alert("「"+i+"を発見！");
	}else{
		alert("見つからぬ...無念！");
	}
}
-->
</script>

</HEAD>

$bodytag

<a href="../index.html">戻る</a>

<div style="z-index:2; position:absolute; top:8; left:50; font-size:20pt; color:greenyellow;">マイメモTips</div>
<div style="z-index:3; position:absolute; top:5; left:47; font-size:20pt; color:green;">マイメモTips</div>

<div style="z-index:1; position:absolute; top:16; left:200;">
	<B><font color=purple>VineLinux</font></B>や
	<B><font color=green>Windows</font></B>について随時メモってます．
</div>

<!--
<br><br>内容検索 <input type="text" name="fin1" value="" size="15">
<input type="button" name="fin2" value="検索" onClick="FIN(fin1.value)">
-->
<hr>

end_of_show_head
}

# おわりの部分の表示
sub show_foot {
print <<"end_of_show_foot";
<A NAME="write">
<FORM ACTION="$bbsurl#list" METHOD="post">
タイトル  
  <INPUT TYPE="text" SIZE=40 NAME="myname" VALUE="$c_myname">
<!--パス  
  <INPUT TYPE="text" SIZE=20 NAME="mypass" VALUE="$c_mypass">-->
<br>
<!--
  メールアドレス<br>
  <INPUT TYPE="text" SIZE=30 NAME="mymail" VALUE="$c_mymail"><P>
  URLはここ。<P>
-->
  URL:　<INPUT TYPE="text" SIZE=75 NAME="myhttp" VALUE="$c_myhttp">
<!--  <INPUT TYPE="CHECKBOX" NAME="mycookie" VALUE="on" CHECKED>次回もこの情報を使う<P>
-->
  <br>
  <TEXTAREA NAME="mycomment" COLS=60 ROWS=4></TEXTAREA><br>
  <INPUT TYPE="submit" VALUE="書き込み">　<INPUT TYPE="reset" VALUE="リセット">
  <INPUT TYPE="hidden" NAME="myaction" VALUE="write">
</FORM>

<A NAME="list">
	</BODY>
	</HTML>
end_of_show_foot
}

# ファイルの表示
sub show_file {
    local($filename) = @_;
    local($i);

    # オープン
    if (!open(TXT, "$filename")) {
        &print_error("ファイル $filename がないです。");
    }

    # ロック
    if (!&lock_file(TXT)) {
        close(TXT);
        &print_error("作業中なのでファイルが読めないです。");
    }

    # 読み込む
    seek(TXT, 0, 0);
    @lines = <TXT>;

    # すぐにアンロック
    &unlock_file(TXT);

    # クローズ
    close(TXT);

    # すべて表示
    for ($i = 0; $i <= $#lines; $i++) {
        print "$lines[$i]";
    }
}

# 現在日時を文字列化する
sub get_date_string {
    local($sec, $min, $hour, $day, $mon, $year);
    ( $sec, $min, $hour, $day, $mon, $year ) = localtime(time);
    $year += 1900;
    $mon++;
    # 必要なら０を付加する
    if ($hour < 10) {
        $hour = "0$hour";
    }
    if ($min < 10) {
        $min  = "0$min";
    }
    if ($sec < 10) {
        $sec  = "0$sec";
    }
    return "$year年$mon月$day日 $hour時$min分";
}

# タイトル部分
# &page_begin("メッセージ");
sub page_begin {
    local ($msg) = @_;
    print "\n";
    print "<HTML>\n";
    print "<HEAD>\n";
    print "<TITLE>$msg</TITLE>\n";
    print "</HEAD>\n";
    print "$bodytag\n";
    print "<H1>$msg</H1>\n";
}

# ページの終わり
sub page_end {
    print "<HR>\n";
    print "<A HREF=$homepage>戻る。</A>\n";
    print "<HR>\n";
    print "<H4>Modified by $modifier</H4>\n";
    print "</BODY>\n";
    print "</HTML>\n";
}

# エラー表示
# &print_error("メッセージ");
sub print_error {
    local($msg) = @_;
    &page_begin($msg);
#    print "もう一度試すか、";
#    print "<A HREF=mailto:$admin>$admin</A>";
#    print "まで連絡して。\n";
    &page_end($msg);
    exit(0);
}

# ロック
sub lock_file {
    local(*FILE) = @_;
    local($retry_count) = 10;
    if ($uselock) {
        while ($retry_count-- > 0) {
            $lockresult = eval("flock(FILE, $LOCK_NBEX)");
            if ($@) {
                # flock が使えない場合
                $uselock = 0;
                $retry_count = 0; # ロックできたことにしてしまう
                last;
            }
            if (!$lockresult) {
                sleep(2);
            } else {
                last;
            }
        }
    }
    if ($retry_count >= 0) {
        # ロックできた
        return 1;
    } else {
        # ロックできなかった
        return 0;
    }
}

# アンロック
sub unlock_file {
    local(*FILE) = @_;
    if ($uselock) {
        if ($unlockwait > 0) {
            sleep($unlockwait);
        }
        flock(FILE, $LOCK_UN);
    }
}

# フォームからの情報を連想配列 %form に入れる
# &init_form('euc');
sub init_form {
    local($query, @assocarray, $assoc, $property, $value, $charcode, $method);
    $charcode = $_[0];
    $method = $ENV{'REQUEST_METHOD'};
    $method =~ tr/A-Z/a-z/;
    if ($method eq 'post') {
        read(STDIN, $query, $ENV{'CONTENT_LENGTH'});
    } else {
        $query = $ENV{'QUERY_STRING'};
    }
    @assocarray = split(/&/, $query);
    foreach $assoc (@assocarray) {
        ($property, $value) = split(/=/, $assoc);
        $value =~ tr/+/ /;
        $value =~ s/%([A-Fa-f0-9][A-Fa-f0-9])/pack("C", hex($1))/eg;
        &jcode'convert(*value, $charcode);
        $form{$property} = $value;
    }
}

# 修正履歴
# 1998-01-30 Version 1.0.5  flock 使えないときは lock を断念するようにした。
# 1998-11-06 Version 1.0.4  出版時公開版
