Friday, June 10, 2011

A simple bash IRC logging bot

Couple of years ago I googled for a simple bash IRC logging bot that I could start on my router to log some channels. I've found a very simple script that worked but didn't handle PINGs from the server. So I extended it a bit trying to keep it as simple as possible.

root@alix:~# cat ./irclogbot.sh 
#!/bin/sh 

nick="blb$$"
channel=testchannel
server=irc.freenode.net
config=/tmp/irclog

[ -n "$1" ] && channel=$1
[ -n "$2" ] && server=$2
config="${config}_${channel}"

echo "NICK $nick" > $config 
echo "USER $nick +i * :$0" >> $config 
echo "JOIN #$channel" >> $config 

trap "rm -f $config;exit 0" INT TERM EXIT

tail -f $config | nc $server 6667 | while read MESSAGE 
do
  case "$MESSAGE" in
    PING*) echo "PONG${MESSAGE#PING}" >> $config;;
    *QUIT*) ;;
    *PART*) ;;
    *JOIN*) ;;
    *NICK*) ;;
    *PRIVMSG*) echo "${MESSAGE}" | sed -nr "s/^:([^!]+).*PRIVMSG[^:]+:(.*)/[$(date '+%R')] \1> \2/p";;
    *) echo "${MESSAGE}";;
  esac
done 


PING's are handled in the line 22. Lines 23-27 are only added to make output readable and could be removed to log raw data. 

The feedback inside of the 'while' loop allows me to use the script as a simple client too. IRC commands written into the $config file will be executed. For example one can send a text message into the channel by writing the following command:

echo "PRIVMSG #testchannel :Testing bash bot. Ignore it" >> /tmp/irclog_testchannel 
which makes it possible to re-purpose the bot by adding additional logic.

Insted of nc one can use telnet and in this case only busybox internal commands will be used

5 comments:

Erik said...

That`s just awesome. I was about to write my own bash script for logging but failed. Then I found yours and it`s exactly what I wanted to do. Best of all: I know what I did wrong now and understood how easy it really is :)

Thanks a lot

Erik

Anonymous said...

Thanks for sharing this. It was very useful to me.

I have changed a few things to avoid using nc, and use Bash built-in TCP sockets.

---

# Open the TCP connection.
exec 3<>/dev/tcp/$SERVER/$PORT
...
# Process each server command and logs everything.
while read -u 3 MESSAGE
do
MESSAGE=$(sed 's/\r//' <<< $MESSAGE )
echo "$(date -u +'%F %T') $MESSAGE" >>$LOG
case "$MESSAGE" in

alex said...

yes, you can use bash sockets too but as I mentioned already neither nc nor bash is available on an embedded system with the busybox and ash. Replacing nc with telnet makes the script working on my router too.

Unknown said...

This script works great. I've tried nc, telnet and bash builtin tcp. I have two tips for others reading this and trying.

1. If you are using the bash tcp code posted above, you can scrap the config file and redirect the output on your echos with '>&3' instead. Like so:

echo -e "NICK ${nick}" >&3
echo -e "USER $nick +i * :$0" >&3
(sleep 1;echo -e "JOIN #${channel}" >&3) &

2. Also as seen above, I noticed some servers was not ready to accept JOIN right away so I ran it in a subshell with a sleep before. The '&' character makes the commands run in the background while the script in the main shell continues as normal.

Alberto34 said...

Sometimes first reply to ping server not work, why?