Bot.pm.v2
package Bot;
use strict;
use warnings;
use Module::Reload;
use POE qw(
Component::Client::DNS
Component::Client::TCP
);
### direct subroutine: setup extra stuff
sub new {
my($class, $kernel, $heap) = @_;
$class = ref $class if ref $class;
my $self = {
Kernel => $kernel,
Heap => $heap,
};
bless $self, $class;
### register "dns_resolve' state
$kernel->state('dns_resolve', 'Bot');
### create DNS resolver
$heap->{resolver} ||= POE::Component::Client::DNS->spawn();
return $self;
}
### method invoked on Bot object
sub handle {
my($self, $dest, $prefix, $what) = @_;
my $heap = $self->{Heap};
### get list of valid Net::DNS::RR types
my @rr = keys %Net::DNS::RR::RR;
my $rr_regex = join("|", @rr);
my $response;
if ( $what =~ /^reload$/i ) {
Module::Reload->check;
$response = "OK, I reloaded";
$self = $self->new( $self->{Kernel}, $heap );
}
elsif ( $what =~ /^($rr_regex)\s+([\w.-]+)\?\s*$/ ) {
$heap->{resolver}->resolve(
type => $1,
host => $2,
event => 'dns_resolve',
context => { Dest => $dest, Prefix => $prefix },
timeout => 15,
);
}
elsif ( $what =~ /^nettime\s+([\w.-]+)\s*$/ ) {
my $remotehost = $1;
POE::Component::Client::TCP->new(
RemoteAddress => $remotehost,
RemotePort => 'time',
Filter => 'Bot::Filter::Nettime',
ServerInput => sub {
my($time) = $_[ARG0];
my $response = "According to $remotehost, it is " .
localtime($time);
$heap->{Irc}->yield( privmsg => $dest, "$prefix$response" );
},
);
}
else {
$response = "are you talking to me? $what?";
}
$heap->{Irc}->yield( privmsg => $dest, "$prefix$response" )
if defined $response;
}
### a POE state: called when a question from irc is resolved
sub dns_resolve {
my($kernel, $heap, $response) = @_[KERNEL, HEAP, ARG0];
my $context = $response->{context};
my $dest = $context->{Dest};
my $prefix = $context->{Prefix};
my $irc = $heap->{Irc};
my $type = $response->{type};
my $host = $response->{host};
if ( my $pkt = $response->{response} ) {
my $rcode = $pkt->header->rcode;
my $aa = $pkt->header->aa;
$irc->yield( privmsg => $dest, $prefix .
"$type record for $host: got " .
($aa ? "" : "non-") . "authoritive answer" .
( $rcode eq "NOERROR" ? "" : ", $rcode"));
my @answ = $pkt->answer();
for my $a ( @answ ) {
my $astr = $a->string();
$astr =~ s/;.*$/ /gm;
$astr =~ s/[\t\n]/ /g;
$irc->yield( privmsg => $dest, $prefix . $astr );
}
}
else {
my $err = $response->{error};
$irc->yield( privmsg => $dest, $prefix .
"Cannot find $type records for $host: $err" );
}
}
package Bot::Filter::Nettime;
use POE::Filter;
our @ISA = 'POE::Filter';
sub new {
my $class = shift;
my $self = { buffer => '' };
bless $self, $class;
}
sub get {
my($self, $data) = @_;
for my $d ( @$data ) {
$self->{buffer} .= $d;
}
my @ret;
while ( length $self->{buffer} >= 4 ) {
my $nettime_pkt = substr($self->{buffer}, 0, 4, '');
### rfc868 (nettime) returns seconds since 1-jan-1900.
### so we need to substract number of seconds before unix epoch,
### 1-jan-1970: 70 years, and 17 leap days, or: (70*365+17)*86400
push @ret, unpack("N", $nettime_pkt) - (70*365+17)*86400;
}
return \@ret;
}
1;