irctk

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

README (23006B)


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