All pastes #904202 Raw Edit

Kon's New IRC code

public text v1 · immutable
·published 2008-02-14 19:51 UTC
rendered paste body
////////////////////////////////////////////////
////////////////PROGRAM INFO////////////////////
// "Kon" is a "learning bot" written in C#.   //
// The bot will connect to an IRC server and  //
// "watch" the conversations.  It will then   //
// "learn" from them.  You'll then be able to //
// talk to it and hopefully it'll hold a conv-//
// ersation.                                  //
////////////////////////////////////////////////
// "Kon" is an ongoing project started by     // 
// James Iyouboushi.                          //
// Emails: jmp1139@my.gulfcoast.edu           //
//         Iyouboushi@gmail.com               //
////////////////////////////////////////////////
// This file was last updated on: 2/14/2008   //
////////////////////////////////////////////////


using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using System.Text;

namespace Kon
{

#region delegates
    public delegate void CommandReceived(string ircCommand);
    public delegate void TopicSet(string channel, string ircTopic);
    public delegate void TopicOwner(string channel, string ircUser, string topicDate);
    public delegate void NamesList(string userNames);
    public delegate void ServerMessage(string serverMessage);
    public delegate void Join(string channel, string ircUser);
    public delegate void Part(string channel, string ircUser);
    public delegate void Mode(string channel, string ircUser, string userMode);
    public delegate void NickChange(string userOldNick, string userNewNick);
    public delegate void Kick(string channel, string userKicker, string userKicked, string kickMessage);
    public delegate void Quit(string userQuit, string quitMessage);
    public delegate void Query(string userName, string message);
#endregion

    class IRC
    {

#region variables

        // Public variables
        public        bool            canQuit             = false;
            
        // Private variables
        private       int             ircPort             = 6667;
        private       string          ircServer           = "bots.esper.net"; 
        private       string          nickNameMain        = "Kon";
        private       string          nickNameBckup       = "KonPlushie";
        private       string          ircUser             = "USER Kon 1 * :SPLASH !!!";
        private       string          ircRealName         = "Kon";
        private       string          channel             = "#KonBot";
        private       string          version             = "Kon - Version 1.0.6 - created by James Iyouboushi [iyouboushi@gmail.com]";
        private       string          modifiedLine        = "";
        private       bool            AIML                = false;
        private       bool            google              = false;
        public        bool            logging             = true;
 //       public        bool            showServerMsgs      = false;
        public        bool            showPongReply       = false;
        private       TcpClient       ircConnection;
        private       NetworkStream   ircStream;
        public static StreamWriter    ircWriter;
        public static StreamWriter    loggerWriter;
        public static StreamReader    ircReader;
        private       Thread          listenerThread;
        public static AI              myAI;               // Kon's own brain (AI.cs)
        public static AIMLbrain       myAIML;             // Kon's AIML brain (AIML.cs)
        public static googleBrain     myGoogle;           // Kon's Google brain (google.cs)
        
        // Private constants
        private const string          CRLF                = "\r\n";
        private const string          LOG_FILE            = "KonLog.txt";
#endregion

#region events
        public event CommandReceived    eventReceiving;
        public event TopicSet           eventTopicSet;
        public event TopicOwner         eventTopicOwner;
        public event NamesList          eventNamesList;
        public event ServerMessage      eventServerMessage;
        public event Join               eventJoin;
        public event Part               eventPart;
        public event Mode               eventMode;
        public event NickChange         eventNickChange;
        public event Kick               eventKick;
        public event Quit               eventQuit;
        public event Query              eventQuery;
#endregion

#region properties
        public string IrcServer
        {
            get { return this.ircServer; }
            set { this.ircServer = value; }
        }

        public int IrcPort
        {
            get { return this.ircPort; }
            set { this.ircPort = value; }
        } 

        public string NickNameMain
        {
            get { return this.nickNameMain; }
            set { this.nickNameMain = value; }
        }

        public string NickNameBckup
        {
            get { return this.nickNameBckup; }
            set { this.nickNameBckup = value; }
        }

        public string IrcUser
        {
            get { return this.ircUser; }
            set { this.ircUser = value; }
        }

