• (2 Pages)
  • +
  • 1
  • 2

IRC Bot 101 - basic bot layout and creation. Rate Topic: -----

#1 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8371
  • View blog
  • Posts: 31,098
  • Joined: 12-June 08

Posted 06 July 2011 - 08:17 PM

*
POPULAR

With the latest (at the time of writing this) competition under way (IRC Competition) I thought it was best if I rolled up my sleeves, created a bot shell, and shared the knowledge.

What this will teach you is the basic mechanics of connecting to an IRC server, responding to the IDENT, and processing a few commands. This is not the end all be all of IRC bot help, but it should give enough of you the push to develop the concepts farther and a good base to work from.

A few quick topics to discuss.
1. Don't be a dick with the bot code you create from this. If a server doesn't allow bots be cool and move to another server. Don't spam people or harass people with this. Just be cool. There are plenty of servers that don't mind bots as long as they are not abusive.

2. If you hit a server that bans you because you borked your bot code don't freak out. Just move on. The IRC network is huge. I accidentally banned myself from a few places as I was testing out the code for this tutorial.

3. IRC What is it?
IRC stands for 'internet relay chat'. It's the original real time instant messaging system that was built back in the late 80's as an alternative to BBS messages. Hit the wiki page up and fill your brain with history. Just know it's big, it's been around for a long time, and operates on a total open source protocols.

4. IRC clients - I suggest downloading a client and play with that first. Get a feel for what it's all about before you dive into the code. Clients provide a great way to test the bot commands! Being this is a .NET tutorial the main two clients I would recommend would be mIRC or xChat.

5. IRC Commands - there are a ton of them. As always wiki has a great list, but some may not work on servers. Usually if you check the server's website they will have documentation on the commands available. Wiki link.

Here is the main class. Plunk this down into your VB.NET solution. Don't worry - the main is below to show you how to get everything hooked up. The in depth bits and pieces are in the comments.

The basic flow is you create an object with critical components, and then make the object connect to the server. It'll open up a TCPClient connection to the IRC server on a specific port. While that is happening the class will open up a second connection to listen your port 113 for the identification code. It'll grab the code and respond. Assuming you haven't gone too far off the reservation the server will accept the IDENT and connect your bot to the room you specified. From there it will go into a loop listening for responses back from the server. This might be people entering the room, messages being posted, or the like. This bot will respond to two commands when anyone enters them.

Good luck!

