diff -urN tiarra-20040313/ChangeLog tiarra-20040319/ChangeLog
--- tiarra-20040313/ChangeLog	2004-03-13 22:23:39.000000000 +0900
+++ tiarra-20040319/ChangeLog	2004-03-26 13:04:03.000000000 +0900
@@ -1,3 +1,28 @@
+2004-03-19  Topia  <topia@clovery.jp>
+
+	* main/IrcIO.pm, main/LinedINETSocket.pm:
+	  - IO::Handle 1.21 において、 LEN が存在しないと croak がでる bug
+	    の回避。
+
+	* main/ModuleManager.pm:
+	  - モジュールの destruct を呼ぶ際に、 $show_msg でなく
+	    RunLoop->shared_loop->notify_error を使うように。
+
+	* main/IrcIO/Client.pm:
+	(inform_joinning_channels):
+	  - フックの引数を変更。
+	  - フックコール中にエラーが発生しても
+	    最低限すべてのチャンネル情報だけは送信するように。
+
+	* module/Client/Cache.pm:
+	  - IrcIO::Client::Hook/channel-info を使用して、
+	    知っているチャンネルモードを強制的に先行して送るようにした。
+
+	* module/Log/Recent.pm:
+	(IrcIO::Client::Hook/channel-info):
+	  - 引数変更に同期。
+	  - クライアントオプション no-recent-logs をみるようにした。
+
 2004-03-13  phonohawk  <phonohawk@ps.sakura.ne.jp>
 
 	* main/Hook.pm (Hook::call, HookTarget::call_hooks):
@@ -1477,7 +1502,7 @@
 
 	* これ以前のログは書いていません。
 
-#       Id: $Id: ChangeLog,v 1.138 2004/03/13 07:17:33 admin Exp $
-#   Author: $Author: admin $
-#     Date: $Date: 2004/03/13 07:17:33 $
-# Revision: $Revision: 1.138 $
+#       Id: $Id: ChangeLog,v 1.139 2004/03/19 13:21:06 topia Exp $
+#   Author: $Author: topia $
+#     Date: $Date: 2004/03/19 13:21:06 $
+# Revision: $Revision: 1.139 $
diff -urN tiarra-20040313/main/IrcIO/Client.pm tiarra-20040319/main/IrcIO/Client.pm
--- tiarra-20040313/main/IrcIO/Client.pm	2004-03-13 22:23:39.000000000 +0900
+++ tiarra-20040319/main/IrcIO/Client.pm	2004-03-26 13:04:03.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Client.pm,v 1.27 2004/03/13 07:17:34 admin Exp $
+# $Id: Client.pm,v 1.28 2004/03/19 13:21:06 topia Exp $
 # -----------------------------------------------------------------------------
 # IrcIO::Clientはクライアントからの接続を受け、
 # IRCメッセージをやり取りするクラスです。
@@ -443,6 +443,15 @@
 		Prefix => $this->fullname,
 		Command => RPL_ENDOFNAMES,
 		Params => [$local_nick,$ch_name,'End of NAMES list']));
+
+	# channel-infoフックの引数は (IrcIO::Client, 送信用チャンネル名, ネットワーク, ChannelInfo)
+	eval {
+	    IrcIO::Client::HookTarget->shared->call(
+		'channel-info', $this, $ch_name, $network, $ch);
+	}; if ($@) {
+	    # エラーメッセージは表示するが、送信処理は続ける
+	    RunLoop->shared_loop->notify_error("__PACKAGE__ hook call error: $@");
+	}
     };
 
     my %channels = map {
@@ -462,9 +471,6 @@
 	    my $ch_name = $_;
 	    if (Mask::match($mask, $ch_name)) {
 		$send_channelinfo->(@{$channels{$ch_name}});
-		# channel-infoフックの引数は (IrcIO::Client, チャンネル名)
-		IrcIO::Client::HookTarget->shared->call(
-		    'channel-info', $this, $ch_name);
 		delete $channels{$ch_name};
 		last;
 	    }
@@ -472,10 +478,8 @@
     }
 
     # のこりを出力
-    while (my ($ch_name, $pair) = each %channels) {
-	$send_channelinfo->(@$pair);
-	IrcIO::Client::HookTarget->shared->call(
-	    'channel-info', $this, $ch_name);
+    foreach (values %channels) {
+	$send_channelinfo->(@$_);
     }
 }
 
