irccd: Mercurial repository edition

Added by David Demelier 9 days ago

The Mercurial repository will be publicly edited on Wednesday 07 November evening.

I've discovered that the tag 2.2.0 and its signature commit were created on the wrong branch and this requires manual history edition. This means that you should either download a fresh copy of the repository or to strip and update.

Warning: if you have local changesets, those will be removed.

# you need strip extension
hg strip -r 0
hg pull
hg up @

irccd: System specific features (2 comments)

Added by David Demelier 4 months ago

While I have added those options in 2.0.0, I felt that it's not the purpose of a program to perform these operations. Even though there are common unix features, they also break unix philosophy of doing only one thing right.


Handling UID/GID switching from code requires number of checks. We need to check if setgid, setuid are available and with appropriate headers.

Some systems already have a daemon utility to run a program in background specifying a user to run as.

Exemple on FreeBSD:

daemon -u nobody irccd -v


The daemonize process was very early in the previous code. And when debugging I was always specifying the -f flag to be sure irccd does not run in background. Unfortunately I forgot many times and I got multiple daemon trying to connect in many servers. This was quite frustrating even though I understand it's my own issue.

But as explained above, there is already a daemon tool to actually spawn a process into a daemon, there is also nohub or simple tmux for some people.

Daemon has also been considered deprecated by macOS and therefore a warning was issued at compile time that requires a special compiler flag to disable a warning and I hate to disable warnings.

In my opinion, it's the business of a service manager to spawn a process into the background and taking care of it. Systemd by default assume programs do not fork by themselves unless you specify Type=forking in the unit file.


Irccd no longers write it's own process id into a file. For the same reasons above, I think it's the responsability of the service manager to track its process and be sure it's still running.

What does that change for me?

Not much.

Irccd 3.0.0 will come with a service file for FreeBSD and to configure the user/group of the service FreeBSD already used the convention program_user and program_group in the /etc/rc.conf. That means you will able to change its UID/GID like this:


for systemd, the unit file won't set a user/group by default for now because it's very hard to determine portable user and group across the distributions. But with systemd override support, you will be able to set User and Group properties.


Remember, the unix philosophy prefers to delegate as much as possible functions that could be handled by external tools. This changes has removed a high number of #ifdef and CMake checks, keeping the code cleaner.

The whole change has removed around 343 lines of code.

irccd: 3.0.0

Added by David Demelier 7 months ago

Irccd 3.0.0 is coming soon!

The next major irccd version will be released in the next few months. While it's a major version step ahead 2.0.0, it has less more changes than the step between 1.y and 2.y. There are still exciting features that I'll show you now.

Native plugins

Native plugins are finally here!

You can now write a plugin in C++ in case of need. Even though I really encourage to write a Javascript plugin, one may need to use C++ for various reasons (e.g. networking).

A plugin needs to derive from plugin class and export a unique symbol name, that's it.

Example of very basic plugin:

#include <iostream>

#include <irccd/daemon/plugin.hpp>

class my_plugin : public plugin {
        : plugin("translate-me", "")

    void on_load(irccd&) override
        std::cout << "native plugin loaded!" << std::endl;

// Note, one may need BOOST_SYMBOL_EXPORT on Windows though.
extern "C" my_plugin irccd_plugin_translate_me;

// And define it.
my_plugin irccd_plugin_translate_me;

Note: the symbol name is tied to the file name by default. For example, if you want to load a native plugin with id “translate-me”, a file|dylib|dll will be searched and the symbol irccd_plugin_translate_me must be exported (hyphens are translated to underscores).

Warning: remember that irccd has currently no safe way to protect itself for broken plugins, if your plugin crashes, irccd will too.

The exported IrccdDefinePlugin will help developers to build and install plugins along with their documentation easily.

Live rule editing

The irccdctl tool gained a set of rule editing functions. The following commands have been added:

