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]