https://gitlab.synchro.net/main/sbbs/-/issues/1146#note_9021
## Historical context — why this gate worked for 25 years and only broke in January
Some bonus archaeology while diagnosing this, in case it changes how the fix is framed.
`git blame` on the four gate lines:
| Server | File:Line | Introducing commit |
|---|---|---|
| Telnet | `MainFormUnit.cpp:357` | `d0252720e` (2026-05-21, "sbbsctrl: Add 'Log to Disk' option for Terminal and Web servers", resolves #1108) |
| Mail | `MainFormUnit.cpp:524` | `7e3e47141` (2000-10-10, "Initial check-in: v3.00c alpha code for Win32") |
| FTP | `MainFormUnit.cpp:620` | `7e3e47141` (2000-10-10, "Initial check-in: v3.00c alpha code for Win32") |
| Web | `MainFormUnit.cpp:717` | `d0252720e` (2026-05-21, same as Telnet) |
So the `&& XxxStop->Enabled` half of the gate for **Mail and FTP** is original 2000-era code. It worked in practice for 25+ years because of an accident of the surrounding code: the old `xxx_set_state` callbacks had a `switch` with **only two explicit cases** (`SERVER_STOPPED` and `SERVER_READY`). Every other transitional state (init, "terminating, waiting for clients to disconnect", etc.) fell through and left `XxxStop->Enabled` at its previous value — i.e. `true` the whole way through a graceful shutdown, only flipping false on the final `SERVER_STOPPED` callback, which fires *after* the per-server thread emits its summary line. So the gate happened to be open at exactly the right moment.
That changed on 2026-01-12 in commit `f65fd89a1` ("Resolve crashes during graceful server termination(s)"). That commit fixed a real bug — VCL controls being touched from background server-thread callbacks after the form was already destroyed — by moving all control updates out of the state callbacks and onto the 2 Hz LogTimer, with the mapping rewritten as flat assignments:
```cpp
MainForm->FtpStop->Enabled = (state == SERVER_READY); MainForm->FtpRecycle->Enabled = (state == SERVER_READY); MainForm->FtpPause->Enabled = (state == SERVER_READY);
```
Correct for its stated purpose, but it tightened `XxxStop->Enabled` from "best-effort proxy for is-server-running" to strict `state == SERVER_READY`. The moment shutdown begins, state leaves `SERVER_READY`, the next LogTimer tick flips `XxxStop->Enabled` to `false`, and the gate slams shut well before the `#### XxxX Server thread terminated (...)` line is logged.
**Telnet and Web** weren't a regression — `d0252720e` (May 2026, resolves #1108) added disk-logging to those two servers for the first time and *copied the Mail/FTP gate pattern verbatim*, inheriting the broken semantics on arrival.
### Implication for the fix
The suggested fix (drop `&& XxxStop->Enabled` from all four handlers) is still the right call, but it's worth knowing that *the gate itself was never load-bearing* — it was a 25-year-old belt-and-suspenders check that happened to work because of how the old switch left the flag alone during transitions. `f65fd89a1` didn't introduce the gate; it removed the slack that was masking it. So there's no "preserve the historical intent" angle to worry about here — the gate was redundant from the start, and the user's "Log to Disk" preference alone is the correct condition.
— *Authored by Claude (Claude Code), on behalf of @rswindell*
--- SBBSecho 3.37-Linux
* Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)