#!/usr/local/bin/perl

#

# schedule.cgi

#

# Version 1.0.0

#

# Copyright (C) 2000 by Minomusi

# http://members.cool.jp/~minomusi/

##########

# 設定部分

# ↓漢字ライブラリ jcode.pl のファイル名

$jcodelib = 'jcode.pl';

# ↓保存されるファイルの漢字コード('sjis' 'euc' 'jis' のいずれか)

$kanjicode = 'sjis';

#電子メールの宛先

$admin = 'minomusi.ztv.ne.jp';

# ↓表示されるページの <BODY> タグ(背景色や背景イメージ指定で利用)

$bodytag = '<BODY BGCOLOR="#FFFFFF">';

#保存ファイル名

$files = 'schedule.txt';

##########

# 設定部分

# ロック関連

$uselock = 1; # ロックを使うなら1。うまく動かないとき0にする。

$LOCK_NBEX = 6; # ブロックしない排他的ロック

$LOCK_UN = 8; # アンロック

$unlockwait = 0; # ロックテスト用。ロックはずす前に待つ秒数指定。

# 漢字ライブラリの読み込み

require "$jcodelib";

# 初期化

&init_form($kanjicode);

# ヘッダの送出

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

# 情報の取得

$year = $form{'year'};

$mon = $form{'mon'};

$day = $form{'day'};

$text = $form{'text'};

$submit = $form{'submit'};

# ファイルのオープン

if (!open(SCHEDULE,"$files")) {

&print_error("スケジュールファイルが見つかりません。");

}

# これまでのデータファイルを読み込む。

@data = <SCHEDULE>;

# ファイルを閉じる

close(SCHDULE);

# データ数を確認

$ban=$#data;

# データ配列を連想配列に格納

for ($kaz=0; $kaz<=$ban; $kaz=$kaz+2){

chop($data1=$data[$kaz]);

chop($data2=$data[$kaz+1]);

$scedule{$data1}=$data2;

}

# 現在日時を読み込む

$datestr = &get_date_string;

# スケジュールファイルからキーの一覧を読み取る。

@filedays = keys %scedule;

# 古くなったスケジュールを削除

foreach $list (@filedays){

if ($list<$datestr){

delete $scedule{$list};

}

}

# カレンダーから受け取った月、日を2桁にする。

$month = $mon+1;

$monthday = sprintf("%02d",$month);

$thisday = sprintf("%02d",$day);

$calenday = "$year$monthday$thisday";

# 削除ボタンが押されていれば、ファイルを削除

if ($submit eq "削除"){

delete $scedule{$calenday};

}

# テキストファイルから特殊文字を変換

$text =~ s/&/&amp;/g;

$text =~ s/"/&quot;/g;

$text =~ s/,/&#44;/g;

# テキストを一行に変換する

$text =~ s/\r\n/<BR>/g;

$text =~ s/\n/<BR>/g;

$text =~ s/<BR><BR>/<BR> <BR>/g;

# 更新ボタンが押されていれば、ファイルを更新

if ($submit eq "更新"){

$scedule{$calenday} = $text;

}

# ファイルの書き込み

&file_change($files,%scedule);

# 指定した日時が現在よりも小さければ、エラーを表示。

if ($calenday<$datestr){

&print_error("現在より前のスケジュールは削除されています。");

}

# 指定した日のファイルを検索

$text=$scedule{"$calenday"};

# テキストの改行

$text=~s/<BR>/\n/g;

# 表示開始

&page_begin("スケジュール");

&home_begin;

&page_end;

# 終了

exit(0);

#

# 以下はサブルーチン

#

exit(0);

##########

# 本体部分

# &home_begin;

sub home_begin {

$hyouji='表示';&jcode'convert(*hyouji, $kanjicode);

print <<"END_OF_HTML";

<FORM ACTION="schedule.cgi" ENCTYPE=x-www-form-encoded METHOD=POST>

<CENTER>

<TABLE BGCOLOR="#228b22">

<TH>

<FONT SIZE=5 COLOR="#FFFFFF">スケジュール</FONT>

</TH>

</TABLE>

<INPUT TYPE="hidden" NAME="year" VALUE=$year>

<INPUT TYPE="hidden" NAME="mon" VALUE=$mon>

<INPUT TYPE="hidden" NAME="day" VALUE=$day>

$year 年 $month 月 $day 日<p>

<TEXTAREA NAME="text" ROWS="22" COLS="72"

>$text</TEXTAREA><P>

<INPUT NAME="submit" TYPE="submit" VALUE="更新"><SPACER SIZE="20"><INPUT TYPE="reset" VALUE="リセット"><SPACER SIZE="20"><INPUT NAME="submit" TYPE="submit" VALUE="削除"><SPACER SIZE="20"><INPUT TYPE="button" VALUE="カレンダー" onClick="javascript:location.href='calendar.cgi?year=$year&mon=$mon&button=1'">

<P>

<TABLE>

<TD ALIGN="left">

<UL>

<LI>書き込み、書き換えの時は、書き込んだあと、更新ボタンをクリックして下さい。

<LI>スケジュールデータを削除したい時は、削除ボタンをクリックして下さい。

<LI>リセットボタンをクリックしても、$hyouji部分が変化するだけで、データは削除されません。

<LI>キャッシュが残っているために、データが変化していないように見える場合があります。<BR>

おかしいなと思ったときは、ブラウザのリロードボタンをクリックしてみて下さい。

</UL>

</TD>

</TABLE>

</CENTER>

</FORM>

END_OF_HTML

}

# タイトル部分

# &page_begin("メッセージ");

sub page_begin {

local ($msg) = @_;

print "<HTML>\n";

print "<HEAD>\n";

print "<TITLE>$msg</TITLE>\n";

print "</HEAD>\n";

print "$bodytag\n";

}

# ページの終わり

sub page_end {

print "</BODY>\n";

print "</HTML>\n";

exit(0);

}

# フォームからの情報を連想配列 %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;

}

}

# エラー表示

# &print_error("メッセージ");

sub print_error {

local($msg) = @_;

&page_begin($msg);

print "<H2>$msg</H2>\n";

print "恐れ入りますが、再度試していただくか、";

print "<A HREF=mailto:$admin>$admin</A>";

print "までお知らせください。\n";

print "<BR><CENTER><FORM><INPUT TYPE=\"button\" value=\"戻る\" onClick=\"JavaScript:history.back()\"></FORM></CENTER>\n";

&page_end;

}

# 現在日時を読み込む

sub get_date_string {

local($sec, $min, $hour, $day, $mon, $year);

( $sec, $min, $hour, $day, $mon, $year ) = localtime(time);

$year += 1900;

$mon++;

$mon = sprintf("%02d",$mon);

$day = sprintf("%02d",$day);

return "$year$mon$day";

}

# ファイルを開き、書き込む

sub file_change {

local($filename,@files,@data);

($filename,@files)=@_;

if (!open(FILE,">$filename")) {

&print_error("ファイルが見つかりません。");

}

if (!&lock_file(FILE)) {

close(FILE);

&print_error("書き込みの衝突が起きました。");

}

foreach $list(@files){

print FILE "$list\n";

}

truncate(FILE, tell(FILE));

&unlock_file(FILE);

close(FILE);

}

# ロック

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);

}

}