        public string IrcRealName
        {
            get { return this.ircRealName; }
            set { this.ircRealName = value; }
        } 

        // Needs to eventually be changed to allow for more than one channel
        public string Channel
        {
            get { return this.channel; }
            set { this.channel = value; }
        } 

        public TcpClient IrcConnection
        {
            get { return this.ircConnection; }
            set { this.ircConnection = value; }
        }

        public NetworkStream IrcStream
        {
            get { return this.ircStream; }
            set { this.ircStream = value; }
        }

        public StreamWriter IrcWriter
        {
            get { return ircWriter; }
            set { ircWriter = value; }
        }

        public StreamReader IrcReader
        {
            get { return ircReader; }
            set { ircReader = value; }
        } 
#endregion	


#region constructors

        ////////////////////////////////////////////////
        //////////////CONSTRUCTORS//////////////////////
        // There are two constructors.  One will only //
        // use defaults found at the top of this file.//
        // That constructor shouldn't be called but is//
        // merely a failsafe.                         //
        ////////////////////////////////////////////////
        public IRC()
        {
            // Connect to IRC
            connect();
        }

        public IRC(String server, int port, String mainNick, String backupNick, String chan)
        {
            // Validate the incoming information.  Keep in mind that if any of these are wrong it 
            // will use defaults defined at the top of this file.
            if (server != "")
                ircServer = server;
            if (port != 0)
                ircPort = port;
            if (mainNick != "")
                nickNameMain = mainNick;
            if (backupNick != "")
                nickNameBckup = backupNick;
            if (chan != "")
                channel = chan;

            // Connect to IRC using the settings
            connect();
        }

#endregion


#region connect
        public void connect()
        {
            // Assign events
            eventReceiving += new CommandReceived(ircCommandReceived);
            eventTopicSet += new TopicSet(ircTopicSet);
            eventTopicOwner += new TopicOwner(ircTopicOwner);
            eventNamesList += new NamesList(ircNamesList);
            eventServerMessage += new ServerMessage(ircServerMessage);
            eventJoin += new Join(ircJoin);
            eventPart += new Part(ircPart);
            eventMode += new Mode(ircMode);
            eventNickChange += new NickChange(ircNickChange);
            eventKick += new Kick(ircKick);
            eventQuit += new Quit(ircQuit);
            eventQuery += new Query(ircQuery);

            // Connect to the IRC server.
            ircConnection = new TcpClient(ircServer, ircPort);
            ircStream = ircConnection.GetStream();
            ircReader = new StreamReader(this.ircStream);
            ircWriter = new StreamWriter(this.ircStream);

            // If logging is enabled, let's turn it on and indicate what time we started
            if (logging == true)
            {
                loggerWriter = new StreamWriter(LOG_FILE, true);
                loggerWriter.WriteLine("---------[STARTING: " + DateTime.Now + "]");
            }

            // Authenticate our user
            ircWriter.WriteLine(String.Format("USER " + ircUser)); 
            ircWriter.Flush();

            // Needs to be extended to check if the main nick is in use and use the bckup if necessary
            ircWriter.WriteLine(String.Format("NICK " + nickNameMain));
            ircWriter.Flush();

            if (channel != "")
            {
                ircWriter.WriteLine(String.Format("JOIN " + channel));
                ircWriter.Flush();
            }

            // Start up our incoming data listener
            IncomingData();

            // Turn on the AI stuff.
            myAI = new AI();

            if (google == true)
                myGoogle = new googleBrain();

            if (AIML == true)
                myAIML = new AIMLbrain();

        }
#endregion

#region quitProgram
        private void quit_program()
        {
            ircWriter.Close();
            ircReader.Close();
            ircConnection.Close();

            if (logging == true)
            {
                loggerWriter.WriteLine("---------[QUITTING: " + DateTime.Now + "]");
                loggerWriter.Close();
            }
            canQuit = true;
        }
#endregion


#region IncomingData
        ////////////////////////////////////////////////
        /////////////INCOMING DATA//////////////////////
        ////////////////////////////////////////////////
        // These methods will handle the incoming     //
        // data and process it.                       //
        ////////////////////////////////////////////////

