BBS: TELESC.NET.BR Assunto: src/syncterm/ripper.c De: Deuc¨ Data: Sat, 21 Mar 2026 19:53:02 -0700 ----------------------------------------------------------- https://gitlab.synchro.net/main/sbbs/-/commit/6cce9286f030bf47bd57e6d5 Modified Files: src/syncterm/ripper.c Log Message: Fix three |# (RIP_NO_MORE) parsing bugs in parse_rip() Bug reported by NightFox, who should really open bug reports on SourceForge instead of making people chase things down secondhand. 1. Stale '!' rendered when |# follows non-RIP text When non-RIP bytes precede '!' in the same buffer (e.g. the common case of \n\r or \r\n line endings before a RIP line), rip_start is non-zero. The |# handler called handle_rip_line() which took its first branch: deferring the RIP data to pending, truncating blen to rip_start, and returning false. But the handler unconditionally ran rip_start = pos + 1, which now exceeded blen. At the end of parse_rip(), rip_start <= maxlen was true but rip_start > blen, so buffer_rip was skipped but rip_start was returned as the output length reading the stale '!' byte from the physically-uncleared buffer position. Commit 27e6a20f added the rip_start <= blen guard to prevent a crash but did not fix the data leak. Fix: check handle_rip_line()'s return value. When it returns false (deferred), don't modify rip_start. When it returns true (processed immediately), do the post-processing as before. Also pass RIP_STATE_BANG instead of RIP_STATE_CMD since both paths want BANG state after |#. 2. |# must flush immediately, even when deferred The entire purpose of the |# special handling (added in 93e05beb) is to flush RIP commands without waiting for a line terminator. When handle_rip_line() defers (returns false), the RIP data sits in pending unprocessed until the next parse_rip() call defeating the flush semantics. This matters for interactive commands like the NY2008 popup (|1000) that block waiting for user input: the popup wouldn't appear until after the next data arrived. Fix: when handle_rip_line() returns false, process pending immediately via do_rip_string() and reset newstate to FLUSHING so the next flush call knows there's nothing left to process. 3. |# bytes leak as visible text from moredata When handle_rip_line()'s first branch defers RIP data, remaining bytes after |# are saved to moredata. On the next parse_rip() call, the flush path processes pending and switches to moredata. But handle_rip_line() unconditionally resets rip_start to the sentinel (maxlen+1), even though the restored state (BANG) means the moredata buffer is entirely RIP data. With rip_start as sentinel, the |# handler's handle_rip_line() call took the second path with remove=0, failing to remove the |# bytes from the buffer. They were then returned to the caller as visible text. Fix: after the flush path switches to moredata, re-check the restored state. If it's not BOL/MOL (i.e. still inside a RIP sequence), reset rip_start to 0. 4. Allow '!' to start new RIP sequence after |# Per the spec, |# means "end of RIPscrip scene." Testing against RIPterm (reference implementation) confirms that '!' after |# on the same line starts a new RIP sequence. SyncTERM's BANG state only accepted '|', sending '!' to unrip_line -> MOL where it was rejected as a RIP start character. Fix: accept '!', '\x01', and '\x02' in RIP_STATE_BANG, updating rip_start and staying in BANG. This matches RIPterm's behavior where both |#|#|# (repeated NO_MORE) and |#!|... (new sequence) work on the same line. Co-Authored-By: Claude Opus 4.6 (1M context)n --- mSynchronetn hgVertrauen n hHome of Synchronet n gh[vert/cvs/bbs].synchro.net ----------------------------------------------------------- [Voltar]