IRC Client

For me learning (programming;) ) languages is something close to a hobby. Apart from what is commonly used (BASIC, C, Pascal and variations) I also tried things like LISP, Prolog, Haskell and some scripting languages (e.g. UnrealScript) and more recently – Ruby. First I bumped into it while searching for an IRC bot, but it looked horrible… However, that was mainly bacause Ruby syntax is quite flexible and that example was just not to my taste… For various reasons I decided to give it another shot and learn it – to my suprise, it’s pretty easy and – what is more important – useful. Maybe not for mainstream applications, but for some web and text-processing related things it’s great…

That’s why I choosed to learn this language by writing… a web image downloader:) It worked, but only with limited number of sites – nowadays very few web pages use “normal” HTML and getting the images can be quite tricky…

That’s why I created another – more practical – app: an IRC Client. There are quite a few nice clients to choose from (mIRC for Windows, ircII for linux console), but I though that:
1) it would be good to have a simple platform for writing bots (Autumn Leaves (although also written in Ruby) is quite heavy… some others don’t work to well…)
2) it would be good to learn the IRC protocol, and this app is good for it because it shows and can accept raw irc messages
3) maybe it will serve as a learning example for someone…

What can it do?
1) join and talk to multiple channels, as well as handle private chats,notices and server messages (what is just enough for most of the people out there)
2) change user mode
3) List users/channels (the last one needs some work to be user friendly…)
4) send any IRC command entered by user (but you do have to know what you are doing and you do it at your own risk)
5) receive dcc file sends (resume supported)
6) process dcc download queue (actually, I use this client mostly for it’s xdcc capabilities – batch downloads, autoresumes, cooldowns etc… works perfectly with bots I’ve encountered:)  and handles big (9GB… ) files)
7) record channel conversations to file
8) Read configuration from environment variables: IRCNICK, IRCSERVER, IRCPORT – thanks Rob Pitt!

Output from the help command

