#!/usr/local/bin/perl

## --------------------------------------------------------------------------
## Lime Counter v1.1
## by KENT (99/05/22)
## E-Mail: kent@lemon.ne.jp
## WWW: http://www.lemon.ne.jp/~kent/
## ・このスクリプトはフリーソフトです。
## ・このスクリプトを使用したいかなる損害も作者はその責を負いません。
## ・メールによる設置に関する質問はご遠慮ください。
## ---------------------------------------------------------------------------
## [ 1. ページカウンタの使い方 ]
##  a. タグの記述例 (1) ページのURLは自動で取得する場合
##    <IMG SRC="cgi-bin/lime.cgi?page=1&name=ページ名">
##  b. タグの記述例 (2) ページのURLを手動で指定する場合
##    <IMG SRC="cgi-bin/lime.cgi?page=1&name=ページ名
##     &hp=http://www.host.com/~user/">  (注：タグは実際には改行しないで下さい）
##
##  注：・b.のタグ記述例は見やすくするためにわざと２行にして書いていますが、
##        実際に記述する場合には改行せずに「１行で」記述してください。
##      ・「ページ名」の部分は日本語でもOKですが、半角カナや機種依存文字は不可。
##      ・ page=1 の 1 の数値はページ毎に必ず変えてください。
##
##  c. アクセス一覧集計の閲覧例
##     http://www.host.com/~user/cgi-bin/limemgr.cgi
##  d. ファイルロック処理をする場合、lime.cgi を置くディレクトリの
##     パーミッションは 777 とする。
## ----------------------------------------------------------------------------
## [ 2. ダウンロードカウンタの使い方 ]
##  e. タグの記述例 (1) ページのURLは自動で取得する場合
##     <a href="cgi-bin/lime.cgi?down=http://www.host.com/data.lzh&name=テスト">
##      DATA.LZH</a>
##  f. タグの記述例 (2) ページのURLを手動で指定する場合
##     <a href="cgi-bin/lime.cgi?down=http://www.host.com/data.lzh&name=テスト
##      &hp=http://www.host.com/~user/">DATA.LZH</a>
##      (注：タグは実際には改行しないで下さい）
##
##  注：・f.のタグ記述例は見やすくするためにわざと２行にして書いていますが、
##        実際に記述する場合には改行せずに「１行で」記述してください。
##      ・「ページ名」の部分は日本語でもOKですが、半角カナや機種依存文字は不可。
##
##  g. アクセス一覧集計の閲覧例
##     http://www.host.com/~user/cgi-bin/limemgr.cgi
##  h. ファイルロック処理をする場合、lime.cgi を置くディレクトリの
##     パーミッションは 777 とする。
## ----------------------------------------------------------------------------
## [ 3. チェックモードの使い方 ]
##  i. http://www.host.com/~user/cgi-bin/lime.cgi?mode=check
##     mode=checkという引数を付けてブラウザから指定する
##
## ----------------------------------------------------------------------------

require './jcode.pl';

## 基本設定
$logfile  = "./lime.log";		# ログファイル名
$lockkey  = 2;				# ロックの形式 (0=no 1=symlink 2=open)
$lockfile = "./lime.lock";		# ロックファイル
$dummy = "./dummy.gif";			# ダミーGIF画像（ページカウンタ使用の場合）
## 設定完了

$buffer = $ENV{'QUERY_STRING'};

@pairs = split(/&/, $buffer);
foreach $pair (@pairs) {
	($name,$value) = split(/=/, $pair);
	$value =~ tr/+/ /;
	$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;

	$value =~ s/"/&quot\;/g;
	$value =~ s/<>/&gt\;&lt\;/g;

	$FORM{$name} = $value;
}

$page = $FORM{'page'};
$name = $FORM{'name'};
$mode = $FORM{'mode'};
$hp   = $FORM{'hp'};
$down = $FORM{'down'};
$down =~ s/^http\:\/\///;
$down =~ s/^http\:\///;

# チェックモード
if (!$buffer || $mode eq "check") { &check; }

