Skip to content

Add draft/multiline support - #525

Open
skizzerz wants to merge 5 commits into
solanum-ircd:mainfrom
skizzerz:multiline
Open

Add draft/multiline support#525
skizzerz wants to merge 5 commits into
solanum-ircd:mainfrom
skizzerz:multiline

Conversation

@skizzerz

Copy link
Copy Markdown
Contributor

This includes two components:

  • A new core s2s batch type solanum.chat/echo controlled by the ECHOB server capability. Used for echo-message support for batched messages. Note that unlike normal commands, the contents of an echo batch are sent to the client as-is (e.g. no parsing/substitution of UIDs/SIDs). Limited validation is still performed to ensure the prefix/origin is not coming from a fake direction. The echo batch parameters contain the origin instead which will be sent to the target client rather than any origin inside of the batch messages.
  • The draft/multiline extension. This is currently explicitly unstable due to the s2s batch changing from draft/multiline to unprefixed multiline once the spec is ratified. The MULTILN server capability will switch meaning as well come ratification time. This is an implementation detail and could be adjusted if desired (to e.g. just use unprefixed multiline for s2s batches even right now which would allow better mixed-version support in the future).

@progval progval left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bugs founds by irctest:

  • The batch is sent to clients without the draft/multiline cap
  • Tags inside the batch should be stripped (eg. time)
  • A client sending @batch with an incorrect id should get FAIL BATCH INVALID_REFTAG, but gets nothing. eg.
    1778706225.616 1 -> S: BATCH +123 draft/multiline #test
    1778706225.616 1 -> S: @batch=231 PRIVMSG #test :hi
    1778706225.616 1 -> S: PING synchronize579081.364567705
    1778706226.618 S -> 1: @time=2026-05-13T21:03:46.617Z :My.Little.Server PONG My.Little.Server :synchronize579081.364567705
    
  • draft/multiline-concat messages with blank content are not rejected (the spec does not explicitly require this, but implicitly recommends it)

@skizzerz

skizzerz commented May 13, 2026

Copy link
Copy Markdown
Contributor Author

The batch is sent to clients without the draft/multiline cap

Can you provide a trace/example of this? Spotted the issue, will fix.

Tags inside the batch should be stripped (eg. time)

This is not required by the specification and is too difficult to implement in solanum. This will be left as-is.

A client sending @batch with an incorrect id should get FAIL BATCH INVALID_REFTAG, but gets nothing. eg.

This is not required by the specification. In fact, it violates "Once a client has opened a batch, it MUST NOT send any messages that are not part of the batch". The server is allowed to respond (or not respond) however it wants when a client violates the specification.

The INVALID_REFTAG fail code is for the BATCH command, as it indicates that "all past and future messages in this batch will be ignored". A client that subsequently sends commands with the rejected batch tag will have their commands silently rejected (ignored), which is exactly what solanum does.

draft/multiline-concat messages with blank content are not rejected (the spec does not explicitly require this, but implicitly recommends it)

Can you provide a trace of this? It should've been rejected.

@progval

progval commented May 14, 2026

Copy link
Copy Markdown
Contributor

Can you provide a trace of this? It should've been rejected.

You're right, it's rejected. I didn't see it because it's only rejected when Solanum gets the BATCH -, while Ergo rejects it immediately.

@progval

progval commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

I just noticed that every command in the multiline batch has a different value for the @time tag, eg.

1781377075.764 S -> 2: @msgid=1178137707467200684442XAAAAABI3Rlc3Q=;time=2026-06-13T18:57:54.731Z :alice!~username@127.0.0.1 BATCH +6i1Dl1g9jlkvJDE draft/multiline #test
1781377075.764 S -> 2: @batch=6i1Dl1g9jlkvJDE;time=2026-06-13T18:57:54.737Z :alice!~username@127.0.0.1 PRIVMSG #test :hello
1781377075.764 S -> 2: @batch=6i1Dl1g9jlkvJDE;time=2026-06-13T18:57:54.740Z :alice!~username@127.0.0.1 PRIVMSG #test :#how is 
1781377075.764 S -> 2: @batch=6i1Dl1g9jlkvJDE;draft/multiline-concat;time=2026-06-13T18:57:54.741Z :alice!~username@127.0.0.1 PRIVMSG #test :everyone?

The spec does not specify which one clients should display next to the message; so we may end up with clients displaying different timestamp for the same message. Can this be solved in Solanum, or should we suggest a spec update?

For what it's worth, Unreal has the same time on the inner messages as on the BATCH + but a different value for BATCH - (EDIT: I was wrong, there is no @time on Unreal's BATCH -)

@skizzerz

Copy link
Copy Markdown
Contributor Author

Spec update sounds best here. There is no way to do this in a generic fashion in solanum that works for all batch types (as other server-to-client batch types do want inner tags), which means I'd either need to select specific tags to suppress for multiline batches (and other tags won't be suppressed), or each tag module needs to specifically indicate how it works with multiline.

This is a lot of work, and it's fairly ugly, for something that can be solved with one sentence in a spec and that clients will probably end up doing anyway even if the spec isn't updated.

@skizzerz
skizzerz force-pushed the multiline branch 2 times, most recently from f309c8b to bbdfb9e Compare July 27, 2026 18:12
The specficiation indicates that reference tags can only contain ASCII
letters, numbers, and the hyphen character, so enforce this. IsIdChar
neatly maps to ASCII letters/numbers.
This batch is gated behind a new server capab ECHOB. It allows for
echoing multiple lines of text within a batch (potentially with nested
batches) for the echo-message mechanism. Unlike most s2s messages, any
contents within a solanum.chat/echo batch are sent to the client exactly
as-is; they are *not* parsed to e.g. replace UID/SIDs with the relevant
client-facing identifiers. Limited parsing to validate the origin/prefix
is not coming from a fake direction is still performed, so inner
messages cannot have spoofed senders. Instead, the sender information is
encoded in batch parameters so the destination server can spoof that
information when delivering to the client.

While nothing in the codebase currently uses this, it is used for the
draft/multiline extension.
This introduces a new MULTILN server capability. The batch type is
draft/multiline for both c2s and s2s currently, however s2s also accepts
bare (unprefixed) multiline for forward compatibility for when the draft
is ratified. If the draft changes in incompatible ways between now and
ratification, a new server capab will likely be used instead, however
the draft is unlikely to change in any significant fashion so this bit
of future-proofing should ease upgrades/migrations.
Multiline support brings two new CAPABs along with some S2S batch types.
Some related tests for generic c2s batches were shoved in here as well
for lack of a better spot to put them.

This change required actually bringing extension modules into the unit
test runtime. This was easier for meson since we could just update the
existing shell script, but for autotools I brought dependencies
specifically on the extension .so files needed for tests (as relying on
everything in patsubst like we do for core/autoload modules would
attempt to depend on filter.so even on systems where libhs isn't
available, which would fail the build).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants