irctk-extensions − irctk extensions protocol specification
The extensions communication protocol, allows third party programs to receive and send messages to and from IRCTk, with the idea of writing extensions to integrate IRCTk with the surrounding system. Different type of messages are provided, and the extensions, running as external programs, can request which specific messages to receive from IRCTk.
This document describe the extensions communication protocol as a simple, line-oriented, stream of bytes. Such stream is bi-directional, meaning, IRCTk and an extension can exchange messages between each other.
The protocol can be kept simple due to the fact that the IRC protocol as described in RFC1459, is itself a line-oriented protocol, thus there is no need to handle bytes sequences in a, somehow, “structured” fashion, nor there is the need to introduce escape sequences for special characters.
The protocol described herein can be used to write client-side bots, or to integrate IRCTk with the surrounding system (think about opening URLs in a browser), leveraging the capabilities built into the systems running the application.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
This specification documents the version 1.0 of the extensions protocol.
A message, exchanged between IRCTk and an extension program, is a UTF-8 CSV-like encoded line, terminated by the sequence CRLF (carriage-return line-feed).
A message line contains a series of fields, separated by a tab (ASCII code 9 character). The number of fields varies depending on the message type. An example of a basic message might be the following:
34563\tirc\t1234\tfoo\tmention\tfalse\taway\tLibera\t#openbsd\
\ttime=2023-08-03T19:47:05.231Z\tPRIVMSG\tHello,
World!CRLF
In this example, the fields are:
|
34563 |
The message id. |
|||
|
irc |
The message type, in this case an irc command. |
1681676304
The message timestamp.
|
1234 |
The channel id the message is coming from. |
|||
|
foo |
The user that sent the message. |
|||
|
mention |
Message level.
|
false |
Application window focus state. |
|||
|
away |
The client user current status (he is away, in this moment). |
|||
|
Libera |
The network name. |
#openbsd
The channel name.
time=2023-08-03T19:47:05.231Z
IRCv3 message tags.
|
PRIVMSG |
IRC command.
Hello, world!
The command arguments.
|
CRLF |
The termination sequence. |
All the message types sent by either IRCTk or an extension, MUST follow the aforementioned format.
The extensions protocol supports six message types:
|
• |
Handshake |
|||
|
• |
Ack |
|||
|
• |
Nack |
|||
|
• |
Filter |
|||
|
• |
Irc |
|||
|
• |
Plumb |
If a field on a message type definition is marked as “EMPTY”, it means that the field itself MUST be present in the message, with a length of zero bytes. An empty field is defined by two consecutive tab characters or, if the final field of a message can be empty, by a tab character and the termination sequence.
Unless explicitly marked as “EMPTY”, every message MUST have an “id” as first field. This is required to keep track of messages that must receive an acknowledge from either the application or an extension. The ID might be numeric, or a random generated string, and it can be reused once a previous exchange, using that id, is completed. However, it is RECOMMENDED that both IRCTk and the loaded extensions, use a unique message id for every exchange whenever possible.
ACK/NACK: yes
The handshake messages are exchanged between IRCTk and an extension when the latter is first loaded.
An handshake message have the following fields:
|
Id |
The message id |
|||
|
Type |
The message type. Handshake, in this case. |
|||
|
Version |
The protocol version.
|
Name |
Application, or extension name. |
AppVersion
Application or extension version.
Capabilities
Space-separated list of capabilities (EMPTY).
The means of this message type, is to establish if the loaded extension is compatible with the version of IRCTk and it’s extension protocol that loaded it.
Additionally, combined with proper filters, extensions MAY be able to handle particular IRCv3 capabilities, that will be requested by IRCTk and forwarded with the coming messages.
ACK/NACK: no
The ACK is a generic acknowledge message that might be sent by the application, or by an extension, in response to a request in order to say that it was accepted. It has the following fields:
|
Id |
The message id |
|||
|
Type |
The message type. ack, in this case. |
|||
|
Comment |
A string, commenting the ACK (EMPTY).
ACK/NACK: no
See “ACK”, but in this case, the request or message is denied. The fields are:
|
Id |
The message id |
|||
|
Type |
The message type. ack, in this case. |
|||
|
Comment |
A string, commenting the NACK (EMPTY).
ACK/NACK: yes
A “filter” message, is used by an extension, to inform IRCTk to only send messages of the type specified in the filter or a specific command specified in the filter. More than one filter message may be sent by an extension in order to specify additional types or commands to receive.
By default all the messages processed by IRCTk will be forwarded to an extension.
A filter message has the following fields:
|
Id |
The message id |
|||
|
Type |
The message type. filter, in this case. |
type/command
The message type or command to filter for.
Silent change in behaviour by IRCTk without acknowledge is not allowed. An extension MUST NOT change it’s working behaviour until an ACK for the sent request is received.
An extension wanting to receive messages only for specific command of a specific type, MUST first request a filter for the message type first, and then send a filter requests for the specific command. For example, an extension asking to send messages of type “irc” only, with no further command filtering requests, will cause IRCTk to send all the messages of type irc it receives, to the extension.
Refer to the “Communication example” section for additional details.
ACK/NACK: no
A message of type “irc” is, essentially, an IRC command received by IRCTk from a server, or a command coming from the IRCTk user’s GUI itself. All those commands, unless filters are in place, are relayed to an extension. On the other hand, an extension can send an irc message to IRCTk, to show specific information, or to relay a message to a specific channel (client-side) bot. The fields are:
|
Id |
The message id (EMPTY) |
|||
|
Type |
The message type. ack, in this case. |
Timestamp
Timestamp of the message, in seconds, from the epoch (EMPTY).
|
Cid |
The id of the channel in IRCTk (EMPTY). | ||
|
Nick |
The nick of the user that sent the message (EMPTY). | ||
|
Level |
Message level, from “info”, to “mention” (EMPTY). | ||
|
Focus |
true or false. Define if the application window is on focus (EMPTY). | ||
|
Status |
Client user’s status. Might be “away” or not (EMPTY). | ||
|
Network |
The network name.
|
Channel |
The channel name.
|
Tags |
A list of IRCv3 tags (EMPTY). |
|||
|
Command |
The IRC command.
|
Args |
The command arguments. |
An example of this message (received by an extension), is the one written in the introduction section.
In this revision of the specification, the “id” field for the IRC message type can be empty, but it may become mandatory it in a future version of the spec.
The “Tags” field, is a string representing a list of tags as defined in the IRCv3 message tags specification. This specification extends on that by adding an additional escape sequences for the the tabulation character.
The escape sequence will appear, literally, in a tag value to represent a tabulation character, as the tabulation is among the permitted characters in a tag value. This is needed, as the tab character is used as a separation character for a the various message fields. An example might be:
firsttag=myvalue;secondtag=new\tvalue
ACM/NACK: no
A plumb, is a generic message sent by IRCTk to an extension with just some text data.
It’s up to the extension to decide what to do with this type of message. An extension MUST NOT send messages of this type and IRCTk MUST ignore such messages.
Fields are as follows:
|
Id |
Message Id (EMPTY). |
|||
|
Type |
The message type, “plumb” in this case. |
|||
|
Cid |
The Id of the channel where the plumb happened (EMPTY). |
|||
|
Network |
The network name (EMPTY).
|
Channel |
The channel name (EMPTY).
|
Data |
The text string. |
When IRCTk first starts an extension, a small handshake sequence takes place, where just some messages are exchanged. IRCTk will, initially, send the following message:
1234\thandshake\t1.0\tirctk\t1.0<CR><LF>
To which, the extension will answer with an ACK if everything is fine:
1234\tack\tok<CR><LF>
or with an NACK, if something is wrong:
1234\tnack\tko<CR><LF>
If everything is ok, the extension will send it’s details:
5678\thandshake\t1.0\textension-name\t0.1<CR><LF>
If everything is fine, IRCTk will acknowledge that the extension is compatible:
5678\tack\tok<CR><LF>
Or deny running the extension if something is wrong (the comment is an example):
5678\tnack\textension not supported<CR><LF>
If everything is ok, the extension is finally “ready” and the flow of other type of messages can start. As an example, an extension may ask to receive messages of type irc, only for the privmsg command:
55354\tfilter\tirc<CR><LF>
45634\tfilter\tprivmsg<CR><LF>
The application ACKs the requests:
55354\tack\tok<CR><LF>
45634\tack\tok<CR><LF>
The application then sends messages of type IRC and for the privmsg command to the extensions. An extension may send an irc message, that will be posted in the corresponding channel. The following is an example of a minimum valid IRC message coming from an extension:
\tirc\t\t\t\t\t\t\tLibera\t#irctk\tPRIVMSG\tHello, world!<CR><LF>
The message will be posted, by IRCTk, to the channel #irctk on the configured Libera network.
irctk(1)
The first revision of this specification appeared with IRCTk 1.0
Andrea Biscuola [email protected]