        private void IncomingData()
        {
            // Start a new thread for the incoming data
            listenerThread = new Thread(new ThreadStart(ReceiveData));
            listenerThread.Start();
        }

        private void ReceiveData()
        {
            // Listen for commands
            string ircCommand;
            while ((ircCommand = ircReader.ReadLine()) != null)
            {
                if (eventReceiving != null)
                    this.eventReceiving(ircCommand); 
                
                string[] commandParts = new string[ircCommand.Split(' ').Length];
                commandParts = ircCommand.Split(' ');
                if (commandParts[0].Substring(0, 1) == ":")
                {
                    commandParts[0] = commandParts[0].Remove(0, 1);
                }
                
                if (commandParts[0] == ircServer)
                {
                    // Server message
                    switch (commandParts[1])
                    {
                        case "332":
                            ircTopic(commandParts);
                            break;
                        case "333":
                                ircTopicOwner(commandParts);
                                break;
                            case "353":
                                ircNamesList(commandParts);
                                break;
                            case "366":
                                //this.ircEndNamesList(commandParts);
                                break;
                            case "372":
                                //this.ircMOTD(commandParts); 
                                break;
                            case "376":
                                //*this.ircEndMOTD(commandParts);
                                break;
                            default: 
                                ircServerMessage(commandParts);
                                break;
                        }
                    }
                    else if (commandParts[0] == "PING")
                    {
                        // Server PING, send PONG back
                        ircPing(commandParts);
                    }
                    else
                    {
                        // Normal message
                        string commandAction = commandParts[1];
                        switch (commandAction)
                        {
                            case "JOIN":
                                ircJoin(commandParts);
                                break;
                            case "PART":
                                ircPart(commandParts);
                                break;
                            case "MODE":
                                ircMode(commandParts);
                                break;
                            case "NICK":
                                ircNickChange(commandParts);
                                break;
                            case "KICK":
                                ircKick(commandParts);
                                break;
                            case "QUIT":
                                ircQuit(commandParts);
                                break;
                            case "PRIVMSG":
                                ircQuery(commandParts);
                                break;
                        }
                    }
                }

                // No longer able to read data, let's quit.                
                quit_program();
        } 
#endregion

        public void getCommand()
        {

        }


#region Server Messages
        private void ircTopic(string[] ircCommand)
        {
            string channel = ircCommand[3];
            string ircTopic = "";
            for (int intI = 4; intI < ircCommand.Length; intI++)
            {
                ircTopic += ircCommand[intI] + " ";
            }
            if (eventTopicSet != null) 
                this.eventTopicSet(channel, ircTopic.Remove(0, 1).Trim()); 
        } 

        private void ircTopicOwner(string[] ircCommand)
        {
            string channel = ircCommand[3];
            string ircUser = ircCommand[4].Split('!')[0];
            string TopicDate = ircCommand[5];
            if (eventTopicOwner != null)
                this.eventTopicOwner(channel, ircUser, TopicDate); 
        } 

        private void ircNamesList(string[] ircCommand)
        {
            string UserNames = "";
            for (int intI = 5; intI < ircCommand.Length; intI++)
            {
                UserNames += ircCommand[intI] + " ";
            }
            if (eventNamesList != null)
                this.eventNamesList(UserNames.Remove(0, 1).Trim()); 
        } 

        private void ircServerMessage(string[] ircCommand)
        {
            string serverMessage = "";
            for (int intI = 1; intI < ircCommand.Length; intI++)
            {
                serverMessage += ircCommand[intI] + " ";
            }
            if (eventServerMessage != null) 
                this.eventServerMessage(serverMessage.Trim()); 
        } 
#endregion

#region User Messages
        private void ircJoin(string[] ircCommand)
        {
            string channel = ircCommand[2];
            string ircUser = ircCommand[0].Split('!')[0];
            if (eventJoin != null) 
                this.eventJoin(channel.Remove(0, 1), ircUser); 
        }

        private void ircPart(string[] ircCommand)
        {
            string channel = ircCommand[2];
            string ircUser = ircCommand[0].Split('!')[0];
            if (eventPart != null)
                this.eventPart(channel, ircUser); 
        } /* IrcPart */

        private void ircMode(string[] ircCommand)
        {
            string channel = ircCommand[2];
            string ircUser = ircCommand[0].Split('!')[0];
            string userMode = "";
            for (int intI = 3; intI < ircCommand.Length; intI++)
            {
                userMode += ircCommand[intI] + " ";
            }
            if (userMode.Substring(0, 1) == ":")
                userMode = userMode.Remove(0, 1);

            if (eventMode != null) 
                this.eventMode(channel, ircUser, userMode.Trim()); 
        } 

        private void ircNickChange(string[] ircCommand)
        {
            string userOldNick = ircCommand[0].Split('!')[0];
            string userNewNick = ircCommand[2].Remove(0, 1);
            if (eventNickChange != null) 
                this.eventNickChange(userOldNick, userNewNick); 
        } 

        private void ircKick(string[] ircCommand)
        {
            string userKicker = ircCommand[0].Split('!')[0];
            string userKicked = ircCommand[3];
            string channel = ircCommand[2];
            string kickMessage = "";
            for (int intI = 4; intI < ircCommand.Length; intI++)
            {
                kickMessage += ircCommand[intI] + " ";
            }
            if (eventKick != null) 
                this.eventKick(channel, userKicker, userKicked, kickMessage.Remove(0, 1).Trim()); 
        } 

        private void ircQuit(string[] ircCommand)
        {
            string userQuit = ircCommand[0].Split('!')[0];
            string quitMessage = "";
            for (int intI = 2; intI < ircCommand.Length; intI++)
            {
                quitMessage += ircCommand[intI] + " ";
            }

            if (quitMessage == "")
                quitMessage = version;

            if (eventQuit != null) 
                this.eventQuit(userQuit, quitMessage.Remove(0, 1).Trim()); 
        }
        private void ircQuery(string[] ircCommand)
        {
            string ircUser = ircCommand[0].Split('!')[0];
            string message = "";
            for (int intI = 3; intI < ircCommand.Length; intI++)
            {
                message += ircCommand[intI] + " ";
            }

            // Let's chop off the ":" that starts each message, leaving us with the true message.
            message = message.TrimStart(':');

            if (eventQuery != null)
                this.eventQuery(ircUser, message);
        }

#endregion

#region PingControl
        // New and improved Ping command.  Will send a PONG to keep the bot connected.
        private void ircPing(string[] ircCommand)
        {
            string pingHash = "";
            for (int intI = 1; intI < ircCommand.Length; intI++)
            {
                pingHash += ircCommand[intI] + " ";
            }
            ircWriter.WriteLine("PONG " + pingHash);
            ircWriter.Flush();

            if (showPongReply)
                displayData("PONG " + pingHash);
        }
#endregion

#region logger
        ////////////////////////////////////////////////
        ///////////////////LOGGER///////////////////////
        ////////////////////////////////////////////////
        // Dump the lines into a log file for later   //
        // review.                                    //
        ////////////////////////////////////////////////
        private void LogFile(string line)
        {

            if (logging == true)
            {
                loggerWriter.WriteLine(line);
                loggerWriter.Flush();
                return;
            }
        }
#endregion

#region displayData
        private void displayData(string rawLine)
        {
            // If logging is enabled, let's write it to a log file.
            LogFile(rawLine);

            // Write the line to the console, after a small throttle.
            Thread.Sleep(50);
            Console.WriteLine(rawLine);
        }
#endregion


        private void ircCommandReceived(string ircCommand)
        {

        }

        private void ircTopicSet(string IrcChan, string IrcTopic)
        {
            
        } 

        private void ircTopicOwner(string IrcChan, string IrcUser, string TopicDate)
        {
            
        } 

        private void ircNamesList(string userNames)
        {
            displayData("Names List: " + userNames);
        } 

        private void ircServerMessage(string ServerMessage)
        {
            displayData(ServerMessage);
        } 

        private void ircJoin(string chan, string ircUser)
        {
            displayData(ircUser + " joins " + chan);
            ircWriter.Flush();
        } 

