Skip to content

v1.3(Lovelace): DDial network integration, scrollback rendering fix, and crash forensics

Latest

Choose a tag to compare

@gg582 gg582 released this 26 Sep 15:27
· 37 commits to uncensored since this release

v1.3 (Lovelace) -- named after Ada Lovelace

Chatter joins the live DDial network: station-to-station linking through the MagViz hub, a full MagViz command set for retro dial-in terminals, and a root-cause fix for the scrollback duplication that made relay traffic unreadable.

DDial network integration

  • Station (auxiliary) mode: Chatter now links into the DDial network as a full station via the MagViz hub (magviz.ca:2301). Registered on the hub user list and relaying chat bidirectionally with all linked stations in real time.
  • User ("hijack") upstream mode (CHATTER_DDIAL_MODE=user): the relay acts as an ordinary DDial account. Includes a per-account file lock so two processes never log in twice, a reconnect cooldown (double-login guard) that also covers abnormal termination, /Q logout on shutdown, and dedup of the upstream's own-line echo. A chat message containing "bye" no longer drops the connection.
  • DDial listener (-D bind:port): retro terminals dial in over raw TCP/telnet into a Diversi Dial engine with the MagViz command set — ###password member login, channels 1-999 with ~ dual-channel wire form, colors (/h#RRGGBB), mail, message box, /ig /null /p moderation, paced /300-style output, and more. See docs/DDIAL.md.
  • Chat bridging: dial-in chat reaches the Chatter room (as system entries, so nothing loops back) and the upstream link; upstream chat reaches the room and local dial-ins. Link-echo and local handles are suppressed so no one sees a line twice.

DDial command interoperability from the Chatter room

  • Read-only DDial commands typed in the room (/s, /s1-/s4, /sm, /i, /h, /ls, /b?, /ver) are forwarded raw to the linked station; the reply returns through the normal relay path and lands in the room history (verified live against the MagViz hub).
  • Everything else stays local: protocol commands (/K, /V, /E, ...) can never be injected from chat. Operator-only /ddial raw remains the sole protocol escape hatch.

Scrollback rendering fix

  • session_process_pending_sink's non-incremental fallback re-emitted the entire visible history window every time a single message arrived (incremental redraw had been disabled earlier to avoid screen clears). With relay traffic, every message repainted the whole recent history — the duplicate-block scrollback spam reported during DDial testing — and buried the input line.
  • The fallback now appends only entries newer than the sink cursor; the cursor is advanced when the sender's own line is rendered immediately, invalidated on hard screen clears and on return from protected modes (BBS/RSS/game), and reset when coming back from a scrolled view. Verified: every message renders exactly once across two SSH sessions, dial-in relay, scrollback navigation, and BBS exit.

DDial link line format and relay

  • Linked stations showed our chat as 63Lee Yunjin) msg instead of 63#1[T1:Lee Yunjin) msg: station mode dropped the #slot[T1: prefix whenever the remote never printed our #N(T1:?) status line. Link chat and /P now always carry the speaker's own line number (a Chatter member's chat-link slot, the same one its login was announced with; a dial-in's session slot).
  • The relay's own slot is learned only from our status line, so another user's #2[T1:Bob) line can no longer overwrite it.
  • The idle keepalive no longer writes a telnet IAC NOP into the stream (remotes rendered it as �� in front of the next line); kernel TCP keepalives are used instead.
  • /pm follows the public-chat relay path: a Chatter private message in the room, and the DDial equivalent when the target is on the DDial side (P#slot(handle) msg to a dial-in, link /P<slot> #slot[T1:handle) msg to a user on the linked station). Inbound link /P reaches only its recipient instead of the room history, and our own /P coming back is dropped.
  • /reply is relayed to DDial as a plain chat line (@author text), since DDial has no replies.
  • /users and /connected count DDial participants: dial-ins, plus everyone behind the Station Link, kept in a hash map keyed by handle. It is filled from station user lists ([SYSOP] 73-.SynerChat #0[T1:AriZona Mae #2<T1:Joe Boo:232 ...), login events and chat lines, rebuilt at start-up from the last 2048 history entries, and a user is removed only when they leave (logout, or dropping out of their station's list).
  • History keeps what the link sent; one display-time filter decides what people see, for past and new entries alike and in every view (SSH, scrollback, live broadcast, JSON/web feed): link housekeeping ([SYSOP] station lists, [LINK] login/logout events) is hidden, and relayed DDial chat such as 71#4[T1:MaxMouse) ... is shown as a Chatter message ([id] <MaxMouse> ...).

Usernames with spaces and localized command messages

  • /pm, /mail send, /block confirm and /bbs mute take name|args (e.g. /pm Lee Yunjin|hello), matching the BBS comment syntax; single-word names still work without |.
  • Help labels, usage lines, the /bbs subcommand help, and the system messages of /pm, /mail, /block, /unblock, /kick, /ban, /banname, /banlist, /getaddr, /poke, /pardon, /getos, /resetpw and /showstatus are available in all eight UI languages.

Crash forensics and BBS hardening

  • The SIGSEGV handler now logs the first-fault signal, code, address, fault RIP/RSP, and TID to stderr (journald) before re-raising, because the re-raise used to overwrite the faulting ucontext and erase the real crash location from every core dump.
  • BBS post lookup refuses to iterate a post arena whose capacity exceeds SSH_CHATTER_BBS_MAX_POSTS and rejects ids above 2^40 (defense against the wild-pointer crash class seen on 2026-09-23).

Full changelog: v1.2...v1.3