##### TADChat版豪華絢爛チャットライブラリ
### Kenran Chat Lib / 2007 &copy; 結城由羅＠世界忍者国 / BSD Lisence
### $Id: kenranlib.pl,v 1.4 2007/05/06 05:58:36 jyugoya Exp $
### 本体から分離、yadchatlib.plにマージ中

# YADChat Lib 読み込み
require './yadchatlib.pl';

# 文字コード変換ライブラリ取込み
require './jcode.pl';

###
### ユーティリティ
###

##### 関数：日付生成 #####
sub getDate {
    $ENV{'TZ'} = $CONF{'timezone'};
    local($times) = time;
    local($sec,$min,$hour,$mday,$mon) = localtime($times);
    return sprintf("%s/%s-%02d:%02d:%02d",$mon+1,$mday,$hour,$min,$sec);
}

##### 関数：ダイス #####
sub dice {
    local($num, $type) = @_;
    srand;
    #"$num個の$type面体";
    local($ret) = $num."d".$type.": "; 
    for ($i=0; $i<$num; $i++) {
        $d = int(rand($type)) + 1;
        $sum += $d;
        $ret .= $d;
        if ($i < $num -1) { $ret .= " + " }
    }
    $ret .= " = $sum";
}

##### 関数：入力処理 #####
sub checkInput {
    $IN{'room'} = $query->param('room');
    $IN{'name'} = $query->param('name');
    $IN{'weight'} = $query->param('weight');
    $IN{'reverse'} = $query->param('reverse');
    $IN{'comment'} = $query->param('comment');
    $IN{'mode'} = $query->param('mode');
    $IN{'face'} = $query->param('face');
    $IN{'email'} = $query->param('email');
    $IN{'color'} = $query->param('color');
    $IN{'retime'} = $query->param('retime');
    $IN{'line'} = $query->param('line');

    foreach $key (keys %IN) {
	# 文字コードをEUC変換 (文字コードの統一とサニタイジングのため)
	local($c) = &jcode::getcode(\$IN{$key});
	#print "code: $c\n";
	if ($c eq 1 || $c eq 2) {
	    &jcode::convert(\$IN{$key}, 'euc');
	}

	# タグ処理 (サニタイジング)
	$IN{$key} =~ s/&/&amp;/g;
	$IN{$key} =~ s/</&lt;/g;
	$IN{$key} =~ s/>/&gt;/g;
	$IN{$key} =~ s/"/&quot;/g; # "
	$IN{$key} =~ s/\r//g;
	$IN{$key} =~ s/\n//g;

        # 文字コードを処理系に合わせる
        local($code) = 'euc';
        if ($CONF{'charset'} eq 'Shift_JIS') {
            $code = 'sjis';
        } elsif ($CONF{'charset'} eq 'ISO-2202-JP') {
            $code = 'jis';
	}
        &jcode::convert(\$IN{$key}, $code);
    }
}

