Advertisement
Guest User

Untitled

a guest
May 3rd, 2017
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 9.06 KB | None | 0 0
  1. #!perl
  2.  
  3. #SGBot version 0.0.1
  4. #Author: Grinnz
  5. #Usage: A basic bot that will connect to IRC
  6. use strict;
  7. use warnings;
  8.  
  9. use Net::IRC;
  10.  
  11. my %command = (
  12.     'join' => { func => \&cmd_join, access => 2, on => 1, strip => 1 },
  13.     'leave' => { func => \&cmd_leave, access => 2, on => 1, strip => 1 },
  14.     'quit' => { func => \&cmd_quit, access => 2, on => 1, strip => 0 },
  15.     'say' => { func => \&cmd_say, access => 1, on => 1, strip => 0 },
  16.     'help' => { func => \&cmd_help, access => 0, on => 1, strip => 0 },
  17.     'version' => { func => \&cmd_version, access => 0, on => 1, strip => 0 },
  18.     'reload' => { func => \&cmd_reload, access => 2, on => 1, strip => 0 });
  19. my %cmdwhois = ( cmd => '' );
  20.  
  21. my $conffile = 'sgbot.conf';
  22. my $conf = { debug => 1,
  23.          echo => 1,
  24.          trigger => '`',
  25.          master => '',
  26.          admins => [],
  27.          channels => [ '#bots' ],
  28.          version => '0.0.1',
  29.          server => 'socialgamer.net',
  30.          nick => 'SGBot',
  31.          username => 'bot',
  32.          password => '',
  33.          ircname => 'Bot',
  34.          awaymsg => 'I am a bot.',
  35.          ssl => 0,
  36.          port => 6667 };
  37.  
  38. if (-e $conffile) {
  39.     print "Opening config...\n";
  40.     $conf = load($conffile);
  41. } else {
  42.     print "No config found. Using default configuration...\n";
  43.     save($conf,$conffile);
  44. }
  45.  
  46. my $irc = new Net::IRC;
  47. my $conn = $irc->newconn(Nick     => $conf->{nick},
  48.              Server   => $conf->{server},
  49.              Port     => $conf->{port},
  50.              Ircname  => $conf->{ircname},
  51.              Username => $conf->{username},
  52.              SSL      => $conf->{ssl});
  53.  
  54. $conn->add_global_handler('public', \&on_public);
  55. $conn->add_global_handler('msg', \&on_msg);
  56. $conn->add_global_handler('kick', \&on_kick);
  57. $conn->add_global_handler('disconnect', \&on_disconnect);
  58. $conn->add_global_handler('376', \&on_connect);
  59. $conn->add_global_handler('320', \&on_whois_ident);
  60.  
  61. print "Starting connection to $conf->{server}/$conf->{port}...\n" if $conf->{debug};
  62. $irc->start;
  63.  
  64. # ********
  65. # Handlers
  66. # ********
  67.  
  68. # Executed upon successful connection to the IRC server
  69. sub on_connect {
  70.     my $conn = shift;
  71.     print "Connected. Identifying with Nickserv...\n" if $conf->{debug};
  72.     $conn->privmsg('NickServ',"identify $conf->{nick} $conf->{password}") if $conf->{password};
  73.     $conn->mode($conf->{nick},'+B');
  74.     $conn->away($conf->{awaymsg});
  75.     print "Attempting to join autojoin channels: @{$conf->{channels}}\n" if $conf->{debug};
  76.     $conn->join($_) foreach @{$conf->{channels}};
  77. }
  78.  
  79. sub on_disconnect {
  80.     exit(0);
  81. }
  82.  
  83. # Executed upon a kick
  84. sub on_kick {
  85.     my ($conn,$event) = @_;
  86.     my $kickee = $event->{to}[0];
  87.     my $channel = $event->{args}[0];
  88.     if (lc $kickee eq lc $conf->{nick} and
  89.     grep {lc $channel eq lc $_} @{$conf->{channels}}) {
  90.     print "Kicked from $channel, attempting to rejoin.\n" if $conf->{debug};
  91.     $conn->join($channel);
  92.     }
  93. }
  94.  
  95. # Executed for any public (channel) message
  96. sub on_public {
  97.     my ($conn,$event) = @_;
  98.     my $sender = $event->{nick};
  99.     my $channel = $event->{to}[0];
  100.     my $msg = $event->{args}[0];
  101.    
  102.     parsecmd($conn,$sender,$channel,$msg);
  103. }
  104.  
  105. # Executed for any private message
  106. sub on_msg {
  107.     my ($conn,$event) = @_;
  108.     my $sender = $event->{nick};
  109.     my $msg = $event->{args}[0];
  110.    
  111.     parsecmd($conn,$sender,'private',$msg);
  112. }
  113.  
  114. # Parses a received message for a command
  115. sub parsecmd {
  116.     my ($conn,$sender,$channel,$msg) = @_;
  117.     print "[$channel] $sender: $msg\n" if $conf->{echo};
  118.     if ((strip_formatting($msg) =~ /^\Q$conf->{trigger}\E([[:graph:]]+)/ or
  119.      ($channel eq 'private' and strip_formatting($msg) =~ /^([[:graph:]]+)/)) and
  120.     exists $command{lc $1}) {
  121.     my $cmd = lc $1;
  122.     my $args = '';
  123.     if ($msg =~ /^[[:graph:][:cntrl:]]+ +(.*?)$/) { $args = $1; }
  124.     $args = strip_formatting($args) if $command{$cmd}->{strip};
  125.     print "[$channel] $sender: (command) $cmd $args\n" if $conf->{debug};
  126.     if (!$command{$cmd}->{on}) {
  127.         if ($channel eq 'private') {
  128.         $conn->privmsg($sender,"Error: command $cmd has been disabled.");
  129.         } else {
  130.         $conn->privmsg($channel,"Error: command $cmd has been disabled.");
  131.         }
  132.     } elsif ($command{$cmd}->{access} == 0) {
  133.         print "No access required, executing command\n" if $conf->{debug};
  134.         $command{$cmd}->{func}($conn,$sender,$channel,$args);
  135.     } elsif ($cmdwhois{cmd}) {
  136.         if ($channel eq 'private') {
  137.         $conn->privmsg($sender,"Error: please repeat command in a few seconds.");
  138.         } else {
  139.         $conn->privmsg($channel,"Error: please repeat command in a few seconds.");
  140.         }
  141.     } else {
  142.         $cmdwhois{cmd} = $cmd;
  143.         $cmdwhois{user} = $sender;
  144.         $cmdwhois{chan} = $channel;
  145.         $cmdwhois{args} = $args;
  146.         $conn->whois($sender);
  147.     }
  148.     }
  149. }
  150.  
  151. # Color/formatting stripping for command parser
  152. sub strip_formatting {
  153.     # strip ALL user formatting from IRC input (color, bold, underline, plaintext marker)
  154.     my $arg = shift;
  155.     my $c_code = chr(3);      # how colors are read by us
  156.     my $u_code = chr(31);     # how underlines are read
  157.     my $b_code = chr(2);      # how bold is read
  158.     my $p_code = chr(15);     # how plaintext is read
  159.     $arg =~ s/(($c_code(\d\d?(\,\d\d?)?)?)|$u_code|$b_code|$p_code)//g;
  160.     return $arg;
  161. }
  162.  
  163. # Executed upon receiving the login information for an user
  164. sub on_whois_ident {
  165.     my ($conn,$event) = @_;
  166.     my $nick = $event->{args}[1];
  167.     my $lia = $event->{args}[2];
  168.    
  169.     if ($cmdwhois{cmd} and lc $cmdwhois{user} eq lc $nick) {
  170.     my $cmd = $cmdwhois{cmd};
  171.     my $chan = $cmdwhois{chan};
  172.     my $args = $cmdwhois{args};
  173.     my $isadmin = 0;
  174.     if ($lia =~ /is logged in as ([[:graph:]]+)/) {
  175.         print "$nick is logged in as $1\n" if $conf->{debug};
  176.         if (lc $1 eq lc $conf->{master} or
  177.         grep {lc $1 eq lc $_} @{$conf->{admins}}) {
  178.         print "$1 has admin access.\n" if $conf->{debug};
  179.         $isadmin = 1;
  180.         }
  181.     }
  182.     else {
  183.         print "$nick is an IRCop.\n" if $conf->{debug};
  184.         $isadmin = 1;
  185.     }
  186.    
  187.     if ($isadmin and $command{$cmd}->{access} < 3) {
  188.         $command{$cmd}->{func}($conn,$nick,$chan,$args);
  189.     }
  190.     $cmdwhois{cmd} = '';
  191.     }
  192. }
  193.  
  194. # ********
  195. # Commands
  196. # ********
  197.  
  198. sub cmd_join {
  199.     my ($conn,$sender,$channel,$args) = @_;
  200.     my @chans = split ' ',$args;
  201.     foreach (0..$#chans) {
  202.     $chans[$_] = '#'.$chans[$_] unless $chans[$_] =~ /^#/;
  203.     }
  204.     print "Attempting to join channel(s): @chans\n" if $conf->{debug};
  205.     $conn->join($_) foreach @chans;
  206. }
  207.  
  208. sub cmd_leave {
  209.     my ($conn,$sender,$channel,$args) = @_;
  210.     if ($channel eq 'private') {
  211.     unless ($args) {
  212.         $conn->privmsg($sender,"Please specify a channel");
  213.         return;
  214.     }
  215.     if ($args =~ /^([[:graph:]]+) ?(.*?)$/) {
  216.         my $chan = $1;
  217.         my $msg = $2;
  218.         $chan = '#'.$chan unless $chan =~ /^#/;
  219.         $conn->part("$chan $msg");
  220.     }
  221.     }
  222.     elsif ($args =~ /^(#[[:graph:]]+) ?(.*?)$/) {
  223.         my $chan = $1;
  224.         my $msg = $2;
  225.         $conn->part("$chan $msg");
  226.     }
  227.     else { $conn->part("$channel $args"); }
  228. }
  229.  
  230. sub cmd_quit {
  231.     my ($conn,$sender,$channel,$args) = @_;
  232.     print "Quitting: $args\n" if $conf->{debug};
  233.     $conn->quit($args);
  234. }
  235.  
  236. sub cmd_say {
  237.     my ($conn,$sender,$channel,$args) = @_;
  238.     $channel = $sender if $channel eq 'private';
  239.     $conn->privmsg($channel," - $args");
  240. }
  241.  
  242. sub cmd_help {
  243.     my ($conn,$sender,$channel,$args) = @_;
  244.     my @cmds = keys %command;
  245.     foreach (0..$#cmds) { $cmds[$_] = $conf->{trigger}.$cmds[$_]; }
  246.     $conn->notice($sender,"I respond to the following commands: @cmds");
  247. }
  248.  
  249. sub cmd_version {
  250.     my ($conn,$sender,$channel,$args) = @_;
  251.     $conn->notice($sender,"$conf->{nick} version $conf->{version} by Grinnz");
  252. }
  253.  
  254. sub cmd_reload {
  255.     my ($conn,$sender,$channel,$args) = @_;
  256.     $channel = $sender if $channel eq 'private';
  257.     $conn->privmsg($channel,'Reloading configuration.');
  258.     $conf = load($conffile);
  259. }
  260.  
  261. # ************
  262. # Data storage
  263. # ************
  264.  
  265. # Stores a data structure to a file in plaintext
  266. sub save {
  267.     my ($data,$filename) = @_;
  268.     unless ($data and $filename and ref($data) eq 'HASH') {
  269.     warn "Invalid parameters to store" and return;
  270.     }
  271.    
  272.     warn "Warning: file $filename will be overwritten\n" if -e $filename;
  273.     my $file;
  274.     unless (open $file, '>', $filename) {
  275.     warn "File could not be opened for saving. Aborting." and return;
  276.     }
  277.    
  278.     print $file "# Config file for SGBot\n";
  279.     while (my ($name,$item) = each %{$data}) {
  280.     # Only stores scalars and arrays with no spaces in values!
  281.     print $file "s $name $item\n" if !ref $item;
  282.     print $file "a $name @{$item}\n" if 'ARRAY' eq ref $item;
  283.     }
  284.     close $file;
  285. }
  286.  
  287. # Reads a plaintext file stored with 'store' into a data structure
  288. sub load {
  289.     my $filename = shift;
  290.     my $data = {};
  291.     unless ($filename and -e $filename) {
  292.     warn "Invalid filename specified for load" and return $data;
  293.     }
  294.    
  295.     my $file;
  296.     unless (open $file, '<', $filename) {
  297.     warn "File could not be opened for loading. Aborting." and return $data;
  298.     }
  299.    
  300.     while (<$file>) {
  301.     if (/^([s|a]) ([[:graph:]]+) (.*)$/) {
  302.         $data->{$2} = $3 if $1 eq 's';
  303.         $data->{$2} = [ split ' ',$3 ] if $1 eq 'a';
  304.     }
  305.     }
  306.     close $file;
  307.     return $data;
  308. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement