diff --git a/PBot/BanTracker.pm b/PBot/BanTracker.pm new file mode 100644 index 00000000..c931f669 --- /dev/null +++ b/PBot/BanTracker.pm @@ -0,0 +1,91 @@ +# 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 vars qw($VERSION); +$VERSION = $PBot::PBot::VERSION; + +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) = @_; + + my $pbot = delete $conf{pbot} // Carp::croak("Missing pbot reference to BanTracker"); + $self->{pbot} = $pbot; + + $self->{banlist} = {}; + + $pbot->commands->register(sub { return $self->dumpbans(@_) }, "dumpbans", 60); +} + +sub dumpbans { + my ($self, $from, $nick, $user, $host, $arguments) = @_; + + my $bans = Dumper($self->{banlist}); + return $bans; +} + +sub get_banlist { + my ($self, $conn, $event) = @_; + my $channel = lc $event->{args}[1]; + + delete $self->{banlist}->{$channel}; + + $self->{pbot}->logger->log("Retrieving banlist for $channel.\n"); + $conn->sl("mode $channel +b"); +} + +sub on_banlistentry { + my ($self, $conn, $event) = @_; + my $channel = lc $event->{args}[1]; + my $target = lc $event->{args}[2]; + my $source = lc $event->{args}[3]; + my $timestamp = $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}->{$target} = [ $source, $timestamp ]; +} + +sub track_mode { + my $self = shift; + my ($source, $mode, $target, $channel) = @_; + + if($mode eq "+b") { + $self->{pbot}->logger->log("ban-tracker: $target banned by $source in $channel.\n"); + $self->{banlist}->{$channel}->{$target} = [ $source, gettimeofday ]; + } + elsif($mode eq "-b") { + $self->{pbot}->logger->log("ban-tracker: $target unbanned by $source in $channel.\n"); + delete $self->{banlist}->{$channel}->{$target}; + } else { + $self->{pbot}->logger->log("BanTracker: Unknown mode '$mode'\n"); + } +} + +1; diff --git a/PBot/IRCHandlers.pm b/PBot/IRCHandlers.pm index 7d45d2b9..f956ea3c 100644 --- a/PBot/IRCHandlers.pm +++ b/PBot/IRCHandlers.pm @@ -115,43 +115,59 @@ sub on_action { sub on_mode { my ($self, $conn, $event) = @_; - my ($nick, $host) = ($event->nick, $event->host); + my ($nick, $user, $host) = ($event->nick, $event->user, $event->host); my $mode = $event->{args}[0]; my $target = $event->{args}[1]; my $channel = $event->{to}[0]; $channel = lc $channel; - $self->{pbot}->logger->log("Got mode: nick: $nick, host: $host, mode: $mode, target: " . (defined $target ? $target : "") . ", channel: $channel\n"); + $self->{pbot}->logger->log("Got mode: source: $nick!$user\@$host, mode: $mode, target: " . (defined $target ? $target : "(undef)") . ", channel: $channel\n"); + + if($mode eq "-b" or $mode eq "+b") { + $self->{pbot}->bantracker->track_mode("$nick!$user\@$host", $mode, $target, $channel); + } if(defined $target && $target eq $self->{pbot}->botnick) { # bot targeted if($mode eq "+o") { $self->{pbot}->logger->log("$nick opped me in $channel\n"); + if(exists $self->{pbot}->chanops->{is_opped}->{$channel}) { $self->{pbot}->logger->log("erm, I was already opped?\n"); } + $self->{pbot}->chanops->{is_opped}->{$channel}{timeout} = gettimeofday + 300; # 5 minutes $self->{pbot}->chanops->perform_op_commands(); - } elsif($mode eq "-o") { + } + elsif($mode eq "-o") { $self->{pbot}->logger->log("$nick removed my ops in $channel\n"); + if(not exists $self->{pbot}->chanops->{is_opped}->{$channel}) { $self->{pbot}->logger->log("warning: erm, I wasn't opped?\n"); } + delete $self->{pbot}->chanops->{is_opped}->{$channel}; + } + elsif($mode eq "+b") { + $self->{pbot}->logger->log("Got banned in $channel, attempting unban."); + $conn->privmsg("chanserv", "unban $channel"); } - } else { # bot not targeted + } + else { # bot not targeted if($mode eq "+b") { if($nick eq "ChanServ") { $self->{pbot}->chanops->{unban_timeout}->hash->{$target}{timeout} = gettimeofday + 3600 * 2; # 2 hours $self->{pbot}->chanops->{unban_timeout}->hash->{$target}{channel} = $channel; $self->{pbot}->chanops->{unban_timeout}->save_hash(); } - } elsif($mode eq "+e" && $channel eq $self->{pbot}->botnick) { + } + elsif($mode eq "+e" && $channel eq $self->{pbot}->botnick) { foreach my $chan (keys %{ $self->{pbot}->channels->channels->hash }) { if($self->channels->channels->hash->{$chan}{enabled}) { $self->{pbot}->logger->log("Joining channel: $chan\n"); $self->{pbot}->conn->join($chan); } } + $self->{pbot}->{joined_channels} = 1; } } diff --git a/PBot/PBot.pm b/PBot/PBot.pm index 0741ad8d..f105d405 100644 --- a/PBot/PBot.pm +++ b/PBot/PBot.pm @@ -27,6 +27,8 @@ use PBot::IRC; use PBot::IRCHandlers; use PBot::Channels; +use PBot::BanTracker; + use PBot::LagChecker; use PBot::AntiFlood; @@ -115,6 +117,8 @@ sub initialize { $self->factoids->load_factoids() if defined $factoids_file; $self->factoids->add_factoid('text', '.*', $self->{botnick}, 'version', "/say $VERSION"); + $self->{bantracker} = PBot::BanTracker->new(pbot => $self); + $self->{lagchecker} = PBot::LagChecker->new(pbot => $self); $self->{antiflood} = PBot::AntiFlood->new(pbot => $self); @@ -177,19 +181,21 @@ sub connect { $self->{connected} = 1; #set up default handlers for the IRC engine - $self->conn->add_handler([ 251,252,253,254,302,255 ], sub { $self->irchandlers->on_init(@_) }); - $self->conn->add_handler(376 , sub { $self->irchandlers->on_connect(@_) }); - $self->conn->add_handler('disconnect' , sub { $self->irchandlers->on_disconnect(@_) }); - $self->conn->add_handler('notice' , sub { $self->irchandlers->on_notice(@_) }); - $self->conn->add_handler('caction' , sub { $self->irchandlers->on_action(@_) }); - $self->conn->add_handler('public' , sub { $self->irchandlers->on_public(@_) }); - $self->conn->add_handler('msg' , sub { $self->irchandlers->on_msg(@_) }); - $self->conn->add_handler('mode' , sub { $self->irchandlers->on_mode(@_) }); - $self->conn->add_handler('part' , sub { $self->irchandlers->on_departure(@_) }); - $self->conn->add_handler('join' , sub { $self->irchandlers->on_join(@_) }); - $self->conn->add_handler('quit' , sub { $self->irchandlers->on_departure(@_) }); - $self->conn->add_handler('pong' , sub { $self->lagchecker->on_pong(@_) }); - $self->conn->add_handler('whoisaccount' , sub { $self->antiflood->on_whoisaccount(@_) }); + $self->conn->add_handler([ 251,252,253,254,302,255 ], sub { $self->irchandlers->on_init(@_) }); + $self->conn->add_handler(376 , sub { $self->irchandlers->on_connect(@_) }); + $self->conn->add_handler('disconnect' , sub { $self->irchandlers->on_disconnect(@_) }); + $self->conn->add_handler('notice' , sub { $self->irchandlers->on_notice(@_) }); + $self->conn->add_handler('caction' , sub { $self->irchandlers->on_action(@_) }); + $self->conn->add_handler('public' , sub { $self->irchandlers->on_public(@_) }); + $self->conn->add_handler('msg' , sub { $self->irchandlers->on_msg(@_) }); + $self->conn->add_handler('mode' , sub { $self->irchandlers->on_mode(@_) }); + $self->conn->add_handler('part' , sub { $self->irchandlers->on_departure(@_) }); + $self->conn->add_handler('join' , sub { $self->irchandlers->on_join(@_) }); + $self->conn->add_handler('quit' , sub { $self->irchandlers->on_departure(@_) }); + $self->conn->add_handler('pong' , sub { $self->lagchecker->on_pong(@_) }); + $self->conn->add_handler('whoisaccount' , sub { $self->antiflood->on_whoisaccount(@_) }); + $self->conn->add_handler('banlist' , sub { $self->bantracker->on_banlistentry(@_) }); + $self->conn->add_handler('endofnames' , sub { $self->bantracker->get_banlist(@_) }); } #main loop @@ -331,6 +337,12 @@ sub ignorelist { return $self->{ignorelist}; } +sub bantracker { + my $self = shift; + if(@_) { $self->{bantracker} = shift; } + return $self->{bantracker}; +} + sub lagchecker { my $self = shift; if(@_) { $self->{lagchecker} = shift; } diff --git a/PBot/VERSION.pm b/PBot/VERSION.pm index 564b24e9..14543569 100644 --- a/PBot/VERSION.pm +++ b/PBot/VERSION.pm @@ -13,8 +13,8 @@ use warnings; # These are set automatically by the build/commit script use constant { BUILD_NAME => "PBot", - BUILD_REVISION => 310, - BUILD_DATE => "2011-02-11", + BUILD_REVISION => 311, + BUILD_DATE => "2011-02-12", }; 1;