##### 関数：トリップ取得処理 #####
sub getTrip {
    local($name) = $_[0];
    local($tripped) = $name;
    # トリップ機能が有効ならば、トリップをそれ以外ならばそのままを返す
    if ($CONF{'usetrip'} && $name =~ /(.*)(#|＃)(.*)/){
        $trip = &genTrip($1, $3);
        $tripped = $1 . "◆" . $trip;
    } else {
        $tripped =~ s/◆/◇/g;
    }
    return $tripped;
}

##### 関数：トリップ生成 #####
sub genTrip {
    local($name, $key) = @_;
    local($salt) = substr($key."H.", 1, 2);
    $salt =~ s/[^\.-z]/\./go;
    $salt =~ tr/:;<=>?@[\\]^_`/ABCDEFGabcdef/; #`
    return substr(crypt($key, $salt), -10);
}

##### 関数：アクセス拒否処理 #####
sub checkDeny {
    local($client) = $_[0];
    local($find)=0;
    open(DENY, "$CONF{'denyfile'}")
	|| &error("Open Error : denyfile : $CONF{'denyfile'} : $!");
    while (<DENY>) {
	s/\n//g;
	next if (!$_);
	s/\*/\.\*/g;
	if ($client =~ /$_/i) { $find=1; last; }
    }
    close(DENY);
    if ($find) { &error($CONF{'denymsg'}); }
}

###
# 発言除去処理
sub clear {
    local($client, @lines) = @_;
    local(@temp) = ();
    local($match)=0;
    foreach (@lines) {
	local($cip) = (split(/<>/))[5];
	if ($client eq $cip) {
	    $match=1;
	} else {
	    push(@temp, $_);
	}
    }
    if ($match) {
	$IN{'comment'}="All Clear (^-^)v";
	return @temp;
    }
}

###
#  ログ書き込み処理
sub writeDat {
    # モード選択
    local($mode) = $_[0];
    local($datfile) = $CONF{'datdir'}.'/'.$IN{'room'}.'.dat';
    local($lockfile) =  $CONF{'lockdir'}.'/'.$IN{'room'}.'.lock';

    # 名前の入力がなければエラー
    if ($IN{'name'} eq "") {
	&error("御記名願います。");
    }
    # トリップ処理
    local($tripped) = &getTrip($IN{'name'});

    $bye = 0; # グローバル変数
    local($name, $email, $color)= ("", "", "");
    # 入室モード
    if ($mode eq 'login') {
	# 入室メッセージ設定
	$IN{'comment'} = "$tripped $CONF{'in_msg'}";
	if ($CONF{'showip'}) {
	    $IN{'comment'} .= " &lt;$client&gt;";
	}
	$email = "";
	$name  = $CONF{'navi'};
	$color = $CONF{'navicolor'};
    }
    # 退室モード
    elsif ($mode eq 'logout') {
	$IN{'comment'} = "$tripped $CONF{'out_msg'}";
	$email = "";
	$name  = $CONF{'navi'};
	$color = $CONF{'navicolor'};
	$bye=1;
    }
    # 通常モード
    else {
        # 入力がない場合はそのまま返る
        if ($IN{'comment'} eq "") { return; }

	if ($IN{'email'} eq "") {
	    $name = "<B>$CONF{'pointer'}</B>";
	}
	else {
	    $name = "<B><a href=\"mailto:$IN{'email'}\">";
	    $name .= "$CONF{'pointer'}</a></B>";
	}
	$name .= " $tripped ";
	$email = $IN{'email'};
	$color = $IN{'color'};
	
	# 発言ランキング処理 (オプション)
	if ($CONF{'ranking'}) {
	    &ranking();
	}
    }

    # ログファイルのロック開始
    if ($CONF{'lockmode'}) { &lock($lockfile); }

    # ログファイルを開いてデータ読み込み (配列最大値に注意)
    open(DAT, "<$datfile") || &error("Open Error : datfile : $datfile");
    local(@lines) = <DAT>;
    close(DAT);

    # 発言除去処理 (オプション)
    # 除去コマンドを入力することで自分の記事を削除
    if ($CONF{'clearlog'} && $IN{'comment'} eq $CONF{'clearcom'}) {
	@lines = &clear($client, @lines);
    }
    
    # 最大記事数まで削る
    while ($CONF{'max'} <= @lines) {
	pop(@lines);
    }

    $IN{'comment'} =~ s/\(\*\＾\＾\*\)/\(<font color=#EF8F9C>\*<\/font>\＾\＾<font color=EF8F9C>\*<\/font>\)/;

    # 時間を取得
    local($date) = &getDate();

    # ログをフォーマットして更新
    local($newline) = "$date<>$name<>$email<>";
    $newline .= "$IN{'comment'}<>$color<>$client<>\n";
    unshift (@lines, $newline);
    open(DAT, ">$datfile") || &error("Write Error : datfile : $datfile");
    print DAT @lines;
    close(DAT);

    # ロック解除
    if ($CONF{'lockmode'}) { &unlock($lockfile); }
}

###
#  発言ランキング処理
sub ranking {
    open(RANK,"<$CONF{'rankfile'}")
	|| &error("Open Error : rankfile : $CONF{'rankfile'}");
    @rank = <RANK>;
    close(RANK);

    local($find)=0;
    local(@new) = ();
    # トリップの処理
    local($tripped) = &getTrip($IN{'name'});
    foreach (@rank) {
	local($rname,$rcount,$rtime) = split(/<>/);
	local($nowtime) = time;
	if ($nowtime - $rtime > $CONF{'rankexp'}*24*60*60) {
	    $_=''; next;
	}
	if ($rname eq $tripped) {
	    $find=1; $rcount++;
	    $_ = "$rname<>$rcount<>$nowtime<>\n";
	}
	push(@new, $_);
    }
    # 未登録の場合
    if ($find == 0) {
	unshift(@new, "$tripped<>1<>$nowtime<>\n");
    }
    
    open(RANK,">$CONF{'rankfile'}")
	|| &error("Write Error : rankfile : $CONF{'rankfile'}");
    print RANK @new;
    close(RANK);
}

###
### HTML生成関係
###

###
# ヘッダー出力処理 (共通)
sub printHeader {
    local($extra) = $_[0];

    print "Content-type: $CONF{'content-type'}\n";
    # GZIP圧縮対応コード (2006/02/10)
    if (${'HTTP_ACCEPT_ENCODING'} =~ /gzip/ && $gzip ne '') {
	if (${'HTTP_ACCEPT_ENCODING'} =~ /x-gzip/) {
	    print "Content-encoding: x-gzip\n";
	} else {
	    print "Content-encoding: gzip\n";
	}
	open (STDOUT, "|$gzip -1 -c"); # 圧縮は最速(-1)で
    }
    # GZIP圧縮対応、ここまで
    print "\n"; # ヘッダ終了
    print <<"EOM";
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="$CONF{'lang'}">
<head>
<meta http-equiv="Content-type" content="$CONF{'content-type'}" />
<meta http-equiv="Content-Language" content="$CONF{'lang'}" />
<meta name='robots' content='noindex, nofollow' />
<script type='text/javascript' src='$CONF{'javascript'}'></script>
<link rel="stylesheet" type="text/css" href="$CONF{'chatstyle'}">
<title>$CONF{'title'}</title>
$extra
</head>
EOM
}

##### 関数：ログファイルへの移動表示 #####
sub printGoToLog {
    &printHeader();

    print $query->p("このチャットルームは既に終了しています");
    print $query->p("<a href=\"$CONF{'logdir'}/$IN{'room'}.html\" target=\"_top\">[ ログを見る ]</a>");

    # 表示終了
    print $query->end_html;
    exit(0);
}

###
# フレーム出力処理
sub printFrame {
    # クッキーにリロード時間／行数指定がない場合は初期値を代入
    if ($CK{'retime'} eq "") { $CK{'retime'} = $CONF{'retime'}; }
    if ($CK{'line'} eq "") { $CK{'line'} = $CONF{'line'}; }
    
    $formsrc = "$CONF{'chatcgi'}?room=$IN{'room'}&mode=form&retime=$CK{'retime'}&line=$CK{'line'}";
    $logsrc = "$CONF{'chatcgi'}?room=$IN{'room'}&mode=view&retime=$CK{'retime'}&line=$CK{'line'}";

    &printHeader();
    print <<"EOM";
<frameset rows="177,*" border=0>
<frame name="form" src="$formsrc">
<frame name="log" src="$logsrc">
<noframes>
<body>フレーム非対応のブラウザの方は利用できません</body>
</noframes>
</frameset>
</html>
EOM
    exit(0);
}

###
# プロダウンメニュー生成
sub genPullDown {
    local($script) = "$CONF{'chatcgi'}?room=$IN{'room'}&mode=view&retime=0";
    local($pulldown) =<<"EOM";
<b><a href="javaScript:pullDown()">コチラから入室せずにログが読めます</a></b> <div id="menu" style="position:absolute; visibility:hidden; background-color:#ffbdde; width:60px;">
<a href="$script&line=500" target="_blank">　５００</a><BR>
<a href="$script&line=1000" target="_blank">　１０００</a><BR>
<a href="$script&line=1500" target="_blank">　１５００</a><BR>
<a href="$script&line=2000" target="_blank">　２０００</a><BR>
</div>
EOM
    return $pulldown;
}

###
# 更新時間選択部の文字列生成
sub genReloadTimeSelection {
    # 入力による設定があればそちらを優先
    if ($IN{'retime'} ne "") {
	$CK{'retime'} = $IN{'retime'};
    }
    # 空ならば初期値に設定
    if ($CK{'retime'} eq "") {
	$CK{'retime'} = $CONF{'retime'};
    }

    local($reload) = "更新 <select name=retime>\n";
    foreach (@reload) {
	if ($CK{'retime'} == $_) {
	    $reload .= "<option value=\"$_\" selected>$_秒\n";
	} else {
	    $reload .= "<option value=\"$_\">$_秒\n";
	}
    }
    $reload .= "</select>\n";
    return $reload;
}

###
# 入室情報入力部の文字列生成
sub genLoginInput {
    local($login) =<<"EOM";
<b>NAME</b> <input type="text" name="name" size="25" value="$CK{'name'}"><br>
<b>EMail</b> <input type="text" name="email" size="25" value="$CK{'email'}"><br>
<input type="hidden" name="room" value="$IN{'room'}">
EOM
    return $login;
}

###
# チャット情報入力部の文字列生成
sub genChatInput {
    # トリップ名の処理
    local($tripped) = &getTrip($IN{'name'});
    local($chat) = << "EOM";
<input type="hidden" name="mode" value="chat">
<input type="hidden" name="room" value="$IN{'room'}">
<input type="hidden" name="name" value="$IN{'name'}">
<input type="hidden" name="email" value="$IN{'email'}">
<b>NAME</b>：　<font color="$IN{'color'}">$tripped</font>
<input type="submit" value="発言／リロード">
<input type="reset" value="クリア"><br>
<b>発言</b>　：　<input type="text" size="85" name="comment"><br>
EOM
    return $chat;
}

###
# 行数選択部の文字列生成
sub genLineNumSelection {
    # 入力による設定があればそちらを優先
    if ($IN{'line'} ne "") {
	$CK{'line'} = $IN{'line'};
    }
    # 空ならば初期値に設定
    if ($CK{'line'} eq "") {
	$CK{'line'} = $CONF{'line'};
    }

    local($lines) = "行数 <select name=line>\n";
    foreach (@line) {
	if ($CK{'line'} == $_) {
	    $lines .= "<option value=\"$_\" selected>$_行\n";
	} else {
	    $lines .= "<option value=\"$_\">$_行\n";
	}
    }
    $lines .= "</select><br>\n";
    return $lines;
}

###
# 文字色選択(ラジオボタン)の出力処理
sub genColorRadioBottun {
    # 入力による設定があればそちらを優先
    if ($IN{'color'} ne "") {
	$CK{'color'} = $IN{'color'};
    }
    # 空ならば初期値に設定
    if ($CK{'color'} eq "") {
	$CK{'color'} = $CONF{'color'};
    }

    local($colors) = "<B>文字色選択</B><BR><BR>\n";

    local($half) = int (@COLORS / 2); # 半分に割る
    local($i=0);
    foreach (@COLORS) {
	$i++;
	if ($CK{'color'} eq $_) {
	    $colors .= "<input type=radio name=color value=\"$_\" checked>";
	} else {
	    $colors .= "<input type=radio name=color value=\"$_\">";
	}
	$colors .= "<font color=\"$_\"><B>**</B></font>\n";
	if ($i == $half) { $colors .= "<br>\n"; }
    }
    return $colors;
}

###
# 文字色選択(セレクトメニュー)の出力処理
sub genColorSelection {
    # 入力による設定があればそちらを優先
    if ($IN{'color'} ne "") {
	$CK{'color'} = $IN{'color'};
    }
    # 空ならば初期値に設定
    if ($CK{'color'} eq "") {
	$CK{'color'} = $CONF{'color'};
    }

    local($colors) = "文字色 <select name=color>\n";
    for ($i = 0; $i < scalar(@COLORS); $i++) {
	if ($IN{'color'} eq $COLORS[$i]) {
	    $colors .= "<option value=\"$COLORS[$i]\" selected>$IROIRO[$i]\n";
	} else {
	    $colors .= "<option value=\"$COLORS[$i]\">$IROIRO[$i]\n";
	}
    }
    $colors .= "</select>\n";
}

###
# 顔文字選択部の文字列生成
sub genFaceSelection {
    local ($face) = "かお文字 <select name=\"face\">";
    $face .= "<option value=\"\">なし\n";
    foreach (@faces) {
	$face .= "<option value=\"$_\">$_\n";
    }
    $face .= "</select>\n";
    return $face;
}

###
#  入室用フォーム出力
sub printEntryForm {
    # プルダウンメニューの生成
    local($loglink) = '';
    if ($CONF{'loglink'} == 1) {
        $loglink = &genLogLinkString($IN{'room'});
    } elsif ($CONF{'loglink'} == 2) {
	$loglink = &genPullDown();
    }

    local($login) = &genLoginInput();
    local($reload) = &genReloadTimeSelection();
    local($lines) = &genLineNumSelection();
    local($colors) = &genColorRadioBottun();

    # ヘッダーを出力
    &printHeader();
    local($kazari) = "<font color=\"#DB5673\">＊＊＊</font>";
    print <<"EOM";
<body>
<form method="$CONF{'method'}" action="$CONF{'chatcgi'}"
 target="form" name="entry">
<input type=hidden name=mode value="login">
[<a href="$CONF{'indexurl'}" target="_top">BACK</a>]
 $CONF{'topdesc'} $loglink <br><br>
<h1>$kazari $CONF{'title'} $kazari</h1>
<hr>
<table border="0" cellspacing="0" cellpadding="0" height="100">
<tr align="right">
<td>$login $reload $lines</td>
<td width="100" align="center"><br>
<input type="submit" value="入室"></td>
<td align=center valign=top nowrap><br>
$colors
</td></tr></table></form>
<SCRIPT LANGUAGE="JavaScript">
<!--
self.document.entry.name.focus();
//-->
</SCRIPT>
</body></html>
EOM
    exit(0);
}

### 関数：軽量シンプル版ログイン画面 ###
sub printEntryFormAndDat {
    local($login) = &genLoginInput();
    local($colors) = &genColorSelection();

    # ヘッダーを出力
    &printHeader();

    print <<"EOM";
<body>
<form method="$CONF{'method'}" action="$CONF{'chatcgi'}"
 target="_top" name="entry">
<input type="hidden" name="mode" value="login">
<input type="hidden" name="weight" value="light">
<input type="hidden" name="line" value="20">
<input type="hidden" name="retime" value="0">
[<a href="$CONF{'indexurl'}" target="_top">戻る</a>]
[<a href="$CONF{'chatcgi'}?room=$IN{'room'}&weight=light&line=$CONF{'lightline'}">リロード</a>]
<h1>$CONF{'title'}</h1>
<hr>
$login
$colors
<input type="submit" name="login" value="入室">
<hr>
EOM

    print &genMember();
    local($datfile) = $CONF{'datdir'}."/".$IN{'room'}.".dat";
    print &formatDat($datfile, $CONF{'lightline'}, 'light', $IN{'reverse'});

    print $query->hr;

    print &genCopyright();
    print $query->end_html;
    exit(0);
}

### 関数：軽量シンプル版チャット画面 ###
sub printChatFormAndDat {
    local($chat) = &genChatInput();;
    local($colors) = &genColorSelection();

    # ログ書き込み処理
    &writeDat($IN{'mode'});

    # クッキーの設定
    local($ck) = "name<>$IN{'name'}";
    $ck .= "<>email<>$IN{'email'}";
    $ck .= "<>color<>$IN{'color'}";
    $ck .= "<>retime<>$IN{'retime'}";
    $ck .= "<>line<>$IN{'line'}";
    &setCookie($CONF{'cookiekey'}, $ck, $CONF{'expire'});

    # ヘッダーを出力
    &printHeader();

    print <<"EOM";
<body>
<br>
<h1>$CONF{'title'}</h1>
<hr>
<form method="$CONF{'method'}" action="$CONF{'chatcgi'}"
 target="_top" name="chat">
<input type="hidden" name="line" value="$CONF{'lightline'}">
<input type="hidden" name="weight" value="light">
<input type="hidden" name="retime" value="0">
$chat
$colors
</form>

<form action="$CONF{'chatcgi'}" method="$CONF{'method'}" target="_top"
 name="logout">
<input type="submit" name="logout" value="退室">
<input type="hidden" name="mode" value="logout">
<input type="hidden" name="name" value="$IN{'name'}">
<input type="hidden" name="room" value="$IN{'room'}">
<input type="hidden" name="weight" value="light">
</form>
<hr>
EOM

    print &genMember();
    local($datfile) = $CONF{'datdir'}."/".$IN{'room'}.".dat";
    print &formatDat($datfile, $IN{'line'}, 'light', $IN{'reverse'});

    print $query->hr;
    print &genCopyright();
    print $query->end_html;
    exit(0);
}

###
# ランキング部の文字列生成
sub genRanking {
    local($ranking) =<<"EOM";
[<a href="$CONF{'adminscript'}?mode=ranking&retime=$IN{'retime'}&line=$IN{'line'}"
 target="log">発言ランキング</a>]
EOM
    return $ranking;
}

###
# 発言フォーム出力
sub printChatForm {
    # プルダウンメニューの生成
    local($pulldown) = '';
    if ($CONF{'pulldown'}) {
	$pulldown = &genPullDown();
    }

    local($chat) = &genChatInput();
    local($face) = &genFaceSelection();
    local($colors) = &genColorSelection();
    local($lines) = &genLineNumSelection();
    local($reload) = &genReloadTimeSelection();

    # ランキングの生成
    if ($CONF{'ranking'}) {
	local($ranking) = &genRanking();
    }

    # ログ書き込み処理
    &writeDat('login');

    # クッキーの設定
    local($ck) = "name<>$IN{'name'}";
    $ck .= "<>email<>$IN{'email'}";
    $ck .= "<>color<>$IN{'color'}";
    $ck .= "<>retime<>$IN{'retime'}";
    $ck .= "<>line<>$IN{'line'}";
    &setCookie($CONF{'cookiekey'}, $ck, $CONF{'expire'});

    # ヘッダ出力
    &printHeader();
    print <<"EOM";
<body>
<form name="send" method="$CONF{'method'}" action="$CONF{'chatcgi'}"
 target="log" onSubmit="setTimeout(&quot;autoclear()&quot;,10)">
<table border=0><tr><td colspan=3>
<b><font color="#DB5673" size="2">＊＊＊</font>
$CONF{'title'}
<font color="#DB5673" size="2">＊＊＊</font></b>　
<br> $CONF{'chatalart'} $pulldown
<br><br>$chat
</td></tr>
<tr><td>$face $colors $reload $lines</td></form>
<td valign="top">
<form action="$CONF{'chatcgi'}" method="$CONF{'method'}" target="form">
<input type="submit" value="退室宣言">
<input type="hidden" name="mode" value="logout">
<input type="hidden" name="name" value="$IN{'name'}">
<input type="hidden" name="room" value="$IN{'room'}">
</td></form>
<td>
<form name="cmode">
<input type="checkbox" name="autoclear" checked>
発言自動消去</td></form></tr></table><br>
[<a href="$CONF{'adminscript'}?mode=enter&retime=$IN{'retime'}&line=$IN{'line'}" target="log">管理用</a>]
$ranking
</body></html>
EOM
    exit(0);
}

###
#  在室者処理
sub genMember {
    local($mode) = $_[0];
    local($memfile) = $CONF{'memdir'}.'/'.$IN{'room'}.'.dat';
    local($memlock) = $CONF{'lockdir'}.'/'.$IN{'room'}.'.memlock';

    # ロックをかける
    if ($CONF{'lockmode'}) { &lock($memlock); }

    # メンバー一覧取得
    open(MEM, "<$memfile")
	|| &error("Open Error : memfile : $memfile");
    local(@line) = <MEM>;
    close(MEM);

    # 変数初期化
    local(@new) = ();
    local($member, $update, $even) = ("", 0, 0);
    local($time0, $name0, $client0) = (0, '', '');
    # トリップの処理
    local($tripped) = &getTrip($IN{'name'});
    # 現在時刻を取得
    local($nowtime) = time;
    foreach (@line) {
	($time0, $name0, $client0) = split(/<>/);

	# 一定時間以上発言のない者は削除
	if ($nowtime - $CONF{'memexp'} > $time0) { next; }

	# クライアントIPが同一かつ名前が一緒であれば更新処理をする
	elsif ($client0 eq $client && $name0 eq $tripped) {
	    # 退室者は削除
	    if ($mode eq 'logout') { next; }

	    # 時間と名前を更新して追加
	    push (@new, "$nowtime<>$tripped<>$client<>\n");
	    $name0 = $tripped;
	    $update=1;
	}
	# それ以外は問答無用で更新用配列 @new に追加
	else { push(@new, $_); }
	
	# 参加者表示用文字列を作成 (偶数奇数でマーク変更)
	if (!$even) {
	    $member .= "$name0★"; $even=1;
	}
	else {
	    $member .= "$name0☆"; $even=0;
	}
    }
    
    # 更新処理以外でログアウトもしていないならば新規参加者を追加
    if (!$update && !$bye) {
	if ($IN{'name'} ne $client) {
	    push(@new, "$nowtime<>$tripped<>$client<>\n");
	    if (!$even) {
		$member .= "$tripped★";
	    }
	    else {
		$member .= "$tripped☆";
	    }
	}
    }

    # ファイルを更新する
    if ($IN{'mode'} || $IN{'retime'}) {
	open(MEM,">$memfile")
	    || &error("Write Error : memfile : $memfile");
	print MEM @new;
	close(MEM);
    }

    # ロック解除
    if ($CONF{'lockmode'}) { &unlock($memlock); }

    # 参加者数を認識
    local($num) = 0;
    $num = @new;
    return "参加者($num)：".$member;
}

###
#  退室処理
sub printLogout {
    &writeDat('logout');
    local($member) = &genMember('logout');
    local($tripped) = &getTrip($IN{'name'});
    &printHeader();
    print <<"EOM";
<body>
<center><BR><BR><h3>お疲れ様でした、$tripped さん。またお会いしましょう。</h3>
<form action="$CONF{'indexurl'}" target="_top">
<input type=submit value="離脱"></form></center>
</body></html>
EOM
    exit(0);
}

###
#  ログ表示
sub viewDat {
    # リロードヘッダ
    local($extra) = '';
    if ($IN{'retime'} != 0) {
	local($ename) = &url_enc($IN{'name'});
	local($script) = "$CONF{'chatcgi'}?room=$IN{'room'}&mode=view&retime=$IN{'retime'}&line=$IN{'line'}&name=$ename";
	$extra = "<meta http-equiv=\"refresh\"";
	$extra .= " content=\"$IN{'retime'}; URL=$script\">\n";
    }
    &printHeader($extra);

    ## 参加者表示
    local($member) = &genMember();
    print "<body>\n";
    print "<hr>";
    print "<table width='100%'><tr><td>$member</td>\n";
    print "<td align=right>リロード： ";
    if ($IN{'retime'} == 0) {
	print "手動モード";
    } else { print "$IN{'retime'}秒"; }
    print " 行数: $IN{'line'}行</td></tr></table>\n";

    local($datfile) = $CONF{'datdir'}."/".$IN{'room'}.".dat";
    print &formatDat($datfile, $IN{'line'}, 'normal', $IN{'reverse'});
    
    print $query->hr . "\n";

    # 著作権を表示（削除禁止）
    print &genCopyright();
    print $query->end_html . "\n";
    exit(0);
}

# End of kenranlib
1;
