261 lines
7.1 KiB
Perl
261 lines
7.1 KiB
Perl
#!/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;
|