diff -urN tiarra-20040214/ChangeLog tiarra-20040215/ChangeLog
--- tiarra-20040214/ChangeLog	2004-02-15 09:19:45.000000000 +0900
+++ tiarra-20040215/ChangeLog	2004-02-15 09:21:35.000000000 +0900
@@ -1,3 +1,21 @@
+2004-02-15  Topia  <topia@clovery.jp>
+
+	* module/Client/Cache.pm:
+	  - message_io_hook を追加。サーバとの通信を監視して、
+	    MODE や WHO を発行(して返答をもらっている)途中かどうかを
+	    記憶しておくように。
+	  - message_io_hook で記憶した情報を使って、
+	    (ほかのクライアントなどによって)サーバに情報を問い合わせている
+	    途中の時も、メッセージを破棄するようにした。
+	    2つ以上のクライアントが同時につながったときに効果が出るはず。
+	    テストには LimeChat を 3 つ同時に接続させたが、
+	    サーバへの問い合わせは各チャンネルにつき1回までに抑えられていた。
+	  - クライアントに伝達される必要のあるメッセージではないので、
+	    RunLoop->shared_loop->notify_warn() if ::debug_mode; から
+	    ::debug_printmsg(); に変更。
+	  - WHO キャッシュにおいて、
+	    データ不足であきらめたときのメッセージ表示をやめた。
+
 2004-02-14  Topia  <topia@clovery.jp>
 
 	* 全般:
@@ -1216,7 +1234,7 @@
 
 	* これ以前のログは書いていません。
 
-#       Id: $Id: ChangeLog,v 1.128 2004/02/14 11:48:17 topia Exp $
+#       Id: $Id: ChangeLog,v 1.129 2004/02/15 00:19:31 topia Exp $
 #   Author: $Author: topia $
-#     Date: $Date: 2004/02/14 11:48:17 $
-# Revision: $Revision: 1.128 $
+#     Date: $Date: 2004/02/15 00:19:31 $
+# Revision: $Revision: 1.129 $
diff -urN tiarra-20040214/NEWS tiarra-20040215/NEWS
--- tiarra-20040214/NEWS	2004-02-15 09:19:45.000000000 +0900
+++ tiarra-20040215/NEWS	2004-02-15 09:21:35.000000000 +0900
@@ -1,3 +1,13 @@
+2004-02-15  Topia  <topia@clovery.jp>
+
+	* Client::Cache
+	  - 昨日の分だけでは Excess Flood/Max SendQ Exceeded 対策として
+	    不十分だったので、アップデートを推奨します。
+	  - 2つ以上のクライアントが同時に同じ動作をする場合に、
+	    今回の変更で効果が出ます。
+	    長すぎず短すぎずの絶妙な差で同じ動作をされた場合には
+	    効きませんが、滅多にそんなことはない(と思いたい)です。
+
 2004-02-14  Topia  <topia@clovery.jp>
 
 	* Log::Recent, System::Raw, Channel::Freeze, Channel::Rejoin
diff -urN tiarra-20040214/module/Client/Cache.pm tiarra-20040215/module/Client/Cache.pm
--- tiarra-20040214/module/Client/Cache.pm	2004-02-15 09:19:46.000000000 +0900
+++ tiarra-20040215/module/Client/Cache.pm	2004-02-15 09:21:36.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Cache.pm,v 1.2 2004/02/14 12:16:46 topia Exp $
+# $Id: Cache.pm,v 1.3 2004/02/15 00:19:31 topia Exp $
 # -----------------------------------------------------------------------------
 package Client::Cache;
 use strict;
@@ -20,6 +20,45 @@
     return 0;
 }
 