Public Class My_IRC
    Private _sServer As String = String.Empty '-- IRC server name
    Private _sChannel As String = String.Empty '-- the channel you want to join (prefex with #)
    Private _sNickName As String = String.Empty '-- the nick name you want show up in the side bar
    Private _lPort As Int32 = 6667 '-- the port to connect to.  Default is 6667
    Private _bInvisible As Boolean = False '-- shows up as an invisible user.  Still working on this.
    Private _sRealName As String = "nodibot" '-- More naming
    Private _sUserName As String = "nodi_the_bot" '-- Unique name so of the IRC network has a unique handle to you regardless of the nickname.

    Private _tcpclientConnection As TcpClient = Nothing '-- main connection to the IRC network.
    Private _networkStream As NetworkStream = Nothing '-- break that connection down to a network stream.
    Private _streamWriter As StreamWriter = Nothing '-- provide a convenient access to writing commands.
    Private _streamReader As StreamReader = Nothing '-- provide a convenient access to reading commands.

    Public Sub New(ByVal server As String, ByVal channel As String, ByVal nickname As String, ByVal port As Int32, ByVal invisible As Boolean)
        _sServer = server
        _sChannel = channel
        _sNickName = nickname
        _lPort = port
        _bInvisible = invisible
    End Sub

    Public Sub Connect()

        '-- IDENT explained: 
        '-- -- When connecting to the IRC server they will send a response to your 113 port.  
        '-- -- It wants your user name and a response code back.  If you don't some servers 
        '-- -- won't let you in or will boot you.  Once verified it drastically speeds up 
        '-- -- the connecting time.
        '-- -- -- http://en.wikipedia.org/wiki/Ident
        '-- Heads up - when sending a command you need to flush the writer each time.  That's key.

        Dim sIsInvisible As String = String.Empty
        Dim sCommand As String = String.Empty '-- commands to process from the room.

        '-- objects used for the IDENT response.
        Dim identListener As TcpListener = Nothing
        Dim identClient As TcpClient = Nothing
        Dim identNetworkStream As NetworkStream = Nothing
        Dim identStreamReader As StreamReader = Nothing
        Dim identStreamWriter As StreamWriter = Nothing
        Dim identResponseString As String = String.Empty

        Try
            '-- Start the main connection to the IRC server.
            Console.WriteLine("**Creating Connection**")
            _tcpclientConnection = New TcpClient(_sServer, _lPort)
            _networkStream = _tcpclientConnection.GetStream
            _streamReader = New StreamReader(_networkStream)
            _streamWriter = New StreamWriter(_networkStream)

            '-- Yeah, questionable if this works all the time.
            If _bInvisible Then
                sIsInvisible = 8
            Else
                sIsInvisible = 0
            End If

            '-- Send in your information
            Console.WriteLine("**Setting up name**")
            _streamWriter.WriteLine(String.Format("USER {0} {1} * :{2}", _sUserName, sIsInvisible, _sRealName))
            _streamWriter.Flush()

            '-- Create your nickname.
            Console.WriteLine("**Setting Nickname**")
            _streamWriter.WriteLine(String.Format(String.Format("NICK {0}", _sNickName)))
            _streamWriter.Flush()

            '-- Tell the server you want to connect to a specific room.
            Console.WriteLine("**Joining Room**")
            _streamWriter.WriteLine(String.Format("JOIN {0}", _sChannel))
            _streamWriter.Flush()

            '-- By now the IDENT should be sent to your port 113.  Listen to it, grab the text, 
            '-- and send a response.
            '-- Idents are usually #### , ####
            '-- That is four digits, a space, a comma, and four more digits.  You need to send 
            '-- this back with your user name you connected with and your system.
            identListener = New TcpListener(IPAddress.Any, 113)
            identListener.Start()
            identClient = identListener.AcceptTcpClient
            identListener.Stop()
            Console.WriteLine("ident connection?")
            identNetworkStream = identClient.GetStream
            identStreamReader = New StreamReader(identNetworkStream)

            identResponseString = identStreamReader.ReadLine
            Console.WriteLine("ident got: " + identResponseString)
            identStreamWriter = New StreamWriter(identNetworkStream)
            '-- The general format for the IDENT response.  You can use UNIX, WINDOWS VISTA, WINDOWS XP, or what ever your system is.
            identStreamWriter.WriteLine(String.Format("{0} : USERID : WINDOWS 7 : {1}", identResponseString, _sUserName))
            identStreamWriter.Flush()

            '-- By now you should be connected to your room and visible to anyone else.  
            '-- If you are receiving errors they are pretty explicit and you can maneuver 
            '-- to debuggin them.
            '-- 
            '-- What happens here is the command processing.  In an infinite loop the bot 
            '-- read in commands and act on them.
            While True
                sCommand = _streamReader.ReadLine
                Console.WriteLine(sCommand)

                '-- Not the best method but for the time being it works.  
                '-- 
                '-- Example of a command it picks up
                ' :nodi123!nodi12312@ipxxx-xx.net PRIVMSG #nodi123_test :? hola!
                '-- You can extend the program to better read the lines!
                Dim sCommandParts(sCommand.Split(" ").Length) As String
                sCommandParts = sCommand.Split(" ")

                '-- Occasionally the IRC server will ping the app.  If it doesn't respond in an 
                '-- appropriate amount of time the connection is closed.
                '-- How does one respond to a ping, but with a pong! (and the hash it sends)
                If sCommandParts(0) = "PING" Then
                    Dim sPing As String = String.Empty
                    For i As Int32 = 1 To sCommandParts.Length - 1
                        sPing += sCommandParts(i) + " "
                    Next
                    _streamWriter.WriteLine("PONG " + sPing)
                    _streamWriter.Flush()
                    Console.WriteLine("PONG " + sPing)
                End If

                '-- With my jank split command we want to look for specific commands sent and react to them!
                '-- In theory this should be dumped to a method, but for this small tutorial you can see them here.
                '-- Also any user can input this.  If you want to respond to commands from you only you would 
                '-- have to extend the program to look for your non-bot-id in the sCommandParts(0)
                If sCommandParts.Length >= 4 Then
                    '-- If a statement is proceeded by a question mark (the semi colon's there automatically) 
                    '-- then repeat the rest of the string!
                    If sCommandParts(3).StartsWith(":?") Then
                        Dim sVal As String = String.Empty
                        Dim sOut As String = String.Empty
                        '-- the text might have other spaces in them so concatenate the rest of the parts 
                        '-- because it's all text.
                        For i As Int32 = 3 To sCommandParts.Length - 1
                            sVal += sCommandParts(i)
                            sVal += " "
                        Next
                        '-- remove the :? part.
                        sVal = sVal.Substring(2, sVal.Length - 2)
                        '-- Trim for good measure.
                        sVal = sVal.Trim
                        '-- Send the text back out.  The format is they command to send the text and the room you are in.
                        sOut = String.Format("PRIVMSG {0} : You said '{1}'", _sChannel, sVal)
                        _streamWriter.WriteLine(sOut)
                        _streamWriter.Flush()
                    End If
                    '-- If you don't quit the bot correctly the connection will be active until a ping/pong is failed.  
                    '-- Even if your programming isn't running!
                    '-- To stop that here's a command to have the bot quit!
                    If sCommandParts(3).Contains(":!Q") Then
                        ' Stop
                        _streamWriter.WriteLine("QUIT")
                        _streamWriter.Flush()
                        Exit Sub
                    End If
                End If
            End While

        Catch ex As Exception
            '-- Any exception quits the bot gracefully.
            Console.WriteLine("Error in Connecting.  " + ex.Message)
            _streamWriter.WriteLine("QUIT")
            _streamWriter.Flush()
        Finally
            '-- close your connections
            _streamReader.Dispose()
            _streamWriter.Dispose()
            _networkStream.Dispose()
        End Try

    End Sub