# URLの引数がない場合はリンク元情報を取得する
if ($hp eq "") {
	$hp = $ENV{'HTTP_REFERER'};
	$hp =~ s/\%7E/\~/ig;
}

$hp =~ s/^http\:\/\///;
$hp =~ s/^http\:\///;

# IPアドレスを取得
$addr = $ENV{'REMOTE_ADDR'};

# ロック開始
if ($lockkey == 1) { &lock1; }
elsif ($lockkey == 2) { &lock2; }

# ログを開く
if ($down) { $page = $down; }

open(IN,"$logfile") || &error("$logfile");
@lines = <IN>;
close(IN);

# マッチング／カウントアップ処理
$flag=0;
@new=();
foreach $line (@lines) {
	($no,$hpg,$count,$title,$ip) = split(/<>/, $line);

	if ($page eq "$no") {
		# IPアドレスが同じ場合はカウントアップしない
		if ($addr eq "$ip") { $flag=2; last; }

		# $hpg, $title がない場合
		if ($hpg eq "") { $hpg = $hp; }
		if ($title eq "") {
			&jcode'convert(*name,'sjis');
			$title = $name;
		}

		$flag=1;
		$count++;
		$line = "$no<>$hpg<>$count<>$title<>$addr<>\n";
	}

	push(@new,$line);
}

# 既存ログ更新
if ($flag == 1) {
	open(OUT,">$logfile") || &error("$logfile");
	print OUT @new;
	close(OUT);

# 新規ページ追加更新
} elsif ($flag == 0 && $hp ne "") {
	# ページ名を S-JIS コードへ
	&jcode'convert(*name,'sjis');

	open(OUT,">>$logfile") || &error("$logfile");
	print OUT "$page<>$hp<>1<>$name<>$addr<>\n";
	close(OUT);
}

# ロック解除
if (-e $lockfile) { unlink($lockfile); }


# ダウンロードカウンタの場合
if ($down) {
	# IISサーバ(PerlIS)対応
	if ($ENV{PERLXS} eq "PerlIS") {
		print "HTTP/1.0 302 Temporary Redirection\r\n";
		print "Content-type: text/html\n";
	}
	print "Location: http://$down\n\n";

} else {
	# ダミー画像を表示
	print "Content-type: image/gif\n\n";
	open(GIF,"$dummy");
	binmode(GIF);
	binmode(STDOUT);
	print <GIF>;
	close(GIF);
}

exit;

## --- ロックファイル（symlink関数）処理
sub lock1 {
	local($retry) = 5;
	while (!symlink(".", $lockfile)) {
		if (--$retry <= 0) { &error('lock'); }
		sleep(1);
	}
}

## --- ロックファイル（open関数）処理
sub lock2 {
	local($flag) = 0;
	foreach (1 .. 5) {
		if (-e $lockfile) { sleep(1); }
		else {
			open(LOCK,">$lockfile");
			close(LOCK);
			$flag = 1;
			last;
		}
	}
	if ($flag == 0) { &error('lock'); }
}

## --- エラー処理
sub error {
	if (-e $lockfile) { unlink($lockfile); }
	die "Error : $_[0]";
}

## --- チェックモード
sub check {
	print "Content-type: text/html\n\n";
	print "<html><head><title>LIME COUNTER</title></head>\n";
	print "<body>\n<UL>\n";

	# ログファイルのパス確認
	if (-e $logfile) {
		print "<LI>ログファイルのパス : OK!";
	} else {
		print "<LI>ログファイルがありません。";
	}

	# ログファイルのパーミッション（読みこみ）
	if (-r $logfile) {
		print "<LI>ログファイルの読みこみパーミッション : OK!";
	} else {
		print "<LI>ログファイルの読みこみパーミッションが不正です。";
	}

	# ログファイルのパーミッション（書きこみ）
	if (-w $logfile) {
		print "<LI>ログファイルの書きこみパーミッション : OK!";
	} else {
		print "<LI>ログファイルが書きこみパーミッションが不正です。";
	}

	print "</UL>\n</body></html>\n";
	exit;
}
