IRC chat bot and monitor

Home  >>  Cool  >>  IRC chat bot and monitor

IRC chat bot and monitor

On January 31, 2007, Posted by , In Cool,PowerShell,Utility, With Comments Off on IRC chat bot and monitor

Last weekend, I asked my wife if she could think of anything inappropriate or unusual to do with PowerShell. She came up with some good ideas and one of them was to write a chat/IM client.

A full client takes time, so with a nod toward PowerShell’s administrative uses, I wrote a script that forms the basis of an IRC chat bot.

This script can be used to pipe messages to a chat channel and/or join a set of channels, returning all messages posted there.

I’ve sure most of you out there use Microsoft MSN Windows Live Messenger, or even Yahoo! or AOL, so this may just serve as an example of synchronous TCP/IP messaging in PowerShell.

You can download the script here: chat-irc.ps1.

You may need to unblock it according the the instructions in help about_signing.

Summary of use

This script operates in two modes, sender, or monitor (or both).

Regardless, you need to set up connection info in a hash, eg:

$coninfo = @{
  server="chat.freenode.net"
  port=6667
  nick="mynick"
  user="myuser"
  pwd="my password if required"
  realname="This is my real name"
  hostname"This is my host name, but is generally ignored"
}

💡 I’ve been using chat.freenode.net and my own local hybrid irc server for testing.

To send a message to the #test channel and quit:

chat-irc -coninfo $coninfo -sendto "#test" -message "Hello, world"

To send output from the pipeline, eg a file:

gc file.txt | chat-irc -coninfo $coninfo

To monitor a channel for messages:

chat-irc -coninfo $coninfo -monitor "#test"

This will stay connected until you ctrl+C, are killed by the server, etc, or if chat-irc is sent the message “stopstopstop”.

The output is formatted strings containing from/to/message, however these strings are annotated with noteproperties, so you can do:

chat-irc -coninfo $coninfo -monitor "#test" select *

The properties include sender info (user,host,nick,full), date, to and message.

These two modes can be used together, and the monitor parameter can take
more than one channel, so for example:

chat-irc -coninfo $coninfo -monitor "#foo","#bar" -sendto "#test" -message "hello"

will send “hello” to #test then monitor #foo,#bar and #test for messages.

By default, only messages sent to the monitored channel(s) are output, but you can include private messages with the switch -incprivate, the message of the day with -incmotd, notices with -incnotice and other with -incother.

You can see debug info with -debug and verbose output (all messages)
with -verbose. These latter switches just set the $DebugPreference and $VerbosePreference variables to “Continue” in the script’s scope See Debug and Verbose Colouring for more information on that.

Examples

Here we get chat-irc to monitor the channel #test2 whilst I (millinad) chat to it in a normal IRC chat client.

PS> chat-irc -coninfo $coninfo -monitor "#test2" | select date,nick,message|ft -wrap

date                         nick                        message
----                         ----                        -------
31/01/2007 14:21:20          millinad                    hello soapybot
31/01/2007 14:21:30          millinad                    nice to see you here
31/01/2007 14:21:38          millinad                    time for you to go now
31/01/2007 14:21:40          millinad                    stopstopstop

and in the chat client:

 * soapybot (n=soapybot@*******) has joined #test2
  hello soapybot
  nice to see you here
  time for you to go now
  stopstopstop
 * soapybot (n=soapybot@*******) has left #test2

Now lets do the same thing again, but with debug switched on and private messages enabled. We’ll turn off the pipeline formatting.

PS> chat-irc -coninfo $coninfo -monitor "#test2" -incprivate -debug
DEBUG: Using connection info:
DEBUG: server: chat.freenode.net
DEBUG: port: 6667
DEBUG: user: soapybot
DEBUG: nick: soapybot
DEBUG: pwd: ************
DEBUG: realname: powershell bot using soapyfrog inout-irc.ps1
DEBUG: hostname: localhost
freenode-connect : soapybot : ☺VERSION☺
DEBUG: I *may* have joined channel #test2
millinad : #test2 : hello again
millinad : #test2 : i see you received a ctcp message above. pity you don't understa
nd them.
millinad : #test2 : time to go again
millinad : soapybot : stopstopstop

In the last line, I sent soapybot a direct message to stopstopstop rather than to the channel. Without -incprivate this message would not have been output.

How it works

The script connects to the chat server using System.Net.Sockets.TcpClient. Messages are sent using a System.IO.StreamWriter with ASCII encoding. .NET doesn’t seem to mind of non ASCII chars are translated in this way.

Reading messages is done differently. We can’t use a System.IO.StreamReader, because ReadLine blocks if there isn’t a full line available.

We can’t use asynchronous reading because it’s quite hard to use scriptblocks as delegates (although that might change in future versions of PowerShell), and threading is a bit of an unknown quantity in PowerShell.

Instead I use the Net.Sockets.NetworkStream with its DataAvailable and ReadByte. This means I can check if data is available, and if not, idle or send messages, then check again. Reading byte by byte makes the code easier to read, and it’s not too big a performance hit, we’re bound by the network and the speed of people typing 🙂

Lines are processed in the process-line function where the line is parsed and checked for known numeric responses and commands.

The default handling of a message is in the function _onprivmsg where the message is just formatted and decorated and place into the output pipeline.

💡 If you wanted to have this bot do something else, you would do it here.

A good chat citizen

This script tries to be a good citizen by throttling it’s message sending with 1 second delays between messages. This is set with the -throttledelay parameter (milliseconds). The amount of time the script idles when there is no data from the server is 2 seconds, set with the -idledelay parameter.

Even with these values, it’s still possibly to be killed by a server for flooding. You may want to ask server admin to reduce the flood spec for your bot, or increase the throttledelay.

For example, at chat.freenode.net, piping the output from a directory listing would still cause a flood.

Enjoy 🙂

Comments are closed.