irctk

libircclient binding for scripts
git clone https://a3nm.net/git/irctk/
Log | Files | Refs | README

commit ed5fd26c217e7206f56019fce3e03f6544d16e31
parent 4c1cc7456587b9601c66f84df5cf508fea81653d
Author: Antoine Amarilli <a3nm@a3nm.net>
Date:   Fri,  7 Sep 2012 17:10:48 +0200

more doc

Diffstat:
README | 265+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 204 insertions(+), 61 deletions(-)

diff --git a/README b/README @@ -43,56 +43,198 @@ irctk is written using libircclient, you will need it to compile and run the program. Install libircclient-dev (on Ubuntu and Debian systems), or get it from <https://sourceforge.net/projects/libircclient/> and install it manually. -== 4. Examples == +== 4. How to use == - $ irctk logger@example.com #chan1 #chan2 > irc.log +As a simple interactive use of irctk, here is how you connect to the IRC server +at example.com and join channel #test: -Log what is said on #chan1 and #chan2 on example.com. Lines will be of -the form "[#chan1] <nick> message". +=== 4.1. Connecting to a server === - $ irctk logger@example.com #chan1 #chan2 | while read line; do + $ irctk example.com '#test' + +Messages on the channel will get output on your terminal and you can type +messages that you want so say on the channel. Press ^D to close stdin and +terminate irctk. Note that the use of quotes is to prevent your shell from +interpreting '#' (irctk won't see them). + +More elaborate options are supported. Here is how to connect to a +password-protected channel on a password-protected server on a non-standard +port, specifying a custom nickname, username and real name. + + $ irctk -U jh -R "James Hacker" nick:srvpass@example.com:3724 '#test:chanpass' + +=== 4.2. Using irctk's stdin === + +irctk is meant to be used non-interactively. For instance, you can say the +contents of a file to a server by giving it as standard input: + + $ irctk flooder@example.com '#flood' <file + +As a funnier example, here is how to follow the RSS feed of FML and post the +stories to a channel as they appear in the feed: + + $ rsstail -u 'http://feeds2.feedburner.com/fmylife' -NdzH -n 1 -i 300 | + grep --line-buffered '^ Today' | + ./irctk fmlbot@example.com '#fml' + +Note the use of --line-buffered to make sure that the messages do not get +buffered. If you receive mail to a mbox file, here is how you could use irctk to +get a private message to notify you about the subjects of incoming emails. + + $ tail -f ~/mbox | grep --line-buffered '^Subject:' | + irctk alert@example.com mynick + +As a last example, here is how to follow your server logs on IRC: + + $ ssh server tail -f logfile.log | irctk logger@example.com '#dashboard' + +=== 4.3. Using irctk's stdout === + +As another possible non-interactive use of irctk, you can log what is happening +on a channel by setting stdout to be a file: + + $ irctk logger@example.com '#chan' >file + +Here is a more complex example to log multiple channels in separate files and +with timestamps: + + $ irctk logger@example.com '#chan1' '#chan2' | while read line; do CHAN=$(echo "$line" | cut -d ']' -f 1 | cut -d '[' -f 2) MSG=$(echo "$line" | cut -d ' ' -f 2-) echo "`date +%s` $MSG" >> "$CHAN.log" done -Same, but write in one file per chan, and add timestamps. +Caution, if you want to run irctk in the background, you need to prevent it to +read from standard input (to avoid it being suspended) without closing stdin +(otherwise irctk will terminate). Here is how: - $ irctk you@example.com #chat <message.txt + $ tail -f /dev/null | irctk logger@example.com '#chan' >file & -Send the contents of a file to a channel. +Another example: play a sound whenever your nick is mentionned (but not when you +speak): - $ cowsay <message.txt | irctk you@example.com #chat + $ irctk example.com '#chan' | + grep --line-buffered '[^<]alex' | while read l; do + aplay alert.wav; + done -Send the contents of a file to a channel, where each line is said by a cow. +irctk has specific features to detect when it is addressed. Say you want to log +tasks to do by addressing a bot on IRC: - $ rsstail -u 'http://feeds2.feedburner.com/fmylife' -NdzH -n 1 -i 300 | - grep --line-buffered '^ Today' | - ./irctk fmlbot@example.com '#fml' + $ irctk -f todobot@example.com '#chan' >>~/todo + +To append lines to ~/todo, you can either address todobot on #chan through lines +such as "todobot: buy some milk", or you can send a private message to todobot +(using irssi, "/msg todobot write a poem to alice"). Note that the lines logged +in ~/todo will look like "[#chan] <mynick> todobot: buy some milk"; if you want +to get rid of the cruft, you can use: + + $ irctk -F todobot@example.com '#chan' >>~/todo + +which will only log "buy some milk". + +To combine the use of stdin and stdout, this invocation pipes two irctk calls +together to relay messages from source.com to destination.com (but not the +reverse): -Post FMLs on irc. + $ irctk listener@source.com '#chan1' | + irctk repeater@destination.com '#chan2' + +=== 4.4. Writing interactive bots === + +We will now look at interactive examples where you interface irctk's stdout to +some script or program which will do something intelligent and give something to +say to irctk in return. To do so, we will need a named fifo: $ mkfifo fifo -This creates a named FIFO which you will need for the next examples. +As an extremely simple interactive program, consider the following: $ cat fifo | ./irctk pongbot@example.com '#chat' | - cut -d '>' -f 2- | - grep --line-buffered 'ping' | - while read line; do echo "pong"; done | - tee fifo + awk '/[^<]ping/ { print "pong"; fflush() }' > fifo + +The awk invocation outputs "pong" whenever it sees a line containing "ping" +(excluding things such as "<ping" to avoid the issue of people with a nick +starting with "ping"). Note the use of fflush(), once again to avoid buffering. +The named FIFO is used to connect irctk's stdout to awk's stdin and awk's stdout +to irctk's stdin. Note that the cat invocation is required and "<fifo" will not +work. This means that pongbot will say "pong" on chan whenever someone says +something containing "ping". + +Note that you can use your favorite programming language instead of awk. If you +want to write an IRC bot in an esoteric language with no IRC library (or maybe +even no networking support), all you need to do is write some code which reads +incoming lines on stdin, posts outgoing lines on stdout, and *does not do +buffering*. You can then lift it to IRC very simply: + + $ cat fifo | ./irctk example.com '#chat' | program > fifo + +=== 4.5. Input and output format === + +The output format is of the following form (unless you use -F): + + [#chan] <nick> message + +By default, server events (joins, kicks, renames, etc.) are not output. If you +want them, you can either get them in a human-readable form with the -m flag: + + [#bar] -!- foo has joined #bar + +Alternatively, you can get them in a barebones form with -c: + + [#bar] <foo> /join #bar + +Your own messages will not be included unless you request it with -o. If you +want to see nicknames like <nick!~username@localhost>, use -w. Remember the -f +and -F options presented above to only keep lines addressed to you and to remove +everything but the message (-F implies -f). -Answer "pong" whenever someone says something containing "ping" (or if -his nick contains "ping"). +The input format is of the following form: - $ cat fifo | ./irctk -r pongbot@example.com '#chat' | - grep --line-buffered 'ping' | - while read line; do echo "pong"; echo; done | - tee fifo + [#chan] message -Same, but address the message specifically to the person. The empty "echo" -indicates the end of our answer to the person. (This is important so that irctk -can keep track of the person you are answering.) +You can specify multiple channel names separated by commas (but see the section +"Pipelining" below). + +Because specifying the chan each time can be tedious, irctk has options to guess +it. If you do not specify a destination and just give a message, irctk will say +it to the last active channel by default (i.e., the last channel where something +was heard), which is often a reasonable choice if you are replying to stuff. +There are other possible options: see the section "Implied destinations" below. + +irctk will always try to join a channel before saying something to this channel. +This means that it can join entirely new channels in this fashion. To disable +this behavior and prevent irctk from joining any channels except the ones given +at startup, use -J (can be useful if irctk's stdin is attacker-controlled). + +irctk will interpret some commands starting with '/' in a fashion similar to +irssi. To inhibit this (can be useful if irctk's stdin is attacker-controlled), +use -E. To escape, use '/say' or '/ '. The supported commands are: + + /nick NICKNAME (changes nick) + /mode MODE (set channel mode) + /part [CHAN] (part from a channel) + /join [CHAN] (join a channel) + /topic TOPIC (set channel topic) + /quit REASON (quit) + /invite USER [CHAN] (invite a user to a channel) + /kick USER [REASON] (kick user from current inferred destination) + /me MSG (/me message) + /say MSG (escape) + / MSG (escape) + +Optional channel names "[CHAN]" default to the current inferred destination. + +As an additional convenience, irctk can be made to address the last person who +addressed him with the -r option. In conjunction with the default destination +channel inference, this means that, using -fr, whenever you ask irctk to say +"message", it will say it to the last person who addressed him, on the channel +where it was addressed. This is very convenient to write bots. + +=== 4.6. Complete examples === + +This bot queries on wikipedia whatever is said to him, using the DNS-based +wikipedia query system as an ugly way to get the beginning of pages. $ cat fifo | irctk -Ffr wikibot@example.com '#chat' | while read line; do @@ -100,38 +242,33 @@ can keep track of the person you are answering.) dig +short txt $Q.wp.dg.cx; echo; done | tee fifo -A bot which queries on wikipedia whatever is said to him. +This is a way to play adventure on IRC. (Beware, people can overwrite files when +saving their game, so run as a suitably unpriviledged user.) The "while true" +loop is to restart the game whenever it exits. The socat invocation is used to +disable buffering. $ cat fifo | irctk -Ff DM@example.com '#adventure' | while true; do socat EXEC:adventure,pty,ctty,echo=0 STDIO; done | tee fifo -Multiplayer adventure! (Beware, people can overwrite files when saving -their game, so run as a suitably unpriviledged user.) The "while true" -loop is to restart the game whenever it exits. The socat invocation -is used to disable buffering. - - $ irctk listener@source.com '#chan1' '#chan2' | - irctk repeater@destination.com - -Repeat on destination.com whatever is said on channels #chan1 and #chan2 -of source.com. +Two-way gateway: gateway posts on #chan1 on server1.com whatever +is said to him on #chan2 on server2.com, and vice-versa: $ cat fifo | irctk -fF0 gateway@server1.com '#chan1' | irctk -fF0 gateway@server2.com '#chan2' | tee fifo -Two-way gateway: gateway posts on #chan1 on server1.com whatever -is said to him on #chan2 on server2.com, and vice-versa. - - $ tail -f /var/log/syslog | - irctk syslog@example.com '#syslog' +Run shell commands from your IRC client. BEWARE, this means that whoever is +named "admin" on the IRC server can run arbitrary commands on your machine, so +you really shouldn't do this. -Send your syslog messages to a channel. + $ cat fifo | ./irctk localhost '#tty' | + grep --line-buffered '^\[#tty\] <admin>' | + sed -u 's/^[^>]*> *//' | bash >fifo 2>&1 -TODO poor man's irc client with screen -TODO an IRC shell -TODO an IRC shell running irctk (irception!) +Whatever admin says on #tty will get run in a bash shell and the result will be +returned to the channel. Note that you can of course run irctk in this shell +(irception!). == 5. Pipelining == @@ -158,48 +295,51 @@ irctk will choose one itself. Several possible ways to choose are available, only one of them can be provided on the command line. Here are those options, sorted by ascending complexity. A discussion of other useful options follows. -* --default-always-first + * --default-always-first Messages with no destination will be sent to the first channel specified on the command line invocation of irctk, or to irctk's private channel if none were specified (this isn't very useful). -* --default-all + * --default-all Messages with no destination will be sent to all channels specified on the command line invocation of irctk. (They will *not* be sent to other channels that might have been joined by irctk.) -* --default-last-posted + * --default-last-posted Messages with no destination will be sent to the last channel to which a message was sent. This is useful if you are lazy and want to specify the channel only when you change it. -* --default-last-active (default) + * --default-last-active (default) Messages with no destination will be sent to the last active channel, that is, the last channel on which something took place. This is reasonable if you want to react instantaneously to something which just happened. Note that because irctk reads stdin as greedily as possible, the last active channel is the last active at the moment when you *write* your message to irctk's stdin, not at the -moment when irctk will *say* it. This is usually what you expect. +moment when irctk will *say* it (the two differ if irctk has a long pipe of +things to say). irctk's behavior is usually what you expect here. -This setting is perfect if you want to reply to messages by users and if your -replies are instantaneous. If they are not, consider writing your own logic to -route messages according to your needs. +The --default-last-active option is perfect if you want to reply to messages by +users and if your replies are instantaneous. If your replies take time and other +requests may arrive during that time, irctk will not be able to route the +answers on its own: consider writing your own logic to route messages according +to your needs (and always specify the destination explicitly). == 7. Test suite == You can run the test suite with ./tests_sequential.sh. This requires a working -IRC server to run on localhost:6667. +IRC server on localhost:6667. If you have GNU parallel and if your IRC server isn't afraid of many connections from a single IP, you can run the tests in parallel: ./tests_parallel.sh. == 8. Caveats == -irctk has not been audited thoroughly for bugs or security vulnerabilities. Be +irctk has not been thoroughly audited for bugs or security vulnerabilities. Be cautious if you intend to connect it to an IRC server with untrusted users. IRC servers will usually throttle clients. If want to set up chatty bots, you @@ -211,10 +351,13 @@ server throttles it, then it might exit before all messages have been delivered, and some may get lost. Use -i, or sleep for a few seconds before closing stdin. -irctk will exit if stdin is /dev/null. TODO tail -f /dev/null +You need to use tail -f /dev/null as input to background irctk without having it +suspend or exit (see above). irctk may say greedily the first things it sees on stdin while things to say in -parallel might be available. TODO +parallel might be available later. -irctk can have trouble with buffering. TODO +irctk can have trouble with buffering. When writing pipelines involving irctk, +be sure to disable all buffering (sed -u, awk's fflush, python -u, stdbuf in +some cases, etc.).