huhu/bin/ircbot.pl

262 lines
7.1 KiB
Perl
Raw Normal View History

#!/usr/bin/perl -sw
######################################################################
#
# $Id: ircbot.pl 266 2010-05-18 15:14:08Z alba $
#
# Copyright 2009 Roman Racine
# Copyright 2010 Alexander Bartolich
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
######################################################################
use strict;
use warnings;
use Carp qw(confess);
use Data::Dumper;
use Net::IRC();
use MOD::DBIUtilsPublic();
use MOD::Utils();
use MOD::Displaylib();
use MOD::NotificationSocket();
######################################################################
use constant DEBUG_TO_IRC => 0;
use constant MIN_TIME_BETWEEN_QUERIES => 5;
use constant MAX_TIME_BETWEEN_QUERIES => 30;
######################################################################
my Net::IRC $irc;
my Net::IRC::Connection $conn;
my MOD::DBIUtilsPublic $db;
my MOD::Displaylib $display;
my $channel;
my $last = 'none';
my $pending = 'no';
my $last_query_time = 0;
######################################################################
sub on_connect
######################################################################
{
my $self = shift;
$self->join($channel);
$conn->privmsg($channel,'*huhu*');
check_for_new(1);
}
######################################################################
sub alarm_handler
######################################################################
{
check_for_new(1);
alarm(MAX_TIME_BETWEEN_QUERIES);
}
######################################################################
sub on_public
######################################################################
{
my ($self, $event) = @_;
my $msg = ($event->args)[0];
if ($msg eq '!pending') {
eval { print_pending(1); };
warn $@ if ($@);
}
}
######################################################################
sub on_disconnect
######################################################################
{
my ($self, $event) = @_;
while (1) {
eval {
$self->connect();
}; if ($@) {
sleep 60;
} else {
last;
}
}
}
######################################################################
sub do_connect($$)
######################################################################
{
my $config = shift || confess;
my Net::IRC $irc = shift || confess;
my $nick = $config->{'ircbot_nick'};
my $realname = $config->{'ircbot_realname'};
my $username = $config->{'ircbot_username'};
my $server = $config->{'ircbot_server'};
my $port = $config->{'ircbot_port'};
my $conn = $irc->newconn(
Nick => $nick,
Server => $server,
Port => $port,
Ircname => $realname,
);
confess if (!defined($conn));
$conn->add_global_handler('376', \&on_connect);
$conn->add_global_handler('public', \&on_public);
$conn->add_global_handler('disconnect', \&on_disconnect);
return $conn;
}
######################################################################
sub on_socket_read($)
######################################################################
{
my $read_socket = shift || confess;
my $buffer;
my $rc = sysread($read_socket, $buffer, 512);
if (!defined($rc))
{
if (DEBUG_TO_IRC) { $conn->privmsg($channel, "on_socket_read $!"); }
return;
}
if ($rc == 0)
{
if (DEBUG_TO_IRC) { $conn->privmsg($channel, 'on_socket_read close'); }
# Do not call close($read_socket), this will hang the process.
# Socket is automatically closed when the last reference is freed.
$irc->removefh($read_socket) || confess;
return;
}
$buffer =~ s/\s+$//;
$conn->privmsg($channel, "sysread=$rc [$buffer]");
if ($last_query_time + MIN_TIME_BETWEEN_QUERIES < time())
{
check_for_new(0);
}
}
######################################################################
sub on_socket_accept($)
######################################################################
{
my $accept_socket = shift || confess;
if (DEBUG_TO_IRC)
{
$conn->privmsg($channel, 'on_socket_accept');
}
my $new_socket;
accept($new_socket, $accept_socket) || die "accept: $!";
defined($new_socket) || die 'defined($new_socket)';
$irc->addfh($new_socket, \&on_socket_read, 'r') || die "addfh: $!";
}
######################################################################
sub add_notify_sock($$)
######################################################################
{
my $config = shift || confess;
my Net::IRC $irc = shift || confess;
my $fh = MOD::NotificationSocket::socket_create_listening($config);
if ($fh) { $irc->addfh($fh, \&on_socket_accept, 'r'); }
}
######################################################################
sub print_pending($)
######################################################################
{
my $verbose = shift;
my $result = eval
{
my @overview = qw(Sender Subject Datum);
$db->displayrange('pending', 0, 10, \@overview);
};
if ($@) { warn $@; return; }
$last_query_time = time();
my $ref;
my $count = 0;
while ($ref = $result->fetchrow_arrayref) {
my @columns = @{$ref};
my ($from,$subject,$date) = ($display->decode_line($columns[0]),$display->decode_line($columns[1]),
$columns[2]);
$conn->privmsg($channel,"$date; $from; $subject");
sleep 1;
$count++;
}
if (!$count && $verbose) {
$conn->privmsg($channel,"No postings pending");
}
}
######################################################################
sub check_for_new($)
######################################################################
{
my $verbose = shift;
my $result = eval
{
my @overview = qw(Id Sender Subject Datum);
$db->displayrange('pending', 0, 1, \@overview);
};
if ($@) { warn $@; return; }
$last_query_time = time();
my $ref;
if ($ref = $result->fetchrow_arrayref) {
my @result = @{$ref};
if ($last eq 'none' or $last < $result[0]) {
my ($from,$subject,$date) = ($display->decode_line($result[1]),$display->decode_line($result[2]),
$result[3]);
$conn->privmsg($channel,"New posting: $date; $from; $subject");
$pending = 'yes';
$last = $result[0];
}
} elsif ($pending eq 'yes') {
$conn->privmsg($channel,"No pending postings any more.");
$pending = 'no';
}
}
######################################################################
# main
######################################################################
if ($::pidfile)
{
my $file;
if (open($file, '>', $::pidfile))
{ print $file $$, "\n"; }
else
{ warn "Can't open $::pidfile for writing: $!"; }
}
die "Missing parameter '-config'" unless($::config);
my %config = MOD::Utils::read_private_config($::config);
$channel = $config{'ircbot_channel'} || die;
$db = MOD::DBIUtilsPublic->new(\%config);
$display = MOD::Displaylib->new(\%config,0);
$irc = new Net::IRC;
add_notify_sock(\%config, $irc);
$conn = do_connect(\%config, $irc);
$SIG{'ALRM'} = \&alarm_handler;
alarm(MAX_TIME_BETWEEN_QUERIES);
$irc->start;