#!/usr/bin/perl
# SORRY IF THESE COMMENTS LINE WRAP FOR YOU

# This is my first IRC bot.  I am following the example at www.b0iler.eyeonsecurity.org/tutorials/ircbot.htm
# The bot will be very basic at first, but I plan to expand the functionality later.
# BIG thanx to b0iler.eyeonsecurity.og's IRC bot tutorial for getting me off the ground :)

#    This bot is distributed under the GNU GPL license (http://www.gnu.org/licenses/gpl.txt).       #
#    This bot has NO warranty, and I am not liable for other's use of this bot       #

                            #  NOTES FOR BEGINNERS  #
# This is a program ( "bot" ) written in Perl (version 5.8.0-19) on Linux.  Familiarity with
# Perl (or another programming language), and Unix/Linux is quite advantageous
# for reading and using this program.
# I distribute this code in the hopes that it will help others who are interested in learning how
# to write a bot for IRC.  I hope that you will use your new knowledge responsibly.
#
# I use a lot of variables at the top so that one change to a variable at the top is used throughout the bot
# Also, if you are retyping this, make sure that all syntax is followed exactly.  Most "white space"
# (spaces, tabs, blank lines, etc...) does not change the program, but, for example, changing
# "    if($line =~ /(376|422)/i){     "   to say "   if($line =~ /(37 6|422)/i){    " would change things.
# An example of "white space" that does not change things would be changing:
# "    if($line =~ /(376|422)/i){     "   to say "   if ( $line =~ /( 376|422 ) /i ) {     "
# To execute the Perl script, save the script.  Then change the file to have execute permissions
# for the user.  Something like, "  chmod 700 MyBot.pl   " will do it.  I would suggest making a seperate
# user account on your box just for chatting on IRC and IRC bots.  
# Limit this user's permissions, because if someone can exploit your bot, they may be able
# to execute commands on your box with the permissions of the user who the Perl script is owned by.
# Even worse, if you run the bot as root and it is exploited, they will be able to execute commands as root.
# Obviously, NEVER run your bot when it is owned by root.  Don't even execute it while logged in as root.
#
# To execute the bot (assuming you are at the commandline, in the directory where the bot is) type "  ./MyBot.pl  "
# and you will be able to watch at the command line what is sent by the server to the bot.  Now
# look in the IRC channel (using whatever client u choose) you set for the bot, and it should appear within 2-10  seconds.
# If when you try to execute the Perl script, you get errors, make sure you didn't miss any " " around a
# word, or forget the   ;  at the end of a statement.  Sometimes the error messages are cryptic, but look at
# what line it mentions, and look a few lines above it.  Check that other syntax is not missing.
 

use IO::Socket;

# All Variables Defined Here
$bot_nick = "PickYourOwnName";    # current nick for the bot
$user = "TypeYourOwnAccount";    # name of the user account that is (assumed to be already) registered on that
                      # server by a human
$realname = "IRC bot";   # "real name" passed to server during login
$password = "TypeYourOwnPassword";          # password for the user account
$bot_maintainer = "TypeYourIRCnick";         # if you type in your own irc nick (not the bot's), if the bot receives a
                                                                         # request it doesn't recognize, then it will give your nick as a source
                                                                         # for help using the bot
$server_name = "The.Name.Of.The.Server";  # IRC server to connect to
          # West.US.GamesNET.Net is the one I origionally tested the bot on
          # Make sure the channel you are in doesn't mind you testing your bot there, otherwise make your own channel.
          # do this by logging into a server, then type /join #PickAchannelName, and if it doesn't exist already, the server
          # will create it, and move you into it.  Get your bot to join the channel with you, then have at it.
$port = "6667";                         # on the default port 6667
$new_nick = "Some_other_nick";                         # nick to change to
$channel_name = "#NameOfChannel";         # name of the channel to join
$request = "";                          # type of request, used mostly to seperate request from target
$new_channel_name = "";                 # channel to join
$target = "";                           # target of an action, i.e.  a goofy verbal assault, innocent teasing... etc


########################################################################################################
                                  # Make the connection
$sock = IO::Socket::INET->new(
    PeerAddr => $server_name,
        PeerPort => $port,
        Proto => 'tcp' ) or die "Could not make connection";

########################################################################################################
               # Print the text the server sends after the connection is made
# This could be useful text to grab parameters from.  These parameters could be
# assigned to some variables to make dynamic decisions based on the environment.

while($line = <$sock>){
        print $line;
# Identify bot to server w/ $nick and $user
    if($line =~ /(NOTICE AUTH).*(checking ident)/i){
            print $sock "NICK $bot_nick\nUSER $user 0 0 :$realname\n";
        last;
    }
}

########################################################################################################
                            # Watch for the PING, and send password
while($line = <$sock>){
        print $line;
# Use next line if the server asks for a PING
    if($line =~ /^PING/){
            print $sock "PONG :" . (split(/ :/, $line))[1];
    }
# Log in
    if($line =~ /(376|422)/i){
            print $sock "NICKSERV :identify $password\n";
        last;
    }
}

