diff -urN tiarra-20040526/ChangeLog tiarra-20040604/ChangeLog
--- tiarra-20040526/ChangeLog	2004-05-26 16:04:50.000000000 +0900
+++ tiarra-20040604/ChangeLog	2004-06-04 21:58:25.000000000 +0900
@@ -1,3 +1,43 @@
+2004-06-04  Topia  <topia@clovery.jp>
+
+	* main/IRCMessage.pm:
+	  - MAX_PARAMS(= 14) 定数を追加した。
+	(params):
+	  - 呼び出し時に未定義なら強制的に初期化するようにした。
+	(n_params):
+	  - params を使用するようにした。
+	(_parse):
+	  - $this->push を使用するようにした。
+	(length, push, pop):
+	  - 追加した。
+
+	* main/IrcIO/Client.pm:
+	(_receive_while_logging_in):
+	  - シングルサーバモード時にサーバから RPL_ISUPPORT が提供されていれば、
+	    それを送信するようにした。
+
+	* module/Client/Cache.pm:
+	  - MODE キャッシュ、 WHO キャッシュともに、取得中フラグに有効期限を
+	    つけるようにした。デフォルトで 5 分、 conf では指定できない。
+	  - 念のため RPL_ENDOFWHO もハンドリング。
+
+	* module/Client/Eval.pm:
+	  - メッセージを再構築して、 : をつけなくても良いようにした。
+	    もちろん ::shutdown を実行するには /eval :::shutdown と
+	    しなければならない(笑)。
+	  - $err を初期化して warning が出ないようにした。
+	(network, runloop):
+	  - eval 内部からよく使いそうなものを function 化した。
+
+	* module/System/Raw.pm:
+	  - 配列の最後の要素は (n_params - 1) なので修正して warning が
+	    でないようにした。
+
+2004-06-04  phonohawk  <phonohawk@ps.sakura.ne.jp>
+
+	* main/Unicode/Japanese.pm:
+	Unicode::Japanese 0.22に更新。
+
 2004-05-26  phonohawk  <phonohawk@ps.sakura.ne.jp>
 
 	* main/Unicode/Japanese.pm:
@@ -1649,7 +1689,7 @@
 
 	* これ以前のログは書いていません。
 
-#       Id: $Id: ChangeLog,v 1.150 2004/05/26 07:02:37 admin Exp $
-#   Author: $Author: admin $
-#     Date: $Date: 2004/05/26 07:02:37 $
-# Revision: $Revision: 1.150 $
+#       Id: $Id: ChangeLog,v 1.152 2004/06/04 12:57:30 topia Exp $
+#   Author: $Author: topia $
+#     Date: $Date: 2004/06/04 12:57:30 $
+# Revision: $Revision: 1.152 $
diff -urN tiarra-20040526/NEWS tiarra-20040604/NEWS
--- tiarra-20040526/NEWS	2004-05-26 16:04:50.000000000 +0900
+++ tiarra-20040604/NEWS	2004-06-04 21:58:25.000000000 +0900
@@ -1,3 +1,12 @@
+2004-06-04  Topia  <topia@clovery.jp>
+
+	* 全般
+	  - 今回の変更は RPL_ISUPPORT のクライアントへの送信が必要なければ、
+	    再起動する必要はありません。
+	    再起動せずにリロードしてもエラーが起こることはないと思います。
+	  - 書き忘れていましたが Unicode::Japanes 0.21 (の PurePerl) にて
+	    SI/SO な jis への対応が行われています。(2004-05-26 の update)
+
 2004-03-07  Topia  <topia@clovery.jp>
 
 	* 全般
diff -urN tiarra-20040526/main/IRCMessage.pm tiarra-20040604/main/IRCMessage.pm
--- tiarra-20040526/main/IRCMessage.pm	2004-05-26 16:04:50.000000000 +0900
+++ tiarra-20040604/main/IRCMessage.pm	2004-06-04 21:58:25.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: IRCMessage.pm,v 1.17 2004/02/14 11:48:18 topia Exp $
+# $Id: IRCMessage.pm,v 1.18 2004/06/04 12:57:30 topia Exp $
 # -----------------------------------------------------------------------------
 # IRCMessageはIRCのメッセージを表わすクラスです。実際のメッセージはUTF-8で保持します。
 # 生のメッセージのパース、シリアライズ、そしてメッセージの生成をサポートします。
@@ -37,6 +37,10 @@
 use Unicode::Japanese;
 use Data::Dumper;
 
+# constants
+use constant MAX_PARAMS => 14;
+
+# variable indices
 use constant PREFIX  => 0;
 use constant COMMAND => 1;
 use constant PARAMS  => 2;
@@ -154,12 +158,7 @@
 
 	if ($this->[COMMAND]) {
 	    # commandはもう設定済み。次はパラメータだ。
-	    if ($this->[PARAMS]) {
-		push @{$this->[PARAMS]},$value;
-	    }
-	    else {
-		$this->[PARAMS] = [$value];
-	    }
+	    $this->push($value);
 	}
 	else {
 	    # まだコマンドが設定されていない。
@@ -276,6 +275,11 @@
     return $result;
 }
 
+sub length {
+    my ($this) = shift;
+    length($this->serialize(@_));
+}
+
 sub prefix {
     my ($this,$new_val) = @_;
     $this->[PREFIX] = $new_val if defined($new_val);
@@ -317,11 +321,13 @@
 
 sub params {
     croak "Parameter specified to params(). You must mistaked with param().\n" if (@_ > 1);
-    $_[0]->[PARAMS];
+    my $this = shift;
+    $this->[PARAMS] = [] if !defined $this->[PARAMS];
+    $this->[PARAMS];
 }
 
 sub n_params {
-    scalar @{$_[0]->[PARAMS]||[]};
+    scalar @{shift->params};
 }
 
 sub param {
@@ -333,6 +339,15 @@
     $this->[PARAMS]->[$index];
 }
 
+sub push {
+    my $this = shift;
+    CORE::push(@{$this->params}, @_);
+}
+
+sub pop {
+    CORE::pop(@{shift->params});
+}
+
 sub remark {
     my ($this,$key,$value) = @_;
     # remark() -> HASH*
diff -urN tiarra-20040526/main/IrcIO/Client.pm tiarra-20040604/main/IrcIO/Client.pm
--- tiarra-20040526/main/IrcIO/Client.pm	2004-05-26 16:04:50.000000000 +0900
+++ tiarra-20040604/main/IrcIO/Client.pm	2004-06-04 21:58:25.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Client.pm,v 1.29 2004/04/18 07:44:46 topia Exp $
+# $Id: Client.pm,v 1.30 2004/06/04 12:57:30 topia Exp $
 # -----------------------------------------------------------------------------
 # IrcIO::Clientはクライアントからの接続を受け、
 # IRCメッセージをやり取りするクラスです。
@@ -251,6 +251,43 @@
 	    } values %{RunLoop->shared_loop->networks};
 	    
 	    $send_message->(RPL_YOURHOST, "Your host is $prefix, running version ".::version());
+	    if (!RunLoop->shared_loop->multi_server_mode_p) {
+		# single server mode
+		my $network = (RunLoop->shared_loop->networks_list)[0];
+
+		# send isupport
+		my $msg_tmpl = IRCMessage->new(
+		    Prefix => $prefix,
+		    Command => RPL_ISUPPORT,
+		    Params => [$current_nick],
+		   );
+		# last param is reserved for 'are supported...'
+		my $max_params = IRCMessage::MAX_PARAMS - 1;
+		my @params = ();
+		my $length = 0;
+		my $flush_msg = sub {
+		    if (@params) {
+			my $msg = $msg_tmpl->clone;
+			$msg->push(@params);
+			$msg->push('are supported by this server');
+			$this->send_message($msg);
+		    }
+		    @params = ();
+		    $length = 0;
+		};
+		foreach my $key (keys %{$network->isupport}) {
+		    my $value = $network->isupport->{$key};
+		    my $str = length($value) ? ($key.'='.$value) : $key;
+		    $length += length($str) + 1; # $str and space
+		    # 余裕を見て400バイトを越えたら行を分ける。
+		    if ($length >= 400 || scalar(@params) >= $max_params) {
+			$flush_msg->();
+			$length = length($str);
+		    }
+		    push(@params, $str);
+		}
+		$flush_msg->();
+	    }
 	    $send_message->(RPL_MOTDSTART, "- $prefix Message of the Day -");
 	    foreach my $line (main::get_credit()) {
 		$send_message->(RPL_MOTD, "- ".$line);
ファイルtiarra-20040526/main/Unicode/Japanese.pmとtiarra-20040604/main/Unicode/Japanese.pmは違います
diff -urN tiarra-20040526/module/Client/Cache.pm tiarra-20040604/module/Client/Cache.pm
--- tiarra-20040526/module/Client/Cache.pm	2004-05-26 16:04:51.000000000 +0900
+++ tiarra-20040604/module/Client/Cache.pm	2004-06-04 21:58:26.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Cache.pm,v 1.10 2004/05/08 08:11:31 topia Exp $
+# $Id: Cache.pm,v 1.11 2004/06/04 12:57:30 topia Exp $
 # -----------------------------------------------------------------------------
 # copyright (C) 2003-2004 Topia <topia@clovery.jp>. all rights reserved.
 package Client::Cache;
@@ -12,6 +12,8 @@
 
 sub MODE_CACHE_FORCE_SENDED (){0;}
 sub MODE_CACHE_SENDED (){1;}
+sub MODE_CACHE_EXPIRE_TIME (){5 * 60;}
+sub WHO_CACHE_EXPIRE_TIME (){5 * 60;}
 
 sub new {
     my $class = shift;
@@ -43,7 +45,9 @@
     foreach my $network (RunLoop->shared_loop->networks_list) {
 	foreach my $ch ($network->channels_list) {
 	    $ch->remark(__PACKAGE__."/fetching-switches", undef, 'delete');
+	    $ch->remark(__PACKAGE__."/fetching-switches-expire", undef, 'delete');
 	    $ch->remark(__PACKAGE__."/fetching-who", undef, 'delete');
+	    $ch->remark(__PACKAGE__."/fetching-who-expire", undef, 'delete');
 	}
     }
 
@@ -71,6 +75,8 @@
 	    my $ch = $io->channel($msg->param(0));
 	    if (defined $ch) {
 		$ch->remark(__PACKAGE__."/fetching-switches", 1);
+		$ch->remark(__PACKAGE__."/fetching-switches-expire",
+			    time() + MODE_CACHE_EXPIRE_TIME);
 	    }
 	} elsif ($type eq 'in' &&
 		     $msg->command eq RPL_CHANNELMODEIS &&
@@ -78,6 +84,7 @@
 	    my $ch = $io->channel($msg->param(1));
 	    if (defined $ch) {
 		$ch->remark(__PACKAGE__."/fetching-switches", undef, 'delete');
+		$ch->remark(__PACKAGE__."/fetching-switches-expire", undef, 'delete');
 	    }
 	} elsif ($type eq 'out' &&
 		     $msg->command eq 'WHO' &&
@@ -85,6 +92,8 @@
 	    my $ch = $io->channel($msg->param(0));
 	    if (defined $ch) {
 		$ch->remark(__PACKAGE__."/fetching-who", 1);
+		$ch->remark(__PACKAGE__."/fetching-who-expire",
+			    time() + WHO_CACHE_EXPIRE_TIME);
 	    }
 	} elsif ($type eq 'in' &&
 		     $msg->command eq RPL_WHOREPLY &&
@@ -93,6 +102,15 @@
 	    my $ch = $io->channel($msg->param(1));
 	    if (defined $ch) {
 		$ch->remark(__PACKAGE__."/fetching-who", undef, 'delete');
+		$ch->remark(__PACKAGE__."/fetching-who-expire", undef, 'delete');
+	    }
+	} elsif ($type eq 'in' &&
+		     $msg->command eq RPL_ENDOFWHO &&
+			 Multicast::channel_p($msg->param(1))) {
+	    my $ch = $io->channel($msg->param(1));
+	    if (defined $ch) {
+		$ch->remark(__PACKAGE__."/fetching-who", undef, 'delete');
+		$ch->remark(__PACKAGE__."/fetching-who-expire", undef, 'delete');
 	    }
 	}
     }
@@ -149,8 +167,10 @@
 		    return undef;
 		}
 	    } else {
-		if ($info{ch}->remark(__PACKAGE__."/fetching-switches")) {
-		    # 取得しているクライアントがいるなら、今回は消す。
+		if ($info{ch}->remark(__PACKAGE__."/fetching-switches") &&
+			($info{ch}->remark(__PACKAGE__."/fetching-switches-expire") >= time())) {
+		    # 取得しているクライアントがいて、期限が切れてないなら、
+		    # 今回は消して便乗。
 		    return undef;
 		}
 		# 取得しにいってもらう。
@@ -223,8 +243,10 @@
 		    $sender->remark('who-cache-used', $remark);
 		    return undef;
 		} else {
-		    if ($info{ch}->remark(__PACKAGE__."/fetching-who")) {
-			# 取得しているクライアントがいるなら、今回は消して便乗。
+		    if ($info{ch}->remark(__PACKAGE__."/fetching-who") &&
+			    ($info{ch}->remark(__PACKAGE__."/fetching-who-expire") >= time())) {
+			# 取得しているクライアントがいて、期限が切れてないなら、
+			# 今回は消して便乗。
 			return undef;
 		    }
 		    # 取得しにいってもらう。
diff -urN tiarra-20040526/module/Client/Eval.pm tiarra-20040604/module/Client/Eval.pm
--- tiarra-20040526/module/Client/Eval.pm	2004-05-26 16:04:51.000000000 +0900
+++ tiarra-20040604/module/Client/Eval.pm	2004-06-04 21:58:26.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Eval.pm,v 1.3 2004/03/07 10:34:19 topia Exp $
+# $Id: Eval.pm,v 1.4 2004/06/04 12:57:30 topia Exp $
 # -----------------------------------------------------------------------------
 package Client::Eval;
 use strict;
@@ -15,7 +15,8 @@
     if ($sender->isa('IrcIO::Client')) {
 	# 指定されたコマンドか?
 	if (Mask::match_deep([$this->config->command('all')], $msg->command)) {
-	    my ($method) = $msg->param(0);
+	    # メッセージ再構築
+	    my ($method) = join(' ', @{$msg->params}[0 .. ($msg->n_params - 1)]);
 	    my ($ret, $err);
 	    do {
 		# disable warning
@@ -25,6 +26,7 @@
 		no strict;
 		# untaint
 		$method =~ /\A(.*)\z/s;
+		$err = '';
 		$ret = eval($1);
 	    };
 
@@ -53,6 +55,14 @@
     return $msg;
 }
 
+# useful functions to call from eval
+sub network {
+    return runloop->network(shift);
+}
+
+sub runloop {
+    return RunLoop->shared_loop;
+}
 1;
 =pod
 info: クライアントから Perl 式を実行できるようにする。
diff -urN tiarra-20040526/module/System/Raw.pm tiarra-20040604/module/System/Raw.pm
--- tiarra-20040526/module/System/Raw.pm	2004-05-26 16:04:51.000000000 +0900
+++ tiarra-20040604/module/System/Raw.pm	2004-06-04 21:58:26.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Raw.pm,v 1.4 2004/02/23 02:46:20 topia Exp $
+# $Id: Raw.pm,v 1.5 2004/06/04 12:57:30 topia Exp $
 # -----------------------------------------------------------------------------
 package System::Raw;
 use strict;
@@ -29,7 +29,7 @@
 	    
 	    # メッセージ再構築
 	    my $raw_msg = IRCMessage->new(
-		Line => join(' ', @{$msg->params}[1 .. $msg->n_params]),
+		Line => join(' ', @{$msg->params}[1 .. ($msg->n_params - 1)]),
 		Encoding => 'utf8',
 	       );
 
