ANetBBS Changelog

Versions are internal build numbers. Public releases are tagged
separately. Current release: v1.0b2.58 (July 2026). Full release: August 1 2026.

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.xml is 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.xml and parses with xml.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 crashcsv.DictReader produces a None key when a CSV
    header row has a trailing comma. k.strip() on None raised AttributeError.
    Both parsers now filter if k is not None. Fixed in web/peers.py.
  • Parser exceptions no longer crash background threadparser(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 via TELNETBBSGUIDE_CSV_URL and IPTIA_CSV_URL in .env.

v1.0a2.139 — Fix 500 on BBS Directory (missing PeerBbs columns) (June 2026)

  • Hotfix: PeerBbs model was missing the new columns (is_approved,
    telnet_port, web_url, location, software, submitted_by_user_id)
    added in v1.0a2.138. SQLAlchemy raised InvalidRequestError on
    filter_by(is_approved=True) because the attribute wasn't defined in
    the model class. _ensure_column adds them to the DB but the ORM also
    needs them in the model. Fixed in models.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. New external_bbs_cache table;
    new columns on peer_bbses via _ensure_column.

v1.0a2.137 — Session crash fix; nginx MRC auto-repair (June 2026)

  • Session crash on early disconnectUnboundLocalError in session.start()
    finally block when a connection exited before completing login (bot gate, failed
    login, all nodes full). _hb_task = None was inside the outer try; moved it
    before the try alongside presence = None. core/session.py.

  • nginx MRC auto-repairupdate.sh now detects and inserts the missing
    location /mrcws + location = /mrc-auth-check nginx 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 BuiltinFieldConfig model 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 via UserSecurityAnswer (same table/hashing
    as web). Implemented in _collect_security_questions() in core/session.py;
    save_security_answers() added to UserManager.

v1.0a2.135 — Duplicate email DoS fix; case-insensitive usernames (June 2026)

  • DoS crash fix — registering with a duplicate email caused an unhandled
    IntegrityError that terminated the BBS session. Added email_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 catches IntegrityError as defense-in-depth.
  • Case-insensitive usernames — all username lookups (registration, login,
    get_user, web form validation) now use func.lower() so StingRay and
    stingray are 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;43m bold 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 /t DM local echo — after sending DM, client echoes [DM -> target] message in 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 + UserFieldValue models; 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.

v1.0a2.131 — ANEdit wired into message boards, PMs, echomail; board/thread coloring (June 2026)

  • ANEdit now used for all message composition_post_compose, _send_pm,
    and _compose_echomail all launch the full ANEdit screen editor instead of the
    old line-by-line prompt. Reply flow pre-loads the parent post as > quoted text
    and pre-fills Re: subject.
  • Thread list coloring — board message list now uses full ANSI color: yellow
    numbers, cyan reply count, white subject, green author, grey timestamp. Clears
    screen and shows the board-name banner.
  • Thread reader coloring — post header shows yellow [OP]/grey [Reply N] tags,
    cyan subject, green author. Quoted lines (>) rendered in grey. Footer + prompt
    added.

v1.0a2.130 — ANEdit terminal message editor; security questions on registration (June 2026)

  • ANEdit — new full-featured 79×23 ANSI message editor (features/anedit.py).
    Undo/redo (60 levels), block mark/cut/copy/paste, find & replace-all, smart
    word-wrap, live word/char count, three color themes (F9), help overlay (F1),
    Mystic |XX color-code picker (F4), draft auto-save every 30 s with recovery on
    next entry. Entry point: await launch_anedit(session, quote, subject, username).
  • Security questions at registration — new users must now complete all 3
    password-reset security questions during signup. RegisterForm extended with 3
    SelectField+StringField pairs with duplicate-question validation. Answers
    saved via UserSecurityAnswer before commit.

v1.0a2.129 — IRC ESC exit fix; docs sidebar; bulletins; chat.ans; read/write security (June 2026)

  • IRC startup ESC exit — ESC from startup screen now correctly exits IRC. Root
    cause: run() loop condition checked not self.bms which is always False (list
    always has ≥1 bookmark). Fixed by having _startup_loop() return a boolean and
    run() breaking on True.
  • Docs sidebar spacing — increased padding to 12px/16px, font-size 0.92rem,
    line-height 1.6, min-width 250px (prior fix landed in local files but was not
    in the v1.0a2.125 tarball that was deployed).

v1.0a2.126 — bug fixes: bulletins, docs sidebar, chat.ans, read/write security (June 2026)

  • Bulletins HTML linefeed — swapped bulletin view default from <pre> to
    markdown (with nl2br); \r\n from telnet input now renders as <br> instead
    of blank lines. Raw view still accessible via toggle button.
  • chat.ans display codeschat.py now passes chat.ans through
    display_codes.apply() before writing, so Synchronet @-codes and Mystic |XX
    colors embedded in the ANSI screen are rendered correctly.
  • Docs sidebar spacingpy-1py-2, 0.85rem0.875rem,
    line-height: 1.31.5; sidebar page list no longer cramped on long names.
  • Separate read/write access levelsBoard and FileArea now have a
    min_write_level column (NULL = inherit read level). Admin UI updated with
    side-by-side fields. web/boards.py and bbs_ui.py enforce write level on
    post creation and file upload respectively. Auto-migrated on startup.

v1.0a2.125 — ANetIRC v7: pure-Python asyncio IRC client (June 2026)

Complete rewrite of ANetIRC. Drops the C binary + PTY bridge entirely. The new
anetirc2.py runs as a native asyncio coroutine inside the BBS session.

  • TLS fixedasyncio.open_connection(ssl=ssl_ctx) is non-blocking; the
    old C client's blocking TLS handshake caused hard lockups on SSL servers.
  • Cross-arch — no binary; works on x86-64, ARM, any Python 3.10+ platform.
  • SASL PLAIN — full CAP LS 302CAP REQ :saslAUTHENTICATE PLAIN
    state machine. Password field (7th pipe field) triggers SASL; no password = no
    SASL (plain nick/user registration).
  • Startup manager — inline field editing per bookmark (Tab/Up/Down to move
    between fields, Enter to confirm), TLS toggle (Space), theme cycle (T), save
    (A), delete (D). Three color themes: Cyan/Green/Amber.
  • Word-wrap — lines break at word boundaries; continuation lines indent to
    align with message text. Adapts to any terminal width.
  • Scrollback — PgUp/PgDn, 800 display rows, 2000 stored lines.
  • Tab completion — completes nick from users panel; cycles on repeated Tab.
  • Command history — Up/Down arrows recall previous input lines.
  • mIRC color — incoming color codes stripped; CTCP ACTION rendered as
    * nick action.
  • Backward-compatible — same bookmark config format, same entry point
    (launch_anetirc_telnet). C binary kept in tarball for reference/revert.