diff --git a/PBot/AntiFlood.pm b/PBot/AntiFlood.pm index a7c17eb3..30954347 100644 --- a/PBot/AntiFlood.pm +++ b/PBot/AntiFlood.pm @@ -77,6 +77,8 @@ sub initialize { $self->{pbot}->{commands}->register(sub { return $self->unbanme(@_) }, "unbanme", 0); $self->{pbot}->{commands}->register(sub { return $self->whitelist(@_) }, "whitelist", 10); + + $self->{pbot}->{event_dispatcher}->register_handler('irc.whoisaccount', sub { $self->on_whoisaccount(@_) }); } sub ban_whitelisted { @@ -735,12 +737,13 @@ sub check_nickserv_accounts { } sub on_whoisaccount { - my ($self, $conn, $event) = @_; - my $nick = $event->{args}[1]; - my $account = lc $event->{args}[2]; + my ($self, $event_type, $event) = @_; + my $nick = $event->{event}->{args}[1]; + my $account = lc $event->{event}->{args}[2]; $self->{pbot}->{logger}->log("$nick is using NickServ account [$account]\n"); $self->check_nickserv_accounts($nick, $account); + return 0; } sub adjust_offenses { diff --git a/PBot/BanTracker.pm b/PBot/BanTracker.pm index c8b26ee1..8ef78b99 100644 --- a/PBot/BanTracker.pm +++ b/PBot/BanTracker.pm @@ -31,14 +31,16 @@ sub new { sub initialize { my ($self, %conf) = @_; - my $pbot = delete $conf{pbot} // Carp::croak("Missing pbot reference to BanTracker"); - $self->{pbot} = $pbot; - + $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'); - $pbot->{commands}->register(sub { return $self->dumpbans(@_) }, "dumpbans", 60); + $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 { @@ -49,14 +51,43 @@ sub dumpbans { } sub get_banlist { - my ($self, $conn, $event) = @_; - my $channel = lc $event->{args}[1]; + 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"); - $conn->sl("mode $channel +b"); - $conn->sl("mode $channel +q"); + $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 { @@ -102,32 +133,6 @@ sub get_baninfo { return $bans; } -sub on_quietlist_entry { - my ($self, $conn, $event) = @_; - my $channel = lc $event->{args}[1]; - my $target = lc $event->{args}[3]; - my $source = lc $event->{args}[4]; - my $timestamp = $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 ]; -} - -sub on_banlist_entry { - 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}->{'+b'}->{$target} = [ $source, $timestamp ]; -} - sub track_mode { my $self = shift; my ($source, $mode, $target, $channel) = @_; diff --git a/PBot/EventDispatcher.pm b/PBot/EventDispatcher.pm new file mode 100644 index 00000000..d628b0d4 --- /dev/null +++ b/PBot/EventDispatcher.pm @@ -0,0 +1,48 @@ +package PBot::EventDispatcher; + +use warnings; +use strict; + +use IO::Select; +use Carp (); + +sub new { + Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH'; + 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 in " . __FILE__); + $self->{handlers} = { any => [] }; +} + +sub register_handler { + my ($self, $event_type, $sub) = @_; + + push @{$self->{handlers}->{$event_type}}, $sub; +} + +sub dispatch_event { + my ($self, $event_type, $event_data) = @_; + my $ret = undef; + + if (exists $self->{handlers}->{$event_type}) { + foreach my $handler (@{$self->{handlers}->{$event_type}}) { + $ret = $handler->($event_type, $event_data); + return $ret if $ret; + } + } + + foreach my $handler (@{$self->{handlers}->{any}}) { + $ret = $handler->($event_type, $event_data); + return $ret if $ret; + } + + return $ret; +} + +1; diff --git a/PBot/IRCHandlers.pm b/PBot/IRCHandlers.pm index 0e673d3c..bff0487b 100644 --- a/PBot/IRCHandlers.pm +++ b/PBot/IRCHandlers.pm @@ -14,7 +14,7 @@ use Data::Dumper; sub new { if(ref($_[1]) eq 'HASH') { - Carp::croak("Options to IRCHandlers should be key/value pairs, not hash reference"); + Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference"); } my ($class, %conf) = @_; @@ -27,34 +27,34 @@ sub new { sub initialize { my ($self, %conf) = @_; - my $pbot = delete $conf{pbot}; - Carp::croak("Missing pbot parameter to IRCHandlers") if not defined $pbot; + $self->{pbot} = delete $conf{pbot}; + Carp::croak("Missing pbot parameter to " . __FILE__) if not defined $self->{pbot}; - $self->{pbot} = $pbot; + $self->{pbot}->{event_dispatcher}->register_handler('irc.welcome', sub { $self->on_connect(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.disconnect', sub { $self->on_disconnect(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.motd', sub { $self->on_motd(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.notice', sub { $self->on_notice(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.caction', sub { $self->on_action(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.msg', sub { $self->on_msg(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.mode', sub { $self->on_mode(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.part', sub { $self->on_departure(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.join', sub { $self->on_join(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.kick', sub { $self->on_kick(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.quit', sub { $self->on_departure(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.nick', sub { $self->on_nickchange(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.bannickchange', sub { $self->on_bannickchange(@_) }); + $self->{pbot}->{event_dispatcher}->register_handler('irc.notregistered', sub { $self->on_notregistered(@_) }); } sub default_handler { my ($self, $conn, $event) = @_; - if ($self->{pbot}->{registry}->get_value('irc', 'log_default_handler')) { - my $dump = Dumper $event; - $self->{pbot}->{logger}->log($dump); - } -} - -sub on_connect { - my ($self, $conn) = @_; - $self->{pbot}->{logger}->log("Connected!\n"); - $conn->{connected} = 1; -} - -sub on_disconnect { - my ($self, $conn, $event) = @_; - $self->{pbot}->{logger}->log("Disconnected, attempting to reconnect...\n"); - $conn->connect(); - if(not $conn->connected) { - sleep(5); - $self->on_disconnect($self, $conn, $event); + if(not defined $self->{pbot}->{event_dispatcher}->dispatch_event("irc.$event->{type}", { conn => $conn, event => $event })) { + if ($self->{pbot}->{registry}->get_value('irc', 'log_default_handler')) { + my $dump = Dumper $event; + $self->{pbot}->{logger}->log($dump); + } } } @@ -65,76 +65,95 @@ sub on_init { $self->{pbot}->{logger}->log("*** @args\n"); } +sub on_connect { + my ($self, $event_type, $event) = @_; + $self->{pbot}->{logger}->log("Connected!\n"); + $event->{conn}->{connected} = 1; + return 0; +} + +sub on_disconnect { + my ($self, $event_type, $event) = @_; + $self->{pbot}->{logger}->log("Disconnected...\n"); + $self->{pbot}->{connected} = 0; + return 0; +} + sub on_motd { - my ($self, $conn, $event) = @_; + my ($self, $event_type, $event) = @_; if ($self->{pbot}->{registry}->get_value('irc', 'show_motd')) { - my $server = $event->{from}; - my $msg = $event->{args}[1]; + my $server = $event->{event}->{from}; + my $msg = $event->{event}->{args}[1]; $self->{pbot}->{logger}->log("MOTD from $server :: $msg\n"); } + return 0; } sub on_public { - my ($self, $conn, $event) = @_; + my ($self, $event_type, $event) = @_; - my $from = $event->{to}[0]; - my $nick = $event->nick; - my $user = $event->user; - my $host = $event->host; - my $text = $event->{args}[0]; + my $from = $event->{event}->{to}[0]; + my $nick = $event->{event}->nick; + my $user = $event->{event}->user; + my $host = $event->{event}->host; + my $text = $event->{event}->{args}[0]; $self->{pbot}->{interpreter}->process_line($from, $nick, $user, $host, $text); + return 0; } sub on_msg { - my ($self, $conn, $event) = @_; - my ($nick, $host) = ($event->nick, $event->host); - my $text = $event->{args}[0]; + my ($self, $event_type, $event) = @_; + my ($nick, $host) = ($event->{event}->nick, $event->{event}->host); + my $text = $event->{event}->{args}[0]; my $bot_trigger = $self->{pbot}->{registry}->get_value('general', 'trigger'); $text =~ s/^\Q$bot_trigger\E?(.*)/$bot_trigger$1/; - $event->{to}[0] = $nick; - $event->{args}[0] = $text; - $self->on_public($conn, $event); + $event->{event}->{to}[0] = $nick; + $event->{event}->{args}[0] = $text; + $self->on_public($event_type, $event); + return 0; } sub on_notice { - my ($self, $conn, $event) = @_; - my ($nick, $host) = ($event->nick, $event->host); - my $text = $event->{args}[0]; + my ($self, $event_type, $event) = @_; + my ($nick, $host) = ($event->{event}->nick, $event->{event}->host); + my $text = $event->{event}->{args}[0]; $self->{pbot}->{logger}->log("Received NOTICE from $nick $host '$text'\n"); - if($nick eq "NickServ" && $text =~ m/This nickname is registered/) { + if($nick eq 'NickServ' && $text =~ m/This nickname is registered/) { $self->{pbot}->{logger}->log("Identifying with NickServ . . .\n"); - $conn->privmsg("nickserv", "identify " . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); + $event->{conn}->privmsg("nickserv", "identify " . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); } - if($nick eq "NickServ" && $text =~ m/You are now identified/) { + if($nick eq 'NickServ' && $text =~ m/You are now identified/) { foreach my $chan (keys %{ $self->{pbot}->{channels}->{channels}->hash }) { if($self->{pbot}->{channels}->{channels}->hash->{$chan}{enabled}) { $self->{pbot}->{logger}->log("Joining channel: $chan\n"); - $conn->join($chan); + $event->{conn}->join($chan); } } $self->{pbot}->{joined_channels} = 1; } + return 0; } sub on_action { - my ($self, $conn, $event) = @_; + my ($self, $event_type, $event) = @_; - $event->{args}[0] = "/me " . $event->{args}[0]; + $event->{event}->{args}[0] = "/me " . $event->{event}->{args}[0]; - $self->on_public($conn, $event); + $self->on_public($event_type, $event); + return 0; } sub on_mode { - my ($self, $conn, $event) = @_; - my ($nick, $user, $host) = ($event->nick, $event->user, $event->host); - my $mode_string = $event->{args}[0]; - my $channel = $event->{to}[0]; + my ($self, $event_type, $event) = @_; + my ($nick, $user, $host) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host); + my $mode_string = $event->{event}->{args}[0]; + my $channel = $event->{event}->{to}[0]; $channel = lc $channel; my ($mode, $modifier); @@ -150,7 +169,7 @@ sub on_mode { } $mode = $modifier . $char; - $target = $event->{args}[++$i]; + $target = $event->{event}->{args}[++$i]; $self->{pbot}->{logger}->log("Got mode: source: $nick!$user\@$host, mode: $mode, target: " . (defined $target ? $target : "(undef)") . ", channel: $channel\n"); @@ -171,7 +190,7 @@ sub on_mode { } elsif($mode eq "+b") { $self->{pbot}->{logger}->log("Got banned in $channel, attempting unban."); - $conn->privmsg("chanserv", "unban $channel"); + $event->{conn}->privmsg("chanserv", "unban $channel"); } } else { # bot not targeted @@ -187,19 +206,19 @@ sub on_mode { 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); + $event->{conn}->join($chan); } } - $self->{pbot}->{joined_channels} = 1; } } } + return 0; } sub on_join { - my ($self, $conn, $event) = @_; - my ($nick, $user, $host, $channel) = ($event->nick, $event->user, $event->host, $event->to); + my ($self, $event_type, $event) = @_; + my ($nick, $user, $host, $channel) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host, $event->{event}->to); my $message_account = $self->{pbot}->{messagehistory}->get_message_account($nick, $user, $host); $self->{pbot}->{messagehistory}->add_message($message_account, "$nick!$user\@$host", $channel, "JOIN", $self->{pbot}->{messagehistory}->{MSG_JOIN}); @@ -207,11 +226,12 @@ sub on_join { $self->{pbot}->{registry}->get_value('antiflood', 'join_flood_threshold'), $self->{pbot}->{registry}->get_value('antiflood', 'join_flood_time_threshold'), $self->{pbot}->{messagehistory}->{MSG_JOIN}); + return 0; } sub on_kick { - my ($self, $conn, $event) = @_; - my ($nick, $user, $host, $target, $channel, $reason) = ($event->nick, $event->user, $event->host, $event->to, $event->{args}[0], $event->{args}[1]); + my ($self, $event_type, $event) = @_; + my ($nick, $user, $host, $target, $channel, $reason) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host, $event->{event}->to, $event->{event}->{args}[0], $event->{event}->{args}[1]); $self->{pbot}->{logger}->log("$nick!$user\@$host kicked $target from $channel ($reason)\n"); @@ -237,13 +257,14 @@ sub on_kick { my $text = "KICKED " . (defined $hostmask ? $hostmask : $target) . " from $channel ($reason)"; $self->{pbot}->{messagehistory}->add_message($message_account, "$nick!$user\@$host", $channel, $text, $self->{pbot}->{messagehistory}->{MSG_CHAT}); } + return 0; } sub on_departure { - my ($self, $conn, $event) = @_; - my ($nick, $user, $host, $channel, $args) = ($event->nick, $event->user, $event->host, $event->to, $event->args); + my ($self, $event_type, $event) = @_; + my ($nick, $user, $host, $channel, $args) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host, $event->{event}->to, $event->{event}->args); - my $text = uc $event->type; + my $text = uc $event->{event}->type; $text .= " $args"; my $message_account = $self->{pbot}->{messagehistory}->get_message_account($nick, $user, $host); @@ -270,31 +291,12 @@ sub on_departure { $self->{pbot}->{logger}->log("Logged out $nick.\n"); delete $admin->{loggedin}; } -} - -sub on_notregistered { - my ($self, $conn, $event) = @_; - my ($addr, $msg) = $event->args; - - $self->{pbot}->{logger}->log("Received NOTREGISTERED from $addr: $msg\n"); - $conn->privmsg("nickserv", "ghost " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); - $conn->privmsg("nickserv", "release " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); - $conn->privmsg("nickserv", "identify " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); -} - -sub on_bannickchange { - my ($self, $conn, $event) = @_; - my ($addr, $nick, $msg) = $event->args; - - $self->{pbot}->{logger}->log("Received BANNICKCHANGE from $addr: $nick ($msg)\n"); - $conn->privmsg("nickserv", "ghost " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); - $conn->privmsg("nickserv", "release " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); - $conn->privmsg("nickserv", "identify " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); + return 0; } sub on_nickchange { - my ($self, $conn, $event) = @_; - my ($nick, $user, $host, $newnick) = ($event->nick, $event->user, $event->host, $event->args); + my ($self, $event_type, $event) = @_; + my ($nick, $user, $host, $newnick) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host, $event->{event}->args); $self->{pbot}->{logger}->log("$nick!$user\@$host changed nick to $newnick\n"); @@ -314,6 +316,30 @@ sub on_nickchange { $self->{pbot}->{registry}->get_value('antiflood', 'nick_flood_threshold'), $self->{pbot}->{registry}->get_value('antiflood', 'nick_flood_time_threshold'), $self->{pbot}->{messagehistory}->{MSG_NICKCHANGE}); + return 0; +} + +# todo: fix the following two subroutines so they work properly (e.g., change nick to randomly generated nick and await responses) +sub on_notregistered { + my ($self, $event_type, $event) = @_; + my ($addr, $msg) = $event->{event}->args; + + $self->{pbot}->{logger}->log("Received NOTREGISTERED from $addr: $msg\n"); + $event->{conn}->privmsg("nickserv", "ghost " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); + $event->{conn}->privmsg("nickserv", "release " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); + $event->{conn}->privmsg("nickserv", "identify " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); + return 0; +} + +sub on_bannickchange { + my ($self, $event_type, $event) = @_; + my ($addr, $nick, $msg) = $event->{event}->args; + + $self->{pbot}->{logger}->log("Received BANNICKCHANGE from $addr: $nick ($msg)\n"); + $event->{conn}->privmsg("nickserv", "ghost " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); + $event->{conn}->privmsg("nickserv", "release " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); + $event->{conn}->privmsg("nickserv", "identify " . $self->{pbot}->{registry}->get_value('irc', 'botnick') . ' ' . $self->{pbot}->{registry}->get_value('irc', 'identify_password')); + return 0; } 1; diff --git a/PBot/IgnoreList.pm b/PBot/IgnoreList.pm index 86ddeb45..414bb4f4 100644 --- a/PBot/IgnoreList.pm +++ b/PBot/IgnoreList.pm @@ -148,6 +148,7 @@ sub check_ignore { } } +=cut if(exists $self->{ignore_flood_counter}->{$channel} and $self->{ignore_flood_counter}->{$channel} > 5) { $self->{commands}->ignore_user("", "floodcontrol", "", "", ".* $channel 300"); $self->{ignore_flood_counter}->{$channel} = 0; @@ -157,6 +158,7 @@ sub check_ignore { return 1; } } +=cut } foreach my $ignored (keys %{ $self->{ignore_list} }) { diff --git a/PBot/LagChecker.pm b/PBot/LagChecker.pm index e5833410..4d85b4e7 100644 --- a/PBot/LagChecker.pm +++ b/PBot/LagChecker.pm @@ -33,6 +33,12 @@ sub initialize { my $pbot = delete $conf{pbot} // Carp::croak("Missing pbot reference to LagChecker"); $self->{pbot} = $pbot; + $self->{lag_average} = undef; # average of entries in lag history, in seconds + $self->{lag_string} = undef; # string representation of lag history and lag average + $self->{lag_history} = []; # history of previous PING/PONG timings + $self->{pong_received} = undef; # tracks pong replies; undef if no ping sent; 0 if ping sent but no pong reply yet; 1 if ping/pong completed + $self->{ping_send_time} = undef; # when last ping was sent + # maximum number of lag history entries to retain $pbot->{registry}->add_default('text', 'lagchecker', 'lag_history_max', $conf{lag_history_max} // 3); # lagging is true if lag_average reaches or exceeds this threshold, in seconds @@ -42,12 +48,6 @@ sub initialize { $pbot->{registry}->add_trigger('lagchecker', 'lag_history_interval', sub { $self->lag_history_interval_trigger(@_) }); - $self->{lag_average} = undef; # average of entries in lag history, in seconds - $self->{lag_string} = undef; # string representation of lag history and lag average - $self->{lag_history} = []; # history of previous PING/PONG timings - $self->{pong_received} = undef; # tracks pong replies; undef if no ping sent; 0 if ping sent but no pong reply yet; 1 if ping/pong completed - $self->{ping_send_time} = undef; # when last ping was sent - $pbot->{timer}->register( sub { $self->send_ping }, $pbot->{registry}->get_value('lagchecker', 'lag_history_interval'), @@ -55,6 +55,8 @@ sub initialize { ); $pbot->{commands}->register(sub { return $self->lagcheck(@_) }, "lagcheck", 0); + + $self->{pbot}->{event_dispatcher}->register_handler('irc.pong', sub { $self->on_pong(@_) }); } sub lag_history_interval_trigger { @@ -104,6 +106,7 @@ sub on_pong { $self->{lag_average} = $lag_total / $len; $self->{lag_string} .= "; average: $self->{lag_average}"; + return 0; } sub lagging { diff --git a/PBot/PBot.pm b/PBot/PBot.pm index 11701d91..2e202b95 100644 --- a/PBot/PBot.pm +++ b/PBot/PBot.pm @@ -30,6 +30,7 @@ use PBot::Registry; use PBot::SelectHandler; use PBot::StdinReader; use PBot::IRC; +use PBot::EventDispatcher; use PBot::IRCHandlers; use PBot::Channels; use PBot::BanTracker; @@ -98,20 +99,21 @@ sub initialize { $self->{registry}->add_trigger('irc', 'botnick', sub { $self->change_botnick_trigger(@_) }); $self->{registry}->add_trigger('irc', 'debug', sub { $self->irc_debug_trigger(@_) }); - $self->{select_handler} = PBot::SelectHandler->new(pbot => $self, %conf); - $self->{stdin_reader} = PBot::StdinReader->new(pbot => $self, %conf); - $self->{admins} = PBot::BotAdmins->new(pbot => $self, filename => delete $conf{admins_file}, %conf); - $self->{bantracker} = PBot::BanTracker->new(pbot => $self, %conf); - $self->{lagchecker} = PBot::LagChecker->new(pbot => $self, %conf); - $self->{messagehistory} = PBot::MessageHistory->new(pbot => $self, filename => delete $conf{messagehistory_file}, %conf); - $self->{antiflood} = PBot::AntiFlood->new(pbot => $self, %conf); - $self->{ignorelist} = PBot::IgnoreList->new(pbot => $self, filename => delete $conf{ignorelist_file}, %conf); - $self->{irc} = PBot::IRC->new(); - $self->{irchandlers} = PBot::IRCHandlers->new(pbot => $self, %conf); - $self->{channels} = PBot::Channels->new(pbot => $self, filename => delete $conf{channels_file}, %conf); - $self->{chanops} = PBot::ChanOps->new(pbot => $self, %conf); + $self->{event_dispatcher} = PBot::EventDispatcher->new(pbot => $self, %conf); + $self->{select_handler} = PBot::SelectHandler->new(pbot => $self, %conf); + $self->{stdin_reader} = PBot::StdinReader->new(pbot => $self, %conf); + $self->{admins} = PBot::BotAdmins->new(pbot => $self, filename => delete $conf{admins_file}, %conf); + $self->{bantracker} = PBot::BanTracker->new(pbot => $self, %conf); + $self->{lagchecker} = PBot::LagChecker->new(pbot => $self, %conf); + $self->{messagehistory} = PBot::MessageHistory->new(pbot => $self, filename => delete $conf{messagehistory_file}, %conf); + $self->{antiflood} = PBot::AntiFlood->new(pbot => $self, %conf); + $self->{ignorelist} = PBot::IgnoreList->new(pbot => $self, filename => delete $conf{ignorelist_file}, %conf); + $self->{irc} = PBot::IRC->new(); + $self->{irchandlers} = PBot::IRCHandlers->new(pbot => $self, %conf); + $self->{channels} = PBot::Channels->new(pbot => $self, filename => delete $conf{channels_file}, %conf); + $self->{chanops} = PBot::ChanOps->new(pbot => $self, %conf); - $self->{interpreter} = PBot::Interpreter->new(pbot => $self, %conf); + $self->{interpreter} = PBot::Interpreter->new(pbot => $self, %conf); $self->{interpreter}->register(sub { return $self->{commands}->interpreter(@_); }); $self->{interpreter}->register(sub { return $self->{factoids}->interpreter(@_); }); @@ -156,43 +158,24 @@ sub connect { $self->{logger}->log("Connecting to $server ...\n"); - $self->{conn} = $self->{irc}->newconn( - Nick => $self->{registry}->get_value('irc', 'botnick'), - Username => $self->{registry}->get_value('irc', 'username'), - Ircname => $self->{registry}->get_value('irc', 'ircname'), - Server => $server, - SSL => $self->{registry}->get_value('irc', 'SSL'), - SSL_ca_file => $self->{registry}->get_value('irc', 'SSL_ca_file'), - SSL_ca_path => $self->{registry}->get_value('irc', 'SSL_ca_path'), - Port => $self->{registry}->get_value('irc', 'port')) - or Carp::croak "$0: Can't connect to IRC server.\n"; + while (not $self->{conn} = $self->{irc}->newconn( + Nick => $self->{registry}->get_value('irc', 'botnick'), + Username => $self->{registry}->get_value('irc', 'username'), + Ircname => $self->{registry}->get_value('irc', 'ircname'), + Server => $server, + SSL => $self->{registry}->get_value('irc', 'SSL'), + SSL_ca_file => $self->{registry}->get_value('irc', 'SSL_ca_file'), + SSL_ca_path => $self->{registry}->get_value('irc', 'SSL_ca_path'), + Port => $self->{registry}->get_value('irc', 'port'))) { + $self->{logger}->log("$0: Can't connect to IRC server. Retrying in 15 seconds...\n"); + sleep 15; + } $self->{connected} = 1; #set up handlers for the IRC engine $self->{conn}->add_default_handler(sub { $self->{irchandlers}->default_handler(@_) }, 1); - - $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('motd' , sub { $self->{irchandlers}->on_motd(@_) }); - $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('kick' , sub { $self->{irchandlers}->on_kick(@_) }); - $self->{conn}->add_handler('quit' , sub { $self->{irchandlers}->on_departure(@_) }); - $self->{conn}->add_handler('nick' , sub { $self->{irchandlers}->on_nickchange(@_) }); - $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_banlist_entry(@_) }); - $self->{conn}->add_handler('endofnames' , sub { $self->{bantracker}->get_banlist(@_) }); - $self->{conn}->add_handler(728 , sub { $self->{bantracker}->on_quietlist_entry(@_) }); - $self->{conn}->add_handler('bannickchange' , sub { $self->{irchandlers}->on_bannickchange(@_) }); - $self->{conn}->add_handler('notregistered' , sub { $self->{irchandlers}->on_notregistered(@_) }); + $self->{conn}->add_handler([ 251,252,253,254,255,302 ], sub { $self->{irchandlers}->on_init(@_) }); # ignore these events $self->{conn}->add_handler(['whoisuser', @@ -202,6 +185,7 @@ sub connect { 'whoisidle', 'endofwhois', 'motdstart', + 'endofmotd', 'away', 'endofbanlist'], sub {}); } @@ -215,8 +199,10 @@ sub do_one_loop { sub start { my $self = shift; - $self->connect() if not $self->{connected}; - while(1) { $self->do_one_loop(); } + while(1) { + $self->connect() if not $self->{connected}; + $self->do_one_loop() if $self->{connected}; + } } sub register_signal_handlers { diff --git a/PBot/VERSION.pm b/PBot/VERSION.pm index 1def2a4d..2a47eb9c 100644 --- a/PBot/VERSION.pm +++ b/PBot/VERSION.pm @@ -13,7 +13,7 @@ use warnings; # These are set automatically by the build/commit script use constant { BUILD_NAME => "PBot", - BUILD_REVISION => 798, + BUILD_REVISION => 799, BUILD_DATE => "2014-10-31", };