diff -urN tiarra-20040313/main/IrcIO.pm tiarra-20040319/main/IrcIO.pm
--- tiarra-20040313/main/IrcIO.pm	2004-03-13 22:23:39.000000000 +0900
+++ tiarra-20040319/main/IrcIO.pm	2004-03-26 13:04:03.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: IrcIO.pm,v 1.21 2004/02/04 12:08:54 admin Exp $
+# $Id: IrcIO.pm,v 1.22 2004/03/19 13:21:06 topia Exp $
 # -----------------------------------------------------------------------------
 # IrcIOはIRCサーバー又はクライアントと接続し、IRCメッセージをやり取りする抽象クラスです。
 # -----------------------------------------------------------------------------
@@ -118,7 +118,7 @@
     }
 
     #my $bytes_sent = $this->{sock}->send($this->{sendbuf}) || 0;
-    my $bytes_sent = $this->{sock}->syswrite($this->{sendbuf}) || 0;
+    my $bytes_sent = $this->{sock}->syswrite($this->{sendbuf}, length($this->{sendbuf})) || 0;
     $this->{sendbuf} = substr($this->{sendbuf},$bytes_sent);
 
     if ($this->{disconnect_after_writing} &&
diff -urN tiarra-20040313/main/LinedINETSocket.pm tiarra-20040319/main/LinedINETSocket.pm
--- tiarra-20040313/main/LinedINETSocket.pm	2004-03-13 22:23:40.000000000 +0900
+++ tiarra-20040319/main/LinedINETSocket.pm	2004-03-26 13:04:03.000000000 +0900
@@ -1,6 +1,5 @@
 # -*- cperl -*-
-# $Id: LinedINETSocket.pm,v 1.6 2003/06/03 15:27:42 admin Exp $
-# $Clovery: tiarra/main/LinedINETSocket.pm,v 1.4 2003/03/04 03:03:46 topia Exp $
+# $Id: LinedINETSocket.pm,v 1.7 2004/03/19 13:21:06 topia Exp $
 # copyright (C) 2003 Topia <topia@clovery.jp>. all rights reserved.
 # this module based IrcIO.pm, thanks phonohawk!
 package LinedINETSocket;
@@ -151,7 +150,7 @@
   }
 
   #my $bytes_sent = $this->{sock}->send($this->{sendbuf}) || 0;
-  my $bytes_sent = $this->{sock}->syswrite($this->{sendbuf}) || 0;
+  my $bytes_sent = $this->{sock}->syswrite($this->{sendbuf}, length($this->{sendbuf})) || 0;
   substr($this->{sendbuf}, 0, $bytes_sent) = '';
 
   if ($this->{disconnect_after_writing} &&
diff -urN tiarra-20040313/main/ModuleManager.pm tiarra-20040319/main/ModuleManager.pm
--- tiarra-20040313/main/ModuleManager.pm	2004-03-13 22:23:40.000000000 +0900
+++ tiarra-20040319/main/ModuleManager.pm	2004-03-26 13:04:03.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: ModuleManager.pm,v 1.14 2004/02/23 02:46:18 topia Exp $
+# $Id: ModuleManager.pm,v 1.15 2004/03/19 13:21:06 topia Exp $
 # -----------------------------------------------------------------------------
 # このクラスは全てのTiarraモジュールを管理します。
 # モジュールをロードし、リロードし、破棄するのはこのクラスです。
@@ -132,7 +132,7 @@
 	    eval {
 		$loaded_mods{$_->block_name}->destruct;
 	    }; if ($@) {
-		$show_msg->($@);
+		RunLoop->shared_loop->notify_error->($@);
 	    }
 	}
 	$this->_unload($_);
diff -urN tiarra-20040313/module/Client/Cache.pm tiarra-20040319/module/Client/Cache.pm
--- tiarra-20040313/module/Client/Cache.pm	2004-03-13 22:23:40.000000000 +0900
+++ tiarra-20040319/module/Client/Cache.pm	2004-03-26 13:04:04.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Cache.pm,v 1.6 2004/03/09 07:48:12 topia Exp $
+# $Id: Cache.pm,v 1.7 2004/03/19 13:21:07 topia Exp $
 # -----------------------------------------------------------------------------
 package Client::Cache;
 use strict;
@@ -9,19 +9,31 @@
 use Multicast;
 use NumericReply;
 
