JELP

The Juno Extensible Linking Protocol (JELP) is the preferred server linking protocol for juno-to-juno links.

As of writing, the only implementation known to exist is that of juno itself, but future applications may choose to implement JELP for better compatibility with juno.

This document is to be used as reference when implementing IRC servers and pseudoservers.

Format

The protocol resembles RFC1459 in that each message represents a command with an optional source, target, and additional parameters. The source is prefixed by a colon (:), as is the final parameter if it includes whitespace.

Most messages resemble the following:

:<source> <command> [<parameters> ...]

However, a few do not require a source:

<command> [<parameters> ...]

Some also include message tags.

Line delimiters

A single message occurs per line. Empty lines are silently discarded.

The traditional line ending \r\n (CRLF) is replaced simply by \n (LF); however for easier adoption in legacy software, \r MUST be ignored if present.

The traditional line length limit of 512 bytes does not apply, nor do any limitations on the number of parameters per message. For this reason it is especially important that only trusted servers are linked. However, servers MAY choose to terminate an uplink if the receive queue exceeds a certain size.

Entity identifiers

The protocol is further distinguished from RFC1459 by its use of user and server identifiers as the source and target of commands in place of nicknames, user masks, and server names. This idea is borrowed from other server linking protocols such as TS6; it aims to diminish the effects of name collisions.

  • SID - A server identifier. This is numerical (consisting of digits 0-9).

  • UID - A user identifier. This consists of ASCII letters (a-z, A-Z), prefixed by the numerical SID to which the user belongs. It is case-sensitive.

User and server identifiers in JELP are of arbitrary length but limited to 16 bytes. Servers SHOULD NOT use the prefix on UIDs to determine which server a user belongs to. Servers MAY reuse UIDs that are no longer active should the 16 byte limit be exhausted.

Message tags

Some messages have named parameters called tags. They occur at the start of the message, before the source and command. The format is as follows:

@<name>=<value>[;<name2>=<value2> ...] :<source> <command> [<parameters> ...]

This is particularly useful for messages with optional parameters (as it reduces overall message size when they are not present). More often, however, it is used to introduce new fields without breaking compatibility with existing implementations.

This idea is borrowed from an extension of the IRC client protocol, IRCv3.2 message-tags. The JELP implementation of message tags is compatible with that specification in all respects, except that the IRCv3 limitation of 512 bytes does not apply.

Propagation

  • server mask - command is propagated based on a server mask parameter. The command is sent to all servers with names matching the given mask (for example *, *.example.com, irc.example.com). Those servers do not have to be directly connected.

  • broadcast - command is sent to all servers.

  • one-to-one - command is only sent to the target or the server the target is on.

  • conditional - propagation is dependent on command interpretation and is described in the text. It may also be used to describe another propagation type where the command may or may not be propagated based on its interpretation.

  • none - command is never sent to another server if it is received.

Connection setup

  • Server negotiation - The initiator sends the SERVER command. The receiver verifies the server name, SID, TS, peer address, and versions. If unacceptable, the connection is dropped before password negotiation; otherwise, the receiver replies with its own SERVER command.

  • Password negotiation - If the incoming SERVER passes verification, the initiator sends PASS. The receiver verifies the password, dropping the connection if invalid. If the password is correct, the receiver replies with its own PASS command, followed by READY.

  • Initiator burst - Upon receiving READY, the initiator sends its burst, delimited by BURST and ENDBURST.

  • Receiver burst - Upon receiving ENDBURST, the receiver replies with its own burst. ENDBURST and READY should be handled the same way: in either case, the server sends its burst if it has not already.

Burst

A server burst consists of the following:

  • Initiate the burst with BURST

  • Send out this server's mode mappings

    • AUM - our user modes

    • ACM - our channel modes

  • Introduce descendant servers

    • SID - child server introduction

    • AUM - add each server's user modes

    • ACM - add each server's channel modes

  • Introduce users

    • UID - user introduction

    • OPER - oper flag propagation

    • LOGIN - account name propagation

    • AWAY - mark user as away

  • Burst channels

  • Extensions

    • Any extension burst commands occur here, such as BAN

  • Terminate the burst with ENDBURST

