#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
## globals
use vars qw/@buckleyisms $sock %CONF %results $hyp/;
$|=1;
$CONF{file} = shift;
if (not $CONF{file}) {
$CONF{file}=$0;
$CONF{file}=~s/\.pl$/\.conf/i;
}
&readconf();
$sock=&connect($CONF{server},$CONF{port});
&error("socket: $! $@") if ($sock eq "");
&send("NICK $CONF{nick}");
&send("USER $CONF{ident} 0 * :$CONF{gecos}");
&forks() if (not $CONF{debug});;
my ($auth, @buffer) ;
$auth ="";
@buffer=();
my ($from,$command,@data);
#list of friends (people who get buttified more often) and enemies (people who dont get butted.)
my (%friends, %enemies);
#frequency that normal people and friends get butted
my ($normalfrequency, $friendfrequency);
#last thing said by someone in the channel
my (@previousdata);
my ($previouschannel);
my (@channels);
my ($starttime);
my (%linestotal);
my (%timeoflastbutting);
my ($fullstring);
my $graceperiod = 240;
#pre-setting frequencies
$friendfrequency = 23;
$normalfrequency = 37;
#remove whitespace!
$CONF{channel} =~ s/\s+//;
#add friends from conf file
if (exists $CONF{friends})
{
@_ = split(/s*,s*/,$CONF{friends});
foreach $_ (@_)
{
$friends{$_} = 1;
}
}
#add enemies from conf file
if (exists $CONF{enemies})
{
@_ = split(/s*,s*/,$CONF{enemies});
foreach $_ (@_)
{
$enemies{$_} = 1;
}
}
getbuckleyisms();
#main execution loop
while (1) {
#check for errors.
&error("main: $! $@") if (($! ne "" ) || ($@ ne ""));
#Otherwise move through the buffer.
@buffer=split(/\n/,&gets());
foreach my $thing (@buffer) {
print "$thing\n";
$fullstring = $thing;
#putting the message from $thing into a full string to preserve the whitespace, just in case.
$fullstring =~ s/(.*?)\s+(.*?)\s+(.*?)\s+(.*)/$4/;
$fullstring =~ s/^://;
($from,$command,@data)=split(/\s+/,$thing);
$from ||= '';
$command ||= '';
#if server pings, ping back.
if ($from eq "PING") {
if ($command=~/^:\d+$/) {
&send("PONG $command");
} else {
&send("PONG :$CONF{nick}");
}
}
&error("from server: @data") if ($from eq "ERROR");
#If it has successfully connected to the server, join a channel.
if ($command eq "001") {
if (defined $CONF{channel})
{
&send("JOIN $CONF{channel}") ;
$starttime = time;
#&send("PRIVMSG $CONF{channel} : BUTTING SYSTEMS ONLINE!");
}
}
#otherwise, if it's a message
elsif ($command eq "PRIVMSG") {
#get destination of message
my $to=shift(@data);
#get first word of message (might be command)
my $sub=shift(@data);
## remove preceding ':'
$sub=~s/^://;
##if a user private messages the bot...
if ($to eq $CONF{nick})
{
$to = $from;
$to =~ s/^:(.*)!.*$/$1/;
#!help helps a brotha out, yo
if ($sub eq "!help")
{
&send("PRIVMSG $to : Buckleybot helpfully points out the humor in the current situation.");
}
##if the first word in the string is equal to the password, set the user to be the admin
if ($sub eq $CONF{pass}) {
$auth=$from;
&send("PRIVMSG $to : ADMIN POWERS ENABLED!!");
}
##ADMIN FUNCTIONS
if ($auth eq $from) {
##if the first word is "!quote", send the string that follows to the server
## e.g. "!quote PRIVMSG #testing : HELLO" prints out "HELLO" to #testing
if ($sub eq "!quote" and @data >0 )
{
&send(@data) ;
}
##!echo #channel spits out whatever to the channel
elsif ($sub eq "!echo" and @data >1 )
{
$_ = shift(@data);
&send("PRIVMSG $_ :".join(" ",@data));
}
#!boom spits out whatever to every channel
elsif ($sub eq "!boom" and @data > 0)
{
&send("PRIVMSG $CONF{channel} :".join(" ",@data));
}
elsif ($sub eq "!join" and @data > 0)
{
$CONF{channel} = $CONF{channel}.",";
$CONF{channel} = $CONF{channel}.$data[0];
&send("JOIN $data[0]");
}
elsif ($sub eq "!leave" and @data > 0)
{
$CONF{channel} =~ s/$data[0]//;
&send("PART $data[0]");
}
elsif ($sub eq "!reset" )
{
getbuckleyisms();
}
}
}
#if messages come from channel, start buttifying
elsif ($to =~ /^#/ ) {
my $sender = $from;
$sender =~ s/^:(.*)!.*$/$1/;
##ignores statements from cout and users containing the word "bot"
if (($from !~/^:cout/) && ($from !~/^:[^!]*bot[^!]*!/i)) {
if ($sub eq "!buckley") {
&send("PRIVMSG $to :".join(" ",&buckleyism()));
}
if ($sub eq "!addbuckley" and @data > 0) {
$fullstring =~ s/!addbuckley\s+//;
addbuckleyism($fullstring);
}
}
}
}
}
}
sub buckleyism{
return $buckleyisms[int(rand(@buckleyisms))];
}
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#THIS IS WHERE IT BLOWS UP!!!!!!!
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
sub addbuckleyism{
push @buckleyisms, $_[0];
$_[0] = $_[0] . "\n";
open(FILE2, ">>buckleys.txt");
print FILE2 $_[0];
close FILE2;
}
sub connect {
my ($remote_host,$remote_port,$local_host)=(shift,shift,shift);
my $socket=IO::Socket::INET->new( PeerAddr => $remote_host,
PeerPort => $remote_port,
proto => "tcp",
Type => SOCK_STREAM,
Timeout => 10
);
return $socket;
}
sub gets {
my $data = "";
$sock->recv($data,1024) ;
#or &error("get: $! $@");
return $data;
}
sub send {
my ($text) = join(" ",@_);
$text.="\n";
$sock->send($text);
}
sub forks {
my $spoon=fork();
if (defined $spoon) {
if ($spoon==0) {
return;
} else {
print "exiting, child pid=$spoon\n";
exit;
}
} else {
&error("fork: $! $@");
}
}
sub error {
print "\nerror: @_\n";
exit;
}
sub readconf {
our %CONF;
my ($conffile)=@_;
open(CONF,"$CONF{file}") or &error("readconf: cannot open $CONF{file}");
while (my $line=<CONF>) {
if (substr($line,0,1) ne "#") {
if ($line =~/^\s*([^\s]+)\s*=\s*(.+)$/) {
$CONF{lc($1)}=$2;
}
}
}
close(CONF);
}
#open buckleys.txt and read in all the lines
sub getbuckleyisms{
@buckleyisms = ();
open(FILE1, "buckleys.txt");
while (my $line= <FILE1>){
push(@buckleyisms, $line);
}
close FILE1;
}