mirror of
https://github.com/pragma-/pbot.git
synced 2024-11-27 06:19:25 +01:00
d1e7abc175
to register handlers to listen for events. Update IRCHandlers module to use new event dispatcher to dispatch irc.events. Update several modules to register with dispatcher to listen for irc.events. Improve handling of reconnection upon unexpected disconnection. Todo: update more things to use new event dispatcher logic.
163 lines
5.2 KiB
Perl
163 lines
5.2 KiB
Perl
# File: BanTracker.pm
|
|
# Author: pragma_
|
|
#
|
|
# Purpose: Populates and maintains channel banlists by checking mode +b on
|
|
# joining channels and by tracking modes +b and -b in channels.
|
|
#
|
|
# Does NOT do banning or unbanning.
|
|
|
|
package PBot::BanTracker;
|
|
|
|
use warnings;
|
|
use strict;
|
|
|
|
use Time::HiRes qw/gettimeofday/;
|
|
use Time::Duration;
|
|
use Data::Dumper;
|
|
use Carp ();
|
|
|
|
sub new {
|
|
if(ref($_[1]) eq 'HASH') {
|
|
Carp::croak("Options to BanTracker should be key/value pairs, not hash reference");
|
|
}
|
|
|
|
my ($class, %conf) = @_;
|
|
|
|
my $self = bless {}, $class;
|
|
$self->initialize(%conf);
|
|
return $self;
|
|
}
|
|
|
|
sub initialize {
|
|
my ($self, %conf) = @_;
|
|
|
|
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to BanTracker");
|
|
$self->{banlist} = {};
|
|
|
|
$self->{pbot}->{registry}->add_default('text', 'bantracker', 'chanserv_ban_timeout', '604800');
|
|
|
|
$self->{pbot}->{commands}->register(sub { $self->dumpbans(@_) }, "dumpbans", 60);
|
|
|
|
$self->{pbot}->{event_dispatcher}->register_handler('irc.endofnames', sub { $self->get_banlist(@_) });
|
|
$self->{pbot}->{event_dispatcher}->register_handler('irc.banlist', sub { $self->on_banlist_entry(@_) });
|
|
$self->{pbot}->{event_dispatcher}->register_handler('irc.quietlist', sub { $self->on_quietlist_entry(@_) });
|
|
}
|
|
|
|
sub dumpbans {
|
|
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
|
|
|
my $bans = Dumper($self->{banlist});
|
|
return $bans;
|
|
}
|
|
|
|
sub get_banlist {
|
|
my ($self, $event_type, $event) = @_;
|
|
my $channel = lc $event->{event}->{args}[1];
|
|
|
|
delete $self->{banlist}->{$channel};
|
|
|
|
$self->{pbot}->{logger}->log("Retrieving banlist for $channel.\n");
|
|
$event->{conn}->sl("mode $channel +b");
|
|
$event->{conn}->sl("mode $channel +q");
|
|
return 0;
|
|
}
|
|
|
|
sub on_banlist_entry {
|
|
my ($self, $event_type, $event) = @_;
|
|
my $channel = lc $event->{event}->{args}[1];
|
|
my $target = lc $event->{event}->{args}[2];
|
|
my $source = lc $event->{event}->{args}[3];
|
|
my $timestamp = $event->{event}->{args}[4];
|
|
|
|
my $ago = ago(gettimeofday - $timestamp);
|
|
|
|
$self->{pbot}->{logger}->log("ban-tracker: [banlist entry] $channel: $target banned by $source $ago.\n");
|
|
$self->{banlist}->{$channel}->{'+b'}->{$target} = [ $source, $timestamp ];
|
|
return 0;
|
|
}
|
|
|
|
sub on_quietlist_entry {
|
|
my ($self, $event_type, $event) = @_;
|
|
my $channel = lc $event->{event}->{args}[1];
|
|
my $target = lc $event->{event}->{args}[3];
|
|
my $source = lc $event->{event}->{args}[4];
|
|
my $timestamp = $event->{event}->{args}[5];
|
|
|
|
my $ago = ago(gettimeofday - $timestamp);
|
|
|
|
$self->{pbot}->{logger}->log("ban-tracker: [quietlist entry] $channel: $target quieted by $source $ago.\n");
|
|
$self->{banlist}->{$channel}->{'+q'}->{$target} = [ $source, $timestamp ];
|
|
return 0;
|
|
}
|
|
|
|
sub get_baninfo {
|
|
my ($self, $mask, $channel, $account) = @_;
|
|
my ($bans, $ban_account);
|
|
|
|
$account = undef if $account eq '-1';
|
|
$account = lc $account if defined $account;
|
|
|
|
$self->{pbot}->{logger}->log("[get-baninfo] Getting baninfo for $mask in $channel using account " . (defined $account ? $account : "[undefined]") . "\n");
|
|
|
|
foreach my $mode (keys %{ $self->{banlist}{$channel} }) {
|
|
foreach my $banmask (keys %{ $self->{banlist}{$channel}{$mode} }) {
|
|
if($banmask =~ m/^\$a:(.*)/) {
|
|
$ban_account = lc $1;
|
|
} else {
|
|
$ban_account = "";
|
|
}
|
|
|
|
my $banmask_key = $banmask;
|
|
$banmask = quotemeta $banmask;
|
|
$banmask =~ s/\\\*/.*?/g;
|
|
$banmask =~ s/\\\?/./g;
|
|
|
|
if((defined $account and $account eq $ban_account) or $mask =~ m/^$banmask$/i) {
|
|
if(not defined $bans) {
|
|
$bans = [];
|
|
}
|
|
|
|
my $baninfo = {};
|
|
$baninfo->{banmask} = $banmask_key;
|
|
$baninfo->{channel} = $channel;
|
|
$baninfo->{owner} = $self->{banlist}{$channel}{$mode}{$banmask_key}[0];
|
|
$baninfo->{when} = $self->{banlist}{$channel}{$mode}{$banmask_key}[1];
|
|
$baninfo->{type} = $mode;
|
|
$self->{pbot}->{logger}->log("get-baninfo: dump: " . Dumper($baninfo) . "\n");
|
|
|
|
push @$bans, $baninfo;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $bans;
|
|
}
|
|
|
|
sub track_mode {
|
|
my $self = shift;
|
|
my ($source, $mode, $target, $channel) = @_;
|
|
|
|
if($mode eq "+b" or $mode eq "+q") {
|
|
$self->{pbot}->{logger}->log("ban-tracker: $target " . ($mode eq '+b' ? 'banned' : 'quieted') . " by $source in $channel.\n");
|
|
$self->{banlist}->{$channel}->{$mode}->{$target} = [ $source, gettimeofday ];
|
|
$self->{pbot}->{antiflood}->devalidate_accounts($target, $channel);
|
|
}
|
|
elsif($mode eq "-b" or $mode eq "-q") {
|
|
$self->{pbot}->{logger}->log("ban-tracker: $target " . ($mode eq '-b' ? 'unbanned' : 'unquieted') . " by $source in $channel.\n");
|
|
delete $self->{banlist}->{$channel}->{$mode eq "-b" ? "+b" : "+q"}->{$target};
|
|
|
|
if($mode eq "-b") {
|
|
if($self->{pbot}->{chanops}->{unban_timeout}->find_index($channel, $target)) {
|
|
$self->{pbot}->{chanops}->{unban_timeout}->remove($channel, $target);
|
|
} elsif($self->{pbot}->{chanops}->{unban_timeout}->find_index($channel, "$target\$##stop_join_flood")) {
|
|
# freenode strips channel forwards from unban result if no ban exists with a channel forward
|
|
$self->{pbot}->{chanops}->{unban_timeout}->remove($channel, "$target\$##stop_join_flood");
|
|
}
|
|
}
|
|
} else {
|
|
$self->{pbot}->{logger}->log("BanTracker: Unknown mode '$mode'\n");
|
|
}
|
|
}
|
|
|
|
1;
|