Modes

JELP does not have predefined mode letters. Before any mode strings are sent out, servers MUST send the AUM and ACM commands to map mode letters and types to their names. Servers SHOULD track the mode mappings of all other servers on the network, even for unrecognized mode names.

Throughout this documentation, commands involving mode strings will mention a perspective, which refers to the server whose mode letter mappings should be used in the parsing of the mode string. If the perspective is a user, it refers to the server to which the user is connected.

Below are the lists of mode names, their types, and their usual associated letters. Servers MAY implement any or all of them, but they MUST quietly ignore any unrecognized incoming modes.

Required core commands

These commands MUST be implemented by servers. Failure to do so will result in network discontinuity.

ACM

Maps channel mode letters and types to mode names.

Propagation: broadcast

:<SID> ACM <name>:<letter>:<type> [<more modes> ...]
  • SID - server these mode mappings belong to

  • name - mode name

  • letter - mode letter

  • type - mode type, which describes how to allocate parameters in a mode string. one of

    • 0 - normal mode, no parameter

    • 1 - mode with parameter always

    • 2 - mode with parameter only when setting

    • 3 - banlike list mode

    • 4 - status mode

    • 5 - channel key (special case)

AUM

Maps user mode letters to mode names.

Propagation: broadcast

:<SID> AUM <name>:<letter> [<more modes> ...]
  • SID - server these mode mappings belong to

  • name - mode name

  • letter - mode letter

AWAY

Marks a user as away.

Propagation: broadcast

:<UID> AWAY [:<reason>]
  • UID - user to mark as away

  • reason - optional, reason for being away. if omitted, the user is returning from away state

BURST

Sent to indicate the start of a burst.

This is used for the initial burst as well as the bursts of other descendant servers introduced later.

The corresponding ENDBURST terminates the burst.

Propagation: broadcast

:<SID> BURST <TS>
  • SID - server bursting

  • TS - current UNIX TS

CMODE

Channel mode change.

Propagation: conditional broadcast

:<source> CMODE <channel> <TS> <perspective> <modes> [<parameters> ...]
  • source - user or server committing the mode change

  • channel - channel to change modes on

  • TS - channel TS

  • perspective - mode perspective server

  • modes - mode changes. each mode parameter is a separate parameter of the command

If <TS> is newer than the internal channel TS, drop the message and do not propagate it.

Otherwise, accept and propagate the incoming modes.

ENDBURST

Sent to indicate the end of a burst.

Propagation: broadcast

:<SID> ENDBURST <TS>
  • SID - server whose burst has ended

  • TS - current UNIX TS

Upon receiving, the server should send its own burst if it has not already.

JOIN

Channel join. Used when a user joins an existing channel with no status modes.

Propagation: broadcast

:<UID> JOIN <channel> <TS>
  • UID - user joining the channel

  • channel - channel being joined

  • TS - channel TS

If <channel> does not exist, create it. This should not happen though.

If <TS> is older than the internal channel TS, reset all channel modes and invitations.

Regardless of <TS>, add the user to the channel and propagate the JOIN with the CURRENT channel TS.

See also SJOIN.

KICK

Propagates a channel kick. Removes a user from a channel.

Propagation: broadcast

:<source> KICK <channel> <target UID> :<reason>
  • source - user or server committing the kick

  • channel - channel to remove the target user from

  • target UID - user to remove

  • reason - kick comment

KILL

Temporarily removes a user from the network.

Propagation: broadcast

:<source> KILL <target UID> :<reason>
  • source - user or server committing the kill

  • target UID - user to remove

  • reason - kill comment, visible as part of the user quit message

KILL is not acknowledged (it is NOT followed by QUIT), and for that reason, it cannot be rejected. Pseudoservers whose clients cannot be killed may internally disregard the KILL message but, in that case, must immediately reintroduce the user to uplinks.

NICK

Propagates a nick change.

Propagation: broadcast

:<UID> NICK <nick> <nick TS>
  • UID - user changing nicks

  • nick - new nick

  • nick TS - new nick TS

NOTICE

To the extent that concerns JELP, equivalent to PRIVMSG in all ways other than the command name.

Propagation: conditional

NUM

Sends a numeric reply to a remote user.

Propagation: one-to-one

:<SID> NUM <UID> <num> :<message>
  • SID - source server

  • UID - target user (determines propagation)

  • num - numeric, a three-digit sequence

  • message - numeric message

If <num> starts with 0, rewrite the first digit as 1. This is because the numerics in the 0XX range are permitted only from the server the user is connected to.

Note that <message> may actually contain several numeric parameters combined into a single string. It may also contain a sentinel (in addition to the usual one which prefixes it) at the start or later in the message. For this reason, <message> should not be prefixed with a sentinel when forwarding it to the target user.

OPER

Propagates oper privileges.

The setting of the ircop user mode (+o) is used to indicate that a user has opered-up; this command may be used to modify their permissions list.

Propagation: broadcast

:<UID> OPER [-]<flag> [<flag> ...]
  • UID - user whose privileges are to be changed

  • flag - any number of oper flags may be added or removed in a single message, each as a separate parameter. those being removed are prefixed by -; those being added have no prefix

PART

Propagates a channel part.

Propagation: broadcast

:<UID> PART <channel> :<reason>
  • UID - user to be removed

  • channel - channel to remove the user from

PARTALL

Used when a user leaves all channels.

This is initiated on the client protocol with the JOIN 0 command.

Propagation: broadcast

:<UID> PARTALL
  • UID - user to be removed from all channels

PASS

During registration, sends the connection password.

Propagation: none

PASS <password>
  • password - connection password in plain text

See connection setup.

PING

Verifies uplink reachability.

Propagation: none

PING <message>
  • message - some data which will also be present in the corresponding PONG

PONG

Reply for PING.

Propagation: none

:<SID> PONG <message>
  • SID - server replying to the PING

  • message - data which was specified in the corresponding PING

PRIVMSG

Sends a message.

Propagation: conditional

:<source> PRIVMSG <target> :<message>
  • source - user or server sending the message

  • target - message target, see below

  • message - message text