+sub message_io_hook {
+    my ($this,$msg,$io,$type) = @_;
+
+    if ($io->isa('IrcIO::Server')) {
+	if ($type eq 'out' &&
+		$msg->command eq 'MODE' &&
+		    Multicast::channel_p($msg->param(0)) &&
+			    !defined $msg->param(1)) {
+	    my $ch = $io->channel($msg->param(0));
+	    if (defined $ch) {
+		$ch->remark('fetching-switches', 1);
+	    }
+	} elsif ($type eq 'in' &&
+		     $msg->command eq RPL_CHANNELMODEIS &&
+			 Multicast::channel_p($msg->param(1))) {
+	    my $ch = $io->channel($msg->param(1));
+	    if (defined $ch) {
+		$ch->remark('fetching-switches', undef, 'delete');
+	    }
+	} elsif ($type eq 'out' &&
+		     $msg->command eq 'WHO' &&
+			 Multicast::channel_p($msg->param(0))) {
+	    my $ch = $io->channel($msg->param(0));
+	    if (defined $ch) {
+		$ch->remark('fetching-who', 1);
+	    }
+	} elsif ($type eq 'in' &&
+		     $msg->command eq RPL_WHOREPLY &&
+			 Multicast::channel_p($msg->param(1))) {
+	    # 処理の都合上、一つでも帰ってきた時点で取り消し。
+	    my $ch = $io->channel($msg->param(1));
+	    if (defined $ch) {
+		$ch->remark('fetching-who', undef, 'delete');
+	    }
+	}
+    }
+    return $msg;
+}
+
 sub message_arrived {
     my ($this,$msg,$sender) = @_;
 
@@ -38,33 +77,41 @@
 	    my ($chan_short, $network_name) = Multicast::detach($chan_long);
 	    my $network = RunLoop->shared_loop->network($network_name);
 	    unless (defined $network) {
-		RunLoop->shared_loop->notify_warn(
+		::debug_printmsg(
 		    __PACKAGE__.': "'.$network_name.
 			'" network is not found in tiarra.'
-		       ) if ::debug_mode;
+		       );
 		last;
 	    }
 	    my $ch = $network->channel($chan_short);
-	    last unless (defined $ch && $ch->remark('switches-are-known'));
-	    my $remark = $sender->remark('mode-cache-used') || {};
-	    if (!exists $remark->{$chan_long}) {
-		$sender->send_message(
-		    IRCMessage->new(
-			Prefix => Configuration->shared_conf->general->sysmsg_prefix,
-			Command => RPL_CHANNELMODEIS,
-			Params => [
-			    RunLoop->shared_loop->current_nick,
-			    $chan_long,
-			    $ch->mode_string,
-			   ],
-			Remarks => {
-			    'fill-prefix-when-sending-to-client' => 1,
-			},
-		       )
-		   );
-		$remark->{$chan_long} = 1;
-		$sender->remark('mode-cache-used', $remark);
-		return undef;
+	    last if !defined $ch;
+	    if ($ch->remark('switches-are-known')) {
+		my $remark = $sender->remark('mode-cache-used') || {};
+		if (!exists $remark->{$chan_long}) {
+		    $sender->send_message(
+			IRCMessage->new(
+			    Prefix => Configuration->shared_conf->general->sysmsg_prefix,
+			    Command => RPL_CHANNELMODEIS,
+			    Params => [
+				RunLoop->shared_loop->current_nick,
+				$chan_long,
+				$ch->mode_string,
+			       ],
+			    Remarks => {
+				'fill-prefix-when-sending-to-client' => 1,
+			    },
+			   )
+		       );
+		    $remark->{$chan_long} = 1;
+		    $sender->remark('mode-cache-used', $remark);
+		    return undef;
+		}
+	    } else {
+		if ($ch->remark('fetching-switches')) {
+		    # 取得しているクライアントがいるなら、今回は消す。
+		    return undef;
+		}
+		# 取得しにいってもらう。
 	    }
 	} elsif ($msg->command eq 'WHO' &&
 		     $this->_yesno($this->config->use_who_cache) &&
@@ -73,10 +120,10 @@
 	    my ($chan_short, $network_name) = Multicast::detach($chan_long);
 	    my $network = RunLoop->shared_loop->network($network_name);
 	    unless (defined $network) {
-		RunLoop->shared_loop->notify_warn(
+		::debug_printmsg(
 		    __PACKAGE__.': "'.$network_name.
 			'" network is not found in tiarra.'
-		       ) if ::debug_mode;
+		       );
 		last;
 	    }
 	    my $ch = $network->channel($chan_short);
@@ -108,9 +155,6 @@
 			if (!$p->username || !$p->userhost ||
 				!$p->realname || !$p->server) {
 			    # データ不足。あきらめる。
-			    RunLoop->shared_loop->notify_warn(
-				__PACKAGE__.': cache data not enough: '.$p->info.
-				    ' on '.$p->server) if ::debug_mode;
 			    die 'cache data not enough';
 			}
 
@@ -140,6 +184,12 @@
 		    $remark->{$chan_long} = 1;
 		    $sender->remark('who-cache-used', $remark);
 		    return undef;
+		} else {
+		    if ($ch->remark('fetching-who')) {
+			# 取得しているクライアントがいるなら、今回は消して便乗。
+			return undef;
+		    }
+		    # 取得しにいってもらう。
 		}
 	    }
 	}