        private void ircPart(string IrcChan, string IrcUser)
        {
            
        } 

        private void ircMode(string IrcChan, string IrcUser, string UserMode)
        {
      
        } 

        private void ircNickChange(string UserOldNick, string UserNewNick)
        {
            
        } 

        private void ircKick(string IrcChannel, string UserKicker, string UserKicked, string KickMessage)
        {
            
        } 

        private void ircQuit(string userQuit, string quitMessage)
        {
            displayData(userQuit + " has quit IRC (" + quitMessage + ")");
        }

        private void ircQuery(string nickname, string message)
        {
            modifiedLine = "<" + nickname + "> " + message;

            // Okay, we're ready to display/log it.
            displayData(modifiedLine);

            // And now we're ready to see if it's a command the bot will recognize.
            incomingCommand(message, nickname);
        }


#region sendToChannel
        // Send messages something to the channel
        private void sendToChannel(string message)
        {
            // Let's pause a moment before sending the message
            Thread.Sleep(500);

            // Create the message
            ircWriter.WriteLine("PRIVMSG " + channel + " :" + message);

            // Log it, if the logging option is on
            //LogFile(">> " + channel + " : " + message);

            displayData(">> " + channel + " : " + message);

            // Flush it
            ircWriter.Flush();
        }
#endregion

#region IncomingCommandParser
        ////////////////////////////////////////////////
        /////////////INCOMING COMMAND PARSER////////////
        // The command parser takes the incoming text //
        // from the channel and determines if it's a  // 
        // command it recognizes and will perform it, //
        // if it is.                                  //
        ////////////////////////////////////////////////
        // Available Commands:                        //
        // !splash, !quit, !reload, !reloadAIML,      //
        // !toggleAIML, !toggleGoogle, !braininfo     // 
        ////////////////////////////////////////////////


