#!/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/&/&/g;
$text =~ s/"/"/g;
$text =~ s/,/,/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);
}
}