• docs/v322_new.md src/sbbs

    From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Friday, July 17, 2026 03:05:00
    https://gitlab.synchro.net/main/sbbs/-/commit/9fc5505cbc4dfc9aeaab00ff
    Modified Files:
    docs/v322_new.md src/sbbs3/ctrl/build.bat src/sbbs3/jsexec.vcxproj ntsvcs.vcxproj sbbscon.vcxproj
    Log Message:
    Windows: build all 32-bit Synchronet hosts /LARGEADDRESSAWARE

    Mark sbbs.exe (sbbscon.vcxproj), sbbsNTsvcs.exe (ntsvcs.vcxproj),
    jsexec.exe (jsexec.vcxproj), and sbbsctrl.exe (ctrl/build.bat) as large-address-aware, raising their usable address space from 2GB to
    ~4GB on 64-bit Windows.

    This is a stopgap for GitLab #1185: an access violation in mozjs185
    seen only on 32-bit Windows under JS heap pressure (a web-scrape
    attack), never on Linux-x64. It raises the ceiling; it does not fix
    the underlying pointer corruption, which the SM128 / 64-bit migration
    addresses properly.

    The MSVC projects get <LargeAddressAware>true</LargeAddressAware> in
    both Debug|Win32 and Release|Win32 link steps. Borland's ilink32 has
    no LAA option, so build.bat flips the PE-header bit post-build
    instead.

    Validated: the 2006-era Borland host runs stably under LAA with
    system-wide top-down allocation (Synchronet DLLs executing above 2GB,
    all servers listening, no errors), and jsexec exercised the mozjs GC
    and trace-JIT with ~3.4GB live above 2GB without failure. Sustained
    behavior under real scrape load is not yet proven.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Saturday, July 18, 2026 22:02:00
    https://gitlab.synchro.net/main/sbbs/-/commit/3a5e9cb3628031f8812840c5
    Modified Files:
    docs/v322_new.md src/sbbs3/scfg/scfg.c scfg.h scfgmsg.c
    Log Message:
    Restore SCFG import/export of subs.txt, alongside subs.ini

    subs.txt import/export was removed in mayor-19-caps (e6acb3269a) and its
    menu slots later repurposed for *subs.ini in reef-31-feed (cfb32e03f5).
    Some sysops still rely on the legacy text format (especially for import),
    so this restores it as an additional format while keeping *subs.ini as
    the preferred format going forward.

    Message Areas > Export/Import Areas list subs.txt again, the -import=
    command line recognizes a subs.txt filename once more, and the
    line-oriented parser/writer are back.

    Rather than the old memcpy-over-the-existing-sub (which zeroed every
    field the format doesn't carry - qwk_conf, print modes, area_tag, ...),
    the import now copies only the fields subs.txt actually provides, leaving
    the rest of an over-written sub intact. ptridx is likewise preserved
    (the exported value is meaningless on the importing system).

    Partially addresses issue #1128.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Sunday, July 19, 2026 15:25:00
    https://gitlab.synchro.net/main/sbbs/-/commit/8a79c1ff830f811d824cced5
    Modified Files:
    docs/v322_new.md src/sbbs3/nodedefs.h
    Log Message:
    Document node-rerun-on-recycle behavior; fix stale NODE_RRUN comment

    Add a v3.22a release note for the terminal-server change that flags
    active nodes to re-read their configuration when a recycle is signaled,
    so configuration changes reach new callers without waiting for every
    node to disconnect.

    Also correct the NODE_RRUN definition comment. Its only remaining
    effect in the threaded terminal server is to make a node re-read its configuration on the next logon; nothing is "re-run" and there is no logoff-time action (unlike its neighbors NODE_EVENT and NODE_DOWN).
    The old "Re-run this node when log off" wording described the DOS/OS2 separate-process node model that no longer exists.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Friday, July 24, 2026 11:16:00
    https://gitlab.synchro.net/main/sbbs/-/commit/04b47329aa0cfbc839ec1a4c
    Modified Files:
    docs/v322_new.md src/sbbs3/zmodem.c
    Log Message:
    zmodem: fix SIGFPE when the transmit window is under 4 blocks (#1197)

    zmodem_send_from() picks the ack-request interval as

    subpkts_sent % (max_window_size / block_size / 4)

    which is a division by zero whenever the window is narrower than four
    blocks: with -8 -w8192 the divisor is 8192 / 8192 / 4, that is 1 / 4,
    that is 0. sexyz then dies with SIGFPE right after the ZRQINIT/ZRINIT handshake, having put about 3 KB of handshake on the wire and no file
    data at all. Also affected: -8 -w16384, -2 -w4096, and the same window
    sizes set through MaxWindowSize in sexyz.ini.

    Clamp the interval to a minimum of one, so a window narrower than four
    blocks requests an ACK on every subpacket, which is the only sensible
    reading of "every quarter window" at that size.

    Verified against lrz over the bench harness: -8 -w16384 and -2 -w4096
    both used to die on signal 8 and now complete with a matching SHA-256, at
    3.08 and 0.71 MB/s. Windows that already worked are unchanged, -w32768
    at 4.88 MB/s and -w65536 at 5.03, as is streaming without -w at 11.6.

    SyncTERM shares zmodem.c but never sets max_window_size, so it leaves the
    value at zero, short-circuits the branch, and cannot reach this. The
    exposure is sexyz only.

    A window exactly equal to the block size (-8 -w8192) no longer crashes
    but is still pathologically slow, roughly one subpacket per second with a one-second receive timeout each iteration. That is tracked separately in
    the issue; it is not a regression, since it used to be a crash.

    zmodem_ver bumped 2.3 -> 2.4. Release notes updated, including the already-shipped 2 GB windowed fix and Deuce's send-path speedups, which
    had no v322 entry.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Friday, July 24, 2026 23:28:00
    https://gitlab.synchro.net/main/sbbs/-/commit/aaf394a0d833acd89a64d3a9
    Modified Files:
    docs/v322_new.md src/sbbs3/sexyz.c
    Log Message:
    sexyz: keep the transmit window >= 4x the block size, like lsz (#1197)

    sexyz's -w set only the ZMODEM transmit window and left the block size independent (from -2/-4/-8, default 1 KB), so a window at or below the
    block size was configurable -- and it stalled the transfer to roughly one window per second. lsz and Forsberg sz never allow this: when -w is
    given they force the block down to a quarter of the window
    (blkopt = Txwspac = Txwindow/4), guaranteeing window >= 4*block so the ack-every-quarter-window scheme always has several blocks in flight.

    Do the same after argument parsing, so -8 -w8192 and -w8192 -8 both
    resolve the same way: floor the window to 256, round to a multiple of 64,
    and reduce max_block_size to window/4 when it exceeds it (and the start block_size with it). A one-line notice reports the reduction.

    Effect: the formerly-hanging window<=block configurations now complete --
    -8 -w8192 reduces the block to 2048 and transfers, -4 -w4096 to 1024,
    and so on -- while windows that already left four blocks of headroom
    (-w32768 and up with -8) are untouched and unchanged (4.75 and 4.88 MB/s
    here, streaming still 11.3). This also makes the divide-by-zero guarded
    in 04b47329aa unreachable by configuration, since window/block/4 is now
    always >= 1.

    This does not make sexyz's windowed throughput competitive with lsz --
    at the same block and window sexyz is still many times slower, and very
    small windows (which force tiny blocks) remain slow with occasional
    one-second stalls. That is the separate sexyz windowed-send overhead
    tracked in #1195; this change is only about not permitting the degenerate window<=block configuration that lsz forbids by construction.

    sexyz.c version 3.3 -> 3.4. No zmodem.c change, so SyncTERM is
    unaffected (it never sets a transmit window anyway).

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Saturday, July 25, 2026 22:24:00
    https://gitlab.synchro.net/main/sbbs/-/commit/b17b1d3e3e45bbbc4df47ae6
    Modified Files:
    docs/v322_new.md src/sbbs3/atcodes.cpp getkey.cpp js_bbs.cpp putmsg.cpp sbbs.h terminal.h
    Log Message:
    Unicode @-codes: return the expansion instead of printing it

    @U+XXXX@, @CHECKMARK@, @ELLIPSIS@, @COPY@, @SOUNDCOPY@, @REGISTERED@, @TRADEMARK@, @DEGREE_C@, @DEGREE_F@ and @WIDE:text@ wrote their glyph
    straight to the terminal from inside atcode() and returned an empty
    string. Format modifiers were therefore applied to "": @CHECKMARK-R10@
    emitted the glyph and then right-aligned nothing in a 10-column field.
    Callers that expand an @-code into a buffer for a non-printing reason -- bbs.atcode(), bbs.expand_atcodes(), format_text(), mnemonics(),
    putnode(), notify() and putmsg()'s @CENTER@ -- got an empty expansion
    plus stray output on the current node's terminal.

    These codes now encode into the caller's buffer and set P_UTF8, so show_atcode()'s existing display-width compensation makes alignment and truncation work. formatted_atcode() and expand_atcodes() take an
    optional pmode out-param so the buffer-expansion callers can learn the
    result is UTF-8; @CENTER@ and mnemonics() use it, the latter needing the
    P_UTF8 branch bputs() already has, since it emits byte-by-byte through outchar(). Terminal::center() measures with bstrlen(str, mode & P_UTF8):
    the other code sets bstrlen() recognizes are translated by putmsg(), not bputs(), and a centered line bypasses putmsg()'s character loop.

    The |W (doubled) modifier prints a UTF-8 expansion as-is rather than
    feeding it to wide(), which would double each byte rather than the glyph. Output buffers grew to fit @WIDE:, which triples byte length.

    Introduced in 9374bfe37e (pill-4-pencil), a9eea57362 (begun-3-ended) and 43c793a14b (hold-20-maps).

    Fixes #1198

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Saturday, July 25, 2026 22:24:00
    https://gitlab.synchro.net/main/sbbs/-/commit/dbc654505f7d822a8ece7c0d
    Modified Files:
    docs/v322_new.md src/sbbs3/con_out.cpp terminal.cpp
    Log Message:
    Count UTF-8 columns once, in Terminal::utf8_increment()

    outcp() wrote the codepoint with term_out() and then advanced the column itself, but term_out() -> parse_output() -> Terminal::utf8_increment()
    had already counted it -- so every codepoint outcp() emitted to a UTF-8 terminal advanced the column counter by twice the glyph's display width.
    The counter ran ahead of the cursor, making word-wrap, right-margin
    truncation, centering and the auto-pause line counter wrap early on any
    line containing such text. The call was also unconditional while
    term_out() returns early under CON_ECHO_OFF, so the column advanced for suppressed output too.

    utf8_increment() is now the only place that counts, and it passes sbbs->unicode_zerowidth rather than a hardcoded 0, preserving the
    zero-width quirk the ZWNBSP probe detects at logon. That applies the
    detected value to all UTF-8 output, bputs() included, not just outcp().

    outcp()'s inc_column() was correct when written in 9374bfe37e
    (pill-4-pencil): it paired with putcom(), which does no column
    accounting. It became a double-count in 374282bf81 (skins-28-shop),
    which switched the write to term_out() and introduced utf8_increment().

    Fixes #1200

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Saturday, July 25, 2026 23:32:00
    https://gitlab.synchro.net/main/sbbs/-/commit/005460da2b098c8ec796464a
    Modified Files:
    docs/v322_new.md src/sbbs3/useredit.cpp
    Log Message:
    Uedit: newline before the non-alpha commands that prompt

    getkeys() runs with K_NOCRLF and only alpha commands got a newline
    before their handler, so the '~' (leech), '+' (adjust credits), '*'
    (adjust minutes), '$' (credits) and '/' (AR string) prompts were echoed
    onto the tail of the "User edit (?=Menu) (n of m): " line.

    Present since ca499c9550 (silence-13-chorus) introduced the alpha-only
    newline.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net