End Class



Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.IO

    Public Sub Main()

        Dim foo As New My_IRC("irc.freenode.net", "#nodi123_test", "nodime", 6667, False)
        foo.Connect()

    End Sub


Sample console output:
Spoiler


"Advance" routes from here:
- better command parsing
- better command response
- complex behavior and database interactions
- more complete room management

Is This A Good Question/Topic? 14
  • +

Replies To: IRC Bot 101 - basic bot layout and creation.

#2 smohd  Icon User is offline

  • Critical Section
  • member icon


Reputation: 1752
  • View blog
  • Posts: 4,409
  • Joined: 14-March 10

Posted 06 July 2011 - 08:57 PM

Good tutorial man, I think you should join the competition :^:
Was This Post Helpful? 1
  • +
  • -

#3 Gavisann  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 103
  • View blog
  • Posts: 382
  • Joined: 01-July 11

Posted 06 July 2011 - 09:01 PM

Very helpfulful and well explained, thanks!
Was This Post Helpful? 0
  • +
  • -

#4 Zher0k  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 30-July 11

Posted 30 July 2011 - 09:35 PM

Thanks, very interesting and explained well :)
Was This Post Helpful? 0
  • +
  • -

#5 Psyguy  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 69
  • View blog
  • Posts: 310
  • Joined: 12-January 11

Posted 18 August 2011 - 04:13 PM

Good starting point. I do have a little problem. When my code reaches the identListener.Start(), it hangs. By that I mean, the code doesn't go any further. I don't know whether this is on my end or their end (first time using my code to connect to something over the internet), but I left it running for ~15 minutes and still no progress. Any ideas?
Was This Post Helpful? 0
  • +
  • -

#6 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8371
  • View blog
  • Posts: 31,098
  • Joined: 12-June 08

Posted 18 August 2011 - 06:55 PM

Are you talking about line 80? Do you have any port blocking installed? That should be a pretty quick open and shut business. I was thinking about tossing it into a separate thread, but that would have been more complexity than I was looking for.

This post has been edited by modi123_1: 18 August 2011 - 06:55 PM

Was This Post Helpful? 0
  • +
  • -

#7 Psyguy  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 69
  • View blog
  • Posts: 310
  • Joined: 12-January 11

Posted 18 August 2011 - 10:00 PM

I don't have any ports blocked that i know of...but ya, line 80-81. I can't get past that line of code. i inserted a console output to indicate the start and stop, but I never get to the stop.

Edit: I made sure all my common ports were open...no luck. I'm connecting to the channel (I can see my nickname show up as joining the channel), but i get timed out for ping after a few minutes.

This post has been edited by Psyguy: 18 August 2011 - 10:24 PM

Was This Post Helpful? 0
  • +
  • -

#8 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8371
  • View blog
  • Posts: 31,098
  • Joined: 12-June 08

Posted 19 August 2011 - 06:42 AM

Well that should be picking up the secondary connection for the identification code. Sorry bro I don't know what's going on with your setup. Try commenting it out - maybe the IRC server you are on isn't sending the ident.. which would be odd but not unheard of.
Was This Post Helpful? 0
  • +
  • -

#9 snowfox18  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 21-August 11

Posted 21 August 2011 - 08:48 AM

identListener = New TcpListener(IPAddress.Any, 113)
identListener.Start()

TCPListener can't listen on server....
modi123_1 please.... help me!
Was This Post Helpful? 0
  • +
  • -

#10 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8371
  • View blog
  • Posts: 31,098
  • Joined: 12-June 08

Posted 21 August 2011 - 10:29 AM

I don't know what you are asking.`
Was This Post Helpful? 0
  • +
  • -

#11 snowfox18  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 21-August 11

Posted 21 August 2011 - 08:15 PM

line 80-81 :
identListener.Start()
identClient = identListener.AcceptTcpClient

====>>>>> can't run!.....
Was This Post Helpful? 0
  • +
  • -

#12 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8371
  • View blog
  • Posts: 31,098
  • Joined: 12-June 08

Posted 21 August 2011 - 09:03 PM

Refer to post #6.
Was This Post Helpful? 1
  • +
  • -

#13 snowfox18  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 21-August 11

Posted 22 August 2011 - 06:56 AM

Why when I use the console is running but it does not run with winform?
Was This Post Helpful? 0
  • +
  • -

#14 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8371
  • View blog
  • Posts: 31,098
  • Joined: 12-June 08

Posted 22 August 2011 - 07:02 AM

There's a lot of reasons, but the chief is I don't know how you set up your form. One thought would be the loop isn't working all the time. In a form it would need to be shoved to it's own thread.
Was This Post Helpful? 0
  • +
  • -

#15 snowfox18  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 4
  • Joined: 21-August 11

Posted 24 August 2011 - 06:49 AM

how to replace loop "while true" in winform???? thanks!
I used "thread" but it does not run as desire.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2