irctk

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

README (21819B)


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