#!/usr/bin/perl use strict; use POE; use POE::Component::IRC; use LWP::Simple; # Constants use constant ANSWER_QUESTIONS => 1; # or 0 to remain silent use constant DEBUG_MODE => 1; use constant PASSWORD => 'your_password_here'; use constant WORK_DIR => 'c:/projects/mnemo'; use constant TRIVIA_FILE => 'trivia.txt'; use constant LOG_FILE => 'log.txt'; use constant NICK => 'Mnemo'; use constant USERNAME => 'Mnemo'; use constant IRCNAME => "I'm a fast learner."; use constant DEFAULT_SERVER => 'slimey.uk.eu.dal.net'; use constant PORT => 6667; use constant MAX_MESSAGE_LENGTH => 400; # Global variables my (@chans, @owners, $server, %answer, $lastQuestion); # Subroutines sub _start { my $kernel=$_[KERNEL]; writeLog ("Attempting connection to $server:@{[ PORT ]} ..."); $kernel->alias_set('mykernel'); $kernel->post('client', 'register', 'all'); $kernel->post('client', 'connect', { Debug => DEBUG_MODE, Nick => NICK, Server => $server, Port => PORT, Username => USERNAME, Ircname => IRCNAME, } ); $kernel->run; } sub _stop { my $kernel=$_[KERNEL]; writeLog ("Control session stopped."); print "Control session stopped.\n"; $kernel->post('client', 'quit'); # doesn't seem to work properly $kernel->alias_remove('mykernel'); } sub getResponse { my ($kernel, $message, $chan, $who, $owner)=@_; my $onChannel=0; if ($chan ne '') { $onChannel=1; } $message=~s/@{[ NICK ]},\s*/!/; # Trivia strings if ($message=~m/12(.*)/) { $lastQuestion=$1; # Say the answer if we know it if (ANSWER_QUESTIONS && defined $answer{$lastQuestion}) { my $ans=$answer{$lastQuestion}; $ans=lc($ans); if ($onChannel) { say ($kernel, $chan, $ans); } else { say ($kernel, $who, $ans); } } } elsif ($message=~m/The answer was 04(.*?)/) { if ($lastQuestion ne '' && !(defined $answer{$lastQuestion})) { $answer{$lastQuestion}=$1; # Append new question and answer to trivia file open (FILE, ">>@{[ WORK_DIR ]}/@{[ TRIVIA_FILE ]}") || die "$!"; print FILE "$lastQuestion\n"; print FILE "$answer{$lastQuestion}\n"; close FILE; } } # Owner commands if ($message eq '!die') { if ($owner) { $message=''; _stop(); } } elsif ($message=~/^!join/) { if ($owner) { $message=~s/^!join\s*//; $kernel->post('client', 'join', $message); $message=''; } } elsif ($message=~/^!me/) { $message=~s/^!me\s*//; if ($owner) { my @tokens=split(/ /,$message); # tokens[0] = nick or channel name $message=~s/^.*?\s//; # remove nick or channel name from message say ($kernel, $tokens[0], chr(1)."ACTION $message".chr(1)); $message=''; } } elsif ($message=~/^!part/) { if ($owner) { $message=~s/^!part\s*//; $kernel->post('client', 'part', $message); $message=''; } } elsif ($message=~/^!say/) { $message=~s/^!say\s*//; if ($owner) { my @tokens=split(/ /,$message); # tokens[0] = nick or channel name $message=~s/^.*?\s//; # remove nick or channel name from message say ($kernel, $tokens[0], $message); $message=''; } } else { $message=''; } return $message; } sub irc_001 { my $kernel=$_[KERNEL]; my $ch; # $kernel->post('client', 'mode', NICK, '+i'); for $ch (@chans) { $kernel->post('client', 'join', $ch); } } sub irc_join { my $kernel=$_[KERNEL]; my $who=$_[9]; my $chan=$_[10]; $who=~s/!.*//; $who=lc($who); writeLog ("$who has joined $chan"); } sub irc_msg { my $kernel=$_[KERNEL]; my $fullWho=$_[9]; my $message=$_[11]; my $who=$fullWho; $who=~s/!.*//; $who=lc($who); print "-> $who : $message\n"; writeLog ("-> $who : $message"); my $owner=isOwner($fullWho); if ($message eq "@{[ PASSWORD ]}") { if ($owner==1) { $message="You are already an owner."; } else { my $hostmask=$fullWho; $hostmask=~s/.*!//; push (@owners, $hostmask); $message="Added $hostmask to owners."; } } else { $message=getResponse($kernel, $message, '', $who, $owner); } if ($message ne '') { say ($kernel, $who, $message); } } sub irc_part { my $kernel=$_[KERNEL]; my $who=$_[9]; my $chan=$_[10]; $who=~s/!.*//; $who=lc($who); writeLog ("$who has left $chan"); } sub irc_public { my $kernel=$_[KERNEL]; my $who=$_[9]; my $chan=$_[10]; # This produces ARRAY garbage; somehow works below, but # we have no actual channel name to pass to getResponse my $message=$_[11]; my $owner=isOwner($who); $who=~s/!.*//; $who=lc($who); print "<$who> $message\n"; writeLog ("<$who> $message"); $message=getResponse($kernel, $message, $chan, $who, $owner); if ($message ne '') { say ($kernel, $chan, "$who: $message"); } } sub irc_quit { my $kernel=$_[KERNEL]; my $who=$_[9]; $who=~s/!.*//; $who=lc($who); writeLog ("$who has quit IRC"); } sub isOwner { my $nickHostmask=shift; my $hostmask=$nickHostmask; my $owner=0; $hostmask=~s/.*!//; # ditch the nickname part for my $o (@owners) { if ($hostmask eq $o) { $owner=1; last; } } return $owner; } sub writeLog { my $msg=shift; open (FILE, ">>@{[ WORK_DIR ]}/@{[ LOG_FILE ]}"); print FILE "$msg\n"; close FILE; } sub say { my $kernel=shift; my $who=shift; my $message=shift; if (length $message>MAX_MESSAGE_LENGTH) { $message=substr($message, 0, MAX_MESSAGE_LENGTH)."..."; } $kernel->post('client', 'privmsg', $who, $message); writeLog ("<@{[ NICK ]}> $message"); } # Main program starts here @chans=(); # initial channels to join; not updated while the bot is running @owners=(); # msg the bot with the password to be added to this list srand; $server=DEFAULT_SERVER; if ($#ARGV > 0) { # Command-line arguments: server #channel #channel #channel ... $server=$ARGV[0]; foreach my $arg (@ARGV) { if ($arg ne $ARGV[0]) { unshift @chans, $arg; } } } # Open and store current trivia open (FILE, "@{[ WORK_DIR ]}/@{[ TRIVIA_FILE ]}"); my @temp=; close FILE; for (@temp) { chomp; } for (my $i=0; $inew('client') or die "Couldn't create IRC client."; POE::Session->new('main' => [qw(_start _stop irc_001 irc_join irc_msg irc_part irc_public irc_quit)] ); $poe_kernel->run();