]> jfr.im git - irc/SurrealServices/srsv.git/blob - branches/0.5.0/SrSv/Insp/Parse.pm
efd8fd66615544d5523269e0e4f06600400b8d5e
[irc/SurrealServices/srsv.git] / branches / 0.5.0 / SrSv / Insp / Parse.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
17 package SrSv::IRCd::Parse;
18
19 use strict;
20
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) }
25
26 # FIXME
27 BEGIN { *SJB64 = \&ircd::SJB64; *CLK = \&ircd::CLK; *NICKIP = \&ircd::NICKIP; }
28
29 use SrSv::Conf 'main';
30
31 use SrSv::Debug;
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);
40 use SrSv::User '/./';
41 # Unreal uses unmodified base64 for NICKIP.
42 # Consider private implementation,
43 # tho MIME's is probably faster
44 use MIME::Base64;
45 use Data::Dumper;
46 use SrSv::Insp::UUID;
47 # FIXME
48 use constant {
49 # Wait For
50 WF_NONE => 0,
51 WF_NICK => 1,
52 WF_CHAN => 2,
53 WF_ALL => 3,
54 };
55
56 use SrSv::Shared qw(@servernum);
57
58 our %cmdhash;
59
60 sub 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)
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;
108 my @ids = @$idsr;
109 my $i = 0;
110 my @users;
111 foreach my $id (@ids) {
112 my $op = 0;
113 my @ops = split ("",$status[$i]);
114 foreach my $prefix (@ops) {
115 $op |= $opmodes{$prefix};
116 }
117 my $user = {ID => $id, __OP=>$op}; #ID'S are _already_ decoded in FJOIN!
118 get_user_nick ($user);
119 push @users, $user;
120 $i++;
121 }
122 return ($server, $channel, $ts, $modes, undef, \@users, undef, undef, undef); #bans etc are got from FMODE..
123 }
124 sub parse_sjoin($$$$) {
125 my ($server, $ts, $cn, $parms) = @_;
126 my (@users, @bans, @excepts, @invex, @blobs, $blobs, $chmodes, $chmodeparms);
127
128 $server = '' unless $server;
129
130 if($parms =~ /^:(.*)/) {
131 $blobs = $1;
132 } else {
133 ($chmodes, $blobs) = split(/ :/, $parms, 2);
134 ($chmodes, $chmodeparms) = split(/ /, $chmodes, 2);
135 }
136 @blobs = split(/ /, $blobs);
137
138 foreach my $x (@blobs) {
139 if($x =~ /^(\&|\"|\')(.*)$/) {
140 my $type;
141 push @bans, $2 if $1 eq '&';
142 push @excepts, $2 if $1 eq '"';
143 push @invex, $2 if $1 eq "\'";
144 } else {
145 $x =~ /^([*~@%+]*)(.*)$/;
146 my ($prefixes, $nick) = ($1, $2);
147 my @prefixes = split(//, $prefixes);
148 my $op = 0;
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 '+');
155 }
156
157 push @users, { NICK => $nick, __OP => $op };
158 }
159 }
160
161 return ($server, $cn, $ts, $chmodes, $chmodeparms, \@users, \@bans, \@excepts, \@invex);
162 }
163 sub parse_addline ($) {
164 my ($line) = @_;
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);
168 $reason =~ /:(.*)/;
169 $reason = $1;
170 $setter =~ /:(.*)/;
171 $setter = $1;
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);
177 }
178 sub parse_tkl ($) {
179 my ($in) = @_;
180 # This function is intended to accept ALL tkl types,
181 # tho maybe not parse all of them in the first version.
182
183 # Discard first token, 'TKL'
184 my (undef, $sign, $type, $params) = split(/ /, $in, 4);
185
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') {
193 # format is
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)
197 if ($sign eq '+') {
198 my ($ident, $host, $setter, $expire, $time, $reason) = split(/ /, $params, 6);
199
200 $reason =~ s/^\://;
201 return ($type, +1, $ident, $host, $setter, $expire, $time, $reason);
202 }
203 elsif($sign eq '-') {
204 my ($ident, $host, $setter) = split(/ /, $params, 3);
205 return ($type, -1, $ident, $host, $setter);
206 }
207 }
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
212 if ($sign eq '+') {
213 my ($target, $action, $setter, $expire, $time, $bantime, $reason, $mask) = split(/ /, $params, 8);
214 $mask =~ s/^\://;
215 return ($type, +1, $target, $action, $setter, $expire, $time, $bantime, $reason, $mask);
216 }
217 elsif($sign eq '-') {
218 my ($target, $action, $setter, $expire, $time, $mask) = split(/ /, $params, 6);
219 $mask =~ s/^\://;
220 return ($type, -1, $target, $action, $setter, $mask);
221 }
222 }
223 }
224
225 sub PING($) {
226 my ($event, $src, $dst, @args);
227 $_[0] =~ /^(?:8|PING) :(\S+)$/;
228 # ($event, $src, $dst, $args)
229 return ('PING', undef, undef, WF_NONE, $1);
230 }
231 sub UID ($) {
232 if ($_[0] =~ /^(:\S+) UID (\S+) (\d+) (\S+) (\S+) (\S+) (\S+) (\S+) (\d+) (\S+) :(.*)$/) {
233 print "1111111111111\n";
234 #:583 UID 583AAAAAJ 1307703236 erry__ localhost localhost errietta 127.0.0.1 1307703241 + :errietta
235 my ($server, $uid, $stamp, $nick, $host, $vhost, $ident, $IP, $ts, $modes, $gecos) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
236 print "UID $uid " . decodeUUID($uid) . "\n";
237 my $user = { NICK => $nick, ID => decodeUUID($uid) };
238 return ('NICKCONN', undef, undef, WF_NICK, $user, 0, $ts, $ident, $host, $server, $stamp, $modes, $vhost, $gecos,
239 join('.', unpack('C4', MIME::Base64::decode($IP))));
240 }
241 elsif ($_[0] =~ /^(:\S+) UID (\S+) (\d+) (\S+) (\S+) (\S+) (\S+) (\S+) (\d+) (\S+) (\S+) :(.*)$/) {
242 print "2222222\n";
243 #:965 UID 965AAAAAG 1311863295 erry arceus.pokemonlake.com IceFyre/NetAdmin/erry ~erry 216.14.116.138 1311863255 +IWhiosw +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz :erry
244 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);
245 $modes .= " " . $snomasks;
246 print "UID $uid " . decodeUUID($uid) . "\n";
247 my $user = { NICK => $nick, ID => decodeUUID($uid) };
248 return ('NICKCONN', undef, undef, WF_NICK, $user, 0, $ts, $ident, $host, $server, $stamp, $modes, $vhost, $gecos,
249 join('.', unpack('C4', MIME::Base64::decode($IP))));
250 }
251 }
252 sub EOS($) {
253 my $event;
254 if ($_[1] != "ENDBURST") {
255 $_[0] =~ /^(@|:)(\S+) (?:EOS|ES)/; # Sometimes there's extra crap on the end?
256 my $server;
257 if ($1 eq '@') {
258 $server = $servernum[b64toi($2)];
259 }
260 else {
261 $server = $2;
262 }
263 print "SERVER $server\n";
264 set_server_state($server, 1);
265 return undef() unless get_server_state($remoteserv);
266 if($server eq $remoteserv) { $event = 'SEOS' } else { $event = 'EOS' }
267 print "Ok. we had EOS\n";
268 return ($event, undef, undef, WF_ALL, $server);
269 }
270 else {
271 print "wot\n";
272 $_[0] =~ /^:(\S+) ENDBURST/;
273 my $server = $1;
274 set_server_state($server, 1);
275 print "server $server remote $remoteserv\n";
276 return undef() unless get_server_state($remoteserv);
277 print "This be it! Got endbrust!\n";
278 return ("ENDBURST", undef, undef, WF_ALL, $1);
279 }
280 }
281 our %servIds;
282 sub SERVER($) {
283 #ircd::debug($_[0]) if $debug;
284
285 if($_[0] =~ /^(?:SERVER|\') (\S+) (\S+) :(U[0-9]+)-([A-Za-z0-9]+)-([0-9]+) (.*)$/) {
286 # SERVER test-tab.surrealchat.net 1 :U2307-FhinXeOoZEmM-200 SurrealChat
287 # cmd, servername, hopCount, U<protocol>-<buildflags>-<numeric> infoLine
288 $remoteserv = $1;
289 create_server($1);
290 $servernum[$5] = $1;
291
292 return ('SERVER', undef, undef, WF_ALL, undef, $1, $2, $6, $5, $3, $4);
293 # src, serverName, numHops, infoLine, serverNumeric, protocolVersion, buildFlags
294 }
295 elsif($_[0] =~ /^(:|@)(\S+) (?:SERVER|\') (\S+) (\d+) (\d+) :(.*)$/) {
296 # @38 SERVER test-hermes.surrealchat.net 2 100 :SurrealChat
297 # source, cmd, new server, hopCount, serverNumeric, infoLine
298 my ($numeric, $name);
299 if ($1 eq '@') {
300 $name = $servernum[b64toi($2)];
301 }
302 else {
303 $name = $2;
304 }
305 create_server($3, $name);
306 $servernum[$5] = $3;
307
308 return ('SERVER', undef, undef, WF_ALL, $name, $3, $4, $6, $5);
309 # src, serverName, numHops, infoLine, serverNumeric
310 }
311 if($_[0] =~ /^(?:SERVER|\') (\S+) (\S+) :(.*)$/) {
312 $remoteserv = $1;
313 create_server($1);
314 return ('SERVER', undef, undef, WF_ALL, undef, $1, $2, $3);
315 # src, serverName, numHops, infoLine
316 }
317 elsif($_[0] =~ /^:(\S+) (?:SERVER|\') (\S+) (\d+) :(.*)$/) {
318 # source, new server, hop count, description
319 create_server($2, $1);
320 return ('SERVER', undef, undef, WF_ALL, $1, $2, $3, $4);
321 # src, serverName, numHops, infoLine
322 }
323 elsif ($_[0] =~ /^:(\S+) SERVER (\S+) (\S+) (\d+) (\S+) :(.*)$/) {
324 #:irc.icefyre.org SERVER Services.IceFyre.Org * 1 00B :IceFyre IRC Services
325 my $id = $servIds{$1};
326 create_server($5, $id);
327 return ('SERVER', undef, undef, WF_ALL, $1, $5, $4, $6);
328 }
329 elsif ($_[0] =~ /^SERVER (\S+) (\S+) (\d+) (\S+) :(.*)$/) {
330 print "RIGHT ONE WHOO\n";
331 #SERVER inspircd.erry.omg mypass 0 583 :erry World
332 #SERVER irc.icefyre.org mypass 0 965 :IceFyre IRC Hub
333
334 #SERVER servername password hopcount SID :Server Desc
335 $remoteserv = $4;
336 create_server ($4);
337 #since from now on we'll be getting commands as sent from the SID it's much wiser to keep that than the name.
338 $servIds{$1} = $4;
339 return ("SERVER", undef, undef, WF_ALL, undef, $1, $3, $5, $4);
340 }
341 }
342
343 sub SQUIT($) {
344 if($_[0] =~ /^(?:SQUIT|-) (\S+) :(.*)$/) {
345 my $list = [get_server_children($1)];
346 set_server_state($1, undef());
347 return ('SQUIT', undef, undef, WF_ALL, undef, $list, $2);
348 }
349 elsif($_[0] =~ /^(:|@)(\S+) (?:SQUIT|-) (\S+) :(.*)$/) {
350 my $name;
351 if ($1 eq '@') {
352 $name = $servernum[b64toi($2)];
353 }
354 else {
355 $name = $2;
356 }
357 my $list = [get_server_children($3)];
358 set_server_state($3, undef());
359 return ('SQUIT', undef, undef, WF_ALL, $name, $list, $4);
360 }
361 }
362
363 sub NETINFO($) {
364 $_[0] =~ /^(?:NETINFO|AO) (\S+) (\S+) (\S+) (\S+) (\S+) (\S+) (\S+) :(.*)$/;
365 return ('NETINFO', undef, undef, WF_NONE, $1, $2, $3, $4, $5, $6, $7, $8);
366 }
367
368 sub PROTOCTL($) {
369 $_[0] =~ /^PROTOCTL (.*)$/;
370 return ('PROTOCTL', undef, undef, WF_NONE, $1);
371 }
372
373 sub JOIN($) {
374 $_[0] =~ /^:(\S+) (?:C|JOIN) (\S+)$/;
375 my $user = { ID => decodeUUID($1) };
376 get_user_nick ($user);
377 return ('JOIN', undef, 1, WF_CHAN, $user, $2);
378 }
379
380 sub FJOIN ($) {
381 print "FJOIN\n";
382 #>> 114 :965 FJOIN #erry 1305486096 +nt :o,00BAAAAAX qo,965AAAAAC
383 if ($_[0] =~ m"^:(\S+) FJOIN (\S+) (\d+) (\S+) :(.*)$") {
384 print "?????FJ\n";
385 my ($server, $channel, $ts, $modes, $userstring) = ($1, $2, $3, $4, $5);
386 print "userstring $userstring";
387 my @users = split (" ", $userstring);
388 my (@ids, @status);
389 foreach my $user (@users) {
390 my @params = split (",",$user);
391 push (@status, $params[0]);
392 push (@ids, decodeUUID($params[1]));
393 }
394 return ('SJOIN', undef, undef, WF_CHAN, parse_fjoin($server, $channel, $ts, $modes, \@ids, \@status));
395 }
396 #>> :965 FJOIN #ERRY1 1312013713 +nrst ,965AAAAAB qo,965AAAAAC
397 elsif ($_[0] =~ m"^:(\S+) FJOIN (\S+) (\d+) (\S+) (.*)$") {
398 my ($server, $channel, $ts, $modes, $userstring) = ($1, $2, $3, $4, $5);
399 my @users = split (" ", $userstring);
400 my (@ids, @status);
401 foreach my $user (@users) {
402 my @params = split (",",$user);
403 push (@status, $params[0]);
404 push (@ids, decodeUUID($params[1]));
405 }
406 return ('SJOIN', undef, undef, WF_CHAN, parse_fjoin($server, $channel,$ts, $modes, \@ids, \@status));
407 }
408 #>> 15 :583 FJOIN #opers 1310128904 +Pis :
409 #CHANNELS CONFIGURED TO STAY OPEN WITH CHMODE +P (INSP)
410 elsif ($_[0] =~ m"^:(\S+) FJOIN (\S+) (\d+) (\S+) :$") {
411 print "WHOOOOOOF";
412 #FIXME - Update channel modes.
413 }
414 }
415 sub SJOIN($) {
416 if ($_[0] =~ /^(?:\~|SJOIN) (\S+) (\S+) (.*)$/) {
417 my ($ts, $cn, $payload) = ($1, $2, $3);
418 if ($ts =~ s/^!//) {
419 $ts = b64toi($ts);
420 }
421 return ('SJOIN', undef, undef, WF_CHAN, parse_sjoin($remoteserv, $ts, $cn, $payload));
422 }
423 elsif($_[0] =~ /^(@|:)(\S+) (?:\~|SJOIN) (\S+) (\S+) (.*)$/) {
424 my ($server, $ts, $cn, $payload) = ($2, $3, $4, $5);
425 if ($1 eq '@') {
426 $server = $servernum[b64toi($2)];
427 }
428 else {
429 $server = $2;
430 }
431 if ($ts =~ s/^!//) {
432 $ts = b64toi($ts);
433 }
434 return ('SJOIN', undef, undef, WF_CHAN, parse_sjoin($server, $ts, $cn, $payload));
435 }
436 }
437
438 sub PART($) {
439 my $user;
440
441 if($_[0] =~ /^:(\S+) (?:D|PART) (\S+) :(.*)$/) {
442 $user = {ID => decodeUUID($1)};
443 get_user_nick ($user);
444 return ('PART', undef, 0, WF_CHAN, $user, $2, $3);
445 }
446 elsif($_[0] =~ /^:(\S+) (?:D|PART) (\S+)$/) {
447 $user = {ID => decodeUUID($1)};
448 get_user_nick ($user);
449 return ('PART', undef, 0, WF_CHAN, $user, $2, undef);
450 }
451 }
452 sub FMODE($) {
453 #:583AAAAAR FMODE #erry 1308214721 +ib test!*@* When any mode in the channel is set.
454 #: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.
455 if($_[0] =~ /^:(\S+) FMODE (#\S+) (\d+) (\S+) ?(.*)$/) {
456 my $id = $1;
457 my $chan = $2;
458 my $m = $4;
459 my $a = $5;
460 my $user;
461 print "FMODE ID $id " . length($id);
462 if (length($id) > 3) { #UID
463 print "FFFFFFFFFFF\n";
464 $user = {ID => decodeUUID($id)};
465 get_user_nick ($user);
466 }
467 else { #SID
468 $user = $id;
469 }
470 my $name;
471 my $argz = $5;
472 my @args = split(/ /, $argz);
473 my $modes = $4;
474 print "============MODES $modes=================\n";
475 print "5: $4\n";
476 print "6: $5\n";
477 my @modes = split(//, $modes);
478 my @userargs;
479 foreach my $mode (@modes) {
480 if($mode eq '+' or $mode eq '-') { next; }
481 if ($mode !~ /^[vhoaq]$/) { next; }
482 my $arg = shift (@args);
483 next if $arg eq '';
484 if ($arg =~ /^:(\S+)$/) {
485 $arg = $1;
486 }
487 my $id = decodeUUID($arg);
488 my $tuser = {ID=>$id};
489 get_user_nick ($tuser);
490 push @userargs, $tuser;
491 }
492 return ('MODE', undef, 1, WF_ALL, $user, $chan, $m, $a,
493 @userargs);
494 }
495 elsif($_[0] =~ /^:(\S+) FMODE (#\S+) (\d+) (\S+) :(.*)$/) {
496 my $id = $1;
497 my $user;
498 print "FMODE ID $id " . length($id);
499 if (length($id) > 3) { #UID
500 print "FFFFFFFFFFF\n";
501 $user = {ID => decodeUUID($id)};
502 get_user_nick ($user);
503 }
504 else { #SID
505 $user = $id;
506 }
507 my $name;
508 my $argz = $5;
509 my @args = split(/ /, $argz);
510 my $modes = $4;
511 print "============MODES $modes=================\n";
512 print "5: $4\n";
513 print "6: $5\n";
514 my @modes = split(//, $modes);
515 my @userargs;
516 foreach my $mode (@modes) {
517 if($mode eq '+' or $mode eq '-') { next; }
518 if ($mode !~ /^[vhoaq]$/) { next; }
519 my $arg = shift (@args);
520 next if $arg eq '';
521 my $id = decodeUUID($arg);
522 my $tuser = {ID=>$id};
523 get_user_nick ($tuser);
524 push @userargs, $tuser;
525 }
526 return ('MODE', undef, 1, WF_ALL, $user, $2, $4, $5,
527 @userargs);
528 }
529 }
530 sub MODE($) {
531 my $user;
532 if($_[0] =~ /^(@|:)(\S+) (?:G|MODE) (#\S+) (.*)(?: \d+)?$/) {
533 my $name;
534 if ($1 eq '@') {
535 $name = $servernum[b64toi($2)];
536 $user = {NICK => $name};
537 }
538 else {
539 $name = $2;
540 $user = { ID=>decodeUUID($name)};
541 get_user_nick ($user);
542 }
543 my $argz = $6;
544 my @args = split(/ /, $argz);
545 my $modes = $5;
546 print "============MODES $modes=================\n";
547 print "5: $5\n";
548 print "6: $6\n";
549 my @modes = split(//, $modes);
550 my $newargs = "";
551 foreach my $mode (@modes) {
552 if($mode eq '+' or $mode eq '-') { next; }
553 my $arg = shift (@args);
554 next if $arg eq '';
555 my $id = encodeUUID($arg);
556 my $tuser = {ID=>$id};
557 my $nick = get_user_nick ($tuser);
558 print "!!!!!!!!!!!1!!!!!$nick\n";
559 $newargs .= ($newargs eq ""?$nick:" $nick"); # what an awful way to do it.
560 }
561 my $arguements;
562 if ($newargs eq "") {
563 $arguements = $argz;
564 }
565 else {
566 $arguements = $newargs;
567 }
568 return ('MODE', undef, 1, WF_ALL, $user, $3, $4, $arguements);
569 }
570 elsif($_[0] =~ /^:(\S+) (?:G|MODE) (\S+) :(\S+)$/) {
571 # We shouldn't ever get this, as UMODE2 is preferred
572 $user = { ID => decodeUUID($1) };
573 get_user_nick ($user);
574 return ('UMODE', 0, 0, WF_ALL, $user, $3);
575 }
576
577 }
578
579
580 sub MESSAGE($) {
581 my ($event, @args);
582 if($_[0] =~ /^(@|:)(\S+) (?:\!|PRIVMSG) (\S+) :(.*)$/) {
583
584 my ($name, $srcUser, $dstUser) ;
585 if ($1 eq '@') {
586 $name = $servernum[b64toi($2)];
587 $srcUser = {NICK=>$name};
588 }
589 else {
590 $name = $2;
591 $srcUser = {ID=>decodeUUID($name)};
592 unless (get_user_nick ($srcUser)) {
593 $srcUser = {NICK=>$name};
594 get_user_id ($name);
595 }
596 }
597 my $dest = $3;
598 $dstUser = {ID=>($dest)};
599 unless (get_user_nick ($dstUser)) {
600 $dstUser = {NICK=>$dest};
601 }
602 $event = 'PRIVMSG'; @args = ($srcUser, $dstUser, $4);
603 }
604 elsif($_[0] =~ /^(@|:)(\S+) (?:B|NOTICE) (\S+) :(.*)$/) {
605 my $name;
606 if ($1 eq '@') {
607 $name = $servernum[b64toi($2)];
608 }
609 else {
610 $name = $2;
611 }
612 $event = 'NOTICE'; @args = ($name, $3, $4);
613 }
614 $args[1] =~ s/\@${main_conf{local}}.*//io;
615
616 if(queue_size > 50 and $event eq 'PRIVMSG' and $args[1] !~ /^#/ and $args[2] =~ /^\w/) {
617 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...");
618 }
619
620 return ($event, 0, 1, WF_ALL, @args);
621 }
622
623 sub AWAY($) {
624 if($_[0] =~ /^:(\S+) (?:6|AWAY) :(.*)$/) {
625 my $user = {ID=>decodeUUID($1)};
626 get_user_nick($user);
627 return ('AWAY', undef, undef, WF_ALL, $user, $2);
628 }
629 elsif($_[0] =~ /^:(\S+) (?:6|AWAY)$/) {
630 my $user = {ID => decodeUUID($1)};
631 get_user_nick ($user);
632 return ('BACK', undef, undef, WF_ALL, $user);
633 }
634 }
635
636 sub NICK($) {
637 my ($event, @args);
638 #:97KAAAAAA NICK erry_ 1307878528
639 if($_[0] =~ /^:(\S+) (?:NICK|\&) (\S+) :?(\S+)$/) {
640 my $user = {ID => decodeUUID($1)};
641 get_user_nick ($user);
642 set_user_nick (decodeUUID($1), $2);
643 set_user_id ($2, decodeUUID($1));
644 return ('NICKCHANGE', undef, undef, WF_NICK, $user, $2, $3);
645 }
646 }
647
648 sub QUIT($) {
649 if ($_[0] =~ /^:(\S+) QUIT :Killed \((\S+) \((.*)\)\)$/) {
650 #:583AAAAAH QUIT :Killed (erry (die))
651 # my $victim = {ID=>decodeUUID($1)};
652 # get_user_nick ($victim);
653 # my $murderer = {NICK=>$2};
654 # get_user_id ($murderer);
655 # my $reason = $3;
656 # return ('KILL', 0, 1, WF_NICK, $murderer, $victim, $reason, undef);
657 }
658 elsif ($_[0] =~ /^:(\S+) QUIT :(.*)$/) {
659 my $user = {ID=>decodeUUID($1)};
660 get_user_nick ($user);
661 return ('QUIT', 0, undef, WF_NICK, $user, $2);
662 }
663 }
664 sub OPERQUIT ($) {
665 if ($_[0] =~ /^:(\S+) QUIT :(.*)$/) {
666 my $user = {ID=>decodeUUID($1)};
667 get_user_nick ($user);
668 return ('QUIT', 0, undef, WF_NICK, $user, $2);
669 }
670 }
671
672 sub KILL($) {
673 #:583AAAAAA KILL 123AAAAAA :Killed (erry (die))
674 #:123AAAAAA OPERQUIT :Killed (erry (die))
675 $_[0] =~ /^:(\S+) KILL (\S+) :(.*)$/;
676 my $murderer = {ID=>decodeUUID($1)};
677 get_user_nick ($murderer);
678 my $victim = {ID=>decodeUUID($2)};
679 get_user_nick ($victim);
680 return ("KILL", 0, 1, WF_NICK, $murderer, $victim, $3, undef);
681 }
682 sub KICK($) {
683 #:tabris KICK #diagnostics SurrealBot :i know you don't like this. but it's for science!
684 $_[0] =~ /^(@|:)(\S+) (?:KICK|H) (\S+) (\S+) :(.*)$/;
685 # source, chan, target, reason
686 #$src = 0; #$dst = 2;
687 my $name;
688 if ($1 eq '@') {
689 $name = $servernum[b64toi($2)];
690 }
691 else {
692 $name = $2;
693 }
694 my $user = {ID => decodeUUID($name)};
695 unless (get_user_nick ($user)) {
696 $user = {NICK => $name};
697 get_user_id ($user);
698 }
699 return ('KICK', 0, undef, WF_CHAN, $user, $3, $4, $5);
700 }
701
702 sub HOST($) {
703 if($_[0] =~ /^:(\S+) (?:CHGHOST|AL) (\S+) (\S+)$/) {
704 #:Agent CHGHOST tabris tabris.netadmin.SCnet.ops
705 return ('CHGHOST', 0, 1, WF_CHAN, $1, $2, $3);
706 #setter, target, vhost
707 }
708 elsif($_[0] =~ /^:(\S+) (?:SETHOST|AA) (\S+)$/) {
709 #:tabris SETHOST tabris.netadmin.SCnet.ops
710 return ('CHGHOST', 0, 1, WF_CHAN, $1, $1, $2);
711 }
712
713 elsif ($_[0] =~ /^:(?:\S* )?302 (\S+) :(\S+?)\*?=[+-].*?\@(.*)/) {
714 #:serebii.razorville.co.uk 302 leif :Jesture=+~Jesture00@buzz-3F604D09.sympatico.ca
715 return ('CHGHOST', 0, 1, WF_CHAN, $1, $2, $3);
716 }
717 }
718
719
720 sub USERIP($) {
721 $_[0] =~ /^:(?:\S* )?340 (\S+) :(\S+?)\*?=[+-].*?\@((?:\.|\d)*)/;
722 return ('USERIP', 0, 1, WF_CHAN, $1, $2, $3);
723 }
724
725 sub IDENT($) {
726 if($_[0] =~ /^:(\S+) (?:CHGIDENT|AL) (\S+) (\S+)$/) {
727 return ('CHGIDENT', 0, 1, WF_ALL, $1, $2, $3);
728 #setter, target, IDENT
729 }
730 elsif($_[0] =~ /^:(\S+) (?:SETIDENT|AD) (\S+)$/) {
731 return ('CHGIDENT', 0, 1, WF_ALL, $1, $1, $2);
732 #setter, target, ident
733 }
734 }
735
736
737 sub TOPIC($) {
738 if ($_[0] =~ /^:(\S+) TOPIC (\S+) :(.*)$/) {
739 #:583AAAAAF TOPIC #erry :Welcome to erry(world|net). Have a cookie.
740 my $setter = { ID => decodeUUID($1) };
741 get_user_nick ($setter);
742 return ('TOPIC', 0, 1, WF_ALL, $setter, $2, $setter, 0, $3);
743 }
744 }
745
746 sub UMODE($) {
747 #:tabris | +oghaANWt
748 $_[0] =~ /^:(\S+) (?:UMODE2|\|) (\S+)$/;
749 # src, umodes
750 # a note, not all umodes are passed
751 # +s, +O, and +t are not passed. possibly others
752 # also not all umodes do we care about.
753 # umodes we need care about:
754 # oper modes: hoaACN,O oper-only modes: HSq
755 # regular modes: rxB,izV (V is only somewhat, as the ircd
756 # does the conversions from NOTICE to PRIVSMG for us).
757
758 # Yes, I'm changing the event type on this
759 # It's better called UMODE, and easily emulated
760 # on IRCds with only MODE.
761 return ('UMODE', 0, 0, WF_ALL, $1, $2);
762 }
763 sub OPERTYPE ($) {
764 #:583AAAAAB OPERTYPE SuperNetAdmin
765 #Every OPERTYPE will get +o, so it's safe to assume they're opers,
766 #even if we don't give them privs (either in inspircd or srsv)
767 $_[0] =~ /^:(\S+) OPERTYPE (\S+)$/;
768 my $user = { ID => decodeUUID($1) };
769 get_user_nick ($user);
770 return ("OPERUP", 0, 0, WF_ALL, $user);
771 }
772 sub SVSMODE($) {
773 #:tabris | +oghaANWt
774 $_[0] =~ /^:(\S+) (?:SVS2?MODE|n|v) (\S+) (\S+)$/;
775 # src, umodes
776 # a note, not all umodes are passed
777 # +s, +O, and +t are not passed. possibly others
778 # also not all umodes do we care about.
779 # umodes we need care about:
780 # oper modes: hoaACN,O oper-only modes: HSq
781 # regular modes: rxB,izV (V is only somewhat, as the ircd
782 # does the conversions from NOTICE to PRIVSMG for us).
783
784 return ('UMODE', 0, 0, WF_ALL, $2, $3);
785 }
786
787 sub WHOIS($) {
788 # :tab WHOIS ConnectServ :ConnectServ
789 if($_[0] =~ /^:(\S+) (?:WHOIS|\#) (\S+)$/) {
790 return ('WHOIS', 0, undef, WF_NONE, $1, $2);
791 }
792 elsif($_[0] =~ /^:(\S+) (?:WHOIS|\#) (\S+) :(\S+)$/) {
793 return ('WHOIS', 0, undef, WF_NONE, $1, $3);
794 }
795 }
796
797 sub TSCTL($) {
798 $_[0] =~ /^:(\S+) (?:TSCTL|AW) alltime$/;
799 ircsend(":$main_conf{local} NOTICE $1 *** Server=$main_conf{local} TSTime=".
800 time." time()=".time." TSOffset=0");
801 return;
802 }
803
804 sub VERSION($) {
805 $_[0] =~ /^:(\S+) (?:VERSION|\+).*$/;
806 return ('VERSION', 0, undef, WF_NONE, $1);
807 }
808
809 sub TKL($) {
810 if ($_[0] =~ /^(@|:)(\S+) (?:TKL|BD) (.*)$/) {
811 # We discard the source anyway.
812 #my $server;
813 #if ($1 eq '@') {
814 # $server = $servernum[b64toi($2)];
815 #}
816 #else {
817 # $server = $2;
818 #}
819 return ('TKL', undef, undef, WF_NONE, parse_tkl("TKL $3"));
820 }
821 elsif ($_[0] =~ /^(?:TKL|BD) (.*)$/) {
822 return ('TKL', undef, undef, WF_NONE, parse_tkl("TKL $1"));
823 }
824 }
825
826 sub SNOTICE($) {
827 $_[0] =~ /^(@|:)(\S+) (SENDSNO|Ss|SMO|AU) ([A-Za-z]) :(.*)$/;
828 #@servernumeric Ss snomask :message
829 my $name;
830 if ($1 eq '@') {
831 $name = $servernum[b64toi($2)];
832 }
833 else {
834 $name = $2;
835 }
836 my $event;
837 $event = 'SENDSNO' if(($3 eq 'SENDSNO' or $3 eq 'Ss'));
838 $event = 'SMO' if(($3 eq 'SMO' or $3 eq 'AU'));
839 return ($event, 0, undef, WF_NONE, $name, $4, $5);
840 }
841
842 sub GLOBOPS($) {
843 $_[0] =~ /^(@|:)(\S+) (?:GLOBOPS|\]) :(.*)$/;
844 #@servernumeric [ :message
845 my $name;
846 if ($1 eq '@') {
847 $name = $servernum[b64toi($2)];
848 }
849 else {
850 $name = $2;
851 }
852 return ('GLOBOPS', 0, undef, WF_NONE, $name, $3);
853 }
854
855 sub ISUPPORT($) {
856 $_[0] =~ /^:(\S+) (?:105|005) (\S+) (.+) :are supported by this server$/;
857 # :test-tab.surrealchat.net 105 services.SC.net CMDS=KNOCK,MAP,DCCALLOW,USERIP :are supported by this server
858 foreach my $token (split(/\s+/, $3)) {
859 my ($key, $value) = split('=', $token);
860 $IRCd_capabilities{$key} = ($value ? $value : 1);
861 }
862 }
863
864 sub CAPAB {
865 #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
866 #CAPAB MODULES :m_silence.so,m_watch.so
867 #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
868 #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
869 #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
870 #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
871 #---
872 #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.
873 #I HAVE NO IDEA where to get the watch/silence list limit!!!
874 #let's do this the lame way!
875 #FIXME this is so ugly
876 my $capab = $_[0];
877 print "CAPAB $_[0]\n";
878 $capab =~ /CAPAB (\S+)/;
879 my $type = $1;
880 if ($type eq "END" && $IRCd_capabilities {"REG"} eq "") {
881 ircd::debug ("WARNING: SurrealServices requires m_services_account.so to be loaded in Inspircd.");
882 ircd::debug ("m_services_account.so not loaded! Shutting down NOW!");
883 print "m_services_account.so not loaded! Shutting down NOW!\n";
884 main_shutdown;
885 }
886 if ($capab =~ /m_chghost/ && $type eq "MODSUPPORT") {
887 $IRCd_capabilities{"CHGHOST"} = 1;
888 }
889 if ($capab =~ /m_chgident/ && $type eq "MODSUPPORT") {
890 $IRCd_capabilities{"CHGIDENT"} = 1;
891 }
892 if ($capab =~ /m_cloaking/ ) {
893 $IRCd_capabilities{"CLOAKHOST"} = 1;
894 }
895 if ($capab =~ /cloak=(\S)/ ) {
896 $IRCd_capabilities{"CLOAK"} = $1;
897 }
898 if ($capab =~ /admin=(\S)(\S)/) {
899 $IRCd_capabilities{"ADMIN"} = $2;
900 }
901 if ($capab =~ /founder=(\S)(\S)/) {
902 $IRCd_capabilities{"FOUNDER"} = $2;
903 }
904 if ($capab =~ /halfop=(\S)(\S)/) {
905 $IRCd_capabilities{"HALFOP"} = $2;
906 }
907 if ($capab =~ /silence/) {
908 $IRCd_capabilities{"SILENCE"} = 32; #unless we can make it TELL US
909 }
910 if ($capab =~ /watch/) {
911 $IRCd_capabilities{"WATCH"} = 32; #unless we can make it TELL US
912 }
913 if ($capab =~ /registered/) {
914 $IRCd_capabilities{"REG"} = 1;
915 }
916 $IRCd_capabilities {"INSP"} = 1; #this is _horrible_
917
918 }
919 sub STATS($) {
920 $_[0] =~ /^:(\S+) (?:STATS|2) (\S) :(.+)$/;
921 return ('STATS', undef, undef, WF_NONE, $1, $2, $3)
922 }
923
924 BEGIN {
925 %cmdhash = (
926 PING => \&PING,
927 '8' => \&PING,
928
929 EOS => \&EOS,
930 ES => \&EOS,
931 ENDBURST => \&EOS,
932 SERVER => \&SERVER,
933 "\'" => \&SERVER,
934
935 SQUIT => \&SQUIT,
936 '-' => \&SQUIT,
937
938 NETINFO => \&NETINFO,
939 AO => \&NETINFO,
940
941 PROTOCTL => \&PROTOCTL,
942
943 JOIN => \&JOIN,
944 C => \&JOIN,
945
946 PART => \&PART,
947 D => \&PART,
948
949 SJOIN => \&SJOIN,
950 '~' => \&SJOIN,
951 FJOIN => \&FJOIN,
952 FMODE => \&FMODE,
953 MODE => \&MODE,
954 G => \&MODE,
955
956 PRIVMSG => \&MESSAGE,
957 '!' => \&MESSAGE,
958 NOTICE => \&MESSAGE,
959 B => \&MESSAGE,
960
961 AWAY => \&AWAY,
962 '6' => \&AWAY,
963
964 NICK => \&NICK,
965 '&' => \&NICK,
966
967 QUIT => \&QUIT,
968 ',' => \&QUIT,
969
970 KILL => \&KILL,
971 '.' => \&KILL,
972
973 KICK => \&KICK,
974 H => \&KICK,
975
976 CHGHOST => \&HOST,
977 AL => \&HOST,
978 SETHOST => \&HOST,
979 AA => \&HOST,
980 '302' => \&HOST,
981
982 '340' => \&USERIP,
983
984 CHGIDENT => \&IDENT,
985 AZ => \&IDENT,
986 SETIDENT => \&IDENT,
987 AD => \&IDENT,
988
989 TOPIC => \&TOPIC,
990 ')' => \&TOPIC,
991
992 UMODE2 => \&UMODE,
993 '|' => \&UMODE,
994
995 TSCTL => \&TSCTL,
996 AW => \&TSCTL,
997
998 VERSION => \&VERSION,
999 '+' => \&VERSION,
1000
1001 TKL => \&TKL,
1002 BD => \&TKL,
1003
1004 WHOIS => \&WHOIS,
1005 '#' => \&WHOIS,
1006
1007 SENDSNO => \&SNOTICE,
1008 Ss => \&SNOTICE,
1009
1010 SMO => \&SNOTICE,
1011 AU => \&SNOTICE,
1012
1013 GLOBOPS => \&GLOBOPS,
1014 ']' => \&GLOBOPS,
1015
1016 '105' => \&ISUPPORT,
1017 '005' => \&ISUPPORT,
1018
1019 SVSMODE => \&SVSMODE,
1020 'n' => \&SVSMODE,
1021 SVS2MODE => \&SVSMODE,
1022 'v' => \&SVSMODE,
1023
1024 STATS => \&STATS,
1025 '2' => \&STATS,
1026 UID => \&UID,
1027 OPERTYPE => \&OPERTYPE,
1028 OPERQUIT => \&OPERQUIT, #Opers are so special, they get their own QUIT. SOme of the time.
1029 CAPAB => \&CAPAB,
1030 FMODE => \&FMODE
1031 );
1032 }
1033
1034 1;