diff -urN tiarra-20040401/ChangeLog tiarra-20040407/ChangeLog --- tiarra-20040401/ChangeLog 2004-04-01 18:52:44.000000000 +0900 +++ tiarra-20040407/ChangeLog 2004-04-07 20:57:33.000000000 +0900 @@ -1,3 +1,33 @@ +2004-04-07 phonohawk + + * main/IrcIO/Server.pm (new): + $this->{channels}のキーを、小文字に変換しておく。 + + 大文字小文字に一貫性の無いチャンネル名をクライアントに送る、 + EFnetやFreenet(IRC)のようなircdに接続していると、しばしば + Tiarraは混乱する。この問題を回避するため、チャンネル名同士の + 比較は一旦小文字に変換した上で行うようにする。 + + (channel): + 大文字小文字を無視してチャンネルを探索するように変更。 + $server->channel($name)のようにしてChannelInfoを得ている + 場合には、何ら変更は必要無い。 + + チャンネル名 => ChannelInfoのハッシュを返す、$server->channels + を使っている場合は、そのキーが小文字に変換されている事に注意しなければ + ならない。 + + * main/Multicast.pm (lc, uc): 追加 + IRC方式で大文字と小文字の変換を行う。IRC方式とは、[]\がそれぞれ{}|の + 大文字であると定義されている方式である。 + + * main/Mask.pm (compile): 追加 + マスクからコンパイル済み正規表現を生成する部分を、独立した関数にした。 + 大量のマッチングを高速に行う場合は、Mask::の関数を何度も呼ぶ代わりに + マスクを一度だけコンパイルする事を考えた方が良い。 + Mask.pm内でコンパイル済みマスクはキャッシュしているが、それでも速度は違う。 + + 2004-04-01 Topia * module/Client/Cache.pm: @@ -1537,7 +1567,7 @@ * これ以前のログは書いていません。 -# Id: $Id: ChangeLog,v 1.143 2004/04/01 09:44:41 topia Exp $ -# Author: $Author: topia $ -# Date: $Date: 2004/04/01 09:44:41 $ -# Revision: $Revision: 1.143 $ +# Id: $Id: ChangeLog,v 1.144 2004/04/07 11:49:58 admin Exp $ +# Author: $Author: admin $ +# Date: $Date: 2004/04/07 11:49:58 $ +# Revision: $Revision: 1.144 $ diff -urN tiarra-20040401/main/IrcIO/Server.pm tiarra-20040407/main/IrcIO/Server.pm --- tiarra-20040401/main/IrcIO/Server.pm 2004-04-01 18:52:44.000000000 +0900 +++ tiarra-20040407/main/IrcIO/Server.pm 2004-04-07 20:57:33.000000000 +0900 @@ -1,5 +1,5 @@ # ----------------------------------------------------------------------------- -# $Id: Server.pm,v 1.54 2004/03/07 10:34:19 topia Exp $ +# $Id: Server.pm,v 1.55 2004/04/07 11:49:57 admin Exp $ # ----------------------------------------------------------------------------- # IrcIO::ServerはIRCサーバーに接続し、IRCメッセージをやり取りするクラスです。 # このクラスはサーバーからメッセージを受け取ってチャンネル情報や現在のnickなどを保持しますが、 @@ -35,7 +35,7 @@ $obj->{receiving_exceptlist} = {}; # 同上。RPL_EXCEPTLIST $obj->{receiving_invitelist} = {}; # 同上、RPL_INVITELIST - $obj->{channels} = {}; # チャンネル名 => ChannelInfo + $obj->{channels} = {}; # 小文字チャンネル名 => ChannelInfo $obj->{people} = {}; # nick => PersonalInfo $obj->connect; @@ -54,6 +54,7 @@ } sub channels { + # {小文字チャンネル名 => ChannelInfo}のハッシュリファを返す。 # @options(省略可能): # 'even-if-kicked-out': 既に自分が蹴り出されてゐるチャンネルも返す。この動作は高速である。 my ($this, @options) = @_; @@ -62,11 +63,12 @@ } else { # kicked-outフラグが立つてゐないチャンネルのみ返す。 - my %result = map { - ($_, $this->{channels}{$_}); - } grep { - !$this->{channels}{$_}->remarks('kicked-out'); - } keys %{$this->{channels}}; + my %result; + while (my ($name, $ch) = each %{$this->{channels}}) { + if (!$ch->remark('kicked-out')) { + $result{$name} = $ch; + } + } \%result; } } @@ -154,7 +156,8 @@ } sub channel { - my ($this,$channel_name) = @_; + my $this = $_[0]; + my $channel_name = Multicast::lc($_[1]); $this->{channels}->{$channel_name}; } @@ -415,7 +418,7 @@ sub _receive_after_logged_in { my ($this,$msg) = @_; - + $this->person($msg->nick,$msg->name,$msg->host); # nameとhostを覚えておく。 if ($msg->command eq 'NICK') { @@ -533,7 +536,7 @@ # チャンネル名とnickが1対1で対応 map { my ($ch_name,$nick) = ($ch_names[$_],$nicks[$_]); - my $ch = $this->{channels}->{$ch_name}; + my $ch = $this->channel($ch_name); if (defined $ch) { #$ch->names($nick,undef,'delete'); $kick->($ch,$nick); @@ -542,7 +545,7 @@ } elsif (@ch_names == 1) { # 一つのチャンネルから1人以上をkick - my $ch = $this->{channels}->{$ch_names[0]}; + my $ch = $this->channel($ch_names[0]); if (defined $ch) { map { #$ch->names($_,undef,'delete'); @@ -559,7 +562,7 @@ return; } - my $ch = $this->{channels}->{$msg->param(0)}; + my $ch = $this->channel($msg->param(0)); if (defined $ch) { my $n_params = @{$msg->params}; @@ -624,14 +627,15 @@ m/^([^\x07]+)(?:\x07(.*))?/; my ($ch_name,$mode) = ($1,(defined $2 ? $2 : '')); - my $ch = $this->{channels}->{$ch_name}; + my $ch = $this->channel($ch_name); if (defined $ch) { # 知っているチャンネル。もしkickedフラグが立っていたらクリア。 $ch->remarks('kicked-out',undef,'delete'); } else { # 知らないチャンネル。 - $ch = $this->{channels}->{$ch_name} = ChannelInfo->new($ch_name,$this->{network_name}); + $ch = ChannelInfo->new($ch_name,$this->{network_name}); + $this->{channels}{Multicast::lc($ch_name)} = $ch; } $ch->names($msg->nick, new PersonInChannel( @@ -644,10 +648,11 @@ sub _NJOIN { my ($this,$msg) = @_; my $ch_name = $msg->param(0); - my $ch = $this->{channels}->{$ch_name}; + my $ch = $this->channel($ch_name); unless (defined $ch) { # 知らないチャンネル。 - $ch = $this->{channels}->{$ch_name} = ChannelInfo->new($ch_name,$this->{network_name}); + $ch = ChannelInfo->new($ch_name,$this->{network_name}); + $this->{channels}{Multicast::lc($ch_name)} = $ch; } map { m/^([@+]*)(.+)$/; @@ -665,11 +670,11 @@ my ($this,$msg) = @_; map { my $ch_name = $_; - my $ch = $this->{channels}->{$ch_name}; + my $ch = $this->channel($ch_name); if (defined $ch) { if ($msg->nick eq $this->{current_nick}) { # PARTしたのが自分だった - delete $this->{channels}->{$ch_name}; + delete $this->{channels}->{Multicast::lc($ch_name)}; } else { $ch->names($msg->nick,undef,'delete'); @@ -738,7 +743,7 @@ sub _TOPIC { my ($this,$msg) = @_; - my $ch = $this->{channels}->{$msg->param(0)}; + my $ch = $this->channel($msg->param(0)); if (defined $ch) { # 古いトピックを"old-topic"として註釈を付ける。 $msg->remark('old-topic', $ch->topic); @@ -752,7 +757,7 @@ sub _RPL_NAMREPLY { my ($this,$msg) = @_; - my $ch = $this->{channels}->{$msg->param(2)}; + my $ch = $this->channel($msg->param(2)); return unless defined $ch; my $receiving_namreply = $this->{receiving_namreply}->{$msg->param(2)}; @@ -844,7 +849,7 @@ sub _RPL_NOTOPIC { my ($this,$msg) = @_; - my $ch = $this->{channels}->{$msg->param(1)}; + my $ch = $this->channel($msg->param(1)); if (defined $ch) { $ch->topic(''); } @@ -852,7 +857,7 @@ sub _RPL_TOPIC { my ($this,$msg) = @_; - my $ch = $this->{channels}->{$msg->param(1)}; + my $ch = $this->channel($msg->param(1)); if (defined $ch) { $ch->topic($msg->param(2)); } @@ -860,7 +865,7 @@ sub _RPL_TOPICWHOTIME { my ($this,$msg) = @_; - my $ch = $this->{channels}->{$msg->param(1)}; + my $ch = $this->channel($msg->param(1)); if (defined $ch) { $ch->topic_who($msg->param(2)); $ch->topic_time($msg->param(3)); @@ -869,7 +874,7 @@ sub _RPL_INVITELIST { my ($this,$msg) = @_; - my $ch = $this->{channels}->{$msg->param(1)}; + my $ch = $this->channel($msg->param(1)); my $receiving_invitelist = $this->{receiving_invitelist}->{$msg->param(1)}; if (defined $receiving_invitelist && @@ -894,7 +899,7 @@ sub _RPL_EXCEPTLIST { my ($this,$msg) = @_; - my $ch = $this->{channels}->{$msg->param(1)}; + my $ch = $this->channel($msg->param(1)); my $receiving_exceptlist = $this->{receiving_exceptlist}->{$msg->param(1)}; if (defined $receiving_exceptlist && @@ -919,7 +924,7 @@ sub _RPL_BANLIST { my ($this,$msg) = @_; - my $ch = $this->{channels}->{$msg->param(1)}; + my $ch = $this->channel($msg->param(1)); my $receiving_banlist = $this->{receiving_banlist}->{$msg->param(1)}; if (defined $receiving_banlist && @@ -973,7 +978,7 @@ my ($this,$msg) = @_; # 既知のチャンネルなら、そのチャンネルに # switches-are-known => 1という備考を付ける。 - my $ch = $this->{channels}->{$msg->param(1)}; + my $ch = $this->channel($msg->param(1)); if (defined $ch) { $ch->remarks('switches-are-known',1); diff -urN tiarra-20040401/main/Mask.pm tiarra-20040407/main/Mask.pm --- tiarra-20040401/main/Mask.pm 2004-04-01 18:52:45.000000000 +0900 +++ tiarra-20040407/main/Mask.pm 2004-04-07 20:57:34.000000000 +0900 @@ -1,5 +1,5 @@ # ----------------------------------------------------------------------------- -# $Id: Mask.pm,v 1.14 2004/03/07 10:34:19 topia Exp $ +# $Id: Mask.pm,v 1.15 2004/04/07 11:49:58 admin Exp $ # ----------------------------------------------------------------------------- # $Clovery: tiarra/main/Mask.pm,v 1.10 2003/07/24 03:08:26 topia Exp $ package Mask; @@ -242,13 +242,7 @@ delete $cache_table{$to_delete}; } - my $regex = $str; - $regex =~ s/(\W)/\\$1/g; - $regex =~ s/\\\?/\./g; - $regex =~ s/\\\*/\.\*/g; - $regex = "^$regex\$"; - - my $compiled = qr/$regex/i; + my $compiled = compile($str); push @cache_keys, $str; $cache_table{$str} = $compiled; @@ -256,6 +250,28 @@ } } +sub compile { + # $mask: マスク文字列 + # $consider_case: 真なら、大文字小文字を区別する。 + my ($mask, $consider_case) = @_; + + if (!defined $mask) { + return qr/(?!)/; # マッチしない正規表現 + } + + my $regex = $mask; + $regex =~ s/(\W)/\\$1/g; + $regex =~ s/\\\?/\./g; + $regex =~ s/\\\*/\.\*/g; + $regex = "^$regex\$"; + if ($consider_case) { + qr/$regex/; + } + else { + qr/$regex/i; + } +} + sub _split { # ',' でわけられたマスクを配列にする。 my $mask = shift; diff -urN tiarra-20040401/main/Multicast.pm tiarra-20040407/main/Multicast.pm --- tiarra-20040401/main/Multicast.pm 2004-04-01 18:52:45.000000000 +0900 +++ tiarra-20040407/main/Multicast.pm 2004-04-07 20:57:34.000000000 +0900 @@ -1,5 +1,5 @@ # ----------------------------------------------------------------------------- -# $Id: Multicast.pm,v 1.23 2004/03/07 10:34:19 topia Exp $ +# $Id: Multicast.pm,v 1.24 2004/04/07 11:49:58 admin Exp $ # ----------------------------------------------------------------------------- # サーバーからクライアントにメッセージが流れるとき、このクラスはフィルタとして # ネットワーク名を付加します。 @@ -683,4 +683,19 @@ } } +sub lc { + # IRC方式で、大文字を小文字に変換する。 + my $str = shift; + # {}|は[]\の小文字である。気違いじみている! + $str =~ tr/A-Z[]\\/a-z{}|/; + $str; +} + +sub uc { + # IRC方式で、小文字を大文字に変換する。 + my $str = shift; + $str =~ tr/a-z{}|/A-Z[]\\/; + $str; +} + 1;