########################################################################################################
                                       # Join channel
# A little pause to make sure everything is in sync
sleep 1;
# adjust this sleep up to 5 if your internet connection is slow
# if adjusting this up to 5 does not help, look elsewhere in the code for the problem.

# Join the pre-defined channel
print $sock "JOIN $channel_name\n";


########################################################################################################
                                   #  Main program loop
while ($line = <$sock>) {
    # the server will send pings now and then to make sure that the bot is still connected, and the pings
    # must be responded to, or our connection will be dropped.
        ($command, $text) = split(/ :/, $line); #text is the stuff from the ping or the text from the server

    if ($command eq 'PING'){
        #while there is a line break
            while ( (index($text,"\r") >= 0) || (index($text,"\n") >= 0) ){ chop($text); }
        print $sock "PONG $text\n";
        next;
    }
    # done with ping handling


                # This section will seperate out the lines of text into usable variables

#      A priv_msg looks like
#    :nick!ident@hostname.com PRIVMSG #channel :line of text
#
# $nick = nick
# $hostname = ident
# $type = priv_msg
# $channel = #channel
# $text = line of text

    ($nick,$type,$channel) = split(/ /, $line); #split text by its spaces
    
    ($nick,$hostname) = split(/!/, $nick); # split by the ! to get nick and hostname seperate
    $nick =~ s/://; # remove : from nick
    $text =~ s/://; # remove : from text
    
    # get rid of all line breaks
    $/ = "\r\n";
    while($text =~ m#$/$#){ chomp($text); }
          
# End of parsing, time for functionality
          
# To issue commands to the bot, join the same channel as the bot is in.
# You have to use a different IRC account for yourself than the bot is using.
# Type, for example, "dansbot, change nick=yomama_aint_all_that"
# and the bot will change its IRC alias to yomama_aint_all_that.

          if($channel eq $channel_name){
        
#  CHATTING
          if($text =~ /hi $bot_nick/gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";    
              print $sock "PRIVMSG $channel_name :hi $nick\n";
              
          }
          elsif($text =~ /$bot_nick, how are you?/gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              print $sock "PRIVMSG $channel_name :pretty decent, yourself?\n";
          }
          elsif($text =~ /$bot_nick, what do you think of /gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              ($request, $target) = split(/of/, $text);
              print $sock "PRIVMSG $channel_name :$target?  what a freak child...\n";
          }
          elsif($text =~ /$bot_nick, say hi to /gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              ($request, $target) = split(/to/, $text);
              print $sock "PRIVMSG $channel_name :hi $target\n";
          }
#  COMMANDS
          elsif($text =~ /$bot_nick, change nick=/gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              ($request, $new_nick) = split(/=/, $text);
              print $sock "PRIVMSG $channel_name :changing nick...\n";
              print $sock "NICK :$new_nick\n";
              $bot_nick = $new_nick;
              print $sock "PRIVMSG $channel_name :changing nick complete\n";
          }
          elsif($text =~ /$bot_nick, leave \#/gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              ($request, $channel_name) = split(/\#/, $text);
              print $sock "PART $channel_name\n";
          }
          elsif($text =~ /$bot_nick, quit/gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              print $sock "QUIT : see you later :) \n";
          }
          elsif($text =~ /$bot_nick, join \#/gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              ($request, $new_channel_name) = split(/\#/, $text);
              print $sock "PRIVMSG $channel_name :joining #$new_channel_name\n";
              print $sock "JOIN #$new_channel_name\n";
          }
          elsif($text =~ /$bot_nick, insult /gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              ($request, $target) = split(/insult/, $text);
              # I can't seem to get this "self" part to work so far...
              #if("$target" eq "$bot_nick"){ $target = "self"; }
              print $sock "PRIVMSG $channel_name :flings a slimy booger at $target\n";
          }
          elsif($text =~ /$bot_nick, pm /gi){
              print "<$nick> MESSAGE RECEIVED: \"$text\"\n";
              ($request, $target) = split(/pm/, $text);
              print $sock "PRIVMSG $target :Hi there\n";
          }
          elsif($text =~ /$bot_nick, help/gi){
              print "<$nick> HELP REQUEST RECEIVED: \"$text\"\n";
              print $sock "PRIVMSG $nick : All commands begin with \"dansbot, \" Commands I know so far...\n";
              print $sock "change nick=NewNick\n";
              print $sock "leave \#ChannelName\n";
              print $sock "quit\n";
              print $sock "join #ChannelName\n";
              print $sock "insult NickOfTarget\n";
              print $sock "pm NickOfTarget\n";
              print $sock "help\n";
          }
          
          # default answer to unrecognized communication with bot's name
          elsif($text =~ /$bot_nick/gi){
              print "<$nick> ***UNRECOGNIZED MESSAGE***: \"$text\"\n";
              print $sock "PRIVMSG $channel_name :$nick, request not recognized.  If you need some help, ask $bot_maintainer\n";
          }
          } # end Parsing while loop
} # end Main while Loop
    
#######################################################################################################