Subj : src/sbbs3/zmodem.c To : Git commit to main/sbbs/master From : Rob Swindell (on Debian Linux) Date : Tue Aug 25 2026 01:12:30 https://gitlab.synchro.net/main/sbbs/-/commit/d3e4f8094d0255fafaf436f2 Modified Files: src/sbbs3/zmodem.c Log Message: zmodem: don't drop the CR/LF that terminates a hex header when ESCCTL is on zmodem_recv_hex_header() read the CR/LF ending a hex header through zmodem_rx(), which drops unescaped control characters once escape_ctrl_chars is set. CR and LF are control characters, so with ESCCTL negotiated the terminator was dropped, the header never terminated, and the receiver timed out on it: !Dropping unescaped ctrl char ... (x20) !zmodem_recv_hex_header HEX header not terminated with LF: TIMEOUT !zmodem_recv_header detected an INVALID HEADER The data itself transfers, since data subpackets use binary headers; it is the session teardown that fails. Measured on an 8 MB receive with EscapeCtrlChars=true: 100.17 seconds and exit -1, against 0.07 seconds once fixed. The bytes are all there and verify byte-identical -- the receiver simply cannot read the ZFIN and sits re-sending ZRINIT until it gives up. A hex header's terminator is framing, not data. A hex header is built from printable characters plus CR/LF precisely so it survives a link that mangles control characters, and every implementation sends that terminator unescaped whether or not ESCCTL was negotiated -- so it must not go through the ESCCTL filter at all. Read it with a small helper that calls zmodem_recv_raw() directly and skips flow-control bytes the way zmodem_rx() does. This is long-standing, not a regression: a sexyz built from the commit that moved the sexyz change log out of the packaging directory -- before the plain-byte table and before the bulk receive callback -- reproduces it identically, 100.14 seconds and the same 20 dropped characters. It went unnoticed because EscapeCtrlChars defaults to false and had no command-line equivalent to reach it with. Verified unchanged on the normal path, where every hex header also goes through the new helper: 256 MB receive 482.7 MB/s and send 206.3 MB/s, the 3e-6 corruption gate 5 of 5 receiving and 3 of 3 sending, plus a YMODEM round trip. NOT fixed here, and separate: sending WITH ESCCTL is also broken -- a receiver that requests it (lrz -e) rejects sexyz's escaped data and ZRPOSes until the error budget is spent. That path is driven by the peer's ZRINIT rather than by any local option, reproduces on the same pre-change binary, and needs its own investigation. --- SBBSecho 3.37-Linux * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705) .