1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
# -----------------------------------------------------------------------------
# $Id: Recent.pm 11365 2008-05-10 14:58:28Z topia $
# -----------------------------------------------------------------------------
package Log::Recent;
use strict;
use warnings;
use base qw(Module);
use Module::Use qw(Tools::DateConvert Log::Logger);
use Tools::DateConvert;
use Log::Logger;
use Mask;
sub new {
my $class = shift;
my $this = $class->SUPER::new(@_);
# チャンネル管理の手間を省くため、チャンネルのログはChannelInfoのremarksに保存する。
# privのログだけこのクラスで保持。
$this->{priv_log} = []; # 中身は単なる文字列
$this->{logger} =
Log::Logger->new(
sub {
$this->log(@_);
},
$this,
'S_PRIVMSG','C_PRIVMSG','S_NOTICE','C_NOTICE');
$this->{hook} = IrcIO::Client::Hook->new(
sub {
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) {
foreach my $elem (@$vec) {
$client->send_message(
$this->construct_irc_message(
Prefix => RunLoop->shared_loop->sysmsg_prefix(qw(channel log)),
Command => 'NOTICE',
Params => [$ch_name,$elem->[1]]));
}
}
})->install('channel-info');
$this;
}
sub destruct {
my $this = shift;
$this->{hook} and $this->{hook}->uninstall;
}
sub message_arrived {
my ($this,$msg,$sender) = @_;
# Log::Recent/commandにマッチするか?
if (Mask::match(lc($this->config->command) || '*', lc($msg->command))) {
$this->{logger}->log($msg,$sender);
}
$msg;
}
sub client_attached {
my ($this,$client) = @_;
# no-recent-logs オプションが指定されていれば何もしない
return if defined $client->option('no-recent-logs');
# まずはpriv
my $local_nick = RunLoop->shared->current_nick;
foreach my $elem (@{$this->{priv_log}}) {
$client->send_message(
$this->construct_irc_message(
Prefix => RunLoop->shared_loop->sysmsg_prefix(qw(priv log)),
Command => 'NOTICE',
Params => [$local_nick,$elem->[1]])); # $elem->[0]は常に'priv'
}
# 次に各チャンネル
# foreach my $network (values %{RunLoop->shared->networks}) {
# foreach my $ch (values %{$network->channels}) {
# # ログはあるか?
# 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(
# $this->construct_irc_message(
# Prefix => RunLoop->shared_loop->sysmsg_prefix(qw(channel log)),
# Command => 'NOTICE',
# Params => [$ch_name,$elem->[1]]));
# }
# }
# }
# }
}
*S_PRIVMSG = \&PRIVMSG_or_NOTICE;
*S_NOTICE = \&PRIVMSG_or_NOTICE;
*C_PRIVMSG = \&PRIVMSG_or_NOTICE;
*C_NOTICE = \&PRIVMSG_or_NOTICE;
sub PRIVMSG_or_NOTICE {
my ($this,$msg,$sender) = @_;
my $target = Multicast::detach($msg->param(0));
my $is_priv = Multicast::nick_p($target);
my $cmd = $msg->command;
my $line = do {
if ($is_priv) {
if ($sender->isa('IrcIO::Client')) {
sprintf(
$cmd eq 'PRIVMSG' ? '>%s< %s' : ')%s( %s',
$msg->param(0),
$msg->param(1));
}
else {
sprintf(
$cmd eq 'PRIVMSG' ? '-%s- %s' : '=%s= %s',
$msg->nick || $sender->current_nick,
$msg->param(1));
}
}
else {
my $format = do {
if ($this->config->distinguish_myself && $sender->isa('IrcIO::Client')) {
$cmd eq 'PRIVMSG' ? '>%s< %s' : ')%s( %s';
}
else {
$cmd eq 'PRIVMSG' ? '<%s> %s' : '(%s) %s';
}
};
my $nick = do {
if ($sender->isa('IrcIO::Client')) {
RunLoop->shared_loop->network(
(Multicast::detatch($msg->param(0)))[1])
->current_nick;
}
else {
$msg->nick || $sender->current_nick;
}
};
sprintf $format,$nick,$msg->param(1);
}
};
[$is_priv ? 'priv' : $msg->param(0),$line];
}
sub log {
my ($this,$ch_full,$log_line) = @_;
my $vec = do {
if ($ch_full eq 'priv') {
# privは自分で保存
$this->{priv_log};
}
else {
# privでなければChannelInfoに'recent-log'として保存。
my ($ch_short,$network_name) = Multicast::detach($ch_full);
my $network = RunLoop->shared->network($network_name);
if (!defined $network) {
RunLoop->shared->notify_warn("errorness network name: $network_name");
return;
}
my $ch = $network->channel($ch_short);
if (!defined $ch) {
return;
}
my $log_vec = $ch->remarks('recent-log');
if (!defined $log_vec) {
$log_vec = [];
$ch->remarks('recent-log',$log_vec);
}
$log_vec;
}
};
my $header = Tools::DateConvert::replace(
$this->config->header || '%H:%M'
);
# ログに追加
# 要素は[チャンネル名,ログ行]
push @$vec,[$ch_full,"$header $log_line"];
# 溢れた分を消す
if (@$vec > $this->config->line) {
splice @$vec,0,(@$vec - $this->config->line);
}
}
1;
=pod
info: クライアントを接続した時に、保存しておいた最近のメッセージを送る。
default: off
section: important
# クライアントオプションの no-recent-logs が指定されていれば送信しません。
# 各行のヘッダのフォーマット。省略されたら'%H:%M'。
header: %H:%M:%S
# ログをチャンネル毎に何行まで保存するか。省略されたら10。
line: 15
# PRIVMSGとNOTICEを記録する際に、自分の発言と他人の発言でフォーマットを変えるかどうか。1/0。デフォルトで1。
distinguish-myself: 1
# どのメッセージを保存するか。省略されたら保存可能な全てのメッセージを保存する。
command: privmsg,notice,topic,join,part,quit,kill
=cut
|