diff options
| author | 2015-09-24 01:32:11 +0000 | |
|---|---|---|
| committer | 2015-09-24 01:32:11 +0000 | |
| commit | 9b472795d26cd93d1bb58488ef60a062f5237295 (patch) | |
| tree | 8572778595d145176e720a1b7168c73adbd64ed4 /lib/ASM/Event.pm | |
| parent | b93c3a24f14e0f64bc46b4945a65ae1bba62dc12 (diff) | |
Rework module paths
Diffstat (limited to 'lib/ASM/Event.pm')
| -rw-r--r-- | lib/ASM/Event.pm | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/lib/ASM/Event.pm b/lib/ASM/Event.pm new file mode 100644 index 0000000..e6f4c23 --- /dev/null +++ b/lib/ASM/Event.pm @@ -0,0 +1,887 @@ +package ASM::Event; +use warnings; +use strict; + +use Data::Dumper; +use Text::LevenshteinXS qw(distance); +use IO::All; +use POSIX qw(strftime); +use Regexp::Wildcards; +use HTTP::Request; + +sub cs { + my ($chan) = @_; + $chan = lc $chan; + $chan =~ s/^[@+]//; + return $::channels->{channel}->{$chan} if ( defined($::channels->{channel}->{$chan}) ); + return $::channels->{channel}->{default}; +} + +sub maxlen { + my ($a, $b) = @_; + my ($la, $lb) = (length($a), length($b)); + return $la if ($la > $lb); + return $lb; +} + +sub new +{ + my $module = shift; + my ($conn, $inspector) = @_; + my $self = {}; + $self->{CONN} = $conn; + $self->{INSPECTOR} = $inspector; + ASM::Util->dprint('Installing handler routines...', 'startup'); + $conn->add_default_handler(\&blah); + $conn->add_handler('bannedfromchan', \&on_bannedfromchan); + $conn->add_handler('mode', \&on_mode); + $conn->add_handler('join', \&on_join); + $conn->add_handler('part', \&on_part); + $conn->add_handler('quit', \&on_quit); + $conn->add_handler('nick', \&on_nick); + $conn->add_handler('notice', \&on_notice); + $conn->add_handler('caction', \&on_public); + $conn->add_handler('msg', \&on_msg); + $conn->add_handler('namreply', \&on_names); + $conn->add_handler('endofnames', \&on_names); + $conn->add_handler('public', \&on_public); + $conn->add_handler('376', \&on_connect); + $conn->add_handler('topic', \&irc_topic); + $conn->add_handler('topicinfo', \&irc_topic); + $conn->add_handler('nicknameinuse', \&on_errnickinuse); + $conn->add_handler('bannickchange', \&on_bannickchange); + $conn->add_handler('kick', \&on_kick); + $conn->add_handler('cping', \&on_ctcp); + $conn->add_handler('cversion', \&on_ctcp); + $conn->add_handler('csource', \&on_ctcp_source); + $conn->add_handler('ctime', \&on_ctcp); + $conn->add_handler('cdcc', \&on_ctcp); + $conn->add_handler('cuserinfo', \&on_ctcp); + $conn->add_handler('cclientinfo', \&on_ctcp); + $conn->add_handler('cfinger', \&on_ctcp); + $conn->add_handler('354', \&on_whoxreply); + $conn->add_handler('315', \&on_whoxover); + $conn->add_handler('263', \&on_whofuckedup); + $conn->add_handler('account', \&on_account); + $conn->add_handler('ping', \&on_ping); + $conn->add_handler('banlist', \&on_banlist); + $conn->add_handler('dcc_open', \&dcc_open); + $conn->add_handler('chat', \&on_dchat); + $conn->add_handler('channelmodeis', \&on_channelmodeis); + $conn->add_handler('quietlist', \&on_quietlist); + $conn->add_handler('pong', \&on_pong); + $conn->add_handler('statsdebug', \&on_statsdebug); + $conn->add_handler('endofstats', \&on_endofstats); + $conn->add_handler('channelurlis', \&on_channelurlis); + $conn->add_handler('480', \&on_jointhrottled); + $conn->add_handler('invite', \&blah); # This doesn't need to be fancy; I just need it to go through inspect + bless($self); + return $self; +} + +my $clearstatsp = 1; +my %statsp = (); +my %oldstatsp = (); + +sub on_jointhrottled +{ + my ($conn, $event) = @_; + my $chan = $event->{args}->[1]; + ASM::Util->dprint("$event->{nick}: $chan: $event->{args}->[2]", 'snotice'); + if ($event->{args}->[2] =~ /throttle exceeded, try again later/) { + $conn->schedule(5, sub { $conn->join($chan); }); + } +} + +sub on_statsdebug +{ + my ($conn, $event) = @_; + my ($char, $line) = ($event->{args}->[1], $event->{args}->[2]); + if ($char eq 'p') { + if ($clearstatsp) { + $clearstatsp = 0; + %oldstatsp = %statsp; + %statsp = (); + } + if ($line =~ /^(\d+) staff members$/) { + #this is the end of the report + } else { + my ($nick, $userhost) = split(" ", $line); + $userhost =~ s/\((.*)\)/$1/; + my ($user, $host) = split("@", $userhost); + $statsp{$nick}= [$user, $host]; + } + } +} + +sub on_endofstats +{ + my ($conn, $event) = @_; + if ($event->{args}->[1] eq 'p') { + $clearstatsp=1; + my $tmp = Dumper(\%statsp); chomp $tmp; + if ( join(',', sort(keys %oldstatsp)) ne join(',', sort(keys %statsp)) ) { + open(FH, '>>', 'statsplog.txt'); + say FH strftime('%F %T ', gmtime) . join(',', sort(keys %statsp)); + close(FH); + ASM::Util->dprint(join(",", keys %statsp), 'statsp'); + } + # $event->{args}->[2] == "End of /STATS report" + #end of /stats p + } +} + +my $lagcycles = 0; +my $pongcount = 0; + +sub on_pong +{ + my ($conn, $event) = @_; + alarm 120; + $conn->schedule( 30, sub { $conn->sl("PING :" . time); } ); + ASM::Util->dprint('Pong? ... Ping!', 'pingpong'); + my $lag = time - $event->{args}->[0]; + my @changes = $::fm->scan(); + if (@changes) { + if ($::settingschanged) { + $::settingschanged = 0; + } else { + $conn->privmsg($::settings->{masterchan}, "Config files changed, auto rehash triggered. Check console for possible errors."); + ASM::XML->readXML(); + my @strbl = io('string_blacklist.txt')->getlines; + chomp @strbl; + @::string_blacklist = @strbl; + } + } + if ($lag > 1) { + ASM::Util->dprint("Latency: $lag", 'latency'); + } + if (($pongcount % 3) == 0) { #easiest way to do something roughly every 90 seconds + $conn->sl('STATS p'); + } + if ((time - $::starttime) < 240 ) { + return; #we don't worry about lag if we've just started up and are still syncing etc. + } + if (($lag > 2) && ($lag < 5)) { + $conn->privmsg( $::settings->{masterchan}, "Warning: I'm currently lagging by $lag seconds."); + } + if ($lag >= 5) { + $lagcycles++; + if ($lagcycles >= 3) { + $conn->quit("Automatic restart triggered due to persistent lag. Freenode staff: If this is happening too frequently, please " . + "set a nickserv freeze on my account, and once my connection is stable, unfreeze the account and /kill me to tri" . + "gger a reconnect."); + } else { + $conn->privmsg( $::settings->{masterchan}, "Warning: I'm currently lagging by $lag seconds. This marks heavy lag cycle " . + "$lagcycles - automatic restart will be triggered after 3 lag cycles." ); + } + } + if (($lag <= 5) && ($lagcycles > 0)) { + $lagcycles--; +# $conn->privmsg( $::settings->{masterchan}, "Warning: Heavy lag cycle count has been reduced to $lagcycles" ); + ASM::Util->dprint('$lag = ' . $lag . '; $lagcycles = ' . $lagcycles, 'latency'); + } +} + +sub on_dchat +{ + my ($conn, $event) = @_; + ASM::Util->dprint(Dumper($event), 'dcc'); + if ( #(lc $event->{nick} eq 'afterdeath') && + ($event->{args}->[0] ne '')) { + my $msg = $event->{args}->[0]; + if ($msg =~ /^SPY (.*)/) { + my $chan = $1; + $::spy{lc $chan} = $event->{to}[0]; + } elsif ($msg =~ /^STOPSPY (.*)/) { + delete $::spy{lc $1}; + } elsif ($msg =~ /^RETRIEVE (\S+)/) { + my $chan = lc $1; + my $out = $event->{to}[0]; + my @time = ($::settings->{log}->{zone} eq 'local') ? localtime : gmtime; + say $out 'Retrieving ' . "$::settings->{log}->{dir}${chan}/${chan}" . strftime($::settings->{log}->{filefmt}, @time); + open(FHX, "$::settings->{log}->{dir}${chan}/${chan}" . strftime($::settings->{log}->{filefmt}, @time)); + while (<FHX>) { + print $out $_; + } + close FHX; + } + #lols we gots a chat message! :D + } +} + +sub on_ping +{ + my ($conn, $event) = @_; + $conn->sl("PONG " . $event->{args}->[0]); +# alarm 200; + ASM::Util->dprint('Ping? Pong!', 'pingpong'); +# ASM::Util->dprint(Dumper($event), 'pingpong'); +} + +sub on_account +{ + my ($conn, $event) = @_; + $::sn{lc $event->{nick}}{account} = lc $event->{args}->[0]; +} + +sub on_connect { + my ($conn, $event) = @_; # need to check for no services + $conn->sl("MODE $event->{args}->[0] +Q"); + if (lc $event->{args}->[0] ne lc $::settings->{nick}) { + ASM::Util->dprint('Attempting to regain my main nick', 'startup'); + $conn->privmsg( 'NickServ@services.', "regain $::settings->{nick} $::settings->{pass}" ); + } + $conn->sl('CAP REQ :extended-join multi-prefix account-notify'); #god help you if you try to use this bot off freenode +} + +sub on_join { + my ($conn, $event) = @_; + my $nick = lc $event->{nick}; + my $chan = lc $event->{to}->[0]; + my $rate; +# alarm 200; + if ( lc $conn->{_nick} eq lc $nick) { + $::sc{$chan} = {}; + mkdir($::settings->{log}->{dir} . $chan); + $::synced{$chan} = 0; + unless ( @::syncqueue ) { + $conn->sl('who ' . $chan . ' %tcnuhra,314'); + $conn->sl('mode ' . $chan); + $conn->sl('mode ' . $chan . ' bq'); + } + push @::syncqueue, $chan; + } + $::sc{$chan}{users}{$nick} = {}; + $::sc{$chan}{users}{$nick}{hostmask} = $event->{userhost}; + $::sc{$chan}{users}{$nick}{op} = 0; + $::sc{$chan}{users}{$nick}{voice} = 0; + $::sc{$chan}{users}{$nick}{jointime} = time; + $::sc{$chan}{users}{$nick}{msgtime} = 0; + if (defined($::sn{$nick})) { + my @mship = (); + if (defined($::sn{$nick}->{mship})) { + @mship = @{$::sn{$nick}->{mship}}; + } + @mship = (@mship, $chan); + $::sn{$nick}->{mship} = \@mship; + } else { + $::sn{$nick} = {}; + $::sn{$nick}->{mship} = [ $chan ]; + } + $::sn{$nick}->{dnsbl} = 0; + $::sn{$nick}->{netsplit} = 0; + $::sn{$nick}->{gecos} = $event->{args}->[1]; + $::sn{$nick}->{user} = $event->{user}; + $::sn{$nick}->{host} = $event->{host}; + $::sn{$nick}->{account} = lc $event->{args}->[0]; + $::db->logg($event) if defined $::db; + $::log->logg( $event ); + $::inspector->inspect( $conn, $event ) unless $::netsplit; +} + +sub on_part +{ + my ($conn, $event) = @_; + my $nick = lc $event->{nick}; + my $chan = lc $event->{to}->[0]; + $::log->logg( $event ); + $::db->logg( $event ) if defined $::db; + if (defined $::db and $event->{args}->[0] =~ /^requested by/) { + my $idx = $::db->actionlog( $event); + $::log->sqlIncident($chan, $idx) if $idx; + } +# "to" => [ "#antispammeta" ], +# "args" => [ "requested by ow (test)" ], +# "nick" => "aoregcdu", + $::inspector->inspect( $conn, $event ); + if (defined($::sn{$nick}) && defined($::sn{$nick}->{mship})) { + my @mship = @{$::sn{$nick}->{mship}}; + @mship = grep { lc $_ ne $chan } @mship; + if ( @mship ) { + $::sn{$nick}->{mship} = \@mship; + } else { + delete($::sn{$nick}); + } + } + if ( lc $conn->{_nick} eq $nick ) + { + delete( $::sc{$chan} ); + on_byechan($chan); + } + else + { + delete( $::sc{$chan}{users}{$nick} ); + } +} + +sub on_msg +{ + my ($conn, $event) = @_; + $::commander->command($conn, $event); + ASM::Util->dprint($event->{from} . " - " . $event->{args}->[0], 'msg'); + if ((ASM::Util->notRestricted($event->{nick}, "nomsgs")) && ($event->{args}->[0] !~ /^;;/)) { +# disabled by DL 130513 due to spammer abuse +# $conn->privmsg($::settings->{masterchan}, $event->{from} . ' told me: ' . $event->{args}->[0]); + } +} + +sub on_public +{ + my ($conn, $event) = @_; +# alarm 200; + my $chan = lc $event->{to}[0]; + $chan =~ s/^[+@]//; + $::log->logg( $event ); + $::db->logg( $event ) if defined $::db; + if ($event->{args}->[0] =~ /(https?:\/\/bitly.com\/\w+|https?:\/\/bit.ly\/\w+|https?:\/\/j.mp\/\w+|https?:\/\/tinyurl.com\/\w+)/i) { + my $reqid = $::async->add( HTTP::Request->new( GET => $1 ) ); + $::httpRequests{$reqid} = $event; + my ($response, $id) = $::async->wait_for_next_response( 1 ); + if (defined($response)) { + on_httpResponse($conn, $id, $response); + } + else { $conn->schedule( 1, sub { checkHTTP($conn); } ); } + } + $::inspector->inspect( $conn, $event ); + $::commander->command( $conn, $event ); + $::sc{$chan}{users}{lc $event->{nick}}{msgtime} = time; +} + +sub checkHTTP +{ + my ($conn) = @_; + my ($response, $id) = $::async->next_response(); + if (defined ($response)) { + on_httpResponse($conn, $id, $response); + } + $conn->schedule( 1, sub { checkHTTP($conn); } ); +} + +sub on_httpResponse +{ + my ($conn, $id, $response) = @_; + my $event = $::httpRequests{$id}; + delete $::httpRequests{$id}; + $::inspector->inspect( $conn, $event, $response ); +} +# if ($response->{_previous}->{_headers}->{location} =~ /^https?:\/\/bitly.com\/a\/warning/) + +sub on_notice +{ + my ($conn, $event) = @_; + return if ( $event->{to}->[0] eq '$*' ); # if this is a global notice FUCK THAT SHIT + $::log->logg( $event ); + $::db->logg( $event ) if defined $::db; + $::inspector->inspect( $conn, $event ); + $::services->doServices($conn, $event); +} + +sub on_errnickinuse +{ + my ($conn, $event) = @_; + $_ = ${$::settings->{altnicks}}[rand @{$::settings->{altnicks}}]; + ASM::Util->dprint("Nick is in use, trying $_", 'startup'); + $conn->nick($_); +} + +sub on_bannickchange +{ + my ($conn, $event) = @_; + $_ = ${$::settings->{altnicks}}[rand @{$::settings->{altnicks}}]; + ASM::Util->dprint("Nick is in use, trying $_", 'startup'); + $conn->nick($_); +} + +sub on_quit +{ + my ($conn, $event) = @_; + my @channels=(); + for ( keys %::sc ) { + push ( @channels, lc $_ ) if delete $::sc{lc $_}{users}{lc $event->{nick}}; + } + $event->{to} = \@channels; + if (defined $::db) { + my $idx = $::db->actionlog($event); + $::log->sqlIncident( join(',', @channels), $idx ) if $idx; + $::db->logg( $event ); + } + $::log->logg( $event ); + + if (($::netsplit == 0) && ($event->{args}->[0] eq "*.net *.split") && (lc $event->{nick} ne 'chanserv')) { #special, netsplit situation + $conn->privmsg($::settings->{masterchan}, "Entering netsplit mode - JOIN and QUIT inspection will be disabled for 60 minutes"); + $::netsplit = 1; + $conn->schedule(60*60, sub { $::netsplit = 0; $conn->privmsg($::settings->{masterchan}, 'Returning to regular operation'); }); + } + $::inspector->inspect( $conn, $event ) unless $::netsplit; + #ugh. Repurge some shit, hopefully this will fix some stuff where things are going wrong + foreach my $chan ( keys %::sc ) { + delete $::sc{$chan}{users}{lc $event->{nick}}; + } + delete($::sn{lc $event->{nick}}); +} + +sub blah +{ + my ($self, $event) = @_; + ASM::Util->dprint(Dumper($event), 'misc'); + $::inspector->inspect($self, $event); +} + +sub irc_users +{ + my ( $channel, @users ) = @_; + for (@users) + { + my ( $op, $voice ); + $op = 0; $voice = 0; + $op = 1 if s/^\@//; + $voice = 1 if s/^\+//; + $::sc{lc $channel}{users}{lc $_} = {}; + $::sc{lc $channel}{users}{lc $_}{op} = $op; + $::sc{lc $channel}{users}{lc $_}{voice} = $voice; + $::sc{lc $channel}{users}{lc $_}{jointime} = 0; + } +} + +sub on_names { + my ($conn, $event) = @_; + irc_users( $event->{args}->[2], split(/ /, $event->{args}->[3]) ) if ($event->{type} eq 'namreply'); +} + +sub irc_topic { + my ($conn, $event) = @_; + if ($event->{format} eq 'server') + { + my $chan = lc $event->{args}->[1]; + if ($event->{type} eq 'topic') + { + $::sc{$chan}{topic}{text} = $event->{args}->[2]; + } + elsif ($event->{type} eq 'topicinfo') + { + $::sc{$chan}{topic}{time} = $event->{args}->[3]; + $::sc{$chan}{topic}{by} = $event->{args}->[2]; + } + } + else + { + if ($event->{type} eq 'topic') + { + my $chan = lc $event->{to}->[0]; + $::sc{$chan}{topic}{text} = $event->{args}->[0]; + $::sc{$chan}{topic}{time} = time; + $::sc{$chan}{topic}{by} = $event->{from}; + } + $::log->logg($event); + $::db->logg( $event ) if defined $::db; + $::inspector->inspect($conn, $event); + } +} + +sub on_nick { + my ($conn, $event) = @_; + my @channels=(); + my $oldnick = lc $event->{nick}; + my $newnick = lc $event->{args}->[0]; + foreach my $chan ( keys %::sc ) + { + $chan = lc $chan; + if ( defined $::sc{$chan}{users}{$oldnick} ) + { + if ($oldnick ne $newnick) { #otherwise a nick change where they're only + #changing the case of their nick means that + #ASM forgets about them. + $::sc{$chan}{users}{$newnick} = $::sc{$chan}{users}{$oldnick}; + delete( $::sc{$chan}{users}{$oldnick} ); + } + push ( @channels, $chan ); + } + } + + # unfortunately Net::IRC sucks at IRC so we have to implement this ourselves + if ($oldnick eq lc $conn->{_nick}) { + $conn->{_nick} = $event->{args}[0]; + } + + $::sn{$newnick} = $::sn{$oldnick} if ($oldnick ne $newnick); + $::db->logg( $event ) if defined $::db; + delete( $::sn{$oldnick}) if ($oldnick ne $newnick); + $event->{to} = \@channels; + $::log->logg($event); + # Well, the nick change actually was done from the old nick ... but + # by the time we process it, they already changed nicks. Therefore + # we'll pretend it's the *new* nick that generated the event. + $event->{nick} = $event->{args}[0]; + $::inspector->inspect($conn, $event); +} + +sub on_kick { + my ($conn, $event) = @_; + if (lc $event->{to}->[0] eq lc $::settings->{nick}) { + $conn->privmsg($::settings->{masterchan}, "I've been kicked from " . $event->{args}->[0] . ": " . $event->{args}->[1]); +# $conn->join($event->{args}->[0]); + } + my $nick = lc $event->{to}->[0]; + my $chan = lc $event->{args}->[0]; + $::log->logg( $event ); + if (defined $::db) { + $::db->logg( $event ); + my $idx = $::db->actionlog($event); + $::log->sqlIncident($chan, $idx) if $idx; + } + if (defined($::sn{$nick}) && defined($::sn{$nick}->{mship})) { + my @mship = @{$::sn{$nick}->{mship}}; + @mship = grep { lc $_ ne $chan } @mship; + if ( @mship ) { + $::sn{$nick}->{mship} = \@mship; + } else { + delete($::sn{$nick}); + } + } + if ( lc $conn->{_nick} eq $nick ) + { + delete( $::sc{lc $event->{args}->[0]} ); + on_byechan(lc $event->{to}->[0]); + } + else + { + delete( $::sc{lc $event->{args}->[0]}{users}{$nick} ); + } +} + +sub parse_modes +{ + my ( $n ) = @_; + my @args = @{$n}; + my @modes = split '', shift @args; + my @new_modes=(); + my $t; + foreach my $c ( @modes ) { + if (($c eq '-') || ($c eq '+')) { + $t=$c; + } + else { #eIbq,k,flj,CFLMPQcgimnprstz + if ($t eq '+') { + if ( grep( /[eIbqkfljov]/,($c) ) ) { #modes that take args WHEN BEING ADDED + push (@new_modes, [$t.$c, shift @args]); + } + elsif ( grep( /[CFLMPQcgimnprstz]/, ($c) ) ) { + push (@new_modes, [$t.$c]); + } + else { + die "Unknown mode $c !\n"; + } + } else { + if ( grep( /[eIbqov]/,($c) ) ) { #modes that take args WHEN BEING REMOVED + push (@new_modes, [$t.$c, shift @args]); + } + elsif ( grep( /[CFLMPQcgimnprstzkflj]/, ($c) ) ) { + push (@new_modes, [$t.$c]); + } + else { + die "Unknown mode $c !\n"; + } + } + } + } + return \@new_modes; +} + +sub on_channelmodeis +{ + my ($conn, $event) = @_; + my $chan = lc $event->{args}->[1]; + my @temp = @{$event->{args}}; + shift @temp; shift @temp; + my @modes = @{parse_modes(\@temp)}; + foreach my $line ( @modes ) { + my @ex = @{$line}; + my ($what, $mode) = split (//, $ex[0]); + if ($what eq '+') { + if (defined($ex[1])) { + push @{$::sc{$chan}{modes}}, $mode . ' ' . $ex[1]; + } else { + push @{$::sc{$chan}{modes}}, $mode; + } + } else { + my @modes = grep {!/^$mode/} @{$::sc{$chan}{modes}}; + $::sc{$chan}{modes} = \@modes; + } + } +} + +sub whoGotHit +{ + my ($chan, $mask) = @_; + my $cvt = Regexp::Wildcards->new(type => 'jokers'); + my @affected = (); + if ($mask !~ /^\$/) { + my @div = split(/\$/, $mask); + my $regex = $cvt->convert($div[0]); + foreach my $nick (keys %::sn) { + next unless defined($::sn{$nick}{user}); + if (lc ($nick.'!'.$::sn{$nick}{user}.'@'.$::sn{$nick}{host}) =~ /^$regex$/i) { + push @affected, $nick if defined($::sc{$chan}{users}{$nick}); + } + } + } elsif ($mask =~ /^\$a:(.*)/) { + my @div = split(/\$/, $1); + my $regex = $cvt->convert($div[0]); + foreach my $nick (keys %::sn) { + next unless defined($::sn{$nick}{account}); + if (lc ($::sn{$nick}{account}) =~ /^$regex$/i) { + push @affected, $nick if defined($::sc{$chan}{users}{$nick}); + } + } + } + return @affected; +} + +sub on_mode +{ + my ($conn, $event) = @_; + my $chan = lc $event->{to}->[0]; +# holy shit, I feel so bad doing this +# I have no idea how or why Net::IRC fucks up modes if they've got a ':' in one of the args +# but you do what you must... + my @splitted = split(/ /, $::lastline); shift @splitted; shift @splitted; shift @splitted; + $event->{args}=\@splitted; + if ($chan =~ /^#/) { + my @modes = @{parse_modes($event->{args})}; + ASM::Util->dprint(Dumper(\@modes), 'misc'); + foreach my $line ( @modes ) { + my @ex = @{$line}; + + if ( $ex[0] eq '+o' ) { $::sc{$chan}{users}{lc $ex[1]}{op} = 1; } + elsif ( $ex[0] eq '-o' ) { $::sc{$chan}{users}{lc $ex[1]}{op} = 0; } + elsif ( $ex[0] eq '+v' ) { $::sc{$chan}{users}{lc $ex[1]}{voice} = 1; } + elsif ( $ex[0] eq '-v' ) { $::sc{$chan}{users}{lc $ex[1]}{voice} = 0; } + + elsif ( $ex[0] eq '+b' ) { + $::sc{$chan}{bans}{$ex[1]} = { bannedBy => $event->{from}, bannedOn => time }; + if (lc $event->{nick} !~ /^(floodbot)/) { #ignore the ubuntu floodbots 'cause they quiet people a lot + my @affected = whoGotHit($chan, $ex[1]); + if ( defined($::db) && (@affected) && (scalar @affected <= 4) ) { + foreach my $victim (@affected) { + my $idx = $::db->actionlog($event, 'ban', $victim); + $::log->sqlIncident( $chan, $idx ) if $idx; + } + } + if ($ex[1] =~ /^\*\!\*\@(.*)$/) { + my $ip = ASM::Util->getHostIP($1); + $::sc{$chan}{ipbans}{$ip} = { bannedBy => $event->{from}, bannedOn => time } if defined($ip); + } + } + } + elsif ( $ex[0] eq '-b' ) { + delete $::sc{$chan}{bans}{$ex[1]}; + if ($ex[1] =~ /^\*\!\*\@(.*)$/) { + my $ip = ASM::Util->getHostIP($1); + delete $::sc{$chan}{ipbans}{$ip} if defined($ip); + } + } + + elsif ( $ex[0] eq '+q' ) { + $::sc{$chan}{quiets}{$ex[1]} = { bannedBy => $event->{from}, bannedOn => time }; + if (lc $event->{nick} !~ /^(floodbot)/) { + my @affected = whoGotHit($chan, $ex[1]); + if ( defined($::db) && (@affected) && (scalar @affected <= 4) ) { + foreach my $victim (@affected) { + my $idx = $::db->actionlog($event, 'quiet', $victim); + $::log->sqlIncident( $chan, $idx ) if $idx; + } + } + if ($ex[1] =~ /^\*\!\*\@(.*)$/) { + my $ip = ASM::Util->getHostIP($1); + $::sc{$chan}{ipquiets}{$ip} = { bannedBy => $event->{from}, bannedOn => time } if defined($ip); + } + } + } + elsif ( $ex[0] eq '-q' ) { + delete $::sc{$chan}{quiets}{$ex[1]}; + if ($ex[1] =~ /^\*\!\*\@(.*)$/) { + my $ip = ASM::Util->getHostIP($1); + delete $::sc{$chan}{ipquiets}{$ip} if defined($ip); + } + } + + else { + my ($what, $mode) = split (//, $ex[0]); + if ($what eq '+') { + if (defined($ex[1])) { push @{$::sc{$chan}{modes}}, $mode . ' ' . $ex[1]; } + else { push @{$::sc{$chan}{modes}}, $mode; } + } else { + my @modes = grep {!/^$mode/} @{$::sc{$chan}{modes}}; + $::sc{$chan}{modes} = \@modes; + } + if ( ($ex[0] eq '+r') && (! defined($::watchRegged{$chan})) ) { + $::watchRegged{$chan} = 1; + $conn->schedule(60*45, sub { checkRegged($conn, $chan); }); + } + } + } + $::log->logg($event); + } +} + +sub checkRegged +{ + my ($conn, $chan) = @_; + if (grep {/^r/} @{$::sc{$chan}{modes}} + and not ((defined($::channels->{channel}{$chan}{monitor})) and ($::channels->{channel}{$chan}{monitor} eq "no")) ) + { + my $tgt = $chan; + my $risk = "debug"; + my $hilite=ASM::Util->commaAndify(ASM::Util->getAlert($tgt, $risk, 'hilights')); + my $txtz ="\x03" . $::RCOLOR{$::RISKS{$risk}} . "\u$risk\x03 risk threat [\x02$chan\x02] - channel appears to still be +r after 45 minutes; ping $hilite !att-$chan-$risk"; + my @tgts = ASM::Util->getAlert($tgt, $risk, 'msgs'); + ASM::Util->sendLongMsg($conn, \@tgts, $txtz) + } + delete $::watchRegged{$chan}; +} + +sub on_banlist +{ + my ($conn, $event) = @_; + my ($me, $chan, $ban, $banner, $bantime) = @{$event->{args}}; + $::sc{lc $chan}{bans}{$ban} = { bannedBy => $banner, bannedOn => $bantime }; + if ($ban =~ /^\*\!\*\@((([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9]))$/) { + # ASM::Util->dprint("banlist hostname $ban $1", 'sync'); + my $ip = ASM::Util->getHostIP($1); + $::sc{lc $chan}{ipbans}{$ip} = { bannedBy => $banner, bannedOn => $bantime } if defined($ip); + } +} + +sub on_quietlist +{ + my ($conn, $event) = @_; + my ($me, $chan, $mode, $ban, $banner, $bantime) = @{$event->{args}}; + $::sc{lc $chan}{quiets}{$ban} = { bannedBy => $banner, bannedOn => $bantime }; + if ($ban =~ /^\*\!\*\@((([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9]))$/) { + # ASM::Util->dprint("quietlist hostname $ban $1", 'sync'); + my $ip = ASM::Util->getHostIP($1); + $::sc{lc $chan}{ipquiets}{$ip} = { bannedBy => $banner, bannedOn => $bantime } if defined($ip); + } +} + +sub on_channelurlis +{ + my ($conn, $event) = @_; + $::sc{lc $event->{args}->[1]}{url} = $event->{args}->[2]; +} + +sub on_ctcp +{ + my ($conn, $event) = @_; + my $acct = lc $::sn{lc $event->{nick}}->{account}; + ASM::Util->dprint(Dumper($event), 'ctcp'); + if (($event->{type} eq 'cdcc') && + (defined($::users->{person}->{$acct})) && + (defined($::users->{person}->{$acct}->{flags})) && + (grep {$_ eq 'c'} split('', $::users->{person}->{$acct}->{flags}))) { + ASM::Util->dprint(Dumper($event), 'dcc'); + my @spit = split(/ /, $event->{args}->[0]); + if (($spit[0] eq 'CHAT') && ($spit[1] eq 'CHAT')) { + $::chat = Net::IRC::DCC::CHAT->new($conn, 0, lc $event->{nick}, $spit[2], $spit[3]); + } + } else { + $::inspector->inspect($conn, $event); + } +} + +sub dcc_open +{ + my ($conn, $event) = @_; + $::dsock{lc $event->{nick}} = $event->{args}->[1]; +} + +sub on_ctcp_source +{ + my ($conn, $event) = @_; + $conn->ctcp_reply($event->{nick}, 'SOURCE https://gitlab.devlabs.linuxassist.net/asm/antispammeta/'); +} + +sub on_whoxreply +{ + my ($conn, $event) = @_; + return unless $event->{args}->[1] eq '314'; + my ($tgt, $magic, $chan, $user, $host, $nick, $account, $gecos) = @{$event->{args}}; + $nick = lc $nick; $chan = lc $chan; + if (!defined $::sn{lc $nick}) { + $::sn{$nick} = {}; + $::sn{$nick}->{mship} = [$chan]; + } else { + $::sn{$nick}->{mship} = [grep { lc $_ ne $chan } @{$::sn{$nick}->{mship}}]; + push @{$::sn{$nick}->{mship}}, $chan; + } + $::sn{$nick}->{gecos} = $gecos; + $::sn{$nick}->{user} = $user; + $::sn{$nick}->{host} = $host; + $::sn{$nick}->{account} = lc $account; +} + +sub on_whoxover +{ + my ($conn, $event) = @_; + my $chan = pop @::syncqueue; + $::synced{lc $event->{args}->[1]} = 1; + if (defined($chan) ){ + $conn->sl('who ' . $chan . ' %tcnuhra,314'); + $conn->sl('mode ' . $chan); + $conn->sl('mode ' . $chan . ' bq'); + } else { + my $size = `ps -p $$ h -o size`; + my $cputime = `ps -p $$ h -o time`; + chomp $size; chomp $cputime; + my ($tx, $rx); + if ($conn->{_tx}/1024 > 1024) { + $tx = sprintf("%.2fMB", $conn->{_tx}/(1024*1024)); + } else { + $tx = sprintf("%.2fKB", $conn->{_tx}/1024); + } + if ($conn->{_rx}/1024 > 1024) { + $rx = sprintf("%.2fMB", $conn->{_rx}/(1024*1024)); + } else { + $rx = sprintf("%.2fKB", $conn->{_rx}/1024); + } + $conn->privmsg($::settings->{masterchan}, "Finished syncing after " . (time - $::starttime) . " seconds. " . + "I'm tracking " . (scalar (keys %::sn)) . " nicks" . + " across " . (scalar (keys %::sc)) . " tracked channels." . + " I'm using " . $size . "KB of RAM" . + ", have used " . $cputime . " of CPU time" . + ", have sent $tx of data, and received $rx of data."); + my %x = (); + foreach my $c (@{$::settings->{autojoins}}) { $x{$c} = 1; } + foreach my $cx (keys %::sc) { delete $x{$cx}; } + if (scalar (keys %x)) { + $conn->privmsg($::settings->{masterchan}, "Syncing appears to have failed for " . ASM::Util->commaAndify(keys %x)); + } + } +} + +sub on_whofuckedup +{ + my ($conn, $event) = @_; + ASM::Util->dprint('on_whofuckedup called!', 'sync'); + if ($event->{args}->[1] eq "STATS") { +#most likely this is getting called because we did stats p too often. +#unfortunately the server doesn't let us know what exactly we called stats for. +#anyways, we don't need to do anything for this + } else { #dunno why it got called, print the data and I'll add a handler for it. + ASM::Util->dprint(Dumper($event), 'sync'); + } +} + +sub on_bannedfromchan { + my ($conn, $event) = @_; + ASM::Util->dprint("I'm banned from " . $event->{args}->[1] . "... attempting to unban myself", 'startup'); + $conn->privmsg('ChanServ', "unban $event->{args}->[1]"); +} + +sub on_byechan { + my ($chan) = @_; + #TODO do del event stuff +} + +return 1; |
