]> jfr.im git - irc/SurrealServices/srsv.git/blame - branches/0.5.0/SrSv/Insp/Parse.pm
Fixed some more stuff.. No more getuuid for normal users!
[irc/SurrealServices/srsv.git] / branches / 0.5.0 / SrSv / Insp / Parse.pm
CommitLineData
5e682044 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
17package SrSv::IRCd::Parse;
18
19use strict;
20
21use Exporter 'import';
22# parse_sjoin shouldn't get used anywhere else, as we never produce SJOINs
23# parse_tkl however is used for loopbacks.
24BEGIN { our @EXPORT_OK = qw(parse_line parse_tkl parse_addline) }
25
26# FIXME
27BEGIN { *SJB64 = \&ircd::SJB64; *CLK = \&ircd::CLK; *NICKIP = \&ircd::NICKIP; }
28
29use SrSv::Conf 'main';
30
31use SrSv::Debug;
32use SrSv::IRCd::State qw($ircline $remoteserv create_server get_server_children set_server_state get_server_state %IRCd_capabilities);
33use SrSv::IRCd::Queue qw(queue_size);
34use SrSv::IRCd::IO qw( ircsend ircsendimm);
35use SrSv::IRCd::Send qw (getRevUuid getUuid setRevUuid setUuid);
36use SrSv::Unreal::Modes qw(%opmodes);
026939ee 37use SrSv::RunLevel 'main_shutdown';
5e682044 38# Unreal uses its own modified base64 for everything except NICKIP
39use SrSv::Unreal::Base64 qw(b64toi itob64);
40use SrSv::User '/./';
41# Unreal uses unmodified base64 for NICKIP.
42# Consider private implementation,
43# tho MIME's is probably faster
44use MIME::Base64;
45use Data::Dumper;
7b3a5814 46use SrSv::Insp::UUID;
5e682044 47# FIXME
48use constant {
49 # Wait For
50 WF_NONE => 0,
51 WF_NICK => 1,
52 WF_CHAN => 2,
53 WF_ALL => 3,
54};
55
56use SrSv::Shared qw(@servernum);
57
58our %cmdhash;
59
60sub parse_line($) {
61 my ($in) = @_;
62 if (!$in) {
63 return;
64 }
65 my $cmd;
66
67 if($in =~ /^(?:@|:)(\S+) (\S+)/) {
68 $cmd = $2;
69 }
70 elsif ($in =~ /^(\S+)/) {
71 $cmd = $1;
72 }
73 my $sub = $cmdhash{$cmd};
74 unless (defined($sub)) {
75 print "Bailing out from $ircline:$cmd for lack of cmdhash\n" if DEBUG();
76 return undef();
77 }
78 my ($event, $src, $dst, $wf, @args) = &$sub($in);
79 unless (defined($event)) {
80 print "Bailing out from $ircline:$cmd for lack of event\n" if DEBUG;
81 return undef();
82 }
83 #return unless defined $event;
84
85 my (@recipients, @out);
86 if(defined($dst)) {
87 #$args[$dst] = lc $args[$dst];
88 @recipients = split(/\,/, $args[$dst]);
89 }
90 #if(defined($src)) { $args[$src] = lc $args[$src]; }
91
92 if(@recipients > 1) {
93 foreach my $rcpt (@recipients) {
94 $args[$dst] = $rcpt;
95 push @out, [$event, $src, $dst, $wf, [@args]];
96 }
97 } else {
98 @out = [$event, $src, $dst, $wf, [@args]];
99 }
100
101 return @out;
102}
103#parse_fjoin($server, $channel, $ts, $modes, @nicks, @status)
104sub parse_fjoin ($$$$$$) {
105 my ($server, $channel, $ts, $modes, $idsr, $statusref) = @_;
106 my @status = @$statusref;
107 my @ids = @$idsr;
108 my $i = 0;
109 my @users;
110 foreach my $id (@ids) {
111 my $op = 0;
112 my @ops = split ("",$status[$i]);
113 foreach my $prefix (@ops) {
114 $op |= $opmodes{$prefix};
115 }
7b3a5814 116 my $user = {ID => $id, __OP=>$op}; #ID'S are _already_ decoded in FJOIN!
5e682044 117 get_user_nick ($user);
118 push @users, $user;
119 $i++;
120 }
121 return ($server, $channel, $ts, $modes, undef, \@users, undef, undef, undef); #bans etc are got from FMODE..
122}
123sub parse_sjoin($$$$) {
124 my ($server, $ts, $cn, $parms) = @_;
125 my (@users, @bans, @excepts, @invex, @blobs, $blobs, $chmodes, $chmodeparms);
126
127 $server = '' unless $server;
128
129 if($parms =~ /^:(.*)/) {
130 $blobs = $1;
131 } else {
132 ($chmodes, $blobs) = split(/ :/, $parms, 2);
133 ($chmodes, $chmodeparms) = split(/ /, $chmodes, 2);
134 }
135 @blobs = split(/ /, $blobs);
136
137 foreach my $x (@blobs) {
138 if($x =~ /^(\&|\"|\')(.*)$/) {
139 my $type;
140 push @bans, $2 if $1 eq '&';
141 push @excepts, $2 if $1 eq '"';
142 push @invex, $2 if $1 eq "\'";
143 } else {
144 $x =~ /^([*~@%+]*)(.*)$/;
145 my ($prefixes, $nick) = ($1, $2);
146 my @prefixes = split(//, $prefixes);
147 my $op = 0;
148 foreach my $prefix (@prefixes) {
149 $op |= $opmodes{q} if ($prefix eq '*');
150 $op |= $opmodes{a} if ($prefix eq '~');
151 $op |= $opmodes{o} if ($prefix eq '@');
152 $op |= $opmodes{h} if ($prefix eq '%');
153 $op |= $opmodes{v} if ($prefix eq '+');
154 }
155
156 push @users, { NICK => $nick, __OP => $op };
157 }
158 }
159
160 return ($server, $cn, $ts, $chmodes, $chmodeparms, \@users, \@bans, \@excepts, \@invex);
161}
162sub parse_addline ($) {
163 my ($line) = @_;
164 #return ($type, +1, $ident, $host, $setter, $expire, $time, $reason);
165 #>> 47 :583AAAAAA ADDLINE G test@testie inspircd.erry.omg 1308118489 0 :hi
166 my ($setter, undef, $type, $mask, $server, $time, $expiry, $reason) = split (/ /, $line, 7);
167 $reason =~ /:(.*)/;
168 $reason = $1;
169 $setter =~ /:(.*)/;
170 $setter = $1;
171 my @masks = split (/@/,$mask, 1);
172 my $ident = $masks[0];
173 my $host = $masks[1];
174 #return ($type, +1, $ident, $host, $setter, $expire, $time, $reason);
175 return ($type, +1, $ident, $host, $setter, $expiry, $time, $reason);
176}
177sub parse_tkl ($) {
178 my ($in) = @_;
179 # This function is intended to accept ALL tkl types,
180 # tho maybe not parse all of them in the first version.
181
182 # Discard first token, 'TKL'
183 my (undef, $sign, $type, $params) = split(/ /, $in, 4);
184
185 # Yes, TKL types are case sensitive!
186 # also be aware (and this applies to the net.pm generator functions too)
187 # This implementation may appear naiive, but Unreal assumes that, for a given
188 # TKL type, that all parameters are non-null.
189 # Thus, if any parameters ARE null, Unreal WILL segfault.
190 ## Update: this problem may have been fixed since Unreal 3.2.2 or so.
191 if ($type eq 'G' or $type eq 'Z' or $type eq 's' or $type eq 'Q') {
192 # format is
193 # TKL + type ident host setter expiretime settime :reason
194 # TKL - type ident host setter
195 # for Q, ident is always '*' or 'h' (Services HOLDs)
196 if ($sign eq '+') {
197 my ($ident, $host, $setter, $expire, $time, $reason) = split(/ /, $params, 6);
198
199 $reason =~ s/^\://;
200 return ($type, +1, $ident, $host, $setter, $expire, $time, $reason);
201 }
202 elsif($sign eq '-') {
203 my ($ident, $host, $setter) = split(/ /, $params, 3);
204 return ($type, -1, $ident, $host, $setter);
205 }
206 }
207 elsif($type eq 'F') {
208 # TKL + F cpnNPq b saturn!attitude@netadmin.SCnet.ops 0 1099959668 86400 Possible_mIRC_DNS_exploit :\/dns (\d+\.){3}\d
209 # TKL + F u g saturn!attitude@saturn.netadmin.SCnet.ops 0 1102273855 604800 sploogatheunbreakable:_Excessively_offensive_behavior,_ban_evasion. :.*!imleetnig@.*\.dsl\.mindspring\.com
210 # TKL - F u Z tabris!northman@tabris.netadmin.SCnet.ops 0 0 :do_not!use@mask
211 if ($sign eq '+') {
212 my ($target, $action, $setter, $expire, $time, $bantime, $reason, $mask) = split(/ /, $params, 8);
213 $mask =~ s/^\://;
214 return ($type, +1, $target, $action, $setter, $expire, $time, $bantime, $reason, $mask);
215 }
216 elsif($sign eq '-') {
217 my ($target, $action, $setter, $expire, $time, $mask) = split(/ /, $params, 6);
218 $mask =~ s/^\://;
219 return ($type, -1, $target, $action, $setter, $mask);
220 }
221 }
222}
223
224sub PING($) {
225 my ($event, $src, $dst, @args);
226 $_[0] =~ /^(?:8|PING) :(\S+)$/;
227 # ($event, $src, $dst, $args)
228 return ('PING', undef, undef, WF_NONE, $1);
229}
230sub UID ($) {
231 #:583 UID 583AAAAAJ 1307703236 erry__ localhost localhost errietta 127.0.0.1 1307703241 + :errietta
7b3a5814 232 $_[0] =~ /^(:\S+) UID (\S+) (\d+) (\S+) (\S+) (\S+) (\S+) (\S+) (\d+) (\S+) :(.*)$/;
233 my ($server, $uid, $stamp, $nick, $host, $vhost, $ident, $IP, $ts, $modes, $gecos) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
234 print "UID $uid " . decodeUUID($uid) . "\n";
235 my $user = { NICK => $nick, ID => decodeUUID($uid) };
236 return ('NICKCONN', undef, undef, WF_NICK, $user, 0, $ts, $ident, $host, $server, $stamp, $modes, $vhost, $gecos,
237 join('.', unpack('C4', MIME::Base64::decode($IP))));
5e682044 238}
239sub EOS($) {
240 my $event;
241 print "EOS\n";
242 if ($_[1] != "ENDBURST") {
243 $_[0] =~ /^(@|:)(\S+) (?:EOS|ES)/; # Sometimes there's extra crap on the end?
244 my $server;
245 if ($1 eq '@') {
246 $server = $servernum[b64toi($2)];
247 }
248 else {
249 $server = $2;
250 }
251 print "SERVER $server\n";
252 set_server_state($server, 1);
253 return undef() unless get_server_state($remoteserv);
254 if($server eq $remoteserv) { $event = 'SEOS' } else { $event = 'EOS' }
255 print "Ok. we had EOS\n";
256 return ($event, undef, undef, WF_ALL, $server);
257 }
258 else {
259 print "wot\n";
260 $_[0] =~ /^:(\S+) ENDBURST/;
261 my $server = $1;
262 set_server_state($server, 1);
263 print "server $server remote $remoteserv\n";
264 return undef() unless get_server_state($remoteserv);
265 print "This be it! Got endbrust!\n";
266 return ("ENDBURST", undef, undef, WF_ALL, $1);
267 }
268}
269
270sub SERVER($) {
271 #ircd::debug($_[0]) if $debug;
272
273 if($_[0] =~ /^(?:SERVER|\') (\S+) (\S+) :(U[0-9]+)-([A-Za-z0-9]+)-([0-9]+) (.*)$/) {
92c29160 274 # SERVER test-tab.surrealchat.net 1 :U2307-FhinXeOoZEmM-200 SurrealChat
275 # cmd, servername, hopCount, U<protocol>-<buildflags>-<numeric> infoLine
5e682044 276 $remoteserv = $1;
277 create_server($1);
278 $servernum[$5] = $1;
279
280 return ('SERVER', undef, undef, WF_ALL, undef, $1, $2, $6, $5, $3, $4);
281 # src, serverName, numHops, infoLine, serverNumeric, protocolVersion, buildFlags
282 }
283 elsif($_[0] =~ /^(:|@)(\S+) (?:SERVER|\') (\S+) (\d+) (\d+) :(.*)$/) {
284 # @38 SERVER test-hermes.surrealchat.net 2 100 :SurrealChat
285 # source, cmd, new server, hopCount, serverNumeric, infoLine
286 my ($numeric, $name);
287 if ($1 eq '@') {
288 $name = $servernum[b64toi($2)];
289 }
290 else {
291 $name = $2;
292 }
293 create_server($3, $name);
294 $servernum[$5] = $3;
295
296 return ('SERVER', undef, undef, WF_ALL, $name, $3, $4, $6, $5);
297 # src, serverName, numHops, infoLine, serverNumeric
298 }
299 if($_[0] =~ /^(?:SERVER|\') (\S+) (\S+) :(.*)$/) {
300 $remoteserv = $1;
301 create_server($1);
302 return ('SERVER', undef, undef, WF_ALL, undef, $1, $2, $3);
303 # src, serverName, numHops, infoLine
304 }
305 elsif($_[0] =~ /^:(\S+) (?:SERVER|\') (\S+) (\d+) :(.*)$/) {
306 # source, new server, hop count, description
307 create_server($2, $1);
308 return ('SERVER', undef, undef, WF_ALL, $1, $2, $3, $4);
309 # src, serverName, numHops, infoLine
310 }
311 elsif ($_[0] =~ /SERVER (\S+) (\S+) (\d+) (\S+) :(.*)$/) {
312 #SERVER inspircd.erry.omg mypass 0 583 :erry World
313 #SERVER servername password hopcount SID :Server Desc
314 $remoteserv = $4;
315 create_server ($4);
316 #since from now on we'll be getting commands as sent from the SID it's much wiser to keep that than the name.
317 return ("SERVER", undef, undef, WF_ALL, undef, $1, $3, $5, $4);
318 }
319}
320
321sub SQUIT($) {
322 if($_[0] =~ /^(?:SQUIT|-) (\S+) :(.*)$/) {
323 my $list = [get_server_children($1)];
324 set_server_state($1, undef());
325 return ('SQUIT', undef, undef, WF_ALL, undef, $list, $2);
326 }
327 elsif($_[0] =~ /^(:|@)(\S+) (?:SQUIT|-) (\S+) :(.*)$/) {
328 my $name;
329 if ($1 eq '@') {
330 $name = $servernum[b64toi($2)];
331 }
332 else {
333 $name = $2;
334 }
335 my $list = [get_server_children($3)];
336 set_server_state($3, undef());
337 return ('SQUIT', undef, undef, WF_ALL, $name, $list, $4);
338 }
339}
340
341sub NETINFO($) {
342 $_[0] =~ /^(?:NETINFO|AO) (\S+) (\S+) (\S+) (\S+) (\S+) (\S+) (\S+) :(.*)$/;
343 return ('NETINFO', undef, undef, WF_NONE, $1, $2, $3, $4, $5, $6, $7, $8);
344}
345
346sub PROTOCTL($) {
347 $_[0] =~ /^PROTOCTL (.*)$/;
348 return ('PROTOCTL', undef, undef, WF_NONE, $1);
349}
350
351sub JOIN($) {
352 $_[0] =~ /^:(\S+) (?:C|JOIN) (\S+)$/;
7b3a5814 353 my $user = { ID => decodeUUID($1) };
5e682044 354 get_user_nick ($user);
355 return ('JOIN', undef, 1, WF_CHAN, $user, $2);
356}
357
358sub FJOIN ($) {
359 #>> 13 :97K FJOIN #erry 1307879417 +nt :o,97KAAAAAA ,97KAAAAAB
92c29160 360 if ($_[0] =~ m"^(:\S+) FJOIN (\S+) (\d+) (\S+) (:?)(.*)$") {
361 my ($server, $channel, $ts, $modes, $userstring) = ($1, $2, $3, $4, $6);
362 my @users = split (" ", $userstring);
363 my (@ids, @status);
364 foreach my $user (@users) {
365 my @params = split (",",$user);
366 push (@status, $params[0]);
7b3a5814 367 push (@ids, decodeUUID($params[1]));
92c29160 368 }
369 return ('SJOIN', undef, undef, WF_CHAN, parse_fjoin($server, $channel, $ts, $modes, \@ids, \@status));
370 }
371 #>> 15 :583 FJOIN #opers 1310128904 +Pis :
372 #CHANNELS CONFIGURED TO STAY OPEN WITH CHMODE +P (INSP)
373 elsif ($_[0] =~ m"^(:\S+) FJOIN (\S+) (\d+) (\S+) :$") {
374 print "WHOOOOOOF";
375 #FIXME - Update channel modes.
5e682044 376 }
5e682044 377}
378sub SJOIN($) {
379 if ($_[0] =~ /^(?:\~|SJOIN) (\S+) (\S+) (.*)$/) {
380 my ($ts, $cn, $payload) = ($1, $2, $3);
381 if ($ts =~ s/^!//) {
382 $ts = b64toi($ts);
383 }
384 return ('SJOIN', undef, undef, WF_CHAN, parse_sjoin($remoteserv, $ts, $cn, $payload));
385 }
386 elsif($_[0] =~ /^(@|:)(\S+) (?:\~|SJOIN) (\S+) (\S+) (.*)$/) {
387 my ($server, $ts, $cn, $payload) = ($2, $3, $4, $5);
388 if ($1 eq '@') {
389 $server = $servernum[b64toi($2)];
390 }
391 else {
392 $server = $2;
393 }
394 if ($ts =~ s/^!//) {
395 $ts = b64toi($ts);
396 }
397 return ('SJOIN', undef, undef, WF_CHAN, parse_sjoin($server, $ts, $cn, $payload));
398 }
399}
400
401sub PART($) {
402 my $user;
403
404 if($_[0] =~ /^:(\S+) (?:D|PART) (\S+) :(.*)$/) {
7b3a5814 405 $user = {ID => decodeUUID($1)};
5e682044 406 get_user_nick ($user);
407 return ('PART', undef, 0, WF_CHAN, $user, $2, $3);
408 }
409 elsif($_[0] =~ /^:(\S+) (?:D|PART) (\S+)$/) {
7b3a5814 410 $user = {ID => decodeUUID($1)};
92c29160 411 get_user_nick ($user);
5e682044 412 return ('PART', undef, 0, WF_CHAN, $user, $2, undef);
413 }
414}
415sub FMODE($) {
416 #:583AAAAAR FMODE #erry 1308214721 +ib test!*@* When any mode in the channel is set.
417 #:583 FMODE #erry 1308214721 +b test1!*@* At server connect. Note that the rest of the channel modes are not there but rather at FJOIN. So this will only have bans and the like.
418 if($_[0] =~ /^:(\S+) FMODE (#\S+) (\d+) (\S+) ?(.*)$/) {
419 my $id = $1;
7b3a5814 420 my $user;
421 print "FMODE ID $id " . length($id);
422 if (length($id) > 3) { #UID
423 print "FFFFFFFFFFF\n";
424 $user = {ID => decodeUUID($id)};
425 get_user_nick ($user);
426 }
427 else { #SID
428 $user = $id;
429 }
430 my $name;
431 my $argz = $5;
432 my @args = split(/ /, $argz);
433 my $modes = $4;
434 print "============MODES $modes=================\n";
435 print "5: $4\n";
436 print "6: $5\n";
437 my @modes = split(//, $modes);
438 my @userargs;
439 foreach my $mode (@modes) {
440 if($mode eq '+' or $mode eq '-') { next; }
441 if ($mode !~ /^[vhoaq]$/) { next; }
442 my $arg = shift (@args);
443 next if $arg eq '';
444 my $id = decodeUUID($arg);
445 my $tuser = {ID=>$id};
446 get_user_nick ($tuser);
447 push @userargs, $tuser;
448 }
449 return ('MODE', undef, 1, WF_ALL, $user, $2, $4, $5, @userargs);
5e682044 450 }
451}
452sub MODE($) {
453 my $user;
7b3a5814 454 if($_[0] =~ /^(@|:)(\S+) (?:G|MODE) (#\S+) (.*)(?: \d+)?$/) {
5e682044 455 my $name;
456 if ($1 eq '@') {
457 $name = $servernum[b64toi($2)];
458 $user = {NICK => $name};
459 }
460 else {
461 $name = $2;
7b3a5814 462 $user = { ID=>decodeUUID($name)};
5e682044 463 get_user_nick ($user);
464 }
7b3a5814 465 my $argz = $6;
466 my @args = split(/ /, $argz);
467 my $modes = $5;
468 print "============MODES $modes=================\n";
469 print "5: $5\n";
470 print "6: $6\n";
471 my @modes = split(//, $modes);
472 my $newargs = "";
473 foreach my $mode (@modes) {
474 if($mode eq '+' or $mode eq '-') { next; }
475 my $arg = shift (@args);
476 next if $arg eq '';
477 my $id = encodeUUID($arg);
478 my $tuser = {ID=>$id};
479 my $nick = get_user_nick ($tuser);
480 print "!!!!!!!!!!!1!!!!!$nick\n";
481 $newargs .= ($newargs eq ""?$nick:" $nick"); # what an awful way to do it.
482 }
483 my $arguements;
484 if ($newargs eq "") {
485 $arguements = $argz;
486 }
487 else {
488 $arguements = $newargs;
489 }
490 return ('MODE', undef, 1, WF_ALL, $user, $3, $4, $arguements);
5e682044 491 }
492 elsif($_[0] =~ /^:(\S+) (?:G|MODE) (\S+) :(\S+)$/) {
493 # We shouldn't ever get this, as UMODE2 is preferred
7b3a5814 494 $user = { ID => decodeUUID($1) };
5e682044 495 get_user_nick ($user);
496 return ('UMODE', 0, 0, WF_ALL, $user, $3);
497 }
498
499}
500
7b3a5814 501
5e682044 502sub MESSAGE($) {
503 my ($event, @args);
504 if($_[0] =~ /^(@|:)(\S+) (?:\!|PRIVMSG) (\S+) :(.*)$/) {
505
506 my ($name, $srcUser, $dstUser) ;
507 if ($1 eq '@') {
508 $name = $servernum[b64toi($2)];
509 $srcUser = {NICK=>$name};
510 }
511 else {
512 $name = $2;
7b3a5814 513 $srcUser = {ID=>decodeUUID($name)};
5e682044 514 unless (get_user_nick ($srcUser)) {
515 $srcUser = {NICK=>$name};
516 get_user_id ($name);
517 }
518 }
519 my $dest = $3;
7b3a5814 520 $dstUser = {ID=>($dest)};
5e682044 521 unless (get_user_nick ($dstUser)) {
522 $dstUser = {NICK=>$dest};
523 }
5e682044 524 $event = 'PRIVMSG'; @args = ($srcUser, $dstUser, $4);
525 }
526 elsif($_[0] =~ /^(@|:)(\S+) (?:B|NOTICE) (\S+) :(.*)$/) {
527 my $name;
528 if ($1 eq '@') {
529 $name = $servernum[b64toi($2)];
530 }
531 else {
532 $name = $2;
533 }
534 $event = 'NOTICE'; @args = ($name, $3, $4);
535 }
536 $args[1] =~ s/\@${main_conf{local}}.*//io;
537
538 if(queue_size > 50 and $event eq 'PRIVMSG' and $args[1] !~ /^#/ and $args[2] =~ /^\w/) {
539 ircd::notice($args[1], $args[0], "It looks like the system is busy. You don't need to do your command again, just hold on a minute...");
540 }
541
542 return ($event, 0, 1, WF_ALL, @args);
543}
544
545sub AWAY($) {
546 if($_[0] =~ /^:(\S+) (?:6|AWAY) :(.*)$/) {
7b3a5814 547 my $user = {ID=>decodeUUID($1)};
5e682044 548 get_user_nick($user);
549 return ('AWAY', undef, undef, WF_ALL, $user, $2);
550 }
551 elsif($_[0] =~ /^:(\S+) (?:6|AWAY)$/) {
7b3a5814 552 my $user = {ID => decodeUUID($1)};
5e682044 553 get_user_nick ($user);
554 return ('BACK', undef, undef, WF_ALL, $user);
555 }
556}
557
558sub NICK($) {
559 my ($event, @args);
560 #:97KAAAAAA NICK erry_ 1307878528
561 if($_[0] =~ /^:(\S+) (?:NICK|\&) (\S+) :?(\S+)$/) {
7b3a5814 562 my $user = {ID => decodeUUID($1)};
5e682044 563 get_user_nick ($user);
7b3a5814 564 set_user_nick (decodeUUID($1), $2);
565 set_user_id ($2, decodeUUID($1));
5e682044 566 return ('NICKCHANGE', undef, undef, WF_NICK, $user, $2, $3);
567 }
568}
569
570sub QUIT($) {
92c29160 571 if ($_[0] =~ /^:(\S+) QUIT :Killed \((\S+) \((.*)\)\)$/) {
572 #:583AAAAAH QUIT :Killed (erry (die))
7b3a5814 573 my $victim = {ID=>decodeUUID($1)};
92c29160 574 get_user_nick ($victim);
575 my $murderer = {NICK=>$2};
576 get_user_id ($murderer);
577 my $reason = $3;
578 return ('KILL', 0, 1, WF_NICK, $murderer, $victim, $reason, undef);
579 }
580 elsif ($_[0] =~ /^:(\S+) QUIT :(.*)$/) {
7b3a5814 581 my $user = {ID=>decodeUUID($1)};
92c29160 582 get_user_nick ($user);
583 return ('QUIT', 0, undef, WF_NICK, $user, $2);
5e682044 584 }
92c29160 585}
586sub OPERQUIT ($) {
587 if ($_[0] =~ /^:(\S+) QUIT :(.*)$/) {
7b3a5814 588 my $user = {ID=>decodeUUID($1)};
92c29160 589 get_user_nick ($user);
590 return ('QUIT', 0, undef, WF_NICK, $user, $2);
5e682044 591 }
5e682044 592}
593
92c29160 594sub KILL($) {
595 #All insp sends is :583AAAAAH QUIT :Killed (erry (die))
596 #_VERY_ helpful.
597 #UNLESS you kill someone who's in the services server:
598 #:583AAAAAA KILL 123AAAAAA :Killed (erry (die))
599 #:123AAAAAA OPERQUIT :Killed (erry (die))
600 #And yes, for (some?) opers it's OPERQUIT not QUIT
601 #Joy, JOY, JOY!
602 $_[0] =~ /^:(\S+) KILL (\S+) :(.*)$/;
7b3a5814 603 my $murderer = {ID=>decodeUUID($1)};
92c29160 604 get_user_nick ($murderer);
7b3a5814 605 my $victim = {ID=>decodeUUID($2)};
92c29160 606 get_user_nick ($victim);
607 return ("KILL", 0, 1, WF_NICK, $murderer, $victim, $3, undef);
608}
5e682044 609sub KICK($) {
610#:tabris KICK #diagnostics SurrealBot :i know you don't like this. but it's for science!
611 $_[0] =~ /^(@|:)(\S+) (?:KICK|H) (\S+) (\S+) :(.*)$/;
612 # source, chan, target, reason
613 #$src = 0; #$dst = 2;
614 my $name;
615 if ($1 eq '@') {
616 $name = $servernum[b64toi($2)];
617 }
618 else {
619 $name = $2;
620 }
7b3a5814 621 my $user = {ID => decodeUUID($name)};
5e682044 622 unless (get_user_nick ($user)) {
623 $user = {NICK => $name};
624 get_user_id ($user);
625 }
626 return ('KICK', 0, undef, WF_CHAN, $user, $3, $4, $5);
627}
628
629sub HOST($) {
630 if($_[0] =~ /^:(\S+) (?:CHGHOST|AL) (\S+) (\S+)$/) {
631 #:Agent CHGHOST tabris tabris.netadmin.SCnet.ops
632 return ('CHGHOST', 0, 1, WF_CHAN, $1, $2, $3);
633 #setter, target, vhost
634 }
635 elsif($_[0] =~ /^:(\S+) (?:SETHOST|AA) (\S+)$/) {
636 #:tabris SETHOST tabris.netadmin.SCnet.ops
637 return ('CHGHOST', 0, 1, WF_CHAN, $1, $1, $2);
638 }
639
640 elsif ($_[0] =~ /^:(?:\S* )?302 (\S+) :(\S+?)\*?=[+-].*?\@(.*)/) {
641 #:serebii.razorville.co.uk 302 leif :Jesture=+~Jesture00@buzz-3F604D09.sympatico.ca
642 return ('CHGHOST', 0, 1, WF_CHAN, $1, $2, $3);
643 }
644}
645
646
647sub USERIP($) {
648 $_[0] =~ /^:(?:\S* )?340 (\S+) :(\S+?)\*?=[+-].*?\@((?:\.|\d)*)/;
649 return ('USERIP', 0, 1, WF_CHAN, $1, $2, $3);
650}
651
652sub IDENT($) {
653 if($_[0] =~ /^:(\S+) (?:CHGIDENT|AL) (\S+) (\S+)$/) {
654 return ('CHGIDENT', 0, 1, WF_ALL, $1, $2, $3);
655 #setter, target, IDENT
656 }
657 elsif($_[0] =~ /^:(\S+) (?:SETIDENT|AD) (\S+)$/) {
658 return ('CHGIDENT', 0, 1, WF_ALL, $1, $1, $2);
659 #setter, target, ident
660 }
661}
662
663
664sub TOPIC($) {
665 if ($_[0] =~ /^:(\S+) TOPIC (\S+) :(.*)$/) {
666 #:583AAAAAF TOPIC #erry :Welcome to erry(world|net). Have a cookie.
7b3a5814 667 my $setter = { ID => decodeUUID($1) };
5e682044 668 get_user_nick ($setter);
669 return ('TOPIC', 0, 1, WF_ALL, $setter, $2, $setter, 0, $3);
670 }
671}
672
673sub UMODE($) {
674#:tabris | +oghaANWt
675 $_[0] =~ /^:(\S+) (?:UMODE2|\|) (\S+)$/;
676 # src, umodes
677 # a note, not all umodes are passed
678 # +s, +O, and +t are not passed. possibly others
679 # also not all umodes do we care about.
680 # umodes we need care about:
681 # oper modes: hoaACN,O oper-only modes: HSq
682 # regular modes: rxB,izV (V is only somewhat, as the ircd
683 # does the conversions from NOTICE to PRIVSMG for us).
684
685 # Yes, I'm changing the event type on this
686 # It's better called UMODE, and easily emulated
687 # on IRCds with only MODE.
688 return ('UMODE', 0, 0, WF_ALL, $1, $2);
689}
690sub OPERTYPE ($) {
691 #:583AAAAAB OPERTYPE SuperNetAdmin
692 #Every OPERTYPE will get +o, so it's safe to assume they're opers,
693 #even if we don't give them privs (either in inspircd or srsv)
694 $_[0] =~ /^:(\S+) OPERTYPE (\S+)$/;
7b3a5814 695 my $user = { ID => decodeUUID($1) };
5e682044 696 get_user_nick ($user);
697 return ("OPERUP", 0, 0, WF_ALL, $user);
698}
699sub SVSMODE($) {
700#:tabris | +oghaANWt
701 $_[0] =~ /^:(\S+) (?:SVS2?MODE|n|v) (\S+) (\S+)$/;
702 # src, umodes
703 # a note, not all umodes are passed
704 # +s, +O, and +t are not passed. possibly others
705 # also not all umodes do we care about.
706 # umodes we need care about:
707 # oper modes: hoaACN,O oper-only modes: HSq
708 # regular modes: rxB,izV (V is only somewhat, as the ircd
709 # does the conversions from NOTICE to PRIVSMG for us).
710
711 return ('UMODE', 0, 0, WF_ALL, $2, $3);
712}
713
714sub WHOIS($) {
715# :tab WHOIS ConnectServ :ConnectServ
716 if($_[0] =~ /^:(\S+) (?:WHOIS|\#) (\S+)$/) {
717 return ('WHOIS', 0, undef, WF_NONE, $1, $2);
718 }
719 elsif($_[0] =~ /^:(\S+) (?:WHOIS|\#) (\S+) :(\S+)$/) {
720 return ('WHOIS', 0, undef, WF_NONE, $1, $3);
721 }
722}
723
724sub TSCTL($) {
725 $_[0] =~ /^:(\S+) (?:TSCTL|AW) alltime$/;
726 ircsend(":$main_conf{local} NOTICE $1 *** Server=$main_conf{local} TSTime=".
727 time." time()=".time." TSOffset=0");
728 return;
729}
730
731sub VERSION($) {
732 $_[0] =~ /^:(\S+) (?:VERSION|\+).*$/;
733 return ('VERSION', 0, undef, WF_NONE, $1);
734}
735
736sub TKL($) {
737 if ($_[0] =~ /^(@|:)(\S+) (?:TKL|BD) (.*)$/) {
738 # We discard the source anyway.
739 #my $server;
740 #if ($1 eq '@') {
741 # $server = $servernum[b64toi($2)];
742 #}
743 #else {
744 # $server = $2;
745 #}
746 return ('TKL', undef, undef, WF_NONE, parse_tkl("TKL $3"));
747 }
748 elsif ($_[0] =~ /^(?:TKL|BD) (.*)$/) {
749 return ('TKL', undef, undef, WF_NONE, parse_tkl("TKL $1"));
750 }
751}
752
753sub SNOTICE($) {
754 $_[0] =~ /^(@|:)(\S+) (SENDSNO|Ss|SMO|AU) ([A-Za-z]) :(.*)$/;
755 #@servernumeric Ss snomask :message
756 my $name;
757 if ($1 eq '@') {
758 $name = $servernum[b64toi($2)];
759 }
760 else {
761 $name = $2;
762 }
763 my $event;
764 $event = 'SENDSNO' if(($3 eq 'SENDSNO' or $3 eq 'Ss'));
765 $event = 'SMO' if(($3 eq 'SMO' or $3 eq 'AU'));
766 return ($event, 0, undef, WF_NONE, $name, $4, $5);
767}
768
769sub GLOBOPS($) {
770 $_[0] =~ /^(@|:)(\S+) (?:GLOBOPS|\]) :(.*)$/;
771 #@servernumeric [ :message
772 my $name;
773 if ($1 eq '@') {
774 $name = $servernum[b64toi($2)];
775 }
776 else {
777 $name = $2;
778 }
779 return ('GLOBOPS', 0, undef, WF_NONE, $name, $3);
780}
781
782sub ISUPPORT($) {
783 $_[0] =~ /^:(\S+) (?:105|005) (\S+) (.+) :are supported by this server$/;
784 # :test-tab.surrealchat.net 105 services.SC.net CMDS=KNOCK,MAP,DCCALLOW,USERIP :are supported by this server
785 foreach my $token (split(/\s+/, $3)) {
786 my ($key, $value) = split('=', $token);
787 $IRCd_capabilities{$key} = ($value ? $value : 1);
788 }
789}
790
026939ee 791sub CAPAB {
792#CAPAB MODULES :m_botmode.so,m_chanprotect.so,m_chghost.so,m_chgident.so,m_cloaking.so,m_deaf.so,m_delayjoin.so,m_delaymsg.so,m_gecosban.so,m_globops.so,m_helpop.so,m_messageflood.so,m_muteban.so,m_nokicks.so,m_nonicks.so,m_nonotice.so,m_nopartmsg.so,m_ojoin.so,m_operchans.so,m_operinvex.so,m_permchannels.so,m_redirect.so,m_regex_glob.so,m_remove.so,m_sajoin.so,m_sakick.so,m_sanick.so,m_sapart.so,m_saquit.so,m_serverban.so,m_services_account.so,m_servprotect.so,m_setident.so,m_showwhois.so,m_shun.so
793#CAPAB MODULES :m_silence.so,m_watch.so
794#CAPAB MODSUPPORT :m_chghost.so,m_chgident.so,m_gecosban.so,m_muteban.so,m_nopartmsg.so,m_remove.so,m_sajoin.so,m_sakick.so,m_sanick.so,m_sapart.so,m_saquit.so,m_serverban.so,m_services_account.so,m_showwhois.so,m_silence.so,m_watch.so
795#CAPAB CHANMODES :admin=&a ban=b c_registered=r delayjoin=D delaymsg=d flood=f founder=~q halfop=%h inviteonly=i key=k limit=l moderated=m noextmsg=n nokick=Q nonick=N nonotice=T official-join=!Y op=@o operonly=O permanent=P private=p redirect=L reginvite=R regmoderated=M secret=s topiclock=t voice=+v
796#6 CAPAB USERMODES :bot=B cloak=x deaf=d helpop=h invisible=i oper=o regdeaf=R servprotect=k showwhois=W snomask=s u_registered=r wallops=w
797#CAPAB CAPABILITIES :NICKMAX=32 CHANMAX=65 MAXMODES=20 IDENTMAX=12 MAXQUIT=256 MAXTOPIC=308 MAXKICK=256 MAXGECOS=129 MAXAWAY=201 IP6SUPPORT=1 PROTOCOL=1202 HALFOP=1 PREFIX=(Yqaohv)!~&@%+ CHANMODES=b,k,Ldfl,DMNOPQRTimnprst USERMODES=,,s,BRWdhikorwx SVSPART=1
798#---
799#What we care about: CHANMODES :admin=&a founder=~q Determines if we can set +a and +q on people, halfop %h: likewise... cloak=x determines if we can have cloaks or vhosts. in the modules we care about chghost, chgident, cloaking for vhosts, m_silence and m_watch for silence and watch respectively. Also c_registered, we can _NOT_ continue w/o it.
800#I HAVE NO IDEA where to get the watch/silence list limit!!!
801#let's do this the lame way!
a1a0e944 802 #FIXME this is so ugly
026939ee 803 my $capab = $_[0];
804 print "CAPAB $_[0]\n";
805 $capab =~ /CAPAB (\S+)/;
806 my $type = $1;
807 if ($type eq "END" && $IRCd_capabilities {"REG"} eq "") {
808 ircd::debug ("WARNING: SurrealServices requires m_services_account.so to be loaded in Inspircd.");
809 ircd::debug ("m_services_account.so not loaded! Shutting down NOW!");
810 print "m_services_account.so not loaded! Shutting down NOW!\n";
811 main_shutdown;
812 }
813 if ($capab =~ /m_chghost/ && $type eq "MODSUPPORT") {
814 $IRCd_capabilities{"CHGHOST"} = 1;
815 }
816 if ($capab =~ /m_chgident/ && $type eq "MODSUPPORT") {
817 $IRCd_capabilities{"CHGIDENT"} = 1;
818 }
819 if ($capab =~ /m_cloaking/ ) {
820 $IRCd_capabilities{"CLOAKHOST"} = 1;
821 }
822 if ($capab =~ /cloak=(\S)/ ) {
823 $IRCd_capabilities{"CLOAK"} = $1;
824 }
825 if ($capab =~ /admin=(\S)(\S)/) {
826 $IRCd_capabilities{"ADMIN"} = $2;
827 }
828 if ($capab =~ /founder=(\S)(\S)/) {
829 $IRCd_capabilities{"FOUNDER"} = $2;
830 }
1eb006d9 831 if ($capab =~ /halfop=(\S)(\S)/) {
832 $IRCd_capabilities{"HALFOP"} = $2;
833 }
026939ee 834 if ($capab =~ /silence/) {
835 $IRCd_capabilities{"SILENCE"} = 32; #unless we can make it TELL US
836 }
837 if ($capab =~ /watch/) {
838 $IRCd_capabilities{"WATCH"} = 32; #unless we can make it TELL US
839 }
840 if ($capab =~ /registered/) {
841 $IRCd_capabilities{"REG"} = 1;
842 }
a1a0e944 843 $IRCd_capabilities {"INSP"} = 1; #this is _horrible_
026939ee 844
845}
5e682044 846sub STATS($) {
847 $_[0] =~ /^:(\S+) (?:STATS|2) (\S) :(.+)$/;
848 return ('STATS', undef, undef, WF_NONE, $1, $2, $3)
849}
850
851BEGIN {
852 %cmdhash = (
853 PING => \&PING,
854 '8' => \&PING,
855
856 EOS => \&EOS,
857 ES => \&EOS,
858 ENDBURST => \&EOS,
859 SERVER => \&SERVER,
860 "\'" => \&SERVER,
861
862 SQUIT => \&SQUIT,
863 '-' => \&SQUIT,
864
865 NETINFO => \&NETINFO,
866 AO => \&NETINFO,
867
868 PROTOCTL => \&PROTOCTL,
869
870 JOIN => \&JOIN,
871 C => \&JOIN,
872
873 PART => \&PART,
874 D => \&PART,
875
876 SJOIN => \&SJOIN,
877 '~' => \&SJOIN,
878 FJOIN => \&FJOIN,
879 FMODE => \&FMODE,
880 MODE => \&MODE,
881 G => \&MODE,
882
883 PRIVMSG => \&MESSAGE,
884 '!' => \&MESSAGE,
885 NOTICE => \&MESSAGE,
886 B => \&MESSAGE,
887
888 AWAY => \&AWAY,
889 '6' => \&AWAY,
890
891 NICK => \&NICK,
892 '&' => \&NICK,
893
894 QUIT => \&QUIT,
895 ',' => \&QUIT,
896
897 KILL => \&KILL,
898 '.' => \&KILL,
899
900 KICK => \&KICK,
901 H => \&KICK,
902
903 CHGHOST => \&HOST,
904 AL => \&HOST,
905 SETHOST => \&HOST,
906 AA => \&HOST,
907 '302' => \&HOST,
908
909 '340' => \&USERIP,
910
911 CHGIDENT => \&IDENT,
912 AZ => \&IDENT,
913 SETIDENT => \&IDENT,
914 AD => \&IDENT,
915
916 TOPIC => \&TOPIC,
917 ')' => \&TOPIC,
918
919 UMODE2 => \&UMODE,
920 '|' => \&UMODE,
921
922 TSCTL => \&TSCTL,
923 AW => \&TSCTL,
924
925 VERSION => \&VERSION,
926 '+' => \&VERSION,
927
928 TKL => \&TKL,
929 BD => \&TKL,
930
931 WHOIS => \&WHOIS,
932 '#' => \&WHOIS,
933
934 SENDSNO => \&SNOTICE,
935 Ss => \&SNOTICE,
936
937 SMO => \&SNOTICE,
938 AU => \&SNOTICE,
939
940 GLOBOPS => \&GLOBOPS,
941 ']' => \&GLOBOPS,
942
943 '105' => \&ISUPPORT,
944 '005' => \&ISUPPORT,
945
946 SVSMODE => \&SVSMODE,
947 'n' => \&SVSMODE,
948 SVS2MODE => \&SVSMODE,
949 'v' => \&SVSMODE,
950
951 STATS => \&STATS,
952 '2' => \&STATS,
953 UID => \&UID,
954 OPERTYPE => \&OPERTYPE,
026939ee 955 OPERQUIT => \&OPERQUIT, #Opers are so special, they get their own QUIT. SOme of the time.
956 CAPAB => \&CAPAB,
7b3a5814 957 FMODE => \&FMODE
5e682044 958 );
959}
960
9611;