]> jfr.im git - irc/SurrealServices/srsv.git/blob - branches/erry-devel/modules/logserv.pm
initial commit of erry's Insp work.
[irc/SurrealServices/srsv.git] / branches / erry-devel / modules / logserv.pm
1 # This file is part of SurrealServices.
2 #
3 # SurrealServices is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # SurrealServices is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with SurrealServices; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 package logserv;
17
18 use strict;
19 no strict 'refs';
20 use Storable;
21
22 use SrSv::Process::InParent qw(chanlog addchan delchan ev_sjoin ev_join ev_part
23 ev_kick ev_mode ev_nickconn ev_nickchange ev_quit ev_message ev_notice
24 ev_chghost ev_kill ev_topic ev_connect saveconf loadconf join_chans);
25
26 use SrSv::Conf2Consts qw(main);
27 use SrSv::IRCd::Event 'addhandler';
28 use SrSv::IRCd::State 'initial_synced';
29 use SrSv::Agent;
30 use SrSv::User::Notice;
31 use SrSv::Log qw( :all );
32
33 my %userlist;
34 my %chanlist;
35
36 our $lsnick = 'LogServ';
37 my $chanopmode = '+v';
38
39 loadconf();
40 agent_connect($lsnick, 'services', undef, '+pqzBHSD', 'Log Service');
41 agent_join($lsnick, main_conf_diag);
42 ircd::setmode($lsnick, main_conf_diag, '+o', $lsnick);
43 join_chans();
44
45 sub chanlog($@) {
46 my ($cn, @payload) = @_;
47 write_log("logserv:$cn", '', @payload)
48 # This if allows us to be lazy
49 if defined($chanlist{lc $cn});
50 }
51
52 sub addchan($$) {
53 my ($user, $cn) = @_;
54 unless(defined($chanlist{lc $cn})) {
55 open_log("logserv:$cn", lc($cn).'.log');
56 $chanlist{lc $cn} = 1;
57 agent_join($lsnick, $cn);
58 ircd::setmode($lsnick, $cn, $chanopmode, $lsnick);
59 notice($user, "Channel $cn will now be logged");
60 saveconf();
61 return 1;
62 } else {
63 notice($user, "Channel $cn is already being logged");
64 return 0;
65 }
66 }
67
68 sub delchan($$) {
69 my ($user, $cn) = @_;
70 if(defined($chanlist{lc $cn})) {
71 close_log("logserv:$cn");
72 delete($chanlist{lc $cn});
73 agent_part($lsnick, $cn, "Channel has been deleted by ".$user->{NICK});
74 notice($user, "Channel $cn will not be logged");
75 saveconf();
76 return 1;
77 } else {
78 notice($user, "Channel $cn is not being logged");
79 return 0;
80 }
81 }
82
83 # Handler Functions
84
85 addhandler('SJOIN', undef, undef, 'logserv::ev_sjoin');
86 sub ev_sjoin {
87 # ($server, $cn, $ts, $chmodes, $chmodeparms, \@users, \@bans, \@excepts, \@invex);
88 my (undef, $cn, undef, undef, undef, $users, undef, undef, undef) = @_;
89 foreach my $user (@$users) {
90 ev_join($user->{NICK}, $cn);
91 }
92 }
93
94 addhandler('JOIN', undef, undef, 'logserv::ev_join');
95 sub ev_join {
96 my ($nick, $cn) = @_;
97 return if is_agent($nick); # Ignore agent joins.
98 return unless defined($userlist{lc $nick}); # Sometimes we get JOINs after a KILL or QUIT
99 {
100 $userlist{lc $nick}{CHANS}{$cn} = 1;
101 }
102 if(initial_synced()) {
103 if($cn eq '0') {
104 foreach my $cn (keys(%{$userlist{lc $nick}{CHANS}})) {
105 ev_part($nick, $cn, 'Left all channels');
106 }
107 } else {
108 my ($ident, $vhost) = @{$userlist{lc $nick}{INFO}};
109 chanlog($cn, "-!- $nick [$ident\@$vhost] has joined $cn");
110 }
111 }
112 }
113
114 addhandler('PART', undef, undef, 'logserv::ev_part');
115 sub ev_part {
116 my ($nick, $cn, $reason) = @_;
117 return if is_agent($nick); # Ignore agent parts.
118 return unless defined($userlist{lc $nick}); # Sometimes we get JOINs after a KILL or QUIT
119 {
120 delete($userlist{lc $nick}{CHANS}{$cn});
121 }
122 my ($ident, $vhost) = @{$userlist{lc $nick}{INFO}};
123 chanlog("$cn", "-!- $nick [$ident\@$vhost] has left $cn [$reason]");
124 }
125
126 addhandler('KICK', undef, undef, 'logserv::ev_kick');
127 sub ev_kick {
128 my ($src, $cn, $target, $reason) = @_;
129 return unless defined($userlist{lc $target}); # Sometimes we get JOINs after a KILL or QUIT
130 if(lc $target eq lc $lsnick) {
131 agent_join($lsnick, $cn);
132 ircd::setmode($lsnick, $cn, '+o', $lsnick);
133 return;
134 }
135 {
136 delete($userlist{lc $target}{CHANS}{$cn});
137 }
138 chanlog("$cn", "-!- $target was kicked by $src [$reason]");
139 }
140
141 addhandler('MODE', undef, undef, 'logserv::ev_mode');
142 sub ev_mode {
143 my ($src, $cn, $modes, $parms) = @_;
144 return unless initial_synced();
145 chanlog("$cn", "-!- mode/$cn [$modes".($parms ? " $parms" : '')."] by $src");
146 }
147
148 addhandler('NICKCONN', undef, undef, 'logserv::ev_nickconn');
149 sub ev_nickconn {
150 my ($nick, $ident, $host, $modes, $vhost, $cloakhost) = @_[0,3,4,7,8,11];
151 if ($vhost eq '*') {
152 if ({modes::splitumodes($modes)}->{x} eq '+') {
153 if(defined($cloakhost)) {
154 $vhost = $cloakhost;
155 }
156 else {
157 # Since we have no desire to do ircd::userhost checks
158 # This makes us dependent on VHP or CLK.
159 # Do we care? Not at the moment.
160 # This should NEVER happen with VHP or CLK.
161 $vhost = $host;
162 }
163 } else {
164 $vhost = $host;
165 }
166 }
167 $userlist{lc $nick} = {
168 INFO => [$ident, $vhost],
169 CHANS => {},
170 };
171 }
172
173 addhandler('NICKCHANGE', undef, undef, 'logserv::ev_nickchange');
174 sub ev_nickchange {
175 my ($old, $new) = @_;
176 return unless defined($userlist{lc $old}); # Sometimes we get JOINs after a KILL or QUIT
177 unless (lc($old) eq lc($new)) {
178 $userlist{lc $new} = $userlist{lc $old};
179 delete($userlist{lc $old});
180 }
181 foreach my $cn (keys(%{$userlist{lc $new}{CHANS}})) {
182 chanlog($cn, "-!- $old is now known as $new");
183 }
184 }
185
186 addhandler('QUIT', undef, undef, 'logserv::ev_quit');
187 sub ev_quit {
188 my ($nick, $reason) = @_;
189 my ($ident, $vhost) = @{$userlist{lc $nick}{INFO}};
190 if (initial_synced()) {
191 foreach my $cn (keys(%{$userlist{lc $nick}{CHANS}})) {
192 chanlog($cn, "$nick [$ident\@$vhost] has quit [$reason]");
193 }
194 }
195 delete($userlist{lc $nick});
196 }
197
198 addhandler('LOOP_PRIVMSG', undef, qr/^#/, 'logserv::ev_loop_message');
199 sub ev_loop_message {
200 my ($nick, $cn, $messages) = @_;
201 my $channel = $cn;
202 $channel =~ s/^[+%@&~]+//;
203 return unless defined($chanlist{lc $channel});
204 foreach my $message (@$messages) {
205 if ($message =~ /^\001(\w+)(?: (.*))\001$/i) {
206 my ($ctcp, $payload) = ($1, $2);
207 if($ctcp eq 'ACTION') {
208 $message = "* $nick $payload";
209 }
210 else {
211 $message = "$nick requested CTCP $1 from $cn: $2";
212 }
213 } else {
214 $message = "<$nick> $message";
215 }
216 }
217 chanlog($channel, @$messages);
218 }
219 addhandler('LOOP_NOTICE', undef, qr/^#/, 'logserv::ev_loop_notice');
220 sub ev_loop_notice {
221 my ($nick, $cn, $messages) = @_;
222 my $channel = $cn;
223 $channel =~ s/^[+%@&~]+//;
224 return unless defined($chanlist{lc $channel});
225 foreach my $message (@$messages) {
226 $message = "-$nick:$cn- $message";
227 }
228 chanlog($channel, @$messages);
229 }
230
231 addhandler('PRIVMSG', undef, qr/^#/, 'logserv::ev_message');
232 sub ev_message {
233 my ($nick, $cn, $message) = @_;
234 my $channel = $cn;
235 $channel =~ s/^[+%@&~]+//;
236 return unless defined($chanlist{lc $channel});
237 if ($message =~ /^\001(\w+)(?: (.*))\001$/i) {
238 my ($ctcp, $payload) = ($1, $2);
239 if($ctcp eq 'ACTION') {
240 chanlog($channel, "* $nick $payload");
241 }
242 else {
243 chanlog($channel, "$nick requested CTCP $1 from $cn: $2");
244 }
245 } else {
246 chanlog($channel, "<$nick> $message");
247 }
248
249 }
250 addhandler('NOTICE', undef, qr/^#/, 'logserv::ev_notice');
251 sub ev_notice {
252 my ($nick, $cn, $message) = @_;
253 my $channel = $cn;
254 $channel =~ s/^[+%@&~]+//;
255 return unless defined($chanlist{lc $channel});
256 chanlog($channel, "-$nick:$cn- $message");
257 }
258
259 addhandler('CHGHOST', undef, undef, 'logserv::ev_chghost');
260 sub ev_chghost {
261 my (undef, $nick, $vhost) = @_;
262 return unless defined($userlist{lc $nick}); # Sometimes we get JOINs after a KILL or QUIT
263 {
264 my ($ident, undef) = @{$userlist{lc $nick}{INFO}};
265 $userlist{lc $nick}{INFO} = [$ident, $vhost];
266 }
267
268 }
269
270 addhandler('KILL', undef, undef, 'logserv::ev_kill');
271 sub ev_kill {
272 my ($src, $target, $reason) = @_;
273 return if is_agent($target) or !defined($userlist{lc $target}); # Ignore agent kills.
274 my ($ident, $vhost) = @{$userlist{lc $target}{INFO}};
275 if (initial_synced()) {
276 foreach my $cn (keys(%{$userlist{lc $target}{CHANS}})) {
277 chanlog($cn, "$target [$ident\@$vhost] has quit [Killed ($src ($reason))]");
278 }
279 }
280 delete($userlist{lc $target});
281 }
282
283 addhandler('TOPIC', undef, undef, 'logserv::ev_topic');
284 sub ev_topic {
285 my ($src, $cn, $setter, undef, $topic) = @_;
286 # We don't care about the timestamp
287 return unless initial_synced();
288 chanlog($cn, "$src changed the topic of $cn to: $topic".($setter ne $src ? " ($setter)" : ''));
289 }
290
291 # Internal Only functions.
292
293 sub saveconf() {
294 my @channels = keys(%chanlist);
295 Storable::nstore(\@channels, "config/logserv/chans.conf");
296 }
297
298 sub loadconf() {
299 (-d "config/logserv") or mkdir "config/logserv";
300 return unless(-f "config/logserv/chans.conf");
301 my @channels = @{Storable::retrieve("config/logserv/chans.conf")};
302 foreach my $cn (@channels) {
303 $chanlist{lc $cn} = 1;
304 }
305 }
306
307 sub join_chans() {
308 foreach my $cn (keys(%chanlist)) {
309 open_log("logserv:$cn", lc($cn).'.log');
310 agent_join($lsnick, $cn);
311 ircd::setmode($lsnick, $cn, $chanopmode, $lsnick);
312 }
313 }
314
315 sub init { }
316 sub begin { }
317 sub end { }
318 sub unload { saveconf(); }
319
320 1;