IRC Client by Lurker_pas
Available commands:
>> help – shows this help
>> say *message* – sends specified message to channel
>> notice *message* – sends specified notice to channel
>> psay *nick* *message* – sends specified message to specified client
>> quit – quits
>> channels – lists channels
>> users – lists users on the active channel
>> mode *modechange* – sets user mode ([+|-][i|w|s|o])
>> join *channel* – join specified channel
>> leave *channel* – leave specified channel
>> context *channel* – set the channel you want to talk to
>> /*command* – direct IRC protocol command (without validation)
>> raw – start showing all unprocessed messages from server
>> unraw – stop showing all unprocessed messages from server
>> record *filename* – start recording channel messages to the specified file
>> dontrecord – stop recording
>> dccaccept *name* – accept all dcc sends from *name*
>> dccdeny *name* – deny all dcc sends from *name*
>> dccrequestresume – request resume if file sent by dcc send exists
>> dccdontrequestresume – dont request resume
>> dcclist *name* – send xdcc list command to *name*
>> dccinfo *name* *pack* – request info from *name* on pack number *pack*
>> dccqueue *name* *pack* – add pack *pack* from *name* to the auto-download
>> queue
>> dccqueue *name* *start*:*stop*:*step* – add packs from *start* to *stop*
>> stepping by *step* from *name* to the auto-download queue
>> dccqueueclear – clear the auto-download queue
>> dccqueueremove *item*- remove the given element from the auto-download queue
>> dccqueuecancel – cancel the current download by the auto-download queue
>> dccqueuecooldown *seconds* – set the ‘after-download’ cooldown for
>> *seconds* seconds
>> dccqueuelist – list contents of the download queue
>> dccautoresume – turn on download auto-retry
>> dccdontautoresume – turn off download auto-retry
>> dccautoresumecooldown *seconds* – set the ‘auto-resume’ cooldown for
>> *seconds* seconds
>> dccautoresumemaxretries *number* – set the number of ‘auto-resume’
>> retries to *number*
>> talk – enter talk mode
>> !talk – leave talk mode
>> echo – print all messages sent to the IRC server
>> dontecho – dont print the messages sent to the IRC server
>> msg – print special messages sent from the IRC server
>> dontmsg – dont print special messages sent from the IRC server
>> NOTE : *record* records only channel messages from subscribed channels
>> – no private chats are recorded
>> NOTE : *dccaccept name* must be invoked >>before<< the actual download
>> occurs (before dccget or dccqueue…)
>> NOTE : queue cooldown is given in (integer) seconds

In action:

The same “conversation” on #test, as seen from both sides:



The app was put here, directly on the blog, but recently it grew a little too big to, so you can download it from there

Quick’N’Dirty tutorial
1) Enter server name (eg. or
2) Enter your nick (eg. newbie667)
3) Wait for server welcome spa… messages;)
4) type “join xyz” where xyz is your favourite channel (eg. gamedev (on afternet))
5) type “talk”
6) Everything you type now will be sent to the channel….
7) When you want to leave, type “!talk” and then “quit”
8) That’s it!

Of course you can join multiple channels and change the one you are talking to with “context” (you are listening to all of them simultaneously) or private message people using “psay”, put notices using “notice”, interact with bots using various “dcc…” commands (remember to add a bot to your whitelist using “dccaccept” before starting any downloads!) – batch downloading is what this client is good at – the “talk” mode was added only recently;)


NOTICE: This app runs well on Linux (Debian), but not on Windows – this is caused by gets (and all known to me equivalents) hanging ALL threads
NOTICE: This app was developed based on a simple IRC bot from

Code(old one, just for sake of history and those who want to see the basic stuff, not overloaded with extra features):

NOTE >> This code doesn’t work well with all irc servers, as different servers send a bit different messages…
NOTE >> If you just want to take a look and see how everything is organized, go ahead,
NOTE >> but if you want to use it, then download the newest code from here
NOTE >> That code contains many improvements and more features…

#!!OUTDATED!! Please see the notices
#Created 2007 10 10
#Author: Lurker_pas
#Based on: simple IRC bot from

require “socket”
require “monitor”

class IRCClient

def initialize(server, port, nick)
@server = server
@port = port
@nick = nick
@channel = “”
@dead = false
@raw = false

def print_help
puts “IRC Client by Lurker_pas”
puts “Available commands:”
puts “>> help – shows this help”
puts “>> say *message* – sends specified message to channel”
puts “>> psay *nick* *message* – sends specified message to specified client”
puts “>> quit – quits”
puts “>> mode *modechange* – sets user mode ([+|-][i|w|s|o])”
puts “>> join *channel* – join specified channel”
puts “>> leave *channel* – leave specified channel”
puts “>> context *channel* – set the channel you want to talk to”
puts “>> /*command* – direct IRC protocol command (without validation)”
puts “>> raw – start showing all unprocessed messages from server”
puts “>> unraw – stop showing all unprocessed messages from server”


def send(s)
puts “–> #{s}”
@irc.print “#{s}\r\n”
def connect()
puts “Connecting to server #{@server} at port #(@port)…”
@irc =, @port)
puts “Setting Nick to #{@nick} and User to #{@nick} user…”
send “USER #{@nick} server #{@server} :#{@nick} user”
send “Nick #{@nick}”

def handle_server_input(s)
case s.strip
when /^PING :(.+)$/i
puts “[ Server ping ]”
send “PONG :#{$1}”
when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s.+\s:[01]PING (.+)[01]$/i
puts “[ CTCP PING from #{$1}!#{$2}@#{$3} ]”
send “NOTICE #{$1} :01PING #{$4}01”
when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s.+\s:[01]VERSION[01]$/i
puts “[ CTCP VERSION from #{$1}!#{$2}@#{$3} ]”
send “NOTICE #{$1} :01VERSION Ruby-IRCClient v0.00101″
when /^:(\S*)!(.)* PRIVMSG #{@nick} :(.*)$/
puts $1+” >>*>> “+$3
when /^:(\S*)!(.)* PRIVMSG (#\S+) :(.*)$/
puts $1+”@”+$3+” >> “+$4
if @raw then
puts s

def user_handler(lock)
while true
s = gets

if s=~ /^say / then
lock.synchronize do
send “PRIVMSG #{@channel} :”+s.gsub(/^say /,””)

if s=~ /^psay (\S*) (.*)/ then
lock.synchronize do
send “PRIVMSG “+$1+” :”+$2

if s=~ /^context (.+)/ then
@channel = $1
if !(@channel =~ /^#.*/) then
@channel = “#”+@channel