<target> can be any of the following:

  • a user

  • a channel

    • Propagation: all servers with non-deaf users on the channel

  • @ followed by a status mode letter and a channel name, to message all users on the channel with that status or higher

    • Propagation: all servers with -D users of appropriate status

    • Example: @o#channel - all users on #channel with +o or higher

  • = followed by a channel name, to send to channel ops only, for op moderation

  • a user@server.name message, to send to users on a specific server. the exact meaning of the part before the @ is not prescribed, except that "opers" allows IRC operators to send to all IRC operators on the server in an unspecified format. this can also be used for more secure communications to external services

  • a message to all users on server names matching a mask ($$ followed by mask)

  • a message to all users with hostnames matching a mask ($# followed by mask)

    • Unimplemented

    • Propagation: broadcast

    • Only allowed to IRC operators

QUIT

Propagates a user or server quit.

Propagation: broadcast

Form 1

:<UID> QUIT :<reason>
  • UID - user quitting

  • reason - quit comment

Form 2

[@from=] :<SID> QUIT :<reason>
  • from - optional, user that initiated the SQUIT

  • SID - server quitting

  • reason - quit comment

READY

Sent to indicate that the initiator should send its burst.

Propagation: none

READY

See connection setup.

SAVE

Used to resolve nick collisions without casualty.

Propagation: broadcast

:<SID> SAVE <UID> <nick TS>
  • SID - server saving the user

  • UID - user to be saved

  • nick TS - user's nick TS, as known by the saving server

If the user target already has their UID as their nick or <nick TS> does not match the internal nick TS, drop the message and do not propagate.

Otherwise, change the user's nickname to their UID, set their nick TS to 100, and propagate the message.

SERVER

During registration, introduces the server.

Propagation: none

SERVER <SID> <name> <proto version> <version> <TS> :<description>
  • SID - server ID

  • name - server name

  • proto version - JELP protocol version (checked for compatibility)

  • version - IRCd or package version (not checked)

  • TS - current UNIX TS

  • description - server description to show in LINKS, MAP, etc. This MUST be the last parameter, regardless of any additional parameters which may be added in between the <TS> and <description> at a later date. If the description starts with the sequence (H) (including the trailing space), the server should be marked as hidden

See connection setup.

SID

Introduces a server.

Propagation: broadcast

:<source SID> SID <SID> <name> <proto version> <version> <TS> :<description>
  • source SID - parent server

  • SID - server ID

  • name - server name

  • proto version - JELP protocol version (checked for compatibility)

  • version - IRCd or package version (not checked)

  • TS - current UNIX TS

  • description - server description to show in LINKS, MAP, etc. This MUST be the last parameter, regardless of any additional parameters which may be added in between the <TS> and <description> at a later date. If the description starts with the sequence (H) (including the trailing space), the server should be marked as hidden

SJOIN

Bursts a channel.

This command MUST be used for channel creation and during burst. It MAY be used for existing channels as a means to grant status modes upon join.

Propagation: broadcast

:<SID> SJOIN <channel> <TS> <modes> [<parameters> ...] :<user list>
  • SID - server bursting the channel

  • channel - channel being burst or created

  • TS - channel TS

  • modes - all channel modes besides statuses. each mode parameter is a separate parameter of the SJOIN command. if no modes are set, a single + must be present

  • user list - membership and status modes. this will always be the last parameter, regardless of any mode parameters before it. the format is a space-separated of UID!modes, where modes are the status modes that the user has in the channel. if a user has no modes, the ! may be omitted

If the channel does not exist, create it.

Otherwise:

If <TS> is older than the internal channel TS, clear all modes and invites, accept new modes and statuses, and forward as-is.

If <TS> is equal to the current internal channel TS, accept new modes and statuses and forward as-is.

If <TS> is newer than the current internal channel TS, disregard modes and statuses and forward the message without them.

In any case, add the listed users to the channel.

TOPIC

Propagates a channel topic change.

Propagation: broadcast

:<source> TOPIC <channel> <TS> <topic TS> :<topic text>
  • source - user or server setting the topic

  • channel - channel whose topic is being changed

  • TS - channel TS

  • topic TS - new topic TS

  • topic text - new topic text

Regardless of <TS>, set the topic and propagate it with the CURRENT channel TS.

TOPICBURST

Bursts a channel topic.

Propagation: broadcast

:<SID> TOPICBURST <channel> <TS> <set by> <topic TS> :<topic text>
  • SID - server bursting the topic

  • channel - channel whose topic is being burst

  • TS - channel TS

  • set by - server name or user mask that set the topic

  • topic TS - new topic TS

  • topic text - new topic text

Accept the topic and propagate if any of the following are true:

  • the channel currently has no topic

  • <TS> is older than the internal channel TS

  • <TS> is equal to the internal channel TS and <topic TS> is newer than the internal topic TS

Otherwise, drop the message and do not propagate.

UID

Introduces a user.

Propagation: broadcast

:<SID> UID <UID> <nick TS> <modes> <nick> <ident> <host> <cloak> <ip> :<realname>
  • SID - server to which the user belongs

  • UID - UID

  • nick TS - nick TS

  • modes - user modes in the perspective of <SID> (no parameters) or a single + if no modes are set

  • nick - nick

  • ident - ident/username

  • host - real canonical host

  • cloak - visible host

  • ip - IP address. must be prefixed with 0 if starts with :

  • realname - real name

UMODE

Propagates a user mode change.

Propagation: broadcast

:<UID> UMODE <modes>
  • UID - user whose modes are to be changed

  • modes - modes in the perspective of <UID> (no parameters)

USERINFO

Propagates the changing of one or more user fields.

Propagation: broadcast

[@nick=][;nick_time=][;real_host=][;host=][;ident=][;account=] :<UID> USERINFO
  • nick - optional, new nick

  • nick time - optional, new nick time. MUST be present if <nick> is present

  • real_host - optional, new real canonical host

  • host - optional, new visible canonical host

  • ident - optional, new ident/username

  • account - optional, new account name or * for logout

  • UID - user whose fields should be changed

Optional core commands

These commands SHOULD be implemented by servers when applicable, but failure to do so will not substantially affect network continuity.

ADMIN

Remote ADMIN request.

Propagation: one-to-one

:<UID> ADMIN <server>
  • UID - user making the request

  • server - server name or $-prefixed SID (determines propagation)

CONNECT

Remote CONNECT.

Propagation: one-to-one

:<source> CONNECT <mask> <server>
  • source - user or server initiating the CONNECT

  • mask - parameter for CONNECT command. this may be an absolute server name or a mask matching zero or more servers

  • server - server name or $-prefixed SID (determines propagation)

FJOIN

Forces a user to join a channel.

Propagation: one-to-one

:<SID> FJOIN <UID> <channel> [<TS>]
  • SID - server committing the force join

  • UID - user to force to join (determines propagation)

  • channel - channel to force the user to join

  • TS - optional, channel TS

If <TS> is provided, the channel must exist, and the internal channel TS must match the provided one. If this is not the case, drop the message. The server must handle the request as though it were a normal JOIN message from the client, taking bans and other restrictions into account.

If <TS> is omitted, the join should be forced regardless of whether the channel is preexisting or has restrictions to prevent the user from joining.

In either case, if the join was successful, the server must acknowledge the join with either SJOIN (if the channel was just created) or JOIN (otherwise).

FLOGIN

Forces a user to login to an account.

Used by external services.

Propagation: broadcast

:<SID> FLOGIN <UID> <account>
  • SID - server forcing the login

  • UID - user to force to login

  • account - name of the account

Unlike other force commands, FLOGIN cannot fail and therefore does not need to be acknowledged.

FNICK

Forces a nick change.

Propagation: one-to-one

:<SID> FNICK <UID> <new nick> <new nick TS> <old nick TS>
  • SID - server forcing the nick change

  • UID - user whose nick should be changed (determines propagation)

  • new nick - new nick

  • new nick TS - new nick TS

  • old nick TS - old nick TS

If <old nick TS> is not equal to the internal nick TS, drop the message.

Otherwise, if the new nick is already in use by an unregistered connection, cancel registration and drop that connection.

If the new nick is already in use by a user, kill the user.

Update the nick and nick TS and acknowledge the change by broadcasting a NICK message to all servers including the one which issued FNICK.

FOPER

Forces an oper privilege change.

Propagation: one-to-one

:<SID> FOPER <UID> [-]<flag> [<flag> ...]
  • SID - server forcing the privilege change

  • UID - user whose privileges will be changed (determines propagation)

  • flag - any number of oper flags may be added or removed in a single message, each as a separate parameter. those being removed are prefixed by -; those being added have

Update the flags and acknowledge the change by broadcasting an OPER message to all servers including the one which issued FOPER.

FPART

Forces a user to part a channel.

Propagation: one-to-one

:<SID> FPART <UID> <channel> <TS> [:<reason>]
  • SID - server forcing the user to part

  • UID - user to force to part (determines propagation)

  • TS - channel TS

  • reason - optional, part reason

Commit the mode change and acknowledge it by broadcasting a PART message to all servers including the one which issued FPART.

FUMODE

Forces a user mode change.

Propagation: one-to-one

:<SID> FUMODE <UID> <modes>
  • SID - server forcing the mode change

  • UID - user whose modes should be changed (determines propagation)

  • modes - modes in the perspective of <UID> (no parameters)

Remove the user from the channel and acknowledge the change by broadcasting a UMODE message to all servers including the one which issued FUMODE.

FUSERINFO

Forces the changing of one or more user fields.

Propagation: one-to-one

See USERINFO for fields.

The receiver may accept or reject any of the changes. Acknowledge those which were accepted with a USERINFO message broadcast to all servers including the one which issued FUSERINFO.

INFO

Remote INFO request.

Propagation: one-to-one

@for= :<UID> INFO
  • for - server target (determines propagation)

  • UID - user committing the request

INVITE

Invites a remove user to a channel.

Propagation: one-to-one

:<UID> INVITE <target UID> <channel>
  • UID - user offering the invitation

  • target UID - user to be invited (determines propagation)

  • channel - channel to which the user should be invited

<channel> does not necessarily have to exist, but servers MAY silently discard invitations to nonexistent channels to prevent spam.

KNOCK

Propagates a channel knock.

Propagation: broadcast

:<UID> KNOCK <channel>
  • UID - user knocking

  • channel - channel to knock on

Remote LINKS request.

Propagation: one-to-one

@for= :<UID> LINKS
  • for - server target (determines propagation)

  • UID - user committing the request

LOGIN

Propagates a user account login.

Propagation: broadcast

:<UID> LOGIN <account info>
  • UID - user to login

  • account info - comma-separated account info. the format is unspecified except that the first field is always the account name

Currently, <account info> is only the account name. In previous built-in account mechanisms, other data was also sent. For compatibility in case a future account mechanism makes use of other fields, the account name should be extracted as the sequence terminated by either , or the end of the string.

LUSERS

Remote LUSERS request.

Propagation: one-to-one

@for= :<UID> LUSERS
  • for - server target (determines propagation)

  • UID - user committing the request

MLOCK

Sets a channel mode lock.

:<source> MLOCK <channel> <TS> <modes> [<parameters> ...]
  • source - user or server committing the mode lock

  • channel - channel to lock the modes on

  • TS - channel TS

  • modes - optional, modes to lock. each mode parameter is a separate parameter of the command. for status modes, the parameter should be the mask which is locked. for all other modes with parameters, the parameter value does not matter but must be present. * is used as a filler

If <TS> is newer than the internal channel TS, drop the message and do not propagate it.

Otherwise, if <modes> is omitted, unset the current mode lock and propagate the message with the current channel TS.

Otherwise, set the mode lock locally and propagate the message with the current channel TS and the mode string exactly as it was received.

MOTD

Remote MOTD request.

Propagation: one-to-one

:<UID> MOTD <server>
  • UID - user committing the request

  • server - server name or $-prefixed SID (determines propagation)

REHASH

Remote REHASH.

Propagation: server mask

:<UID> REHASH <mask>
  • UID - user committing the request

  • mask - server mask target. all matching servers will respond (determines propagation)

SNOTICE

Propagates a server notice to remote opers.

Propagation: broadcast

[@from_user=] :<SID> SNOTICE <flag> :<message>
  • from_user - optional, user whose action resulted in this notice

  • SID - server producing the notice

  • flag - server notice flag

  • message - notice text

TIME

Remote TIME request.

Propagation: one-to-one

:<UID> TIME <server>
  • UID - user committing the request

  • server - server name or $-prefixed SID (determines propagation)

USERS

Remote USERS request.

Propagation: one-to-one

@for= :<UID> USERS
  • for - server target (determines propagation)

  • UID - user committing the request

VERSION

Remote VERSION request.

Propagation: one-to-one

:<UID> VERSION <server>
  • UID - user committing the request

  • server - server name or $-prefixed SID (determines propagation)

WHOIS

Remote WHOIS query.

Propagation: one-to-one

@for= :<UID> WHOIS <target UID>
  • for - server target (determines propagation)

  • UID - user committing the request

  • target UID - user whose information is being requested

Extension commands

These commands MAY be implemented by servers but are not required. They are not part of the core JELP protocol implementation. If any unknown command is received, servers MAY choose to produce a warning but SHOULD NOT terminate the uplink.

BAN

During burst, lists all known global ban identifiers and the times at which they were last modified.

Propagation: none

BANDEL

Propagates a global ban deletion.

Propagation: broadcast

BANIDK

In response to BAN during burst, requests information for a ban the receiving server is not familiar with.

Propagation: none

BANINFO

Propagates a global ban.

Used upon adding a new ban and during burst in response to BANIDK.

Propagation: broadcast

MODEREP

MODEREQ

Used for MODESYNC.

SASLDATA

SASLDONE

SASLHOST

SASLMECHS

SASLSET

SASLSTART

Used for SASL authentication.