  • irccdctl rule-add, add a new rule into irccd,
  • irccdctl rule-info, get information about a rule,
  • irccdctl rule-list, list all current rules,
  • irccdctl rule-edit, update an existing rule,
  • irccdctl rule-move, swap rule positions.

Example, listing rules

Listing rules with rule-list:

$ irccdctl rule-list 
rule:        0
plugins:     hangman 
action:      drop

rule:        1
servers:     localhost 
channels:    #games 
plugins:     hangman 
action:      accept

Editing an existing rule

With the same set as before, edit one and see:

$ ./bin/irccdctl -c irccdctl.conf rule-edit --add-channel "#staff" 1
$ ./bin/irccdctl -c irccdctl.conf rule-info 1
rule:        1
servers:     localhost 
channels:    #games #staff 
plugins:     hangman 
action:      accept

Tests, tests and tests

This version adds a very large number of unit tests. I wanted to make this version the most well tested as possible.

I have added unit tests for irccdctl commands, now I will guarantee that irccdctl output stays compatible between minor versions. This also ensure compatibility in irccdctl options and arguments. Error strings are tested as well to be sure that scripts can rely on irccdctl in a safe and compatible way. The network protocol API errors are tested as well, unit tests have been added to ensure compatibility if commands are not completely valid.

Tests your plugins

If you have used irccd in the 1.y era, you may remember the irccd-test command, it was removed in 2.0.0 for some reasons but is now available again. In bonus, it contains a basic completion support for event names (requires libedit library).

$ ./bin/irccd-test ../plugins/ask/ask.js
> onCommand localhost jean #staff Will I be rich?
localhost: connect
localhost: message #staff jean, Yes!!
> onCommand localhost jean #staff Are you sure?
localhost: message #staff jean, Definitely not!

In this example, if you start typing onCom and complete with tab key, you will be completed through onCommand. For the moment, there is no completion on servers names but I'll try to add this later.

Note: as you can see, there is an onConnect event before the response, this happens because each time you invoke an event with a different server, a fake one is created if it does not exist.

Internal code change

Most of the development have been done to switch to Boost. I'm sorry if you feel disappointed of having boost dependency in irccd, but I was not able to provide perfect system compatibility by writing my own code in many places.

On the other hand, irccd does not use boost for everything, the following modules are used:

  • Asio,
  • Filesystem,
  • Process (unit tests only),
  • Timer (Javascript API only),
  • Format.

New tictactoe plugin

A brand new tictactoe plugin has been added. It allows two players playing tictactoe game on IRC. The plugin takes care of checking if users are in the channel and stay the lifetime of the game.

< markand> !tictactoe linkdd 
< irccd>   a b c
< irccd> 1 . . .
< irccd> 2 . . .
< irccd> 3 . . .
< irccd> markand, it's your turn
< markand> a 1
< irccd>   a b c
< irccd> 1 x . .
< irccd> 2 . . .
< irccd> 3 . . .
< irccd> linkdd, it's your turn
< linkdd> a 3
< irccd>   a b c
< irccd> 1 x . .
< irccd> 2 . . .
< irccd> 3 o . .
< irccd> markand, it's your turn

New joke plugin

A very simple joke plugin has been added.

The purpose of this plugin is to randomly choose a joke in a set of user defined jokes. It shuffles the list of jokes and pick one of the current list, therefore, you will not see the same joke until the full pile has been shown.

< markand> !joke
< irccd> keep calm and drop database
< markand> !joke
< irccd> francis: make me a sandwish
< irccd> lisa: do it yourself
< irccd> francis: sudo make me a sandwich
< irccd> lisa: ok

And since the plugin uses the templating system in irccd, it is possible to specify a set of jokes for a different server/channel.

Please note that there is no fallback in that method, if you start using templates in the configuration, you will need to symlink/create jokes for every channels you want to use.

Decomissionning libircclient

Unfortunately, the major part of irccd has left. I have decided to remove libircclient from our code and use a house code itself. Since IRC protocol is very easy, it was pretty quick.

The biggest problem of libircclient is the dependency on the `select(2)` system call. This was pretty hard to mix with the irccd main loop which uses Boost.Asio context object. Instead of creating a thread and complex code for retrieving data, I've created a simple class that does most of the IRC protocol.

It is not that big though:

$ cloc irccd/daemon/irc.*
       2 text files.
       2 unique files.                              
       0 files ignored. v 1.72  T=0.01 s (320.0 files/s, 137922.1 lines/s)
Language                     files          blank        comment           code
C/C++ Header                     1             60            240            287
C++                              1             58             21            196
SUM:                             2            118            261            483

New path system

One of the biggest issue I had in the last two versions was the management of directories. Irccd had used a dynamic directory lookup when loading plugins, this confuse users and is hard to understand. For example, when the plugin ask was loaded, irccd searched different configuration and data directories and if it does not find one, it uses the system wide. You may think it's not a problem, but it is! What if a plugin needs to write some data? This is the reason you see in old documentation that you were needed to create a directory before using a plugin.

In irccd 3.0.0, there is no more “dynamic directories”. Instead, if irccd is started without any directories set, it uses the default system ones, period. There is no more an autodetection of user, system directories. Thus, if you want to use different directories, you may set the [paths] section.

There are two sections, the global [paths] and per-plugin []. The first one is the defaults for everything and the second can be added to adjust settings for a specific plugin.


cache = "/var/cache/irccd" 
config = "/etc/irccd/" 
data = "/var/irccd" 

If the plugin ask is started with this configuration, it will have the following directories set:

  • cache: /var/cache/irccd/plugin/ask
  • config: /etc/irccd/plugin/ask
  • data: /var/irccd/plugin/ask

And then, if you want, you can override any directory without the need to set all.

cache = "/var/cache/irccd" 
config = "/etc/irccd" 
data = "/var/irccd" 

data = "/etc/irccd/jokes" 

Then, ask will have the following paths instead:

  • cache: /var/cache/irccd/plugin/ask (default from `[paths]`),
  • config: /etc/irccd/plugin/ask (default from `[paths]`),
  • data: /etc/irccd/jokes (overriden from `[paths.ask]`).


Another minor changes:

  • If irccd is built from a Mercurial repository, the irccd --version command shows the last revision,
  • If no identity is set into a [server] section, it tries to uses the system username by default,
  • The systemd service file is now first class citizen.

irccd: 2.1.0

Added by David Demelier almost 2 years ago

Irccd 2.1.0 is now available.

For a full list of changes, see the changes in 2.1.0.

Some highlights:



SSL has been added as an experimental feature in the irccd ip transports.

To enable it on a irccd transport

type = ip
port = 7777
ssl = true
key = "path-to-private.key" 
certificate = "path-to-certificate.key" 

To enable it in irccdctl

type = ip
host =
ssl = true


Authentication is also now supported for both unix and ip types.

In irccd configuration:

# as before
password = foo

In irccdctl configuration:

# as before
password = foo

New plugin-config command

A new irccdctl plugin-config has been added, it can configure a plugin at runtime.

With only one argument:

$ irccdctl plugin-config plugin
max-list-columns : 80
max-list-lines   : 3

With two arguments:

$ irccdctl plugin-config plugin max-list-columns

With three arguments:

$ irccdctl plugin-config plugin max-list-lines 5
markand@kiwi ~ $ irccdctl plugin-config plugin
max-list-columns : 80
max-list-lines   : 5


Irccdctl now supports aliases to define custom list of commands.

hello = ( "server-message", "%0", "%1", "hello world !!!" )
goodbye = ( "server-message", "%0", "%1", "goodbye !!! :(" )

unload = ( "plugin-unload", "%0" )
load = ( "plugin-load", "%0" )

This example configure two new aliases: cycle and full-reload. They use placeholders to pass arguments at runtime

$ irccdctl cycle freenode #test
$ irccdctl full-reload ask

irccd: Absolute paths forbidden in some CMake options

Added by David Demelier over 2 years ago

Starting with revision r101 (and future 2.1 version), irccd now completely disallow absolute paths for the following options:



It is highly recommended to make relocatable software. But what does that mean really? It means that wherever the application is installed, you can safely move it to an another location without recompiling it and the application can still run. The only requirement is to keep the same hierarchy.

In the case of irccd, it uses the following defaults on Unix:

  • WITH_BINDIR: bin/
  • WITH_CACHEDIR: var/irccd/
  • WITH_CONFDIR: etc/
  • WITH_DATADIR: share/irccd/
  • WITH_PLUGINDIR: share/irccd/plugins/

Thus, when irccd is installed in bin/ directory, it knows how to go to the configuration directory by going upward a directory and then in etc/ directory. This is done by retrieving the executable path. This means you can safely install irccd into any directory and then move it somewhere else.


cmake . -DCMAKE_INSTALL_PREFIX=/tmp/irccd-test
make install

Now, /tmp/irccd-test/ is filled with bin/, etc/ and such. I can safely move /tmp/irccd-test/ somewhere else, irccd will still knows where to locate its directories.

Why disallowing absolute paths

Irccd's CMake process builds the project into a fake root directory, in ${CMAKE_BINARY_DIR}/fakeroot. This makes easier to test irccd without installing it as the fake root directory already simulates the installed project. It makes also much easier for packagers to determine the installed files as they are exactly the same upon installed.

But to use this fakeroot directory, users must not use absolute paths as CMake options are appended to it, thus, setting WITH_BINDIR to C:/Irccd/bin will define the path to ${CMAKE_BINARY_DIR}/fakeroot/C:/Irccd/bin which is indeed invalid.

To fix this, a warning was shown telling that absolute paths are not recommended and fakeroot was disabled in this case, ending with a lot of conditionals in CMake, polluting the readability.

As it's not usually needed to change these directories and to facilitate irccd's development, it's not possible to make them absolute anymore.

But I want to mix / and /usr/local!

While I think you should keep everything belong to the CMAKE_INSTALL_PREFIX variable, it's still possible to tweak the installation to use different parent directories.

cmake . -DCMAKE_INSTALL_PREFIX=/ -DWITH_BINDIR=usr/local/bin -DWITH_CONFDIR=etc -DWITH_DATADIR=usr/local/share -DWITH_CACHEDIR=var/irccd -DWITH_PLUGINDIR=usr/local/share/irccd/plugins

With that invocation, you'll get irccd installed like this:

  • WITH_BINDIR: /usr/local/bin/irccd(ctl)
  • WITH_DATADIR: /usr/local/share/irccd
  • WITH_CONFDIR: /etc/irccd(ctl).conf
  • WITH_CACHEDIR: /var/irccd
  • WITH_PLUGINDIR: /usr/local/share/irccd/plugins

Incoming improvements

Anyway, these CMake options only alter defaults and a new feature to include more paths in the configuration file will be added soon, see #470.

1 2 3 (1-10/29)

Also available in: Atom