1 # This file is part of SurrealServices.
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.
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.
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
17 package SrSv
::IRCd
::Parse
;
21 use Exporter
'import';
22 # parse_sjoin shouldn't get used anywhere else, as we never produce SJOINs
23 # parse_tkl however is used for loopbacks.
24 BEGIN { our @EXPORT_OK = qw(parse_line parse_tkl parse_addline) }
27 BEGIN { *SJB64
= \
&ircd
::SJB64
; *CLK
= \
&ircd
::CLK
; *NICKIP
= \
&ircd
::NICKIP
; }
29 use SrSv
::Conf
'main';
32 use SrSv
::IRCd
::State
qw($ircline $remoteserv create_server get_server_children set_server_state get_server_state %IRCd_capabilities);
33 use SrSv
::IRCd
::Queue
qw(queue_size);
34 use SrSv
::IRCd
::IO
qw( ircsend ircsendimm);
35 use SrSv
::IRCd
::Send qw
(getRevUuid getUuid setRevUuid setUuid
);
36 use SrSv
::Unreal
::Modes
qw(%opmodes);
37 use SrSv
::RunLevel
'main_shutdown';
38 # Unreal uses its own modified base64 for everything except NICKIP
39 use SrSv
::Unreal
::Base64
qw(b64toi itob64);
41 # Unreal uses unmodified base64 for NICKIP.
42 # Consider private implementation,
43 # tho MIME's is probably faster
56 use SrSv
::Shared
qw(@servernum);
67 if($in =~ /^(?:@|:)(\S+) (\S+)/) {
70 elsif ($in =~ /^(\S+)/) {
73 my $sub = $cmdhash{$cmd};
74 unless (defined($sub)) {
75 print "Bailing out from $ircline:$cmd for lack of cmdhash\n" if DEBUG
();
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
;
83 #return unless defined $event;
85 my (@recipients, @out);
87 #$args[$dst] = lc $args[$dst];
88 @recipients = split(/\,/, $args[$dst]);
90 #if(defined($src)) { $args[$src] = lc $args[$src]; }
93 foreach my $rcpt (@recipients) {
95 push @out, [$event, $src, $dst, $wf, [@args]];
98 @out = [$event, $src, $dst, $wf, [@args]];
103 #parse_fjoin($server, $channel, $ts, $modes, @nicks, @status)
104 sub parse_fjoin
($$$$$$) {
105 my ($server, $channel, $ts, $modes, $idsr, $statusref) = @_;
106 print "parse_fjoin($server,$channel,$ts,$modes,$idsr,$statusref)";
107 my @status = @$statusref;
111 foreach my $id (@ids) {
113 my @ops = split ("",$status[$i]);
114 foreach my $prefix (@ops) {
115 $op |= $opmodes{$prefix};
117 my $user = {ID
=> $id, __OP
=>$op}; #ID'S are _already_ decoded in FJOIN!
118 get_user_nick
($user);
122 return ($server, $channel, $ts, $modes, undef, \
@users, undef, undef, undef); #bans etc are got from FMODE..
124 sub parse_sjoin
($$$$) {
125 my ($server, $ts, $cn, $parms) = @_;
126 my (@users, @bans, @excepts, @invex, @blobs, $blobs, $chmodes, $chmodeparms);
128 $server = '' unless $server;
130 if($parms =~ /^:(.*)/) {
133 ($chmodes, $blobs) = split(/ :/, $parms, 2);
134 ($chmodes, $chmodeparms) = split(/ /, $chmodes, 2);
136 @blobs = split(/ /, $blobs);
138 foreach my $x (@blobs) {
139 if($x =~ /^(\&|\"|\')(.*)$/) {
141 push @bans, $2 if $1 eq '&';
142 push @excepts, $2 if $1 eq '"';
143 push @invex, $2 if $1 eq "\'";
145 $x =~ /^([*~@%+]*)(.*)$/;
146 my ($prefixes, $nick) = ($1, $2);
147 my @prefixes = split(//, $prefixes);
149 foreach my $prefix (@prefixes) {
150 $op |= $opmodes{q
} if ($prefix eq '*');
151 $op |= $opmodes{a
} if ($prefix eq '~');
152 $op |= $opmodes{o
} if ($prefix eq '@');
153 $op |= $opmodes{h
} if ($prefix eq '%');
154 $op |= $opmodes{v
} if ($prefix eq '+');
157 push @users, { NICK
=> $nick, __OP
=> $op };
161 return ($server, $cn, $ts, $chmodes, $chmodeparms, \
@users, \
@bans, \
@excepts, \
@invex);
163 sub parse_addline
($) {
165 #return ($type, +1, $ident, $host, $setter, $expire, $time, $reason);
166 #>> 47 :583AAAAAA ADDLINE G test@testie inspircd.erry.omg 1308118489 0 :hi
167 my ($setter, undef, $type, $mask, $server, $time, $expiry, $reason) = split (/ /, $line, 7);
172 my @masks = split (/@/,$mask, 1);
173 my $ident = $masks[0];
174 my $host = $masks[1];
175 #return ($type, +1, $ident, $host, $setter, $expire, $time, $reason);
176 return ($type, +1, $ident, $host, $setter, $expiry, $time, $reason);
180 # This function is intended to accept ALL tkl types,
181 # tho maybe not parse all of them in the first version.
183 # Discard first token, 'TKL'
184 my (undef, $sign, $type, $params) = split(/ /, $in, 4);
186 # Yes, TKL types are case sensitive!
187 # also be aware (and this applies to the net.pm generator functions too)
188 # This implementation may appear naiive, but Unreal assumes that, for a given
189 # TKL type, that all parameters are non-null.
190 # Thus, if any parameters ARE null, Unreal WILL segfault.
191 ## Update: this problem may have been fixed since Unreal 3.2.2 or so.
192 if ($type eq 'G' or $type eq 'Z' or $type eq 's' or $type eq 'Q') {
194 # TKL + type ident host setter expiretime settime :reason
195 # TKL - type ident host setter
196 # for Q, ident is always '*' or 'h' (Services HOLDs)
198 my ($ident, $host, $setter, $expire, $time, $reason) = split(/ /, $params, 6);
201 return ($type, +1, $ident, $host, $setter, $expire, $time, $reason);
203 elsif($sign eq '-') {
204 my ($ident, $host, $setter) = split(/ /, $params, 3);
205 return ($type, -1, $ident, $host, $setter);
208 elsif($type eq 'F') {
209 # TKL + F cpnNPq b saturn!attitude@netadmin.SCnet.ops 0 1099959668 86400 Possible_mIRC_DNS_exploit :\/dns (\d+\.){3}\d
210 # TKL + F u g saturn!attitude@saturn.netadmin.SCnet.ops 0 1102273855 604800 sploogatheunbreakable:_Excessively_offensive_behavior,_ban_evasion. :.*!imleetnig@.*\.dsl\.mindspring\.com
211 # TKL - F u Z tabris!northman@tabris.netadmin.SCnet.ops 0 0 :do_not!use@mask
213 my ($target, $action, $setter, $expire, $time, $bantime, $reason, $mask) = split(/ /, $params, 8);
215 return ($type, +1, $target, $action, $setter, $expire, $time, $bantime, $reason, $mask);
217 elsif($sign eq '-') {
218 my ($target, $action, $setter, $expire, $time, $mask) = split(/ /, $params, 6);
220 return ($type, -1, $target, $action, $setter, $mask);
226 my ($event, $src, $dst, @args);
227 $_[0] =~ /^(?:8|PING) :(\S+)$/;
228 # ($event, $src, $dst, $args)
229 return ('PING', undef, undef, WF_NONE
, $1);
232 if ($_[0] =~ /^(:\S+) UID (\S+) (\d+) (\S+) (\S+) (\S+) (\S+) (\S+) (\d+) (\S+) :(.*)$/) {
233 #:583 UID 583AAAAAJ 1307703236 erry__ localhost localhost errietta 127.0.0.1 1307703241 + :errietta
234 my ($server, $uid, $stamp, $nick, $host, $vhost, $ident, $IP, $ts, $modes, $gecos) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
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))));
239 elsif ($_[0] =~ /^(:\S+) UID (\S+) (\d+) (\S+) (\S+) (\S+) (\S+) (\S+) (\d+) (\S+) (\S+) :(.*)$/) {
240 #:965 UID 965AAAAAG 1311863295 erry arceus.pokemonlake.com IceFyre/NetAdmin/erry ~erry 216.14.116.138 1311863255 +IWhiosw +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz :erry
241 my ($server, $uid, $stamp, $nick, $host, $vhost, $ident, $IP, $ts, $modes, $snomasks, $gecos) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
242 $modes .= " " . $snomasks;
243 my $user = { NICK
=> $nick, ID
=> decodeUUID
($uid) };
244 return ('NICKCONN', undef, undef, WF_NICK
, $user, 0, $ts, $ident, $host, $server, $stamp, $modes, $vhost, $gecos,
245 join('.', unpack('C4', MIME
::Base64
::decode
($IP))));
250 if ($_[1] != "ENDBURST") {
251 $_[0] =~ /^(@|:)(\S+) (?:EOS|ES)/; # Sometimes there's extra crap on the end?
254 $server = $servernum[b64toi
($2)];
259 print "SERVER $server\n";
260 set_server_state
($server, 1);
261 return undef() unless get_server_state
($remoteserv);
262 if($server eq $remoteserv) { $event = 'SEOS' } else { $event = 'EOS' }
263 print "Ok. we had EOS\n";
264 return ($event, undef, undef, WF_ALL
, $server);
267 $_[0] =~ /^:(\S+) ENDBURST/;
269 set_server_state
($server, 1);
270 print "server $server remote $remoteserv\n";
271 return undef() unless get_server_state
($remoteserv);
272 print "This be it! Got endbrust!\n";
273 return ("ENDBURST", undef, undef, WF_ALL
, $1);
278 #ircd::debug($_[0]) if $debug;
280 if($_[0] =~ /^(?:SERVER|\') (\S+) (\S+) :(U[0-9]+)-([A-Za-z0-9]+)-([0-9]+) (.*)$/) {
281 # SERVER test-tab.surrealchat.net 1 :U2307-FhinXeOoZEmM-200 SurrealChat
282 # cmd, servername, hopCount, U<protocol>-<buildflags>-<numeric> infoLine
287 return ('SERVER', undef, undef, WF_ALL
, undef, $1, $2, $6, $5, $3, $4);
288 # src, serverName, numHops, infoLine, serverNumeric, protocolVersion, buildFlags
290 elsif($_[0] =~ /^(:|@)(\S+) (?:SERVER|\') (\S+) (\d+) (\d+) :(.*)$/) {
291 # @38 SERVER test-hermes.surrealchat.net 2 100 :SurrealChat
292 # source, cmd, new server, hopCount, serverNumeric, infoLine
293 my ($numeric, $name);
295 $name = $servernum[b64toi
($2)];
300 create_server
($3, $name);
303 return ('SERVER', undef, undef, WF_ALL
, $name, $3, $4, $6, $5);
304 # src, serverName, numHops, infoLine, serverNumeric
306 if($_[0] =~ /^(?:SERVER|\') (\S+) (\S+) :(.*)$/) {
309 return ('SERVER', undef, undef, WF_ALL
, undef, $1, $2, $3);
310 # src, serverName, numHops, infoLine
312 elsif($_[0] =~ /^:(\S+) (?:SERVER|\') (\S+) (\d+) :(.*)$/) {
313 # source, new server, hop count, description
314 create_server
($2, $1);
315 return ('SERVER', undef, undef, WF_ALL
, $1, $2, $3, $4);
316 # src, serverName, numHops, infoLine
318 elsif ($_[0] =~ /^:(\S+) SERVER (\S+) (\S+) (\d+) (\S+) :(.*)$/) {
319 #:irc.icefyre.org SERVER Services.IceFyre.Org * 1 00B :IceFyre IRC Services
320 my $id = $servIds{$1};
321 create_server
($5, $id);
322 return ('SERVER', undef, undef, WF_ALL
, $1, $5, $4, $6);
324 elsif ($_[0] =~ /^SERVER (\S+) (\S+) (\d+) (\S+) :(.*)$/) {
325 print "RIGHT ONE WHOO\n";
326 #SERVER irc.icefyre.org mypass 0 965 :IceFyre IRC Hub
328 #SERVER servername password hopcount SID :Server Desc
331 #since from now on we'll be getting commands as sent from the SID it's much wiser to keep that than the name.
333 return ("SERVER", undef, undef, WF_ALL
, undef, $1, $3, $5, $4);
338 if($_[0] =~ /^(?:SQUIT|-) (\S+) :(.*)$/) {
339 my $list = [get_server_children
($1)];
340 set_server_state
($1, undef());
341 return ('SQUIT', undef, undef, WF_ALL
, undef, $list, $2);
343 elsif($_[0] =~ /^(:|@)(\S+) (?:SQUIT|-) (\S+) :(.*)$/) {
346 $name = $servernum[b64toi
($2)];
351 my $list = [get_server_children
($3)];
352 set_server_state
($3, undef());
353 return ('SQUIT', undef, undef, WF_ALL
, $name, $list, $4);
358 $_[0] =~ /^(?:NETINFO|AO) (\S+) (\S+) (\S+) (\S+) (\S+) (\S+) (\S+) :(.*)$/;
359 return ('NETINFO', undef, undef, WF_NONE
, $1, $2, $3, $4, $5, $6, $7, $8);
363 $_[0] =~ /^PROTOCTL (.*)$/;
364 return ('PROTOCTL', undef, undef, WF_NONE
, $1);
368 $_[0] =~ /^:(\S+) (?:C|JOIN) (\S+)$/;
369 my $user = { ID
=> decodeUUID
($1) };
370 get_user_nick
($user);
371 return ('JOIN', undef, 1, WF_CHAN
, $user, $2);
376 #>> 114 :965 FJOIN #erry 1305486096 +nt :o,00BAAAAAX qo,965AAAAAC
377 if ($_[0] =~ m
"^:(\S+) FJOIN (\S+) (\d+) (\S+) :(.*)$") {
378 my ($server, $channel, $ts, $modes, $userstring) = ($1, $2, $3, $4, $5);
379 print "userstring $userstring";
380 my @users = split (" ", $userstring);
382 foreach my $user (@users) {
383 my @params = split (",",$user);
384 push (@status, $params[0]);
385 push (@ids, decodeUUID
($params[1]));
387 return ('SJOIN', undef, undef, WF_CHAN
, parse_fjoin
($server, $channel, $ts, $modes, \
@ids, \
@status));
389 #>> :965 FJOIN #ERRY1 1312013713 +nrst ,965AAAAAB qo,965AAAAAC
390 elsif ($_[0] =~ m
"^:(\S+) FJOIN (\S+) (\d+) (\S+) (.*)$") {
391 my ($server, $channel, $ts, $modes, $userstring) = ($1, $2, $3, $4, $5);
392 my @users = split (" ", $userstring);
394 foreach my $user (@users) {
395 my @params = split (",",$user);
396 push (@status, $params[0]);
397 push (@ids, decodeUUID
($params[1]));
399 return ('SJOIN', undef, undef, WF_CHAN
, parse_fjoin
($server, $channel,$ts, $modes, \
@ids, \
@status));
401 #>> 15 :583 FJOIN #opers 1310128904 +Pis :
402 #CHANNELS CONFIGURED TO STAY OPEN WITH CHMODE +P (INSP)
403 elsif ($_[0] =~ m
"^:(\S+) FJOIN (\S+) (\d+) (\S+) :$") {
404 #FIXME - Update channel modes.
408 if ($_[0] =~ /^(?:\~|SJOIN) (\S+) (\S+) (.*)$/) {
409 my ($ts, $cn, $payload) = ($1, $2, $3);
413 return ('SJOIN', undef, undef, WF_CHAN
, parse_sjoin
($remoteserv, $ts, $cn, $payload));
415 elsif($_[0] =~ /^(@|:)(\S+) (?:\~|SJOIN) (\S+) (\S+) (.*)$/) {
416 my ($server, $ts, $cn, $payload) = ($2, $3, $4, $5);
418 $server = $servernum[b64toi
($2)];
426 return ('SJOIN', undef, undef, WF_CHAN
, parse_sjoin
($server, $ts, $cn, $payload));
433 if($_[0] =~ /^:(\S+) (?:D|PART) (\S+) :(.*)$/) {
434 $user = {ID
=> decodeUUID
($1)};
435 get_user_nick
($user);
436 return ('PART', undef, 0, WF_CHAN
, $user, $2, $3);
438 elsif($_[0] =~ /^:(\S+) (?:D|PART) (\S+)$/) {
439 $user = {ID
=> decodeUUID
($1)};
440 get_user_nick
($user);
441 return ('PART', undef, 0, WF_CHAN
, $user, $2, undef);
445 #:583AAAAAR FMODE #erry 1308214721 +ib test!*@* When any mode in the channel is set.
446 #: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.
447 if($_[0] =~ /^:(\S+) FMODE (#\S+) (\d+) (\S+) ?(.*)$/) {
453 if (length($id) > 3) { #UID
454 $user = {ID
=> decodeUUID
($id)};
455 get_user_nick
($user);
462 my @args = split(/ /, $argz);
464 my @modes = split(//, $modes);
466 foreach my $mode (@modes) {
467 if($mode eq '+' or $mode eq '-') { next; }
468 if ($mode !~ /^[vhoaq]$/) { next; }
469 my $arg = shift (@args);
471 if ($arg =~ /^:(\S+)$/) {
474 my $id = decodeUUID
($arg);
475 my $tuser = {ID
=>$id};
476 get_user_nick
($tuser);
477 push @userargs, $tuser;
479 return ('MODE', undef, 1, WF_ALL
, $user, $chan, $m, $a,
482 elsif($_[0] =~ /^:(\S+) FMODE (#\S+) (\d+) (\S+) :(.*)$/) {
485 if (length($id) > 3) { #UID
486 $user = {ID
=> decodeUUID
($id)};
487 get_user_nick
($user);
494 my @args = split(/ /, $argz);
496 my @modes = split(//, $modes);
498 foreach my $mode (@modes) {
499 if($mode eq '+' or $mode eq '-') { next; }
500 if ($mode !~ /^[vhoaq]$/) { next; }
501 my $arg = shift (@args);
503 my $id = decodeUUID
($arg);
504 my $tuser = {ID
=>$id};
505 get_user_nick
($tuser);
506 push @userargs, $tuser;
508 return ('MODE', undef, 1, WF_ALL
, $user, $2, $4, $5,
514 if($_[0] =~ /^(@|:)(\S+) (?:G|MODE) (#\S+) (.*)(?: \d+)?$/) {
517 $name = $servernum[b64toi
($2)];
518 $user = {NICK
=> $name};
522 $user = { ID
=>decodeUUID
($name)};
523 get_user_nick
($user);
526 my @args = split(/ /, $argz);
528 my @modes = split(//, $modes);
530 foreach my $mode (@modes) {
531 if($mode eq '+' or $mode eq '-') { next; }
532 my $arg = shift (@args);
534 my $id = encodeUUID
($arg);
535 my $tuser = {ID
=>$id};
536 my $nick = get_user_nick
($tuser);
537 $newargs .= ($newargs eq ""?$nick:" $nick"); # what an awful way to do it.
540 if ($newargs eq "") {
544 $arguements = $newargs;
546 return ('MODE', undef, 1, WF_ALL
, $user, $3, $4, $arguements);
548 elsif($_[0] =~ /^:(\S+) (?:G|MODE) (\S+) :(\S+)$/) {
549 # We shouldn't ever get this, as UMODE2 is preferred
550 $user = { ID
=> decodeUUID
($1) };
551 get_user_nick
($user);
552 return ('UMODE', 0, 0, WF_ALL
, $user, $3);
560 if($_[0] =~ /^(@|:)(\S+) (?:\!|PRIVMSG) (\S+) :(.*)$/) {
562 my ($name, $srcUser, $dstUser) ;
564 $name = $servernum[b64toi
($2)];
565 $srcUser = {NICK
=>$name};
569 $srcUser = {ID
=>decodeUUID
($name)};
570 unless (get_user_nick
($srcUser)) {
571 $srcUser = {NICK
=>$name};
576 $dstUser = {ID
=>($dest)};
577 unless (get_user_nick
($dstUser)) {
578 $dstUser = {NICK
=>$dest};
580 $event = 'PRIVMSG'; @args = ($srcUser, $dstUser, $4);
582 elsif($_[0] =~ /^(@|:)(\S+) (?:B|NOTICE) (\S+) :(.*)$/) {
585 $name = $servernum[b64toi
($2)];
590 $event = 'NOTICE'; @args = ($name, $3, $4);
592 $args[1] =~ s/\@${main_conf{local}}.*//io;
594 if(queue_size
> 50 and $event eq 'PRIVMSG' and $args[1] !~ /^#/ and $args[2] =~ /^\w/) {
595 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...");
598 return ($event, 0, 1, WF_ALL
, @args);
602 if($_[0] =~ /^:(\S+) (?:6|AWAY) :(.*)$/) {
603 my $user = {ID
=>decodeUUID
($1)};
604 get_user_nick
($user);
605 return ('AWAY', undef, undef, WF_ALL
, $user, $2);
607 elsif($_[0] =~ /^:(\S+) (?:6|AWAY)$/) {
608 my $user = {ID
=> decodeUUID
($1)};
609 get_user_nick
($user);
610 return ('BACK', undef, undef, WF_ALL
, $user);
616 #:97KAAAAAA NICK erry_ 1307878528
617 if($_[0] =~ /^:(\S+) (?:NICK|\&) (\S+) :?(\S+)$/) {
618 my $user = {ID
=> decodeUUID
($1)};
619 get_user_nick
($user);
620 set_user_nick
(decodeUUID
($1), $2);
621 set_user_id
($2, decodeUUID
($1));
622 return ('NICKCHANGE', undef, undef, WF_NICK
, $user, $2, $3);
627 if ($_[0] =~ /^:(\S+) QUIT :Killed \((\S+) \((.*)\)\)$/) {
628 #:583AAAAAH QUIT :Killed (erry (die))
629 # my $victim = {ID=>decodeUUID($1)};
630 # get_user_nick ($victim);
631 # my $murderer = {NICK=>$2};
632 # get_user_id ($murderer);
634 # return ('KILL', 0, 1, WF_NICK, $murderer, $victim, $reason, undef);
636 elsif ($_[0] =~ /^:(\S+) QUIT :(.*)$/) {
637 my $user = {ID
=>decodeUUID
($1)};
638 get_user_nick
($user);
639 return ('QUIT', 0, undef, WF_NICK
, $user, $2);
643 if ($_[0] =~ /^:(\S+) QUIT :(.*)$/) {
644 my $user = {ID
=>decodeUUID
($1)};
645 get_user_nick
($user);
646 return ('QUIT', 0, undef, WF_NICK
, $user, $2);
651 #:583AAAAAA KILL 123AAAAAA :Killed (erry (die))
652 #:123AAAAAA OPERQUIT :Killed (erry (die))
653 $_[0] =~ /^:(\S+) KILL (\S+) :(.*)$/;
654 my $murderer = {ID
=>decodeUUID
($1)};
655 get_user_nick
($murderer);
656 my $victim = {ID
=>decodeUUID
($2)};
657 get_user_nick
($victim);
658 return ("KILL", 0, 1, WF_NICK
, $murderer, $victim, $3, undef);
661 #:tabris KICK #diagnostics SurrealBot :i know you don't like this. but it's for science!
662 $_[0] =~ /^(@|:)(\S+) (?:KICK|H) (\S+) (\S+) :(.*)$/;
663 # source, chan, target, reason
664 #$src = 0; #$dst = 2;
667 $name = $servernum[b64toi
($2)];
672 my $user = {ID
=> decodeUUID
($name)};
673 unless (get_user_nick
($user)) {
674 $user = {NICK
=> $name};
677 return ('KICK', 0, undef, WF_CHAN
, $user, $3, $4, $5);
681 if($_[0] =~ /^:(\S+) (?:CHGHOST|AL) (\S+) (\S+)$/) {
682 #:Agent CHGHOST tabris tabris.netadmin.SCnet.ops
683 return ('CHGHOST', 0, 1, WF_CHAN
, $1, $2, $3);
684 #setter, target, vhost
686 elsif($_[0] =~ /^:(\S+) (?:SETHOST|AA) (\S+)$/) {
687 #:tabris SETHOST tabris.netadmin.SCnet.ops
688 return ('CHGHOST', 0, 1, WF_CHAN
, $1, $1, $2);
691 elsif ($_[0] =~ /^:(?:\S* )?302 (\S+) :(\S+?)\*?=[+-].*?\@(.*)/) {
692 #:serebii.razorville.co.uk 302 leif :Jesture=+~Jesture00@buzz-3F604D09.sympatico.ca
693 return ('CHGHOST', 0, 1, WF_CHAN
, $1, $2, $3);
699 $_[0] =~ /^:(?:\S* )?340 (\S+) :(\S+?)\*?=[+-].*?\@((?:\.|\d)*)/;
700 return ('USERIP', 0, 1, WF_CHAN
, $1, $2, $3);
704 if($_[0] =~ /^:(\S+) (?:CHGIDENT|AL) (\S+) (\S+)$/) {
705 return ('CHGIDENT', 0, 1, WF_ALL
, $1, $2, $3);
706 #setter, target, IDENT
708 elsif($_[0] =~ /^:(\S+) (?:SETIDENT|AD) (\S+)$/) {
709 return ('CHGIDENT', 0, 1, WF_ALL
, $1, $1, $2);
710 #setter, target, ident
716 if ($_[0] =~ /^:(\S+) TOPIC (\S+) :(.*)$/) {
717 #:583AAAAAF TOPIC #erry :Welcome to erry(world|net). Have a cookie.
718 my $setter = { ID
=> decodeUUID
($1) };
719 get_user_nick
($setter);
720 return ('TOPIC', 0, 1, WF_ALL
, $setter, $2, $setter, 0, $3);
726 $_[0] =~ /^:(\S+) (?:UMODE2|\|) (\S+)$/;
728 # a note, not all umodes are passed
729 # +s, +O, and +t are not passed. possibly others
730 # also not all umodes do we care about.
731 # umodes we need care about:
732 # oper modes: hoaACN,O oper-only modes: HSq
733 # regular modes: rxB,izV (V is only somewhat, as the ircd
734 # does the conversions from NOTICE to PRIVSMG for us).
736 # Yes, I'm changing the event type on this
737 # It's better called UMODE, and easily emulated
738 # on IRCds with only MODE.
739 return ('UMODE', 0, 0, WF_ALL
, $1, $2);
742 #:583AAAAAB OPERTYPE SuperNetAdmin
743 #Every OPERTYPE will get +o, so it's safe to assume they're opers,
744 #even if we don't give them privs (either in inspircd or srsv)
745 $_[0] =~ /^:(\S+) OPERTYPE (\S+)$/;
746 my $user = { ID
=> decodeUUID
($1) };
747 get_user_nick
($user);
748 return ("OPERUP", 0, 0, WF_ALL
, $user);
752 $_[0] =~ /^:(\S+) (?:SVS2?MODE|n|v) (\S+) (\S+)$/;
754 # a note, not all umodes are passed
755 # +s, +O, and +t are not passed. possibly others
756 # also not all umodes do we care about.
757 # umodes we need care about:
758 # oper modes: hoaACN,O oper-only modes: HSq
759 # regular modes: rxB,izV (V is only somewhat, as the ircd
760 # does the conversions from NOTICE to PRIVSMG for us).
762 return ('UMODE', 0, 0, WF_ALL
, $2, $3);
766 # :tab WHOIS ConnectServ :ConnectServ
767 if($_[0] =~ /^:(\S+) (?:WHOIS|\#) (\S+)$/) {
768 return ('WHOIS', 0, undef, WF_NONE
, $1, $2);
770 elsif($_[0] =~ /^:(\S+) (?:WHOIS|\#) (\S+) :(\S+)$/) {
771 return ('WHOIS', 0, undef, WF_NONE
, $1, $3);
776 $_[0] =~ /^:(\S+) (?:TSCTL|AW) alltime$/;
777 ircsend
(":$main_conf{local} NOTICE $1 *** Server=$main_conf{local} TSTime=".
778 time." time()=".time." TSOffset=0");
783 $_[0] =~ /^:(\S+) (?:VERSION|\+).*$/;
784 return ('VERSION', 0, undef, WF_NONE
, $1);
788 if ($_[0] =~ /^(@|:)(\S+) (?:TKL|BD) (.*)$/) {
789 # We discard the source anyway.
792 # $server = $servernum[b64toi($2)];
797 return ('TKL', undef, undef, WF_NONE
, parse_tkl
("TKL $3"));
799 elsif ($_[0] =~ /^(?:TKL|BD) (.*)$/) {
800 return ('TKL', undef, undef, WF_NONE
, parse_tkl
("TKL $1"));
805 $_[0] =~ /^(@|:)(\S+) (SENDSNO|Ss|SMO|AU) ([A-Za-z]) :(.*)$/;
806 #@servernumeric Ss snomask :message
809 $name = $servernum[b64toi
($2)];
815 $event = 'SENDSNO' if(($3 eq 'SENDSNO' or $3 eq 'Ss'));
816 $event = 'SMO' if(($3 eq 'SMO' or $3 eq 'AU'));
817 return ($event, 0, undef, WF_NONE
, $name, $4, $5);
821 $_[0] =~ /^(@|:)(\S+) (?:GLOBOPS|\]) :(.*)$/;
822 #@servernumeric [ :message
825 $name = $servernum[b64toi
($2)];
830 return ('GLOBOPS', 0, undef, WF_NONE
, $name, $3);
834 $_[0] =~ /^:(\S+) (?:105|005) (\S+) (.+) :are supported by this server$/;
835 # :test-tab.surrealchat.net 105 services.SC.net CMDS=KNOCK,MAP,DCCALLOW,USERIP :are supported by this server
836 foreach my $token (split(/\s+/, $3)) {
837 my ($key, $value) = split('=', $token);
838 $IRCd_capabilities{$key} = ($value ? $value : 1);
843 #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
844 #CAPAB MODULES :m_silence.so,m_watch.so
845 #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
846 #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
847 #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
848 #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
850 #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.
851 #I HAVE NO IDEA where to get the watch/silence list limit!!!
853 print "CAPAB $_[0]\n";
854 $capab =~ /CAPAB (\S+)/;
856 if ($type eq "END" && $IRCd_capabilities {"REG"} eq "") {
857 ircd
::debug
("WARNING: SurrealServices requires m_services_account.so to be loaded in Inspircd.");
858 ircd
::debug
("m_services_account.so not loaded! Shutting down NOW!");
859 print "m_services_account.so not loaded! Shutting down NOW!\n";
862 if ($capab =~ /m_chghost/ && $type eq "MODSUPPORT") {
863 $IRCd_capabilities{"CHGHOST"} = 1;
865 if ($capab =~ /m_chgident/ && $type eq "MODSUPPORT") {
866 $IRCd_capabilities{"CHGIDENT"} = 1;
868 if ($capab =~ /m_cloaking/ ) {
869 $IRCd_capabilities{"CLOAKHOST"} = 1;
871 if ($capab =~ /cloak=(\S)/ ) {
872 $IRCd_capabilities{"CLOAK"} = $1;
874 if ($capab =~ /admin=(\S)(\S)/) {
875 $IRCd_capabilities{"ADMIN"} = $2;
877 if ($capab =~ /founder=(\S)(\S)/) {
878 $IRCd_capabilities{"FOUNDER"} = $2;
880 if ($capab =~ /halfop=(\S)(\S)/) {
881 $IRCd_capabilities{"HALFOP"} = $2;
883 if ($capab =~ /silence/) {
884 $IRCd_capabilities{"SILENCE"} = 32; #unless we can make it TELL US
886 if ($capab =~ /watch/) {
887 $IRCd_capabilities{"WATCH"} = 32; #unless we can make it TELL US
889 if ($capab =~ /registered/) {
890 $IRCd_capabilities{"REG"} = 1;
892 $IRCd_capabilities {"INSP"} = 1; #this is _horrible_
896 $_[0] =~ /^:(\S+) (?:STATS|2) (\S) :(.+)$/;
897 return ('STATS', undef, undef, WF_NONE
, $1, $2, $3)
914 NETINFO
=> \
&NETINFO
,
917 PROTOCTL
=> \
&PROTOCTL
,
932 PRIVMSG
=> \
&MESSAGE
,
974 VERSION
=> \
&VERSION
,
983 SENDSNO
=> \
&SNOTICE
,
989 GLOBOPS
=> \
&GLOBOPS
,
995 SVSMODE
=> \
&SVSMODE
,
997 SVS2MODE
=> \
&SVSMODE
,
1003 OPERTYPE
=> \
&OPERTYPE
,
1004 OPERQUIT
=> \
&OPERQUIT
, #Opers are so special, they get their own QUIT. SOme of the time.