-sub _yesno {
-    my ($this, $value, $default) = @_;
+sub MODE_CACHE_FORCE_SENDED (){0;}
+sub MODE_CACHE_SENDED (){1;}
 
-    return $default || 0 if (!defined $value);
-    return 0 if ($value =~ /[fn]/); # false/no
-    return 1 if ($value =~ /[ty]/); # true/yes
-    return 1 if ($value); # 数値判定
-    return 0;
+sub new {
+    my $class = shift;
+    my $this = $class->SUPER::new(@_);
+    $this->{hook} = IrcIO::Client::Hook->new(
+	sub {
+	    my ($hook, $client, $ch_name, $network, $ch) = @_;
+	    if ($ch->remark('switches-are-known')) {
+		# 送信できる場合は強制的に送信してみる
+		my $remark = $client->remark('mode-cache-state') || {};
+		_send_mode_cache($client,$ch_name,$ch);
+		$remark->{$ch_name}->[MODE_CACHE_FORCE_SENDED] = 1;
+		$client->remark('mode-cache-state', $remark);
+	    }
+	})->install('channel-info');
+    $this;
 }
 
 sub destruct {
     my ($this) = shift;
-    # cleaning remarks
+
+    # hook を解除
+    $this->{hook} and $this->{hook}->uninstall;
 
     # チャンネルについている remark を削除。
     foreach my $network (RunLoop->shared_loop->networks_list) {
@@ -34,6 +46,16 @@
     # クライアントについてるのは削除しない。
 }
 
+sub _yesno {
+    my ($this, $value, $default) = @_;
+
+    return $default || 0 if (!defined $value);
+    return 0 if ($value =~ /[fn]/); # false/no
+    return 1 if ($value =~ /[ty]/); # true/yes
+    return 1 if ($value); # 数値判定
+    return 0;
+}
+
 sub message_io_hook {
     my ($this,$msg,$io,$type) = @_;
 
@@ -100,24 +122,13 @@
 	    my $ch = $network->channel($chan_short);
 	    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 => RunLoop->shared_loop->sysmsg_prefix('system'),
-			    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);
+		my $remark = $sender->remark('mode-cache-state') || {};
+		if (!$remark->{$chan_long}->[MODE_CACHE_SENDED]) {
+		    _send_mode_cache($sender,$chan_long,$ch)
+			if (!$remark->{$chan_long}
+				->[MODE_CACHE_FORCE_SENDED]);
+		    $remark->{$chan_long}->[MODE_CACHE_SENDED] = 1;
+		    $sender->remark('mode-cache-state', $remark);
 		    return undef;
 		}
 	    } else {
@@ -212,6 +223,26 @@
     return $msg;
 }
 
+
+sub _send_mode_cache {
+    my ($sendto,$ch_name,$ch) = @_;
+
+    $sendto->send_message(
+	IRCMessage->new(
+	    Prefix => RunLoop->shared_loop->sysmsg_prefix('system'),
+	    Command => RPL_CHANNELMODEIS,
+	    Params => [
+		RunLoop->shared_loop->current_nick,
+		$ch_name,
+		$ch->mode_string,
+	       ],
+	    Remarks => {
+		'fill-prefix-when-sending-to-client' => 1,
+	    },
+	   )
+       );
+}
+
 1;
 =pod
 info: データをキャッシュしてサーバに問い合わせないようにする
diff -urN tiarra-20040313/module/Log/Recent.pm tiarra-20040319/module/Log/Recent.pm
--- tiarra-20040313/module/Log/Recent.pm	2004-03-13 22:23:40.000000000 +0900
+++ tiarra-20040319/module/Log/Recent.pm	2004-03-26 13:04:03.000000000 +0900
@@ -1,5 +1,5 @@
 # -----------------------------------------------------------------------------
-# $Id: Recent.pm,v 1.10 2004/03/13 07:17:35 admin Exp $
+# $Id: Recent.pm,v 1.11 2004/03/19 13:21:07 topia Exp $
 # -----------------------------------------------------------------------------
 # Local: $Clovery: tiarra/module/Log/Recent.pm,v 1.5 2003/02/11 07:59:32 topia Exp $
 package Log::Recent;
@@ -27,16 +27,13 @@
 	    'S_PRIVMSG','C_PRIVMSG','S_NOTICE','C_NOTICE');
     $this->{hook} = IrcIO::Client::Hook->new(
 	sub {
-	    my ($hook, $client, $ch_name) = @_;
-	    my $ch = RunLoop->shared->channel($ch_name);
+	    my ($hook, $client, $ch_name, $network, $ch) = @_;
+	    # no-recent-logs オプションが指定されていれば何もしない
+	    return if defined $client->option('no-recent-logs');
 	    # ログはあるか？
 	    my $vec = $ch->remarks('recent-log');
 	    if (defined $vec) {
-		my $ch_name;
 		foreach my $elem (@$vec) {
-		    $ch_name =
-			RunLoop->shared->multi_server_mode_p ?
-			    $elem->[0] : $ch->name;
 		    $client->send_message(
 			IRCMessage->new(
 			    Prefix => RunLoop->shared_loop->sysmsg_prefix(qw(channel log)),
