First draft
This commit is contained in:
commit
9f47b659a4
1 changed files with 213 additions and 0 deletions
213
ircbot.pl
Normal file
213
ircbot.pl
Normal file
|
@ -0,0 +1,213 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
######################################
|
||||
# Thomas Schwery <thomas@schwery.me> #
|
||||
######################################
|
||||
|
||||
use strict;
|
||||
use IO::Socket;
|
||||
use POSIX;
|
||||
use threads;
|
||||
use Switch;
|
||||
use DBI;
|
||||
|
||||
$/ ="\r\n";
|
||||
my $dbfile = "ircbot.db";
|
||||
|
||||
my ($server, $port, $channel, $nick) = @ARGV;
|
||||
|
||||
print "Server is " . $server . ":" . $port . "\n";
|
||||
print "Channel is " . $channel . "\n";
|
||||
print "Nickname is " . $nick . "\n";
|
||||
print "\n";
|
||||
print "Opening database " . $dbfile . "...\n";
|
||||
|
||||
our $db = DBI->connect("dbi:SQLite:dbname=" . $dbfile,"","");
|
||||
our %users;
|
||||
|
||||
$db->do("CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, last INTEGER DEFAULT 0, time INTEGER DEFAULT 0)");
|
||||
|
||||
$SIG{INT} = \&signal_handler_interrupt;
|
||||
|
||||
our $socket = new IO::Socket::INET( PeerAddr => $server,
|
||||
PeerPort => $port,
|
||||
Proto => 'tcp'
|
||||
);
|
||||
|
||||
die "Unable to open port: $! \n" unless $socket;
|
||||
|
||||
print $socket "USER " . $nick . " " . $nick . " " . $nick . " :lacbot\n";
|
||||
print $socket "NICK " . $nick . "\r\n";
|
||||
print $socket "JOIN " . $channel . "\r\n";
|
||||
|
||||
while(<$socket>) {
|
||||
chomp;
|
||||
if (m/:(.+?)!.*?\sPRIVMSG\s(.*?)\s:(.*)/) {
|
||||
my $user = $1;
|
||||
my $channel = $2;
|
||||
my $message = $3;
|
||||
|
||||
# we need to check for private conversations ...
|
||||
# if the command was sent privately, we respond privately
|
||||
if ($channel eq $nick) {
|
||||
$channel = $user;
|
||||
}
|
||||
|
||||
if ($message =~ m/^!(\w+)(\s.+)?\s*/){
|
||||
processMessage($user, $channel, $1, $2);
|
||||
}
|
||||
|
||||
} elsif (m/^PING\s+:(.*)/) {
|
||||
print $socket "PONG :" . $1 . "\r\n";
|
||||
} elsif (m/:(.+?)!(.+)@.*?\sPART\s(.*)/) {
|
||||
processLeave($1, $2, $3);
|
||||
} elsif (m/:(.+?)!(.+)@.*?\sJOIN\s:(.*)/) {
|
||||
processJoin($1, $2, $3);
|
||||
} else {
|
||||
print "Not matched: " . $_ . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub processStats {
|
||||
my ($channel) = @_;
|
||||
|
||||
my $stmt = $db->prepare("SELECT * FROM users ORDER BY time DESC;");
|
||||
$stmt->execute or die "Couldn't execute statement: " . $stmt->errstr;
|
||||
|
||||
my $stats_string = "User\tTime connected\n";
|
||||
|
||||
while (my @data = $stmt->fetchrow_array()) {
|
||||
my $user = $data[0];
|
||||
my $last_time = $data[1];
|
||||
my $total_time = $data[2];
|
||||
$stats_string .= $user . "\t" . special_format($total_time) . "\n";
|
||||
}
|
||||
|
||||
sendMessage($channel, $stats_string);
|
||||
|
||||
$stmt->finish;
|
||||
}
|
||||
|
||||
sub processLeave {
|
||||
my ($user_nick, $user, $channel) = @_;
|
||||
|
||||
my $date_string = strftime("%s", localtime);
|
||||
my $date_arrival = $users{$user};
|
||||
my $elapsed_time = $date_string - $date_arrival;
|
||||
|
||||
sendMessage($channel, $user_nick . " is leaving us after " . special_format($elapsed_time) . " ... How sad");
|
||||
|
||||
my $stmt_insert = $db->prepare("INSERT OR IGNORE INTO users ('id') VALUES ( ? )");
|
||||
my $stmt_update = $db->prepare("UPDATE users SET time = time + ?, last = ? WHERE id = ?");
|
||||
$stmt_insert->execute($user);
|
||||
$stmt_update->execute($elapsed_time, $date_string, $user);
|
||||
|
||||
$stmt_insert->finish;
|
||||
$stmt_update->finish;
|
||||
}
|
||||
|
||||
sub processJoin {
|
||||
my ($user_nick, $user, $channel) = @_;
|
||||
if ($user_nick eq $nick) {
|
||||
return;
|
||||
}
|
||||
|
||||
my $date_now = strftime("%s", localtime);
|
||||
$users{$user} = $date_now;
|
||||
|
||||
my $stmt = $db->prepare("SELECT last FROM users WHERE id = ?;");
|
||||
$stmt->execute($user) or die "Couldn't execute statement: " . $stmt->errstr;
|
||||
|
||||
my @date = $stmt->fetchrow_array();
|
||||
|
||||
if ($stmt->rows == 0) {
|
||||
sendMessage($channel, "A new user has entered this channel ... How strange ...");
|
||||
return;
|
||||
}
|
||||
|
||||
$stmt->finish;
|
||||
|
||||
my $date_string = @date[0];
|
||||
|
||||
my $seconds_elapsed = $date_now - $date_string;
|
||||
sendMessage($channel, "Hourra, our saviour, the great " . $user_nick .
|
||||
" is returned after " . special_format($seconds_elapsed) . " of absence!");
|
||||
|
||||
}
|
||||
|
||||
sub special_format {
|
||||
my ($seconds) = @_;
|
||||
my $format_string = "";
|
||||
if ($seconds > 3600 * 24) {
|
||||
$format_string .= int($seconds/(3600*24)) . " days ";
|
||||
$seconds %= (3600*24);
|
||||
}
|
||||
if ($seconds > 3600) {
|
||||
$format_string .= int($seconds/3600) . " hours ";
|
||||
$seconds %= 3600;
|
||||
}
|
||||
|
||||
if ($seconds > 60) {
|
||||
$format_string .= int($seconds/60) . " minutes ";
|
||||
$seconds %= 60;
|
||||
}
|
||||
|
||||
if (length($format_string) > 0) {
|
||||
$format_string .= "and ";
|
||||
}
|
||||
|
||||
return $format_string . $seconds . " seconds";
|
||||
}
|
||||
|
||||
sub processMessage {
|
||||
my ($user, $chan, $command, $parameters) = @_;
|
||||
chomp $parameters;
|
||||
|
||||
switch ($command) {
|
||||
case "echo" { sendMessage($chan, $parameters); }
|
||||
case "private" { sendMessage($user, $parameters); }
|
||||
case "fish" {
|
||||
if (length $parameters > 0) {
|
||||
$parameters =~ s/^\s+//;
|
||||
$parameters =~ s/\s+.*$//;
|
||||
if ($parameters eq $nick) {
|
||||
$parameters = $user;
|
||||
}
|
||||
sendAction($chan, "slaps " . $parameters . " with a wet sloppy tuna fish.");
|
||||
sleep 2;
|
||||
sendMessage($chan, "take that bitch");
|
||||
}
|
||||
}
|
||||
case "sandwich" { sendAction($chan, "prepares a yummi sandwich for " . $user); }
|
||||
case "help" {
|
||||
sendMessage($chan, "I cannot help you with your pathetic, meaningless life ...");
|
||||
sendMessage($chan, "All I can do is repeat (!echo), make a sandwich (!sandwich), slap someone (!fish) and listen patiently.");
|
||||
}
|
||||
case "stats" { processStats($chan); }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub sendAction {
|
||||
my ($channel, $message) = @_;
|
||||
print $socket "PRIVMSG " . $channel ." :\x01ACTION " . $message . "\x01\r\n";
|
||||
print "PRIVMSG " . $channel ." :\x01ACTION " . $message . "\x01\r\n";
|
||||
}
|
||||
|
||||
sub sendMessage {
|
||||
my ($channel, $message) = @_;
|
||||
print $socket "PRIVMSG " . $channel . " :" . $message . "\n";
|
||||
print "PRIVMSG " . $channel . " :" . $message . "\n";
|
||||
}
|
||||
|
||||
sub signal_handler_interrupt {
|
||||
print "ctrl-c, exiting...\n";
|
||||
|
||||
print $socket "PRIVMSG " . $channel . " :I loved chatting with you but I " .
|
||||
"really have to go !\r\n";
|
||||
|
||||
print $socket "QUIT " . $channel . "\n";
|
||||
$socket->shutdown(2);
|
||||
$socket->close();
|
||||
exit 0;
|
||||
}
|
Reference in a new issue