Perl IRC Bot (Goki) + ChanOp plugin

Goki is an IRC Bot written in perl, very easy to install, use and develop. One of the best things about Goki is it doesn’t require any additional modules, just give it a try http://goki.sf.net.

Since Goki has no authentication yet, I did a small plugin which will handle a very primitive user’s access list and a few basic channel operator’s commands, nothing more but what you are reading 😉

Follow the instructions:

– Create a file plugin/chanop.pm (or whatever you want)
– Paste the following code:

package chanop; 
#use warnings; # we don't need warnings, we know it's dirty code ;) 
 
# Module wide variables 
 
# add as many nicks as you want, and remember, in order to authenticate  
# you need to have the same nick name (not case sensitive) 
my %chanops = ( 
'xUx' => '12345', 
'demonick' => 'demopass', 
'nick2' => 'somethinghere' 
); 
 
# careful, moving things here could make the bot crash :) 
my %chdata = (); # hash that will hold all data 
 
foreach $key (sort keys %chanops) { 
%{$chdata{lc($key)}} = ('nick' => lc($key), 'pass' => $chanops{$key}); 
} 
 
# Module load functions. Set default values here. 
BEGIN { 
our $VERSION = 0.4; 
$irc = main::IRC; 
# private events 
$irc->add_handler('privcmd auth','do_auth'); 
$irc->add_handler('privcmd who','do_who'); 
$irc->add_handler('privcmd join','do_join'); 
$irc->add_handler('privcmd part','do_part'); 
$irc->add_handler('privcmd kick','do_kick'); 
$irc->add_handler('privcmd ban','do_ban'); 
$irc->add_handler('privcmd voice','do_voice'); 
$irc->add_handler('privcmd devoice','do_devoice'); 
$irc->add_handler('privcmd op','do_op'); 
$irc->add_handler('privcmd deop','do_deop'); 
$irc->add_handler('privcmd sh','do_sh'); 
$irc->add_handler('privcmd say','do_say'); 
} 
 
sub do_say { 
my ( $nick, $hostmask, $text ) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
my $msg = join(" ",@args[1 .. scalar(@args)-1]); 
main::plog "Message sent from $nick to $args[0]\n"; 
$irc->say($args[0],$msg); 
} 
 
sub do_sh { 
my ( $nick, $hostmask, $text ) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
main::plog "Exec attempt by $nick\n"; 
my @output = `$text`; 
my $line; 
foreach $line (@output) { 
$irc->say($nick, $line); 
} 
} 
 
sub do_deop { 
# deop #channel nick 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Deop on $args[0] to $args[1] by $nick\n"; 
$irc->deop($args[0],$args[1]); 
} 
 
sub do_op { 
# op #channel nick 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Op on $args[0] to $args[1] by $nick\n"; 
$irc->op($args[0],$args[1]); 
} 
 
sub do_devoice { 
# devoice #channel nick 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
$irc->devoice($args[0],$args[1]); 
} 
 
sub do_voice { 
# voice #channel nick 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Voice on $args[0] to $args[1] by $nick\n"; 
$irc->voice($args[0],$args[1]); 
} 
 
sub do_ban { 
# ban #channel nick|hostmask 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Ban on $args[0] to $args[1] by $nick\n"; 
$irc->mode($args[0],"+b",$args[1]); 
} 
 
sub do_kick { 
# kick #channel nick reason 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
my $reason = join(" ",@args[2 .. scalar(@args)-1]) || $args[1]; 
main::plog "Kick on $args[0] to $args[1] ($reason) by $nick\n"; 
$irc->kick($args[0],$args[1],$reason); 
} 
 
sub do_part { 
# part #channel 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Parting $args[0] by $nick\n"; 
$irc->part($args[0]); 
} 
 
sub do_join { 
# join #channel 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
my @args = split(" ",$text); 
if ($args[0] !~ /^\#/) { $args[0] = "#" . $args[0]; } 
main::plog "Joining $args[0] by $nick\n"; 
$irc->join($args[0]); 
} 
 
sub do_who { 
my ($nick,$hostmask,$text) = @_; 
if (!&do_auth_check($nick,$hostmask)) { return; } 
foreach my $key (sort keys %chdata) { 
if (exists($chdata{$key}{'hostmask'})) { 
$irc->say($nick, $chdata{$key}{'nick'} . " (". $chdata{$key}{'hostmask'}.")"); 
} 
} 
return; 
} 
 
sub do_auth_check { 
my ($nick,$hostmask) = @_; 
my $tmphostmask = (split("\!",$hostmask))[1]; 
if (!exists($chdata{lc($nick)}{'hostmask'})) { 
main::plog "Unauthorized access from $hostmask\n"; 
return 0; 
} 
if ($chdata{lc($nick)}{'hostmask'} eq $tmphostmask) { return 1; } 
return 0; 
} 
 
sub do_auth { 
my ($nick,$hostmask,$text) = @_; 
my $tmphostmask = (split("\!",$hostmask))[1]; 
if (!exists($chdata{lc($nick)})) { 
main::plog "Invalid user tried to AUTH: $nick ($tmphostmask)\n"; 
return; 
} 
my @args = split(" ",$text); 
if ($chdata{lc($nick)}{'pass'} ne $args[0]) { 
main::plog "Invalid Login attemp from $nick ($tmphostmask)\n"; 
$irc->notice($nick,"Invalid Password, attemp logged!"); 
return; 
} 
if (exists($chdata{lc($nick)}{'hostmask'})) { 
main::plog "RE-AUTH from $nick from ".$chdata{lc($nick)}{'hostmask'}." to $tmphostmask\n"; 
} 
else { main::plog "AUTH from $nick from $tmphostmask\n"; } 
$chdata{lc($nick)}{'hostmask'} = $tmphostmask; 
$irc->notice($nick, "Authentication Succesful!"); 
} 
 
return 1; 
 
# Module unload functions, free memory and close open filehandles here 
END { 
# Does not currently work, but is here for future compatibility 
# $irc->del_handler( '', '' ); 
} 

– Edit file conf/plugin.conf and make it load your plugin by adding a line with the word “chanop” (or the first part of your thanemayoupicked.pm)
– Start your bot and have fun 😉

For future reference and user’s comments go to http://sourceforge.net/forum/forum.php?thread_id=2185241&forum_id=621728