if s=~ /^join (.+)/ then
@channel = $1
if !(@channel =~ /^#.*/) then
@channel = “#”+@channel
lock.synchronize do
send “JOIN #{@channel}”

if s=~ /^leave (.+)/ then
channelname = $1
if !(channelname =~ /^#.*/) then
channelname = “#”+channelname
lock.synchronize do
send “PART #{channelname}”

if s=~ /^raw/ then
@raw = true

if s=~ /^unraw/ then
@raw = false

if s=~ /^mode ([+-][iwso]+)/ then
lock.synchronize do
send “MODE #{@nick} :”+$1

if s=~ /^quit/ then
lock.synchronize do
send “QUIT”
@dead = true

if s=~ /^\/(.*)/ then
lock.synchronize do
send $1.chomp

if s=~ /^help/ then

puts “Invalid command”


def main_loop()
lock =

input = do

while true
ready = select([@irc],nil, nil,1)
break if @dead
next if !ready

for rs in ready[0]
if rs == @irc then
return if @irc.eof
lock.synchronize do
s = @irc.readline.chomp



puts “Enter server name:”
server_name = gets.chomp
puts “Enter nick:”
nick = gets.chomp

irc =, 6667,nick)
rescue Exception => e
puts “Exception while executing”+e

6 Responses to “IRC Client”

  1. Hi there,

    I couldn’t resist playing with your IRC client on and off this afteroon and re-factored it a bit so it used individual reactor methods to react to each IRC message rather than one big handler. If only I knew you had the download-able file I could have played with that!

    Oh well. I edited your old version. It’s not really much different but it supports some of the IRC environment variables from irssi and has the different code layout. Fixed a couple of small bugs too, which you have probably already fixed in your later version. You might like my reaction pattern better than the big handler block as you add more stuff to it otherwise it will end up with one huge big fat method.

    You can get the mercurial repo I made while fiddling with it here if you want to see:

    Here is the mercurial commit log of what I did with it:

    * Sends all commands to methods named react_to_command
    * @origin contains the origin of the last received command (if any)
    * Fixed bug with version reply
    * MOTDs are displayed
    * NOTICES are displayed
    * Fixed 2 bugs with raw command
    * Raw mode has an extra level for even more rawness.
    * Started using predicate?/set_flag! pattern for config (just raw for now)
    * Supports the following environment variables (just like irssi)
    * – IRCSERVER => Connect to this irc server.
    * – IRCPORT => Connect on this irc port.
    * – IRCNICK => Use this nick to IRC with
    * – IRCVERSION => Send this in reply to CTCP VERSION (not from irssi)
    * IRC client VERSION reply can be changed (and the default is now silly)
    * Uses homeless/debugging tools if available
    * A UserInfo class for holding data about users who send us messages
    * CTCP handling code split off into separate functions
    * CTCP handling of VERSION and PING works
    * “raw” mode displays messages with p not puts (to see non-printables better)
    * “ctcp” command allows to send CTCP messages
    * Exceptions are no longer caught to aid debugging
    * Expressions spaced out
    * UTF-8 characters like curley quotes and ellipsis replaced with ASCII equivelents
    * Some minor code style changes (but no logic changes)
    * One maybe two trivial and glaringly obvious bugs fixed
    * Copied and pasted from

  2. Hi,
    Wow, I haven’t tested your code, but it does look a lot nicer than mine. It’s really a shame that you modified the old version, instead of the “new” one… but I guess I’m the one to blame for making the links small and sunk in a long text…I hope it’s a little better now.
    Still, a great job:)

  3. […] ‘IRC’ and ‘Ruby’ and came across Lurker’s Blog.  Lurker coded a very basic command line IRC Client which already provides the following functionality: What can it do? 1) join and talk to multiple […]

  4. not bad at all! :)

  5. lukerpas, can you reupload rp’s improved version somewhere? Thanks :)

  6. OK, I hope that’s the one – at least the name matches:)

    Rob Pitt’s branch->

    Please take into account, that this file is 2 years old and the original client got some more features… But if you are interested in the basic code, then this version is indeed cleaner, nicer and more robust:)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: