Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!perl
- #SGBot version 0.0.1
- #Author: Grinnz
- #Usage: A basic bot that will connect to IRC
- use strict;
- use warnings;
- use Net::IRC;
- my %command = (
- 'join' => { func => \&cmd_join, access => 2, on => 1, strip => 1 },
- 'leave' => { func => \&cmd_leave, access => 2, on => 1, strip => 1 },
- 'quit' => { func => \&cmd_quit, access => 2, on => 1, strip => 0 },
- 'say' => { func => \&cmd_say, access => 1, on => 1, strip => 0 },
- 'help' => { func => \&cmd_help, access => 0, on => 1, strip => 0 },
- 'version' => { func => \&cmd_version, access => 0, on => 1, strip => 0 },
- 'reload' => { func => \&cmd_reload, access => 2, on => 1, strip => 0 });
- my %cmdwhois = ( cmd => '' );
- my $conffile = 'sgbot.conf';
- my $conf = { debug => 1,
- echo => 1,
- trigger => '`',
- master => '',
- admins => [],
- channels => [ '#bots' ],
- version => '0.0.1',
- server => 'socialgamer.net',
- nick => 'SGBot',
- username => 'bot',
- password => '',
- ircname => 'Bot',
- awaymsg => 'I am a bot.',
- ssl => 0,
- port => 6667 };
- if (-e $conffile) {
- print "Opening config...\n";
- $conf = load($conffile);
- } else {
- print "No config found. Using default configuration...\n";
- save($conf,$conffile);
- }
- my $irc = new Net::IRC;
- my $conn = $irc->newconn(Nick => $conf->{nick},
- Server => $conf->{server},
- Port => $conf->{port},
- Ircname => $conf->{ircname},
- Username => $conf->{username},
- SSL => $conf->{ssl});
- $conn->add_global_handler('public', \&on_public);
- $conn->add_global_handler('msg', \&on_msg);
- $conn->add_global_handler('kick', \&on_kick);
- $conn->add_global_handler('disconnect', \&on_disconnect);
- $conn->add_global_handler('376', \&on_connect);
- $conn->add_global_handler('320', \&on_whois_ident);
- print "Starting connection to $conf->{server}/$conf->{port}...\n" if $conf->{debug};
- $irc->start;
- # ********
- # Handlers
- # ********
- # Executed upon successful connection to the IRC server
- sub on_connect {
- my $conn = shift;
- print "Connected. Identifying with Nickserv...\n" if $conf->{debug};
- $conn->privmsg('NickServ',"identify $conf->{nick} $conf->{password}") if $conf->{password};
- $conn->mode($conf->{nick},'+B');
- $conn->away($conf->{awaymsg});
- print "Attempting to join autojoin channels: @{$conf->{channels}}\n" if $conf->{debug};
- $conn->join($_) foreach @{$conf->{channels}};
- }
- sub on_disconnect {
- exit(0);
- }
- # Executed upon a kick
- sub on_kick {
- my ($conn,$event) = @_;
- my $kickee = $event->{to}[0];
- my $channel = $event->{args}[0];
- if (lc $kickee eq lc $conf->{nick} and
- grep {lc $channel eq lc $_} @{$conf->{channels}}) {
- print "Kicked from $channel, attempting to rejoin.\n" if $conf->{debug};
- $conn->join($channel);
- }
- }
- # Executed for any public (channel) message
- sub on_public {
- my ($conn,$event) = @_;
- my $sender = $event->{nick};
- my $channel = $event->{to}[0];
- my $msg = $event->{args}[0];
- parsecmd($conn,$sender,$channel,$msg);
- }
- # Executed for any private message
- sub on_msg {
- my ($conn,$event) = @_;
- my $sender = $event->{nick};
- my $msg = $event->{args}[0];
- parsecmd($conn,$sender,'private',$msg);
- }
- # Parses a received message for a command
- sub parsecmd {
- my ($conn,$sender,$channel,$msg) = @_;
- print "[$channel] $sender: $msg\n" if $conf->{echo};
- if ((strip_formatting($msg) =~ /^\Q$conf->{trigger}\E([[:graph:]]+)/ or
- ($channel eq 'private' and strip_formatting($msg) =~ /^([[:graph:]]+)/)) and
- exists $command{lc $1}) {
- my $cmd = lc $1;
- my $args = '';
- if ($msg =~ /^[[:graph:][:cntrl:]]+ +(.*?)$/) { $args = $1; }
- $args = strip_formatting($args) if $command{$cmd}->{strip};
- print "[$channel] $sender: (command) $cmd $args\n" if $conf->{debug};
- if (!$command{$cmd}->{on}) {
- if ($channel eq 'private') {
- $conn->privmsg($sender,"Error: command $cmd has been disabled.");
- } else {
- $conn->privmsg($channel,"Error: command $cmd has been disabled.");
- }
- } elsif ($command{$cmd}->{access} == 0) {
- print "No access required, executing command\n" if $conf->{debug};
- $command{$cmd}->{func}($conn,$sender,$channel,$args);
- } elsif ($cmdwhois{cmd}) {
- if ($channel eq 'private') {
- $conn->privmsg($sender,"Error: please repeat command in a few seconds.");
- } else {
- $conn->privmsg($channel,"Error: please repeat command in a few seconds.");
- }
- } else {
- $cmdwhois{cmd} = $cmd;
- $cmdwhois{user} = $sender;
- $cmdwhois{chan} = $channel;
- $cmdwhois{args} = $args;
- $conn->whois($sender);
- }
- }
- }
- # Color/formatting stripping for command parser
- sub strip_formatting {
- # strip ALL user formatting from IRC input (color, bold, underline, plaintext marker)
- my $arg = shift;
- my $c_code = chr(3); # how colors are read by us
- my $u_code = chr(31); # how underlines are read
- my $b_code = chr(2); # how bold is read
- my $p_code = chr(15); # how plaintext is read
- $arg =~ s/(($c_code(\d\d?(\,\d\d?)?)?)|$u_code|$b_code|$p_code)//g;
- return $arg;
- }
- # Executed upon receiving the login information for an user
- sub on_whois_ident {
- my ($conn,$event) = @_;
- my $nick = $event->{args}[1];
- my $lia = $event->{args}[2];
- if ($cmdwhois{cmd} and lc $cmdwhois{user} eq lc $nick) {
- my $cmd = $cmdwhois{cmd};
- my $chan = $cmdwhois{chan};
- my $args = $cmdwhois{args};
- my $isadmin = 0;
- if ($lia =~ /is logged in as ([[:graph:]]+)/) {
- print "$nick is logged in as $1\n" if $conf->{debug};
- if (lc $1 eq lc $conf->{master} or
- grep {lc $1 eq lc $_} @{$conf->{admins}}) {
- print "$1 has admin access.\n" if $conf->{debug};
- $isadmin = 1;
- }
- }
- else {
- print "$nick is an IRCop.\n" if $conf->{debug};
- $isadmin = 1;
- }
- if ($isadmin and $command{$cmd}->{access} < 3) {
- $command{$cmd}->{func}($conn,$nick,$chan,$args);
- }
- $cmdwhois{cmd} = '';
- }
- }
- # ********
- # Commands
- # ********
- sub cmd_join {
- my ($conn,$sender,$channel,$args) = @_;
- my @chans = split ' ',$args;
- foreach (0..$#chans) {
- $chans[$_] = '#'.$chans[$_] unless $chans[$_] =~ /^#/;
- }
- print "Attempting to join channel(s): @chans\n" if $conf->{debug};
- $conn->join($_) foreach @chans;
- }
- sub cmd_leave {
- my ($conn,$sender,$channel,$args) = @_;
- if ($channel eq 'private') {
- unless ($args) {
- $conn->privmsg($sender,"Please specify a channel");
- return;
- }
- if ($args =~ /^([[:graph:]]+) ?(.*?)$/) {
- my $chan = $1;
- my $msg = $2;
- $chan = '#'.$chan unless $chan =~ /^#/;
- $conn->part("$chan $msg");
- }
- }
- elsif ($args =~ /^(#[[:graph:]]+) ?(.*?)$/) {
- my $chan = $1;
- my $msg = $2;
- $conn->part("$chan $msg");
- }
- else { $conn->part("$channel $args"); }
- }
- sub cmd_quit {
- my ($conn,$sender,$channel,$args) = @_;
- print "Quitting: $args\n" if $conf->{debug};
- $conn->quit($args);
- }
- sub cmd_say {
- my ($conn,$sender,$channel,$args) = @_;
- $channel = $sender if $channel eq 'private';
- $conn->privmsg($channel," - $args");
- }
- sub cmd_help {
- my ($conn,$sender,$channel,$args) = @_;
- my @cmds = keys %command;
- foreach (0..$#cmds) { $cmds[$_] = $conf->{trigger}.$cmds[$_]; }
- $conn->notice($sender,"I respond to the following commands: @cmds");
- }
- sub cmd_version {
- my ($conn,$sender,$channel,$args) = @_;
- $conn->notice($sender,"$conf->{nick} version $conf->{version} by Grinnz");
- }
- sub cmd_reload {
- my ($conn,$sender,$channel,$args) = @_;
- $channel = $sender if $channel eq 'private';
- $conn->privmsg($channel,'Reloading configuration.');
- $conf = load($conffile);
- }
- # ************
- # Data storage
- # ************
- # Stores a data structure to a file in plaintext
- sub save {
- my ($data,$filename) = @_;
- unless ($data and $filename and ref($data) eq 'HASH') {
- warn "Invalid parameters to store" and return;
- }
- warn "Warning: file $filename will be overwritten\n" if -e $filename;
- my $file;
- unless (open $file, '>', $filename) {
- warn "File could not be opened for saving. Aborting." and return;
- }
- print $file "# Config file for SGBot\n";
- while (my ($name,$item) = each %{$data}) {
- # Only stores scalars and arrays with no spaces in values!
- print $file "s $name $item\n" if !ref $item;
- print $file "a $name @{$item}\n" if 'ARRAY' eq ref $item;
- }
- close $file;
- }
- # Reads a plaintext file stored with 'store' into a data structure
- sub load {
- my $filename = shift;
- my $data = {};
- unless ($filename and -e $filename) {
- warn "Invalid filename specified for load" and return $data;
- }
- my $file;
- unless (open $file, '<', $filename) {
- warn "File could not be opened for loading. Aborting." and return $data;
- }
- while (<$file>) {
- if (/^([s|a]) ([[:graph:]]+) (.*)$/) {
- $data->{$2} = $3 if $1 eq 's';
- $data->{$2} = [ split ' ',$3 ] if $1 eq 'a';
- }
- }
- close $file;
- return $data;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement