ANetBBS Changelog
Versions are internal build numbers. Public releases are tagged
separately. Current release: v1.0b2.33 (July 2026). Full release: August 1 2026.
v1.0b2.33 — ANotherNetwork file areas + real infopack (July 2026)
- FEATURE: ANotherNetwork gets 9 new TIC file-echo areas (
ANN.FILES.NODELIST,.INFOPACK,.BBSSOFT,.DOORS,.EBOOKS,.LINUX,.RETRO,.ANSIART,.TEST), seeded automatically the same way the 26 message areas already are.ANN.FILES.NODELISTis flaggedis_nodelist_sourceso inbound TICs there auto-populate the nodelist. Found and fixed a real bug while wiring this up: unlikeEchoArea.tag,FileArea.taghas a database-levelUNIQUEconstraint, so file areas attach to the BinkP network entry only (not duplicated across both BinkP and QWK entries the way message areas are) — TIC distribution is a BinkP-native mechanism anyway. - New distributable infopack for other sysops to apply with:
annetinfo.zip(goals, rules, full area list, application form, a new CP437 ANSI banner) andannetareas.zip(machine-readable.naarea lists for both message and file areas), built from the project's real seed data rather than placeholder text. - FIX (docs): README's ANotherNetwork description had a stale category count (said 8, actual is 9 including Test) and didn't mention the new file areas.
v1.0b2.32 — Sysop-specific paths scrubbed from shared code (July 2026)
- FIX: several hardcoded fallback paths/usernames from the maintainer's own install had leaked into shared code (drop-file path resolution, default gallery seed data, installer/upgrade-wizard fallbacks, an IRC CTCP reply URL, the sudoers template) — real bugs that would misconfigure a different sysop's install if the normal config lookup ever failed, not just cosmetic. Fixed all of them; also scrubbed the same path from the in-app tutorial, the seeded wiki content, and the GitHub issue template.
- FIX: 3 systemd unit files (
anetbbs-binkp.service,anetbbs-finger.service,anetbbs-mrc-irc-bridge@.service) were missed in the first pass and still had the maintainer's ownUser=/path hardcoded — found via a follow-up audit. Fixed to match every other unit's genericanetbbs//opt/anetbbsconvention. - FIX: a stray third-party email address (copied from wherever a bundled tool was originally adapted from) in
tools/bbs-files-tool.py's help text pointed sysops at an unrelated stranger instead of this project's own issue tracker. - FIX:
tests/msp_loopback_test.py(a manual diagnostic script, not a real test) matched pytest's default test-file naming pattern and had noif __name__ == '__main__':guard — everypytest tests/run was silently starting real MSP/SYSTAT network listeners and mutating process-wide environment variables as an import-time side effect. Renamed tomsp_loopback_check.py(no longer matches pytest's collection pattern) and gated its body behind a propermain()/__main__guard. Also fixed a second, unrelated hardcoded absolute path in the same file left over from a different machine's mount point. - FIX: two more test files (
test_ebook_terminal_menu.py,test_qwk_hub_gating.py) had the sameos.environ['FLASK_ENV']leak pattern as last version'sTestingConfig.SQLALCHEMY_DATABASE_URIfix — set on every test run, never restored. Fixed both. - FIX:
anetbbs/web/healthz.pyandanetbbs/web/preflight.pychecked aFINGER_PORTconfig key that was never actually set anywhere (the real setting isFINGER_LISTEN_PORT), so the finger service's health check/preflight validation silently ignored any non-default port a sysop configured. AddedFINGER_LISTEN_PORT/FINGER_LISTEN_HOSTtoConfigand fixed both call sites. - FIX (docs):
docs/00-overview.md's table of contents was missing links to two existing doc files (17-development.md,20-federation.md); README's wiki page count was stale (41 → actual 43); README's Doors feature list didn't mention the bundleddoor_rlogin/A-Net Online game server; a few wiki pages used dead internal[[Page]]-style links for external tools (SyncTERM, NetRunner, DOSBox-staging) instead of the real external links used elsewhere in the same content. - FIX (docs, full accuracy pass): a broad cross-check of every doc file, the in-app sysop tutorial, and the seeded wiki against the actual current code turned up a large batch of stale/wrong content, most notably:
docs/12-upgrading.mdanddocs/01-installing.mddescribed an entirely stale install/upgrade flow (wrong backup path —/tmp/anetbbs-backup-*, not next to the install; wrong service names — the unifiedanetbbs.servicereplaced the legacy splitanetbbs-telnet/anetbbs-ssha while ago; a wizard prompt list missing half the real prompts; automatic rollback described as an interactive "offer"); the sudoers install instructions indocs/02-sysop-daily-ops.md, the in-app tutorial, and two wiki pages all broke when the sudoers template's placeholder was renamed to__SERVICE_USER__earlier in this same version — a plaincpnow installs a non-functional rule, fixed everywhere to show the requiredsedsubstitution; the wiki's Themes page listed five theme names that don't exist anywhere in the codebase (real theme count is 9, not the fabricated list); the wiki's Doors page anddocs/17-development.mdundercounted door types (7 vs the real 10, missingdoor_dosemu/door_telnet/door_dos_browser); a wiki page referenced atools/db_backup.shscript that doesn't exist;docs/INSTALL.mdwas missing theanetbbssystem-user creation step its own systemd section depends on and had a wrongaptpackage list; a real (non-doc) bug found along the way:anetbbs/web/healthz.py/preflight.pychecked aFINGER_PORTconfig key that was never actually set anywhere, silently ignoring any custom Finger port a sysop configured — fixed by adding the realFINGER_LISTEN_PORT/FINGER_LISTEN_HOSTtoConfig. - No behavior change for the maintainer's own existing install from any of the above.
v1.0b2.31 — Docker support (July 2026)
- FEATURE: Docker deployment alongside the traditional install.sh/systemd path — single-container quick start (supervisord-managed) and a docker-compose "correct way" (one container per service), both built multi-arch (amd64+arm64). See
docs/22-containers.md. - FEATURE: Sysop Control Panel restart/upgrade works under docker-compose via a Docker-socket backend instead of systemctl; one-click self-upgrade pulls a new image tag and recreates containers.
- FIX (hardening, also benefits bare metal): SQLite WAL mode + busy-timeout (
anetbbs/models.py);MSP_PORT/SYSTAT_PORTnow environment-overridable. - FIX: the admin DB Backup download button streamed the SQLite file with a plain copy and no checkpoint — under the new WAL mode, recent writes could sit only in the
-walfile and be missed. Now forcesPRAGMA wal_checkpoint(TRUNCATE)first.update.sh's own automated backups were already safe (sqlite3 .backup). - FIX (critical, live-caught): reading any echomail message via terminal (SSH/telnet/rlogin) failed with "Menu action failed (see server log)". Root cause: the read-only message viewer (
_ViewerScreen.draw_text()inanedit.py) was never updated to accept themisspellparameter added when spell-check shipped (v1.0b2.20) — the shared redraw code the viewer inherits from the editor always passes it. Latent since v1.0b2.20; nobody had tried reading an echomail message via terminal since. Fixed + regression-tested (tests/test_aneview_draw_text.py, verified it reproduces the exact live traceback before the fix and passes after). - FIX (release hygiene):
build-release.shrewritten to build from git's own tracked/ignored file list instead of a manually maintained--excludedenylist, which had letbbs.log(containing a plaintext admin password from a local test boot) leak into 7 prior release tarballs, plus assorted stray test-scratch files. See.gitignorefor the accompanying rule additions. - 30 new tests. Docker builds/runs themselves still need verification with real Docker access — not available in the environment this was built in.
v1.0b2.30 — Federation "Register with Hub" nav fix (July 2026)
- FIX: the "Register this BBS with a federation hub" admin page existed but had no link anywhere in the UI. Added a Register with Hub card to Admin → Network.
- FIX: the v1.0b2.29 hub-gating fix left the Hub Management card linking to a now-404 blueprint on every non-hub install. Hidden unless
REGISTRY_MODE_ENABLED=true. - 2 new tests in
tests/test_qwk_hub_gating.py.
v1.0b2.29 — Local chat, terminal colors, QWK/federation hub gating (July 2026)
- FIX (critical): terminal Local Chat (Chat → 1) was a stub that only echoed your own message back to yourself, never broadcasting to other nodes. Now delegates to the already-working real-time broadcast/queue system in
multinode.py(previously only reachable via a dead, unwiredmultinodemenu action). - FIX (critical):
broadcast()'s self-exclusion compared by username, not by node — two nodes logged in under the same account (e.g. testing with one account on two terminals) both matched the check, so the message was dropped for everyone. Now excludes by the specific sending node's slot. - FIX (critical): MagiTerm, NetRunner, and PuTTY showed no color on most screens (wall, file areas, boards, PMs, bulletins, MRC chat, pre-login welcome, games list) while the main menu rendered fine. The main menu's
.ansart uses the classic ANSI.SYS bright-color convention (bold + base color); nearly everywhere else used the newer "aixterm" 90-97 SGR range with no bold, which those three clients don't recognize (SyncTerm supports both, masking the bug there). Converted every affected color table/constant across 10 files to the classic convention. - FIX (critical): the terminal QWK-node-application wizard wrote to whichever BBS install ran it instead of the real hub, and the hub admin review queue was exposed on every install with no gate ("all the sysops try to put in for a node and it goes to their system"). Added a real hub-side API (
/qwkhub/apply,/qwkhub/status/<token>) and gated the hub-admin blueprint behindREGISTRY_MODE_ENABLED. The hub install needsREGISTRY_MODE_ENABLED=trueset in its.env. - FIX: the federation self-registration wizard always showed "success" even when
REGISTRY_URLwas blank and nothing was sent.REGISTRY_URLnow defaults tohttps://bbs.a-net.fyi, and the registration tick reports back real success/failure. - 9 new tests in
tests/test_multinode_chat.py, plus manual verification against two real concurrent telnet sessions. - 4 new tests in
tests/test_ansi_color_compat.py, plus manual verification against a live telnet session. - 10 new tests in
tests/test_qwk_hub_gating.py, 4 intests/test_registry_tick_status.py.
v1.0b2.28 — A-Net Game Server bundled by default + Ebook Reader (July 2026)
- FEATURE: A-Net Online's rlogin game server (450+ door games) now ships pre-installed and active like LORD does. Each install gets its own randomly generated password and BBS tag on first boot — private to that BBS, never in the public source, and never regenerated afterward. Sysops can change either any time at Admin → Door Games → A-Net Game Server.
- FEATURE: new door_rlogin BBS Tag field — the tag now has its own admin-form field instead of being hyphen-joined into the user-template text, purely for clarity (the wire format itself,
username-TAG, is unchanged). - FEATURE: new built-in web game, Ebook Reader — search + read free Project Gutenberg classics in a book-styled reading view (serif type, page-turn navigation), with bookmarks, reading history, and download-to-
.txt. Also has a terminal version (telnet/SSH/rlogin, main-menu hotkeyK) with the same feature set. - FEATURE: per-front-end Web/Terminal toggle on every game (Admin → Games) — lets a sysop run the Ebook Reader as terminal-only, web-only, or both.
- FIX: bundled-door seeding hardcoded
max_nodes=1for every stock door — wrong for a 20-slot remote multiplayer server. Now respects a per-door override. - FIX:
lrzsz(ZMODEM, used by every terminal file transfer) was missing frominstall.sh's required packages — fresh installs had no working terminal downloads out of the box. Now installed automatically. Existing installs upgrading viaupdate.shneedsudo apt-get install -y lrzszonce by hand (update.sh doesn't manage system packages).
v1.0b2.27 — Telnet door game servers (July 2026)
- FEATURE: new
door_telnetgame type for external telnet-only game servers (e.g. TWGS — Trade Wars Game Server, likegame.a-net-online.lol:2002, A-Net Online's own TWGS). No pre-authentication handshake likedoor_rlogin— justhost:port, user logs in interactively on the remote side. Works on both web and terminal doors, mirrors the rlogin door architecture. Includes a small RFC 854 option-negotiation filter so the remote server doesn't hang and negotiation bytes never reach the player's screen. Configure via Admin → Games → Game Type → "Telnet Door Server".
v1.0b2.26 — MRC: terminal fixes + stale-session cleanup (July 2026)
- FIX:
/mentionsalways showed 0 — mention detection was wired to event types the bridge never sends; moved to the realmrc_messagepath. Status-bar!Nindicator now works live too. - FIX: messages up to 140 chars could get silently truncated to ~120 — terminal client now accounts for the bridge's handle-prefix overhead and splits long messages into
(1/2)/(2/2)chunks instead of losing the tail. - FIX: mention indicator was reverse-video red, illegible on some terminals — switched to explicit fg/bg colors.
- FIX:
/mentionsoutput misaligned on wrap — restructured into a header line + indented body line per mention. - CHANGE:
/helpand/helpserverswapped —/helpnow asks the hub for its own help,/helpservershows the client's local command list. - FIX: outgoing text color never persisted across reconnects — now restores on join and saves via
set_styleon change. - FIX: Tab nick-completion gave no feedback on zero matches and could dump an unbounded candidate list — capped at 12 with a "+N more" hint. Also fixed a real bug where a visibly-present user couldn't be found:
/who's roster is comma-separated on the wire, but the parser was splitting on whitespace. Bridge now also refreshes the roster on/who. - FIX (critical): a mid-round version of the Tab-completion fix briefly deadlocked terminal MRC solid on the next Tab press. Fixed, covered by a timeout-guarded test.
- FIX (bridge): a dropped connection left MRC sessions looking permanently logged in, causing "you can only be logged on once" from the upstream hub. Added a WebSocket heartbeat so the existing (correct) cleanup logic actually runs.
v1.0b2.25 — Paginate large file areas (July 2026)
- FEATURE: file area listings are now paginated (50 files/page) instead of rendering the entire area on one page — same fix pattern as the CHANGELOG page's own pagination (v1.0b2.22), reported after a 7,000+ file door-games area took a while to load. Sort (name/size/date) applies before slicing so page contents stay correct, and pagination links preserve the active sort. New shared
ListPaginationhelper (anetbbs/web/list_pagination.py) with ellipsis-truncated page links, since a large area can span far more pages than the CHANGELOG ever will.
v1.0b2.24 — Configurable login auto-ban (July 2026)
- FEATURE: the login auto-ban is now sysop-configurable from Admin → IP Bans instead of a hardcoded permanent-only trigger. Reported by Firehawke (feature request 2026-07-03): 10 failed logins in 5 minutes triggered a permanent IP ban with no way to configure the threshold, duration, or disable it — caught one of their test users off guard. Now configurable: attempt limit, time window, ban duration in hours (0 = permanent, still available), and an enable/disable switch. Default ban duration changed from permanent to 1 hour, matching the proposed resolution; the 10-attempts/5-minute trigger threshold is unchanged by default but now editable. New
AutoBanConfigsingleton model, settings card added to the existing IP Bans admin page. 8 new tests intests/test_auto_ban.py.
v1.0b2.23 — Multi-screen welcome/goodbye/newuser sequences (July 2026)
- FEATURE: sysops can drop in multiple variants of any lifecycle ANSI screen (
welcome,goodbye,newuser, or a custom slot) and ANetBBS shows all of them, in order, every login — the classic Synchronetlogon1.ans/logon2.ans/logon3.ansmulti-screen convention.welcome132.ansis shown first; addwelcome132_2.ans,welcome132_3.ans, etc. and they display right after, same login — works for thedata/text/<slot>.ansoverride and the bundled stock screens, all three width modes. Each variant controls its own@PAUSE@; nothing is auto-inserted between screens. A single file (the common case) behaves exactly as before, no persisted state of any kind. Prefer one random pick instead of the whole sequence? Use_rannaming (welcome_ran.ans,welcome_2_ran.ans, ...) — shows just one, chosen at random; wins over plain numbered naming if both exist. Seedocs/04-ansi-screens.md. - FIX (pre-existing, unrelated to the feature above — found while testing on the Pi3): an active
BbsAnsiScreenDB row with an empty body blocked the fallback to the bundled stock screen, so the screen silently showed nothing at all instead of falling back. Now an empty-but-active row is treated the same as no row. - FIX:
welcome132.ansandwelcome.answere the last stock screens with a box border still on them, plus (for the 132-col one) a duplicated Sysop/Version line — rebuilt both borderless to matchgoodbye132.ans/newuser132.ans's style. Added@PAUSE@to all three welcome variants and togoodbye.ans— none of them had it, so the banner rendered and immediately fell through to the next prompt, easy to miss at normal typing speed.
v1.0b2.22 — Paginate the web Changelog page (July 2026)
- FEATURE:
/docs/CHANGELOGwas rendering this entire, ever-growing file as one markdown pass on every load, getting slower release after release. Now paginated at 15 version-entries per page (newest first), with Prev/Next + page-number navigation. Other/docs/*pages are unaffected. Verified against the real route: page 1 has the newest entry, page 2 differs, out-of-range page numbers clamp instead of erroring. - Also fixed the "Current release" line above, which was stuck at
v1.0b1.6for a long time — added a note to the version-bump checklist so it's updated alongside every new entry from now on.
v1.0b2.21 — Fix: pyspellchecker was never actually installed (July 2026)
- FIX:
setup.py'sinstall_requiresis a separate, hand-maintained list fromrequirements.txt—update.sh/install.shinstall viapip install -e ., which readssetup.py. v1.0b2.20 addedpyspellcheckertorequirements.txtonly, so it never actually installed through the normal deploy path on any environment. The feature degraded silently (by design — missing spellchecker just means the feature is unavailable, not a crash) rather than erroring, so it looked like a UI bug ("misspelled words aren't underlined") rather than a missing-dependency bug until traced back. Addedpyspellchecker>=0.8.0tosetup.pytoo.
v1.0b2.20 — Spell check + clickable URLs, web and terminal (July 2026)
- FEATURE:
anetbbs/features/anedit.py(terminal message editor) gains live spell check — misspelled words underline as you type, and/spell(/sp) jumps to the next one with a suggestion box (0-5=replace, N=skip, Esc=cancel). Quoted lines and ALL-CAPS jargon (SSH, QWK, ANSI, ...) are excluded from checking. New dependency:pyspellchecker(pure Python, bundled dictionary, no network, degrades silently if missing — same pattern as the optional markdown/bleach deps). - FEATURE: Web compose forms (PM, board post, echomail, netmail) now set
spellcheck="true"explicitly on their textareas, enabling the browser's native spellcheck (red squiggly underline, right-click suggestions). - FEATURE:
https://URLs are now clickable everywhere a message body is shown. Web:render_msg.py'smsgbody/msgbody_richfilters wrap plain URLs in<a href target="_blank">(board posts still auto-embed image URLs as<img>, that's unchanged — just extended to non-image links too). Terminal:bbs_ui.pywraps URLs in OSC 8 hyperlink escapes when displaying board threads, PM bodies, and InterBBS instant messages — clickable on terminals that support it (Windows Terminal, iTerm2, kitty, gnome-terminal), silently ignored (URL text still shows) on ones that don't (SyncTERM and most classic BBS terminal clients). - Verified end-to-end against a real running instance (in-memory-DB Flask test client hitting the actual routes/templates) as well as direct unit tests of every new code path, including an explicit check that the spell-check suggestion picker can't recurse unboundedly on a document full of unrecognised words.
v1.0b2.19 — Fix GitHub #3 for real: the active v2 thread reader was never patched (July 2026)
- FIX: GitHub issue #3 (terminal message reader truncating long paragraphs instead of word-wrapping them) was marked fixed in v1.0b2.15's changelog, but a sysop retested against v1.0b2.18 and found it still truncating — with an exact root-cause diagnosis and a tested patch attached to the issue. The v1.0b2.15 fix touched
read_thread()inanetbbs/features/bbs_ui.py, but that method is shadowed at module import time: near the bottom of the same file,BBSMenuUI.list_threads = _list_threads_v2andBBSMenuUI.read_thread_v2 = _read_thread_v2monkey-patch the class, replacing the class-body methods with newer "v2" versions that add inlineN=new-thread andR=reply support. The board menu actually callslist_threads→_list_threads_v2→read_thread_v2→_read_thread_v2, which still had the original bug:for line in (p['content'] or '').splitlines(): ... line[:_line_w], silently discarding everything past the terminal width on any paragraph without manual line breaks. Rewrote_read_thread_v2to build its output through_wrap_text()and the_page_lines()pager (same infrastructure the v1.0b2.15 fix added), so long paragraphs wrap and long threads now paginate with--MORE--, closing the gap the original bug report asked for ("Long messages should be paginated") that even the reporter's own patch didn't fully close. Also fixed_line_w = max(76, _w - 4)→max(20, _w - 4): the old floor of 76 could make lines overflow on a narrower-than-80-column terminal. - Verified by reconstructing the full paragraph from its wrapped output and diffing word-for-word against the original — confirmed no content loss — before shipping. Also grepped every
BBSMenuUI.<name> = <name>override in the file afterward: private messages and Inter-BBS instant messages have no such shadow, so their v1.0b2.15 fixes are confirmed to still be the active code path.