IRC: what is sent is recorded locally, never confirmed by the server #129

Closed
opened 2026-09-06 12:04:38 -04:00 by Salastil · 1 comment
Owner

When moho sends an IRC message it writes the line into the log itself, because the
server does not echo it back (send_plain, backend/irc.rs:2050-2054, which says so
and cites libpurple doing the same). That works, and it has two costs.

The line on screen is not the line the network saw: no server-assigned time, no msgid,
and none of the truncation or mangling a server may apply to a long or unusual
message. And a send that the server rejects - a bad target, a mode that forbids it -
still appears to have happened, since the local copy is written before anything comes
back.

What is needed

  • Request echo-message and use the server's copy as the message of record where the
    capability exists, keeping the local write as the fallback where it does not.
  • labeled-response alongside it, so a reply can be matched to the send that caused
    it rather than to the next thing that arrives.
  • Care with chathistory (#73): with echo-message a sent line arrives twice unless
    the local copy is reconciled by msgid - which is exactly what the existing comment
    about generated ids warns of.

Done looks like: the line in the log is the line the network delivered, and a
refused send says so.

Reference: modern IRCv3 clients; the echo-message and labeled-response caps.

When moho sends an IRC message it writes the line into the log itself, because the server does not echo it back (`send_plain`, `backend/irc.rs:2050-2054`, which says so and cites libpurple doing the same). That works, and it has two costs. The line on screen is not the line the network saw: no server-assigned time, no msgid, and none of the truncation or mangling a server may apply to a long or unusual message. And a send that the server rejects - a bad target, a mode that forbids it - still appears to have happened, since the local copy is written before anything comes back. **What is needed** - Request `echo-message` and use the server's copy as the message of record where the capability exists, keeping the local write as the fallback where it does not. - `labeled-response` alongside it, so a reply can be matched to the send that caused it rather than to the next thing that arrives. - Care with `chathistory` (#73): with echo-message a sent line arrives twice unless the local copy is reconciled by msgid - which is exactly what the existing comment about generated ids warns of. **Done looks like:** the line in the log is the line the network delivered, and a refused send says so. Reference: modern IRCv3 clients; the `echo-message` and `labeled-response` caps.
Salastil added the featureprotocollow priority labels 2026-09-06 12:04:38 -04:00
Author
Owner

Finished — https://git.salastil.com/Salastil/nobilis/commit/d888104 and https://git.salastil.com/Salastil/moho/commit/7e9f07b

echo-message and labeled-response are now requested, and where the server echoes, its copy is the one written: the network's own msgid and timestamp, and proof the message was delivered rather than merely handed over. The send carries a label so a refusal can be matched to the send that caused it. A server that grants the capability and then does not echo would swallow the message, so anything unaccounted for after six seconds is written locally after all.

The bug this uncovered is bigger than the ticket. CAP * ACK :multi-prefix puts the granted list in the parameter before the trailing one; moho read the trailing one, so the match arm never matched on any server, ever. Nothing errored — the client simply believed every network it had connected to supported nothing. That also silently disabled #73's history backfill, which is gated on chathistory being granted. Fixed in both the main loop and the registration loop, the latter because the ACKs arrive exactly while it is scanning for the welcome and it discarded everything else.

Verified live on Libera: one row for a sent message, carrying the server's msgid 11788713052914… rather than a generated id.

Finished — https://git.salastil.com/Salastil/nobilis/commit/d888104 and https://git.salastil.com/Salastil/moho/commit/7e9f07b `echo-message` and `labeled-response` are now requested, and where the server echoes, its copy is the one written: the network's own msgid and timestamp, and proof the message was delivered rather than merely handed over. The send carries a label so a refusal can be matched to the send that caused it. A server that grants the capability and then does not echo would swallow the message, so anything unaccounted for after six seconds is written locally after all. **The bug this uncovered is bigger than the ticket.** `CAP * ACK :multi-prefix` puts the granted list in the parameter *before* the trailing one; moho read the trailing one, so the match arm never matched on any server, ever. Nothing errored — the client simply believed every network it had connected to supported nothing. That also silently disabled #73's history backfill, which is gated on `chathistory` being granted. Fixed in both the main loop and the registration loop, the latter because the ACKs arrive exactly while it is scanning for the welcome and it discarded everything else. Verified live on Libera: one row for a sent message, carrying the server's msgid `11788713052914…` rather than a generated id.
Salastil removed the protocol label 2026-09-06 12:49:17 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Salastil/moho#129