IRC bot in D

README.md

kameloso CircleCI Linux/OSX Travis Linux/OSX and documentation Windows Issue 46 GitHub commits since last release

kameloso sits and listens in the channels you specify and reacts to events, like bots generally do.

A variety of features comes bundled in the form of compile-time plugins, some of which are examples and proofs of concepts. It's made to be easy to write your own (API documentation is available online). Any and all ideas for inclusion welcome.

It works well with the majority of server networks. IRC is standardised but servers still come in many flavours, some of which outright conflict with others. If something doesn't immediately work, most often it's simply because we haven't encountered that type of event before, and so no rules for how to parse it have yet been written. Once discovered it's not a difficult thing to do.

Please report bugs. Unreported bugs can only be fixed by accident.

Current functionality includes:

  • bedazzling coloured terminal output like it's the 90s
  • automatic mode sets (eg. auto +o on join for op)
  • looking up titles of pasted web URLs
  • logs
  • sed-replacement of the last message sent (s/this/that/ substitution)
  • saving notes to offline users that get played back when they come online
  • seen plugin; reporting when a user was last seen, written as a rough example plugin
  • user quotes
  • Twitch chat support (with default-disabled example bot); see notes on connecting to Twitch below
  • piping text from the terminal to the server (Linux/OSX and other Posix-likes only)
  • mIRC colour coding and text effects (bold, underlined, ...), mapped to ANSI terminal formatting
  • SASL authentication (plain)
  • configuration stored on file; create one and edit it to get an idea of the settings available

If nothing else it makes for a good read-only terminal lurkbot.