        private void incomingCommand(string message, string nick)
        {

            // Break the command into their tokenized parts so we can determine what to do
            string[] commandString;
            commandString = message.Split(new char[] { ' ' });

            // Get the first element of the command string and convert it to upper case
            string command = commandString[0].ToString();
            command = command.ToUpper();

 #region Commands
            if (command == "!SPLASH")
            {
                Thread.Sleep(1000);   // throttle it so it won't commit a flood if tons of people use it.
                sendToChannel("Kon Splash!");
            }

            if (command == "!QUIT")
            {
                // For now, the nicks allowed to use this will be hardcoded
                if (nick == "Iyouboushi")
                {
                    ircWriter.WriteLine("QUIT " + ":" + version);
                    ircWriter.Flush();

                    Console.WriteLine("Kon can now be closed");
                    Thread.Sleep(500);
                    quit_program();
                }
            }

            if (command == "!RELOADAIML")
            {
                // For now, the nicks allowed to use this will be hardcoded
                if (nick == "Iyouboushi")
                {
                    sendToChannel("4Reloading AIML..please wait before using any commands..");
                    Console.WriteLine(">> RELOADING AI");
                    myAI = null;
                    myAI = new AI();

                    // Let's put the thread to sleep while it's reloading.
                    Thread.Sleep(1300);
                    sendToChannel("2AI Reloaded!");
                }
            }

            if (command == "!TOGGLEAIML")
            {
                // For now, the nicks allowed to use this will be hardcoded
                if (nick == "Iyouboushi")
                {
                    if (AIML)
                    {
                        AIML = false;
                        myAIML = null;
                        sendToChannel("4No longer using AIML for replies...");
                    }
                    else
                    {
                        AIML = true;
                        google = false;  // Can't run both google and AIML.
                        sendToChannel("4Loading AIML files..please wait before using any commands..");
                        myAIML = new AIMLbrain();
                        sendToChannel("4Now using AIML in addition to my brain for replies...");
                    }
                }
            }

            if (command == "!TOGGLEGOOGLE")
            {
                // For now, the nicks allowed to use this will be hardcoded
                if (nick == "Iyouboushi")
                {
                    if (google)
                    {
                        google = false;
                        sendToChannel("4No longer using Google for replies...");
                        myGoogle = null;
                    }
                    else
                    {
                        google = true;
                        AIML = false;  // Can't run both google and AIML.
                        sendToChannel("4Now using Google in addition to my brain for replies...");
                        myGoogle = new googleBrain();
                        myAIML = null;
                    }
                }
            }

            if (command == "!BRAININFO")
            {
                sendToChannel("My brain contains " + myAI.getBrainLength() + " lines.");
            }
  #endregion


            // Time to see if someone is talking to the bot.
            string addressingBot = nickNameMain + ":";
            addressingBot = addressingBot.ToUpper();

            if ((command == addressingBot) || (command == "KON:"))
            {
                string conversation = "";
                string[] messageWithoutCommand;
                messageWithoutCommand = message.Split(new char[] { ' ' });
                int msgLength = messageWithoutCommand.Length - 1;

                for (int i = 1; i <= msgLength; i++)
                {
                    conversation = conversation + messageWithoutCommand[i] + " ";
                }


                // Check to see if it's just an emoticon.. and if so.. let's not pass it.
                if (conversation.StartsWith(":"))
                {

                    // Let's pull something from Kon's brain.
                    string reply = myAI.pullFromBrain();
                    reply = reply.Replace("un-named user", nick);
                    reply = reply.Replace("UNNAMED USER", nick);
                    sendToChannel(reply);
                    Thread.Sleep(500);
                }

                if (conversation.StartsWith(";"))
                {
                    // Pull something from Kon's random brain
                    string reply = myAI.pullFromBrain();
                    reply = reply.Replace("un-named user", nick);
                    reply = reply.Replace("UNNAMED USER", nick);
                    sendToChannel(reply);
                    Thread.Sleep(500);
                }

                if (conversation.StartsWith("kill me"))
                {
                    // Pull something from Kon's random brain
                    string reply = myAI.pullFromBrain();
                    reply = reply.Replace("un-named user", nick);
                    reply = reply.Replace("UNNAMED USER", nick);
                    sendToChannel(reply);
                    Thread.Sleep(500);
                }

                else
                {
                    try
                    {

                        // Replace all punctuation with spaces to prevent it from going nuts
                        conversation = conversation.Replace(".", "");
                        conversation = conversation.Replace("!", "");
                        conversation = conversation.Replace(",", "");
                        conversation = conversation.Replace("?", "");

                        // Get the reply from the bot

                        String reply = "";

                        // Throttle it a little bit in case there's too many people talking to it at once.
                        Thread.Sleep(500);

                        #region AIMLbrain
                        // If AIML is enabled we'll use the AIML files to find a reply for the user.
                        if (AIML)
                        {
                            // Let's get the reply from the AIML structure
                            reply = AIMLbrain.getReply(reply, conversation, nick);
                        }
                        #endregion

                        #region googleBrain
                        // If the google method is enabled, we'll turn to the web to pull out a response.
                        if (google)
                        {
                            conversation = conversation.Replace("?", "");
                            conversation.Trim();
                            reply = myGoogle.getReply(conversation);
                            reply = reply.Replace("UNNAMED USER", nick);
                        }
                        #endregion


                        // This is a last ditch effort to try and respond to the user. If the other methods have failed,
                        // this will reach into kon's most basic brain and pull out a reply.
                        if (reply == "")
                        {
                            reply = myAI.pullFromBrain();
                            reply = reply.Replace("un-named user", nick);   // this will change later.
                            reply = reply.Replace("UNNAMED USER", nick);    // so will this.
                        }

                        // Make sure the reply isn't too long so it doesn't crash the bot.
                        int replyLength = reply.Length;
                        if (replyLength >= 150)
                            reply = reply.Substring(0, 150);
                        else
                            reply = reply.Substring(0, replyLength);

                        // Display the response and log it.
                        sendToChannel(reply);
                    }
                    catch (Exception e)
                    {
                        // Show the exception
                        Console.WriteLine(e.ToString() + CRLF);

                        // Sleep, before we try again
                        Thread.Sleep(1000);
                    }
                }

            }

            else
            {
                // We're going to force the bot to learn something
                myAI.addToBrain(message, nick);
            }


        }
#endregion

    } 
}