irctk

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

README (21247B)


      1 irctk -- an IRC toolkit
      2 Copyright (C) 2010-2015 by Antoine Amarilli
      3 
      4 == 0. License ==
      5 
      6 This program is free software: you can redistribute it and/or modify it under
      7 the terms of the GNU General Public License as published by the Free Software
      8 Foundation, version 3.
      9 
     10 This program is distributed in the hope that it will be useful, but WITHOUT ANY
     11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
     12 PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     13 
     14 You should have received a copy of the GNU General Public License along with
     15 this program (see file "COPYING").  If not, see <http://www.gnu.org/licenses/>.
     16 
     17 == 1. Description ==
     18 
     19 irctk is a general-purpose IRC toolkit. It connects to an IRC server specified
     20 on the command line, joins channels specified on the command line, posts what it
     21 receives from stdin to the channels and outputs to stdout what it hears on the
     22 channels. This makes it possible to write simple IRC bots and scripts very
     23 quickly, either in the shell or in your favourite programming language.
     24 
     25 == 2. Installation ==
     26 
     27 You will need the libircclient library (version >= 1.8 with SSL support) to
     28 compile and run irctk, as well as libssl-dev. On Debian Jessie and later,
     29 sufficiently recent versions can be installed with:
     30 
     31   sudo apt-get install libircclient1 libircclient-dev libssl-dev
     32 
     33 You can then compile irctk by issuing "make". Install irctk by yourself in a
     34 location of your PATH if you want to use it as "irctk", otherwise replace
     35 "irctk" by "./irctk" in the next examples.
     36 
     37 The rest of this section presents how to compile libircclient by yourself if
     38 necessary, and how to install irctk without requiring root privileges.
     39 
     40 === 2.1. Compiling libircclient ===
     41 
     42 If you need to install libircclient manually, get libircclient-1.8 from
     43 <http://sourceforge.net/projects/libircclient/>, compile it and install it (this
     44 requires the package libssl-dev on Debian, and of course make, a C compiler,
     45 etc., which you can get on Debian systems by installing e.g. the package
     46 build-essential):
     47 
     48   ./configure --enable-openssl  --enable-shared
     49   make
     50   sudo make install
     51 
     52 === 2.2. Installing without root ===
     53 
     54 If you cannot install libircclient system-wide, compile it as previously
     55 explained, without the "sudo" command. Then, issue (in the libircclient folder):
     56 
     57   ln -s src/libircclient.so src/libircclient.so.1
     58 
     59 Now go back to the irctk folder, add at the end of the CFLAGS line the
     60 following, adjusting for the location of the libircclient folder:
     61 
     62   -I/where/you/put/libircclient-1.8/include
     63 
     64 Compile with "make", and now run irctk with the following invocation:
     65 
     66   LD_LIBRARY_PATH="/where/you/put/libircclient-1.8/src/:$LD_LIBRARY_PATH" ./irctk
     67 
     68 == 3. How to use ==
     69 
     70 === 3.1. Connecting to a server ===
     71 
     72 As a simple interactive use of irctk, here is how you connect to the IRC server
     73 at example.com and join channel #test:
     74 
     75   $ irctk example.com '#test'
     76 
     77 Messages on the channel will get output on your terminal, and you can type
     78 messages that you want so say to the channel. Press ^D to close stdin and
     79 terminate irctk. Note that the use of quotes around "#test" is to prevent your
     80 shell from interpreting '#' (irctk won't see them).
     81 
     82 More elaborate options are supported. Here is how to connect to a
     83 password-protected channel on a password-protected server on a non-standard
     84 port, specifying a custom nickname, username and real name.
     85 
     86   $ irctk -U jh -R "J. Hacker" nick:srvpass@example.com:3724 '#test:chanpass'
     87 
     88 To connect to a server with SSL support, run:
     89 
     90   $ irctk --ssl example.com
     91 
     92 To additionally disable SSL certificate checking, and allow self-signed and
     93 invalid certificates (at the risk of falling in a man-in-the-middle attack),
     94 run:
     95 
     96   $ irctk --ssl --no-check-certificate example.com
     97 
     98 Connection will fail if you specify --ssl but the server does not support SSL,
     99 or vice versa.
    100 
    101 === 3.2. Using irctk's stdin ===
    102 
    103 irctk is meant to be used non-interactively. For instance, you can say the
    104 contents of a file on a channel by giving it as standard input:
    105 
    106   $ irctk flooder@example.com '#flood' <file
    107 
    108 Of course, it is more interesting to pipe to irctk something which will produce
    109 more and more lines as events occur. For instance, here is how to follow your
    110 server logs on IRC:
    111 
    112   $ ssh server tail -f logfile.log | irctk logger@example.com '#dashboard'
    113 
    114 If you receive mail to a mbox file, here is how you could use irctk to
    115 get a private message to notify you about the subjects of incoming emails.
    116 
    117   $ tail -f ~/mbox | grep --line-buffered '^Subject:' |
    118       irctk alert@example.com mynick
    119 
    120 Note the use of --line-buffered to make sure that the messages do not get
    121 buffered. Here is how to follow the RSS feed of FML and post the stories to a
    122 channel as they appear in the feed:
    123 
    124   $ rsstail -u 'http://feeds2.feedburner.com/fmylife' -NdzH -n 1 -i 300 |
    125       grep --line-buffered '^ Today' |
    126       irctk fmlbot@example.com '#fml'
    127 
    128 === 3.3. Using irctk's stdout ===
    129 
    130 You can log what is happening on a channel by setting stdout to be a file:
    131 
    132   $ irctk logger@example.com '#chan' >file
    133 
    134 You can add timestamps:
    135 
    136   $ irctk logger@example.com '#chan' |
    137       awk '{ print strftime("%s"), $0; fflush() }' > file
    138 
    139 Caution, if you want to run irctk in the background to do something like this,
    140 you need to prevent it from reading stdin (to avoid it being suspended) without
    141 closing stdin (otherwise irctk will terminate). Here is how:
    142 
    143   $ tail -f /dev/null | irctk logger@example.com '#chan' >file &
    144 
    145 Another example: play a sound whenever your nick is mentioned (but not when you
    146 speak):
    147 
    148   $ irctk example.com '#chan' |
    149       grep --line-buffered '[^<]yournick' | while read l; do
    150         aplay alert.wav;
    151       done
    152 
    153 irctk has specific features to detect when someone addresses it. Say you want to
    154 log tasks to do by addressing a bot on IRC:
    155 
    156   $ irctk -f todobot@example.com '#chan' >>~/todo
    157 
    158 To append lines to ~/todo, you can either address todobot on #chan through
    159 messages like "todobot: buy some milk", or you can send a private message to
    160 todobot (using irssi, "/msg todobot write a poem to alice"). Note that the lines
    161 logged in ~/todo will look like "[#chan] <mynick> todobot: buy some milk"; if
    162 you want to get rid of the cruft, you can use:
    163 
    164   $ irctk -F todobot@example.com '#chan' >>~/todo
    165 
    166 which will only log "buy some milk" (and implies -f).
    167 
    168 To combine the use of stdin and stdout, this invocation pipes two irctk calls
    169 together to relay messages from source.com to destination.com (but not the
    170 reverse):
    171 
    172   $ irctk listener@source.com '#chan1' |
    173      irctk repeater@destination.com '#chan2'
    174 
    175 === 3.4. Writing interactive bots ===
    176 
    177 We will now look at interactive examples where you interface irctk's stdout to
    178 some script or program which will do something intelligent and give something to
    179 say to irctk in return. To do so, we will need a named FIFO:
    180 
    181   $ mkfifo fifo
    182 
    183 As an extremely simple interactive program, consider the following:
    184 
    185   $ cat fifo | irctk pongbot@example.com '#chan' |
    186       awk '/[^<]ping/ { print "pong"; fflush() }' > fifo
    187 
    188 The awk invocation outputs "pong" whenever it sees a line containing "ping"
    189 (excluding things such as "<ping" to avoid the issue of people with a nick
    190 starting with "ping"). This means that pongbot will say "pong" on #chan whenever
    191 someone says something containing "ping". Note the use of fflush(), once again
    192 to avoid buffering. The named FIFO is used to connect irctk's stdout to awk's
    193 stdin and awk's stdout to irctk's stdin. Note that the cat invocation is
    194 required and "<fifo" will not work.
    195 
    196 Of course, you can use your favorite programming language instead of awk. If you
    197 want to write an IRC bot in an esoteric language with no IRC library (or maybe
    198 even no networking support), all you need to do is write some code which reads
    199 incoming lines on stdin, posts outgoing lines on stdout, and *does not buffer*.
    200 You can then lift your program to IRC very simply:
    201 
    202   $ cat fifo | irctk example.com '#chat' | program > fifo
    203 
    204 === 3.5. Input and output format ===
    205 
    206 The output format of irctk is of the following form (unless you use -F):
    207 
    208   [#chan] <nick> message
    209 
    210 By default, server events (joins, kicks, renames, etc.) are not output. If you
    211 want them, you can either get them in a human-readable form with the -m flag:
    212 
    213   [#bar] -!- foo has joined #bar
    214 
    215 Alternatively, you can get them in a barebones form with -c:
    216 
    217   [#bar] <foo> /join #bar
    218 
    219 Your own messages will not be included unless you specify --own. If you want to
    220 see nicknames like <nick!~username@localhost>, use --with-host. You can also use
    221 the -f and -F options presented above to only keep lines addressed to you and to
    222 remove everything but the message (-F implies -f).
    223 
    224 The input format is of the following form:
    225 
    226   [channel] message
    227 
    228 The channel can be either of the form "#chan" (a regular channel) or of the form
    229 "user" (the channel of private messages exchanged with user). You can specify
    230 multiple channel names separated by commas (but see the section "Pipelining"
    231 below).
    232 
    233 Because specifying the chan each time can be tedious, irctk can try to guess it.
    234 If you do not specify a destination and just give a message, irctk will say it
    235 to the last active channel by default (i.e., the last channel where something
    236 was heard), which is often a reasonable choice if you are replying to someone.
    237 There are other possible options: see the section "Implied destinations" below.
    238 
    239 irctk will always try to join a channel before saying something to this channel.
    240 This means that it can join entirely new channels in this fashion. To disable
    241 this behavior and prevent irctk from joining any channels except the ones given
    242 at startup, use --no-join (can be useful if irctk's stdin is
    243 attacker-controlled). Note that this only affects the behavior of irctk on
    244 regular channels: even with --no-join, irctk will be able to send private
    245 messages to anyone, and will try to send messages to unknown channels (just
    246 without trying to join them first).
    247 
    248 irctk will interpret some commands starting with '/' in a fashion similar to
    249 irssi. To inhibit this (can be useful if irctk's stdin is attacker-controlled),
    250 use --no-command-to-event.
    251 
    252 When irctk is provided attacker-controlled input, the right way to escape is to
    253 prepend '/say' or '/ ' before every line provided to irctk (be careful if the
    254 attacker may provide newlines).
    255 
    256 The supported commands are:
    257 
    258   /nick NICKNAME (change nick)
    259   /mode MODE (set channel mode)
    260   /part [CHAN] (part from a channel)
    261   /join [CHAN] (join a channel)
    262   /topic TOPIC (set channel topic)
    263   /quit REASON (quit)
    264   /invite USER [CHAN] (invite a user to a channel)
    265   /kick USER [REASON] (kick user from current inferred destination)
    266   /me MSG (/me message)
    267   /notice MSG (say as a notice)
    268   /oper USER [PASS] (obtain operator privileges)
    269   /quote COMMAND (send raw command to IRC server)
    270   /say MSG (escape)
    271   / MSG (escape)
    272   /notice MSG (like /say but use NOTICE)
    273 
    274 Optional channel names "[CHAN]" in the above list default to the current
    275 inferred destination (i.e., the last active channel by default).
    276 
    277 As an additional convenience, irctk can be made to address the last person who
    278 addressed it, with the -r option. In conjunction with the default destination
    279 channel inference, this means that, using -fr, whenever you ask irctk to say
    280 "message", it will say that to the last person who addressed it, on the channel
    281 where it was addressed. This is very convenient to write bots.
    282 
    283 === 3.6. Complete examples ===
    284 
    285 This bot queries user names using finger and returns a status line for them (or
    286 an error if they do not exist):
    287 
    288 cat fifo | irctk -Fr fingerbot@example.com '#chat' |
    289   while read; do
    290     finger -s -- "$REPLY" 2>&1 | tail -1
    291   done >fifo
    292 
    293 The following bot can be used to roll dice: say something like "dmbot: 3d42" and
    294 it will reply with the result. Note that this example is bash-specific. Thanks
    295 to p4bl0 <http://pablo.rauzy.name/> for writing it.
    296 
    297 cat fifo | irctk -Fr dmbot@example.com '#chat' |
    298   while read line; do
    299     if grep -E '^[0-9]{1,2}d[0-9]{1,3}$' <<<"$line" &>/dev/null; then
    300       D=(${line/d/ })
    301       for ((i = 0; i < ${D[0]}; i++)); do
    302         echo -n $((RANDOM % ${D[1]} + 1))" "
    303       done
    304       echo
    305     else
    306       echo "format error: must be NdM with N<100 and M<1000"
    307     fi
    308   done >fifo
    309 
    310 This bot queries on wikipedia whatever is said to it, using the DNS-based
    311 wikipedia query system as an ugly way to get the beginning of pages.
    312 
    313   $ cat fifo | irctk -Fr wikibot@example.com '#chat' |
    314       while read line; do
    315         Q=$(echo "$line" | tr ' ' '_' | tr -dc 'a-zA-Z_()');
    316         dig +short txt $Q.wp.dg.cx; echo;
    317       done >fifo
    318 
    319 This is a way to play adventure on IRC. (Beware, people can overwrite files when
    320 saving their game, so run as a suitably unpriviledged user.) The "while true"
    321 loop is to restart the game whenever it exits. The socat invocation is used to
    322 disable buffering. To play, say "DM: command".
    323 
    324   $ cat fifo | irctk -F DM@example.com '#adventure' |
    325       while true; do
    326         socat EXEC:adventure,pty,ctty,echo=0 STDIO;
    327       done >fifo
    328 
    329 Two-way gateway: gateway posts on #chan1 on server1.com whatever is said to it
    330 on #chan2 on server2.com, and vice-versa:
    331 
    332   $ cat fifo | irctk -F0 gateway@server1.com '#chan1' |
    333       irctk -F0 gateway@server2.com '#chan2' | tee fifo
    334 
    335 Run shell commands from your IRC client (just by saying them in #tty, no need to
    336 address the bot). BEWARE, this means that whoever is named "admin" on the IRC
    337 server can run arbitrary commands on your machine, so you really shouldn't do
    338 this.
    339 
    340   $ cat fifo | irctk localhost '#tty' |
    341       grep --line-buffered '^\[#tty\] <admin>' |
    342       sed -u 's/^[^>]*> *//' | bash >fifo 2>&1
    343 
    344 Whatever admin says on #tty will get run in a bash shell and the result will be
    345 returned to the channel. Note that you can of course run irctk in this shell
    346 (irception!), but beware of feedback loops if you attempt to join the same
    347 channel!
    348 
    349 === 3.7. Implied destinations ===
    350 
    351 You can always specify the channel to which you speak by using a "[#channel]"
    352 prefix. You can specify multiple channels for the same message using commas (but
    353 see "Pipelining"). If you do not specify a channel, then irctk will choose one
    354 itself. Note that you can start your message with "[]" if your message starts
    355 with a '[' but you want irctk to infer the channel.
    356 
    357 Several possible ways to choose are available, only one of them can be provided
    358 on the command line. Here are those options, sorted by ascending complexity. A
    359 discussion of other useful options follows.
    360 
    361   * --default-always-first
    362 
    363 Messages with no destination will be sent to the first channel specified on the
    364 command line invocation of irctk (or to irctk's private channel if none were
    365 specified, which is not very useful).
    366 
    367   * --default-all
    368 
    369 Messages with no destination will be sent to all channels specified on the
    370 command line invocation of irctk. (They will *not* be sent to other channels
    371 that might have been joined by irctk later.)
    372 
    373   * --default-last-posted
    374 
    375 Messages with no destination will be sent to the last channel to which a message
    376 was sent. This is useful if you are writing to stdin manually and want to
    377 specify the channel only when it changes. Note that you can use -P to display
    378 the current default destination on stderr; if you send irctk's stdout elsewhere
    379 to avoid clobbering your terminal, this makes irctk (almost) look like irssi's
    380 prompt. (For instance, you can send stdout to a FIFO and display it in another
    381 window (or use GNU screen) to get a poor man's IRC client.)
    382 
    383   * --default-last-active (default)
    384 
    385 Messages with no destination will be sent to the last active channel, that is,
    386 the last channel on which something took place. This is reasonable if you want
    387 to react instantaneously to something which just happened. Note that because
    388 irctk reads stdin as greedily as possible, the last active channel should be the
    389 last active at the moment when you *write* your message to irctk's stdin, not at
    390 the moment when irctk will *say* it (the two differ if irctk has a long pipe of
    391 things to say). irctk's behavior is usually what you expect here.
    392 
    393 The --default-last-active option is perfect if you want to reply to messages by
    394 users and if your replies are instantaneous. If your replies take time and other
    395 requests may arrive during that time, irctk will not be able to route the
    396 answers on its own: consider writing your own logic to route messages according
    397 to your needs (and always specify the destination explicitly).
    398 
    399 === 3.8. Tracking ===
    400 
    401 Because of the delay between messages which irctk observes to avoid getting
    402 kicked by a pissed server, messages can be sent to the server a long time after
    403 irctk received them on stdin. This means that if you addressed someone doing
    404 something like "nick: message" or "[nick] message" or using -r, then that person
    405 might have changed nick in the meantime and the message may not get routed
    406 correctly.
    407 
    408 As a countermeasure, you can specify --track-renames so that messages addressed
    409 to a user in one of the above fashions get sent to the user's current nick.
    410 (They will get sent to their last known nick if they part or quit.) There is
    411 also a --unique-names options with which irctk will maintain unique names for
    412 users (based on the first seen nick for a user), expose them on stdout, and
    413 expect them on stdin. This is useful if you want to write a bot which stores
    414 e.g. a score for each user and if you want users to keep their score even if
    415 they change nick. These tracking modes are not enabled by default.
    416 
    417 Note: because a rename may be seen too late, this option is not guaranteed to
    418 work, and some messages may get mistakenly addressed to an older nick.
    419 
    420 === 3.9. Pipelining ===
    421 
    422 irctk has a built-in rate limitation (configurable with -i) which it tries to
    423 apply independently on each channel. This means that, to ensure the fastest
    424 possible delivery, messages to channels with an empty queue will be sent
    425 *before* messages to channels with a busy queue. no matter the order on which
    426 they were provided on standard input. However, within a given channel, the order
    427 relation on messages will match their order on standard input.
    428 
    429 If you specify multiple destination channels like "[#a,#b,#c]", however, the
    430 resulting message will be said on all the channels simultaneously (and will
    431 therefore wait for the buffers of all relevant channels to be empty). If you do
    432 not want this synchronization, you should say the message several times,
    433 addressed to each individual channel.
    434 
    435 Beware of the fact that the IRC server may limit irctk's rate in a fashion which
    436 irctk will not be able to control, so any slowdowns you see may not be irctk's
    437 fault. Use -o to see when irctk is sending your messages, to see who is slowing
    438 things down.
    439 
    440 == 4. Test suite ==
    441 
    442 You can run the test suite with ./tests_sequential.sh. This requires a working
    443 IRC server on localhost:6667. I use ircd-hybrid from Debian testing, configured
    444 with throttle_time = 0 and anti_spam_exit_message_time = 0. This also requires
    445 valgrind (which is packaged for Debian).
    446 
    447 If you have GNU parallel and if your IRC server isn't afraid of many connections
    448 from a single IP, you can run the tests in parallel: ./tests_parallel.sh. This
    449 isn't guaranteed to work.
    450 
    451 == 5. Caveats, limitations and FAQ ==
    452 
    453 irctk has not been thoroughly audited for bugs or security vulnerabilities. Be
    454 cautious if you intend to connect it to an IRC server with untrusted users.
    455 
    456 IRC servers will usually throttle clients. If want to set up chatty bots, you
    457 will need to have control over the IRC server and configure it adequately (for
    458 ircd-hybrid, look at "can_flood" and also at "default_floodcount").
    459 
    460 irctk will exit whenever it has sent all messages on stdin to the server. If the
    461 server throttles it, then it might exit before all messages have been
    462 delivered, and some may get lost. Use -i and -I, or sleep for a few seconds
    463 before closing stdin.
    464 
    465 You need to use tail -f /dev/null as input if you want to background irctk
    466 without having it suspend or exit (see above).
    467 
    468 irctk may say greedily the first things it sees on stdin while things to say in
    469 parallel might be available later.
    470 
    471 irctk can have trouble with buffering. When writing pipelines involving irctk,
    472 be sure to disable all buffering (sed -u, awk's fflush, python -u, stdbuf in
    473 some cases, etc.).
    474 
    475 If you get a "LIBIRC_ERR_SSL_NOT_SUPPORTED not declared" error when compiling,
    476 it means you are not compiling against the right version of libircclient (see
    477 section 2).
    478 
    479 == 6. Related projects ==
    480 
    481   * ii <http://tools.suckless.org/ii/>
    482 
    483 ii is filesystem and FIFO-based but irctk is entirely FIFO-based. ii's control
    484 FIFO is irctk's stdin, but ii's output files are replaced by irctk's stdout.
    485 irctk does not write to disk or read from disk. irctk also includes features
    486 which make it easy to write bots in shell script one-liners.
    487 
    488   * sic <http://tools.suckless.org/sic>
    489 
    490 sic is pretty similar to irctk, except irctk abstracts more things from the
    491 underlying IRC protocol and has more features (e.g., SSL support and the various
    492 options). Conversely, sic is <= 250 LOC without dependency on an external
    493 library.
    494 
    495   * IrcTK <https://github.com/maxcountryman/irctk>
    496 
    497 irctk has nothing to do with this except the similar name.
    498