Current limitations:

  • missing good how-to-use guide. Use the source, Luke!
  • the dmd and ldc compilers may segfault if building in anything other than debug mode (bug #18026).
  • the stable release of the gdc compiler doesn't yet support static foreach and thus cannot be used to build this bot. The development release based on D version 2.081 segfaults upon compiling (bug #307).
  • IRC servers that have not been tested against may exhibit weird behaviour if parsing goes awry. Need concrete examples to fix; please report errors and abnormalities.

Use on networks without services (NickServ/Q/AuthServ/...) may be difficult, since the bot identifies people by their account names. You will probably want to register yourself with such, where available.

Testing is primarily done on freenode, so support and coverage is best there. Twitch also sees extensive testing, but mostly as a client idling in channels and less as a bot hosting commands.

TL;DR: abridged

$ ./kameloso --help

-n       --nickname Nickname
-s         --server Server address [irc.freenode.net]
-P           --port Server port [6667]
-A        --account Services account name
-p       --password Services account password
           --admins Administrators' services accounts, comma-separated
-H          --homes Home channels to operate in, comma-separated
-C       --channels Non-home channels to idle in, comma-separated
-w    --writeconfig Write configuration to file

A dash (-) clears, so -C- translates to no channels, -A- to no account name, etc.

Table of contents


Getting started

Prerequisites

You need a D compiler and the dub package manager. There are three compilers available; see here for an overview. You need one based on D version 2.076 or later (released September 2017). You will also need some 4 Gb of RAM to build all features (Linux, excluding tests).

kameloso can be built using the reference compiler dmd and the LLVM-based ldc. The stable release of the GCC-based gdc is currently too old to be used.

Downloading

$ git clone https://github.com/zorael/kameloso.git
$ cd kameloso

Do not use dub fetch until we have released v1.0.0. It will download an ancient version.

Compiling

$ dub build

This will compile it in the default debug mode, which adds some extra code and debugging symbols.

You can automatically skip these and add some optimisations by building it in release mode with dub build -b release. Mind that build times will increase. Refer to the output of dub build --help for more build types.

The above might currently not work, as the compiler may crash on some build configurations under anything other than debug mode. (bug #18026)

Unit tests are built into the language, but you need to compile the project in unittest mode to include them. Tests are run at the start of the program, not during compilation. Furthermore, test builds will only run the unit tests and immediately exit.

$ dub test

Build configurations

There are several configurations in which the bot may be built.

  • vanilla, builds without any specific extras
  • colours, compiles in terminal colours
  • web, compiles in plugins with web lookup (webtitles, reddit and bashquotes)
  • colours+web, unsurprisingly includes both of the above
  • posix, default on Posix-like systems (Linux, OSX, ...), equals colours+web
  • windows, default on Windows, equals web (no colours)
  • cygwin, equals colours+web but with extra code needed for running it under the default Cygwin terminal (mintty)

List them with dub build --print-configs. You can specify which to compile with the -c switch. Not supplying one will make it build the default for your operating system.

$ dub build -c cygwin

How to use

Configuration

The bot needs the services account name of one or more administrators of the bot, and/or one or more home channels to operate in. To define these you need to generate and edit a configuration file.

$ ./kameloso --writeconfig

A new kameloso.conf will be created in a directory dependent on your platform.

  • Linux: ~/.config/kameloso (alternatively where $XDG_CONFIG_HOME points)
  • OSX: $HOME/Library/Application Support/kameloso
  • Windows: %LOCALAPPDATA%\kameloso
  • Other unexpected platforms: fallback to current working directory

Open the file in there in a text editor and fill in the fields. Peruse it to get an idea of the features available.

Command-line arguments

You can override some settings with arguments on the command line, listed by calling the program with --help. If you specify some and also add --writeconfig it will save these changes to the file so you don't have to repeat them, without having to manually edit the configuration file.

$ ./kameloso \
    --server irc.freenode.net \
    --nickname "kameloso" \
    --admins "you,friend,thatguy" \
    --homes "#channel,#elsewhere" \
    --channels "#d,##networking" \
    --writeconfig

Configuration file written to /home/user/.config/kameloso/kameloso.conf

Later invocations of --writeconfig will only regenerate the file. It will never overwrite custom settings, only complement them with new ones. Mind however that it will remove any lines not corresponding to a valid setting, so comments are removed.

Display settings

If you have compiled in colours and you have bright terminal background, the colours may be hard to see and the text difficult to read. If so, make sure to pass the --bright argument, and/or modify the configuration file; brightTerminal under [Core]. The bot uses the full range of 8-colour ANSI, so if one or more colours are too dark or bright even with the right brightTerminal setting, please see to your terminal appearance settings. This is not uncommon, especially with backgrounds that are not fully black or white. (read: Monokai, Breeze, Solaris, ...)

Other files

More server-specific resource files will be created the first time you connect to a server. These include users.json, in which you whitelist which accounts get to access the bot's features. Where these are stored also depends on platform; in the case of OSX and Windows they will be put in subdirectories of the same directory as the configuration file, listed above. On Linux, under ~/.local/share/kameloso (or wherever $XDG_DATA_HOME points). As before it falls back to the working directory on other unknown platforms.

Example use

Once the bot has joined a home channel, it's ready. Mind that you need to authorise yourself with services with an account listed as an administrator in the configuration file to make it listen to you. Before allowing anyone to trigger any functionality it will look them up and compare their accounts with its white- and blacklists. Refer to the admins field in the configuration file, as well as your generated users.json.

$ ./kameloso
     you joined #channel
kameloso sets mode +o you
     you | I am a fish
     you | s/fish/snek
kameloso | you | I am a snek
     you | !addquote you This is a quote
kameloso | Quote saved. (1 on record)
     you | !quote you
kameloso | you | This is a quote
     you | !note OfflinePerson Why so offline?
kameloso | Note added.
     you | !seen OfflinePerson
kameloso | I last saw OfflinePerson 1 hour and 34 minutes ago.
     you | kameloso: sudo PRIVMSG #channel :this is a raw IRC command
kameloso | this is a raw IRC command
     you | https://www.youtube.com/watch?v=s-mOy8VUEBk
kameloso | [youtube.com] Danish language (uploaded by snurre)

Online help and commands

Send help to the bot in a private message for a summary of available bot commands, and help [plugin] [command] for a brief description of a specific one. Mind that commands defined as regular expressions cannot be shown, due to technical reasons.

The prefix character (here "!") is configurable; refer to your generated configuration file. Common alternatives are . and ~, making it .note and ~quote respectively.

[Core]
prefix              !

It can technically be any string and not just one character. Enquote it if you want any spaces as part of the prefix token, like "please ".

Twitch

To connect to Twitch servers you must supply an OAuth token pass. Generate one here, then add it to your kameloso.conf in the pass field.

[IRCBot]
nickname            twitchaccount
pass                oauth:the50letteroauthstringgoeshere
homes               #twitchaccount
channels            #streamer1,#streamer2,#streamer3

[IRCServer]
address             irc.chat.twitch.tv
port                6667

pass is not the same as authPassword. It is supplied very early during login (or registration) to allow you to connect -- even before negotiating username and nickname, which is otherwise the very first thing to happen. authPassword is something that is sent to a services bot (like NickServ or AuthServ) after registration has finished and you have successfully logged onto the server. (In the case of SASL authentication, authPassword is used during late registration.)

Mind that in many ways Twitch does not behave as a full IRC server. Most common IRC commands go unrecognised. Joins and parts are not always advertised. Participants in a channel are not always enumerated upon joining it, and you cannot query the server for the list. You cannot ask the server for information about a single user either. You cannot readily trust who is +o and who isn't, as it will oscillate to -o at irregular intervals. You also can only join channels for which a corresponding Twitch user account exists.

See this Twitch help page on moderation and this page on harassment for available moderator commands to send as normal channel PRIVMSG messages.

Known limitation: a user that is in more than one observed channel can rarely be displayed with a badge in one that he/she actually has in another. This is because a user can only have one set of badges at a time per the current implementation.

Use as a library

The IRC event parsing bits are largely decoupled from the bot parts of the program, needing only some common non-bot-oriented helper modules.

Feel free to copy these and drop them into your own project. Look up the structs IRCBot and IRCParser to get started. See the versioning at the top of irc/common.d. Some very basic examples can be found in tests/events.d.

Debugging and generating unit tests

Writing an IRC bot when servers all behave differently is difficult, and you will come across unexpected events for which there are no rules on how to parse. It may be some messages silently have weird values in the wrong fields (e.g. nickname where channel should go), or be empty when they shouldn't. Very likely there will be an error message. Please file an issue.

You can generate unit test assert blocks for new events by passing the command-line --asserts flag, specifying the requested server information and pasting the raw line. Copy the generated assert block and place it in tests/events.d, or wherever is appropriate.

If more state is necessary to replicate the environment, such as needing things from RPL_ISUPPORT or a specific resolved server address (from early NOTICE or RPL_HELLO), paste/fake the raw line for those first and it will inherit the implied changes for any following lines throughout the session. It will print the changes evoked, so you'll know if you succeeded.

Known bugs

Windows

  • Web URL lookup, including the web titles and Reddit plugins, will not work out of the box with secure HTTPS connections due to missing libraries. Download a "light" installer from slproweb.com and install to system libraries, and it should no longer warn on program start.
  • Terminal colours may also not work in the default cmd console, depending on your version of Windows and likely your terminal font. Unsure of how to fix this. Powershell works fine.
  • Use in Cygwin terminals without compiling the aforementioned cygwin configuration will be unpleasant (terminal output will be broken). Here too Powershell consoles are not affected and can be used with any configuration. cmd also works without cygwin, albeit with the previously mentioned colour issues.
  • When run in such Cygwin terminals, the bot cannot gracefully shut down upon Ctrl+C, due to technical limitations. Any changes will have to be saved in a different way.

Posix

  • If the pipeline FIFO is removed while the program is running, it will hang upon exiting, requiring manual interruption with Ctrl+C. This is a tricky problem to solve, as it requires figuring out how to do non-blocking reads.

Roadmap

  • pipedream zero: no compiler segfaults
  • pipedream: DCC
  • pipedream two: ncurses?
  • seen doing what? channel-split? IRCEvent-based? (later)
  • private notes (later)

Built with

License

This project is licensed under the MIT license - see the LICENSE file for details.

Acknowledgements