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.0a2.149 — Echomail area sysop-only flag + security levels (June 2026)
- Echomail
EchoAreaForm: addedis_sysop_onlyBooleanField;min_access_levelalready existed in the form but wasn't exposed in the template. - Area edit form (
echomail/admin/area_form.html): Active, Subscribed, Sysop Only checkboxes now shown together in a flags box; Min Access Level field alongside with hint text. - Areas list (
echomail/admin/areas.html): Status column replaced with four separate columns — Active ✓/✗, Subscribed ✓/✗, Sysop Only 🔒/—, Level badge (color-coded by range). new_arearoute: now savesis_sysop_onlyandmin_access_levelon area creation.web/echomail.py: extracted_check_area_access(area)helper; applied to area view, thread, compose, and next-unread routes. Area index and compose dropdown filter by bothis_sysop_onlyandmin_access_level <= user.access_level.- New templates:
auth/verify_sent.html,auth/verified.html,auth/resend_verification.html. - Admin nav: new "SMTP / Email" link above Settings divider.
6 new web games
- Klondike Solitaire — full rules, undo, auto-foundation, win detection.
- Video Poker (Jacks or Better) — 5-card draw, pay table, multi-bet, hold mechanic.
- Texas Hold'em vs CPU — 4-player table, easy/medium/hard bluffing AI, full 7-card hand eval.
- Blackjack — hit/stand/double/split, 4-deck shoe, chip-click bet UI, dealer to 17.
- Slot Machines — 3 themed machines (Classic Bars, Lucky Fruits, Retro BBS) with animated reels.
- Galaga — Canvas arcade: enemy formations, dive attacks, tractor-beam boss capture, particle FX, touch controls.
v1.0a2.146 — Fix dial-out directory DB lookup in terminal context (June 2026)
- Root cause of dial-out directory not syncing:
_load_directory()in
features/dialout.pyqueried the DB without a Flask app_context. Terminal
processes have no ambient Flask context so the query raised silently
(except pass), always falling back to the hardcoded DEFAULT_DIRECTORY.
Addedwith _app().app_context():— same pattern as bbs_ui.py / menu_engine.py.
Both PeerBbs (web directory) and DialoutDestination entries now appear on
SSH/telnet.
v1.0a2.145 — BBS Directory: edit local entries + remove Who's Online (June 2026)
- Local BBS entries in the web admin (
/bbses/admin) can now be edited via a
modal form — all fields: name, hostname, port, web URL, location, software,
FTN address, description, active toggle. Previously delete/disable only. - Removed finger/who's-online polling entirely:
_do_finger,_refresh_peer,
background refresh, online count badges, "Who's on" button, admin columns.
view.htmlis now a clean BBS detail/connect page.
v1.0a2.144 — Dial-out dir sync + User access flags (June 2026)
- Terminal dial-out menu now reads from PeerBbs (web BBS Directory Local tab)
as primary source, with DialoutDestination as secondary. Entries added via
the web BBS Directory are now visible on SSH/telnet. - New
user_access_flagstable; sysop can suspend echomail, MRC, IRC, games,
QWK downloads, or file downloads per user from/admin/users/<id>/manage.
New table — upgrade-safe, no migration needed. Suspended users see a clear
message and are returned to the menu.
v1.0a2.143 — Fix ANSI menu action: @PAUSE@ pagination + end-of-screen hold (June 2026)
@PAUSE@in ANSI body now splits into pages; user presses any key to advance.
Previously the code passed through as literal text on screen.ansimenu action now forces a final key-wait after the screen displays so
the menu doesn't immediately redraw and erase the content._show_ansi_screengainsforce_pause=Falseparam;_act_ansipassesTrue.
v1.0a2.142 — BBS Directory: correct EtherTerm XML parser (June 2026)
- Both TelnetBBSGuide and IPTIA use the same EtherTerm
dialdirectory.xml
format:<BBS name="..." ip="..." port="..." protocol="TELNET" />.
Switched from ElementTree (fails on unescaped&in BBS names) and
failed CSV/pipe parsers to a single regex-based_parse_etherterm_xml()
shared by both sources. Parses 1,075 TelnetBBSGuide entries and 1,810
IPTIA entries correctly. TelnetBBSGuide is fetched as a monthly ZIP;
dialdirectory.xmlis extracted from inside it.
v1.0a2.141 — BBS Directory: correct TelnetBBSGuide + IPTIA formats (June 2026)
- TelnetBBSGuide: rewritten from CSV to ZIP parser. Monthly file URL
constructed dynamically (ibbs{MM}{YYYY}.zip); falls back to previous
month if current month returns 404. Extracts the text file from inside
the ZIP and parses pipe-delimited rows with flexible column detection. - IPTIA: rewritten from CSV to XML parser. Fetches
dialdirectory.xmland parses withxml.etree.ElementTree, trying
common tag names for name/address/port/sysop/location/software/web/description. - Both parsers handle unknown field names gracefully; exceptions are caught
and return 0 instead of crashing the background thread.
v1.0a2.140 — BBS Directory CSV parser fixes (June 2026)
- IPTIA parser crash —
csv.DictReaderproduces aNonekey when a CSV
header row has a trailing comma.k.strip()onNoneraisedAttributeError.
Both parsers now filterif k is not None. Fixed inweb/peers.py. - Parser exceptions no longer crash background thread —
parser(text)and
the DB insert block are now each wrapped in try/except so a malformed CSV
silently returns 0 instead of killing the refresh thread. - TelnetBBSGuide URL updated to
/bbs/list/full/csv/; both external URLs
are now overridable viaTELNETBBSGUIDE_CSV_URLandIPTIA_CSV_URLin.env.
v1.0a2.139 — Fix 500 on BBS Directory (missing PeerBbs columns) (June 2026)
- Hotfix:
PeerBbsmodel was missing the new columns (is_approved,
telnet_port,web_url,location,software,submitted_by_user_id)
added in v1.0a2.138. SQLAlchemy raisedInvalidRequestErroron
filter_by(is_approved=True)because the attribute wasn't defined in
the model class._ensure_columnadds them to the DB but the ORM also
needs them in the model. Fixed inmodels.py.
v1.0a2.138 — Enhanced BBS Directory: TelnetBBSGuide + IPTIA tabs (June 2026)
- Three-tab BBS Directory — Local (existing peers + user self-submission
with sysop approval), TelnetBBSGuide (CSV fetched + cached every 6h),
IPTIA (same pattern). Each entry shows name, sysop, location, software,
description, and Telnet/Web connect buttons. Admin panel handles pending
approvals and manual external refresh. Newexternal_bbs_cachetable;
new columns onpeer_bbsesvia_ensure_column.
v1.0a2.137 — Session crash fix; nginx MRC auto-repair (June 2026)
-
Session crash on early disconnect —
UnboundLocalErrorinsession.start()
finallyblock when a connection exited before completing login (bot gate, failed
login, all nodes full)._hb_task = Nonewas inside the outertry; moved it
before thetryalongsidepresence = None.core/session.py. -
nginx MRC auto-repair —
update.shnow detects and inserts the missing
location /mrcws+location = /mrc-auth-checknginx blocks if absent.
Without them web MRC WebSocket connections returned 404 from gunicorn.
v1.0a2.136 — Security questions at terminal registration; sysop profile field control (June 2026)
-
Sysop profile field control — new
BuiltinFieldConfigmodel lets sysops
enable/disable each built-in profile field (Display Name, Bio, Location, Website,
Forum Signature, FTN Tagline, Date of Birth, Show Email Option) from
/admin/custom-fields. Disabled fields are hidden from both the profile edit
form and the public profile view. Defaults to all enabled. Custom fields
(add/edit/delete) remain on the same page. -
Security questions on terminal registration — new users registering via
telnet/SSH now complete the same 3 password-recovery security Q&A as web
registration. Questions are presented numbered; user picks 3 different ones
and enters answers. Answers saved viaUserSecurityAnswer(same table/hashing
as web). Implemented in_collect_security_questions()incore/session.py;
save_security_answers()added toUserManager.
v1.0a2.135 — Duplicate email DoS fix; case-insensitive usernames (June 2026)
- DoS crash fix — registering with a duplicate email caused an unhandled
IntegrityErrorthat terminated the BBS session. Addedemail_exists()and
username_exists()pre-checks in the registration loop; user is re-prompted
with a clear message instead of crashing.create_user()now returns a result
code string and catchesIntegrityErroras defense-in-depth. - Case-insensitive usernames — all username lookups (registration, login,
get_user, web form validation) now usefunc.lower()soStingRayand
stingrayare treated as the same account. Existing usernames unchanged.
v1.0a2.134 — MRC terminal fixes; Custom User Fields; User ID # (June 2026)
- MRC PAUSED indicator —
\x1b[1;37;43mbold white on orange (was invisible reverse-video in SyncTERM) - MRC char count — top-right of status bar shows remaining chars (140 - typed); cyan > 15, yellow ≤ 15, red if over
- MRC
/tDM local echo — after sending DM, client echoes[DM -> target] messagein pink - MRC tab autocomplete case fix — old code doubled wrong-case prefix; now deletes from start and re-inserts full canonical-case name
- MRC status bar live update —
_draw_status_line()called after every keypress, backspace, and Ctrl+U - Custom User Fields — new
UserField+UserFieldValuemodels; admin CRUD at/admin/custom-fields; field types: text/textarea/url/number/select; shown on public profile and admin user-manage page - User ID # —
user.id(auto-increment PK) displayed in admin users list and public profile page
v1.0a2.132 — ANEdit: CP437 char fix (■/·); slash /commands replace F-keys (June 2026)
- CP437 fix — title bar used
●/○(not in CP437), displayed as?on
SSH/telnet terminals. Replaced with■(CP437 0xFE, modified) and·(clean).
Also fixed em-dash—in flash messages and box titles. - Slash /commands — F-keys are unreliable over SSH. ANEdit now intercepts
/
typed at column 0 and reads a short command:/?or/help= help,/t= theme,
/m= mark,/cc= color picker,/find,/replace,/undo,/redo,/save,
/send,/q= abort. Unknown commands fall back to inserting the text. F-keys
retained as secondary bindings. Hint bar and help overlay updated.