Skip to content

1.8.6#172

Open
awehttam wants to merge 178 commits intomainfrom
claudesbbs
Open

1.8.6#172
awehttam wants to merge 178 commits intomainfrom
claudesbbs

Conversation

@awehttam
Copy link
Owner

@awehttam awehttam commented Mar 7, 2026

Note: This release introduces localization (i18n) support across the
entire application — templates, admin panel, API error responses, JavaScript
UI, and outgoing emails. Localization touches virtually every part of the
system. Testing has been performed, but some areas may have been missed.
If you encounter any text that appears untranslated, displays a raw key
(e.g. ui.some.key), or behaves unexpectedly after upgrading, please report
it at https://github.com/awehttam/binkterm-php/issues.

⚠️ Make sure you've made a backup of your database and files before upgrading.

Summary of Changes

Localization (i18n) Support

  • Translation catalogs now support broader UI/API coverage across web pages and admin tools. Ships with English (en), Spanish (es), and French (fr). See docs/Localization.md for a full technical reference and translation contributor workflow.
  • Note: The Spanish (es) and French (fr) translations were generated by AI and have not been independently reviewed for accuracy. They may contain errors, awkward phrasing, or incorrect terminology. Community corrections are welcome via pull request.
  • API responses are now expected to use error_code / message_code (with optional params), so clients can localize consistently per user locale.
  • JavaScript translations use lazy catalog loading (/api/i18n/catalog). Pages that render text dynamically must initialize after user settings + i18n catalogs are loaded to avoid English fallback text.
  • The telnet and SSH daemons (through the shared BbsSession class) now support localization. All user-facing strings in the telnet server, shell menus, message editor, echomail/netmail browsers, polls, shoutbox, and door launcher are translated via the terminalserver catalog namespace (config/i18n/<locale>/terminalserver.php). The daemon defaults to the system locale (I18N_DEFAULT_LOCALE) pre-login and switches to the user's saved locale immediately after a successful login.
  • scripts/create_translation_catalog.php now supports Anthropic Claude in addition to OpenAI for automated locale generation. Provider is auto-detected from the presence of ANTHROPIC_API_KEY or OPENAI_API_KEY in .env, or set explicitly with --provider=claude|openai. Default Claude model is claude-sonnet-4-6; default OpenAI model is gpt-4o-mini. See docs/Localization.md for full usage.
  • New CI checks enforce i18n quality:
    • php scripts/check_i18n_error_keys.php validates error key coverage.
    • php scripts/check_i18n_hardcoded_strings.php blocks new hardcoded UI strings not in the allowlist.

BinktermPHP Terminal Server

The BinktermPHP Terminal Server provides a BBS-style interactive terminal accessible over two protocols:

  • Telnet (telnet_daemon.php) — default port 2323; TLS available on port 8023
  • SSH (ssh/ssh_daemon.php) — pure-PHP SSH-2 daemon; default port 8022

Both access methods share the same session logic (BbsSession) and deliver identical BBS features: menus, messaging, file areas, doors, polls, shoutbox, and more.

SSH Access

  • New SSH-2 server (ssh/ssh_daemon.php) — pure-PHP SSH daemon using only ext-openssl and ext-gmp, no new Composer dependencies. Default port 8022 (configurable via SSH_PORT in .env). Correct SSH credentials skip the BBS login screen; failed auth drops to the login/register screen instead of disconnecting. Host key is auto-generated on first run at data/ssh/ssh_host_rsa_key. See docs/SSHServer.md for full documentation.

Telnet Access

  • TLS encryption (experimental): enabled by default on port 8023 with an auto-generated self-signed certificate stored in data/telnet/. Set TELNET_TLS=false in .env to disable, or provide your own certificate via TELNET_TLS_CERT and TELNET_TLS_KEY. Use --no-tls on the command line to disable for a single run.

Terminal Features

  • New File Areas section in the BBS terminal (F from the main menu)
  • Z-Modem file transfer support has been introduced. Both a native internal Z-Modem implementation and support for lrzsz are available. Native internal is presently recommended.
  • Terminal netmail reader now supports downloading file attachments via ZMODEM (Z in the message viewer when attachments exist).
  • Terminal mail browser position is now persisted in users_meta using terminal_* keys. Netmail restores the last page + selected message. Echomail restores the echoarea list page and per-area message position (page + selected message).
  • New API endpoints for terminal state persistence:
    • GET /api/user/terminal-mail-state
    • POST /api/user/terminal-mail-state
  • Optional debug toggle to force unique outbound attachment filenames during terminal ZMODEM sends:
    • TELNET_ZMODEM_DEBUG_UNIQUE_NAMES=true
  • The message reader now supports Page Up / Page Down keys for scrolling through long messages a full screen at a time (in addition to the existing Up/Down line-by-line scrolling).
  • The message reader now renders LSC-001 MARKUP kludge formatted messages with ANSI terminal formatting. Markdown messages display headings, bold, italic, code blocks, bullet lists, block quotes, and horizontal rules using ANSI escape sequences. StyleCodes messages display bold, italic, underline, and inverse video. Unrecognized formats fall back to plain text. Quoted lines (> ) are always rendered as plain dim text regardless of the declared markup format.
  • Markdown strikethrough (~~text~~) now renders as dim -text- in the terminal and <del>text</del> in the web message reader.
  • In the message list, you can now type a message number to jump directly to it. The selection highlight updates live as digits are typed; press Enter to open.
  • The terminal capability detection wizard now correctly detects ASCII-only terminals. When UTF-8 is not supported, the wizard shows a CP437 box-drawing test; terminals that cannot render CP437 are set to ASCII mode instead of defaulting to CP437.

File Areas

  • ClamAV improvements: Files can now be manually scanned for viruses by admins from the file details modal using the new Virus Scan button. New .env option:
    • CLAMAV_ALLOW_INFECTED=true — accept infected files rather than rejecting them; scan result is still recorded
  • Virus detection error: When an upload is rejected due to virus detection, the UI now shows a specific "File rejected: virus detected" message instead of the generic upload failure. The rejection is also logged to the server log. See docs/AntiVirus.md for full setup and configuration instructions.
  • The file areas sidebar now has a search/filter box to quickly find areas by tag or description.
  • The file areas sidebar list is now scrollable with a fixed height, matching the echomail reader style.
  • The page and sidebar heading has been renamed from "Files" to "File Areas".
  • TIC file encoding fix: TIC files and FILE_ID.DIZ contents containing CP437 or ISO-8859-1 characters no longer cause a PostgreSQL encoding error. Text is converted to UTF-8 before database insertion.
  • TIC bundle extraction fix: Files distributed via TIC that are compressed inside a FidoNet day-of-week bundle (e.g. .FR0) are now correctly extracted and made available for TIC processing instead of being silently discarded.
  • Inbound processing lock: process_packets.php now uses a file lock to prevent multiple concurrent instances.
  • Unprocessed files: After packet and TIC processing, any unrecognized files remaining in data/inbound/ are moved to data/inbound/unprocessed/ for manual review instead of accumulating indefinitely.
  • File owners and admins can now edit a file through the web interface. The Edit button appears in the file detail modal for users who have permission. The edit dialog allows changing the filename (which renames the file on disk), the short description, and the long description in a single operation.
  • Admins can move a file to a different file area from the same edit dialog. A "Move to Area" dropdown is shown to admins only; selecting a different area moves the physical file on disk to the new area's storage directory and updates the database record.

Native Doors

  • Anonymous (guest) access: sysops can now allow unauthenticated users to launch specific native doors by setting allow_anonymous: true and guest_max_sessions: N in config/nativedoors.json. Requires migration v1.10.17.2 (run via setup.php).
  • New native door: PubTerm (Public Terminal) — connects anonymous users to the BBS via telnet. Disabled by default; enable in Admin → Native Doors. Configure target host/port via PUBTERM_HOST and PUBTERM_PORT in .env (defaults to 127.0.0.1:2323). Linux uses telnet -E -K; Windows uses PuTTY plink (install via winget install PuTTY.PuTTY, or set PUBTERM_PLINK_BIN in .env). When enabled, a "Connect via Telnet" button appears on the login page.
  • New Guest Doors page (/guest-doors) listing all anonymous-accessible native doors. Enable via Admin → BBS Settings → Enable Guest Doors Page. When enabled, a Guest Doors link appears in the navigation for logged-out users.
  • Manifests now support a platform field in requirements (e.g. ["linux", "windows"]). The admin UI shows a warning badge if a door's platform requirements don't match the server OS.
  • Manifests now support launch_command_windows for platform-specific launch commands on Windows.
  • Documentation reorganised: new docs/Doors.md entry point covers all door types and shared multiplexing bridge setup (including --daemon mode); docs/DOSDoors.md and docs/NativeDoors.md updated to reference it.

DOS Door Multiplexing Server

  • SIGHUP config reload: send kill -HUP $(cat data/run/multiplexing-server.pid) to reload .env values without restarting. The following settings reload live: DOSDOOR_DISCONNECT_TIMEOUT, DOSDOOR_DEBUG_KEEP_FILES, DOSDOOR_CARRIER_LOSS_TIMEOUT. Settings that require a full restart: DOSDOOR_WS_PORT, DOSDOOR_WS_BIND_HOST, DOSDOOR_TRUSTED_PROXIES, DB_*.
  • Trusted proxy support: resolves the real client IP from the X-Forwarded-For header when the connection originates from a trusted proxy. Set DOSDOOR_TRUSTED_PROXIES in .env to a comma-separated list of proxy IPs (default: 127.0.0.1). Connections from unlisted addresses always use the raw socket IP.
  • Log lines are now prefixed with [sessionId|username|ip] for every session-scoped event, including emulator adapter output (DOSBox, DOSEMU, Native), DB updates, and drop file writes. This makes it straightforward to correlate all activity for a specific user or connection in the log.

TIC / File Areas (FidoNet)

  • Fixed a PostgreSQL encoding error (Character not in repertoire) that occurred when processing TIC files whose FILE_ID.DIZ or Desc/LDesc fields contained CP437 or ISO-8859-1 characters. Descriptions are now converted to valid UTF-8 before database insertion, matching the encoding handling already applied to message packets.

Echomail / Netmail

  • Fixed multi-level echomail quoting: when replying to a message containing already-quoted lines (e.g. RW>> text), the bumped quote now consistently carries a leading space ( RW>>> text) matching the FSC-0032 quoting style used for first-level quotes.
  • Fixed netmail replies using plain > quoting instead of FSC-0032 initials style. Netmail replies now quote identically to echomail replies.
  • Fixed 30–45 second delay when sending echomail or netmail. The immediate outbound poll triggered after sending was blocking the HTTP response on non-PHP-FPM setups (Apache mod_php, nginx without FPM). The admin daemon now spawns the poll in the background so the response returns as soon as the message is saved. Requires admin daemon restart — see upgrade instructions below.
  • Netmail attachments now supported for local delivery. Sending a file attachment to a user on the local system (including the sysop) stores the file directly into the recipient's private file area. Previously this returned an error. Crashmail is not required for local attachment delivery.
  • Fixed locally sent netmail (e.g. messages to Sysop) not appearing in the sender's All view — only in Sent. The message record is now owned by the sender so it appears in both views; the sysop still sees it in their inbox via address matching.
  • Fixed malformed or misaddressed echomail (e.g. newsletter feeds without AREA:/SEEN-BY/PATH kludges) being incorrectly delivered to the sysop's netmail inbox. The sysop catch-all fallback in address routing has been removed. Undeliverable messages are now dropped with a detailed log entry (from, to, subject, date, MSGID) and the original .pkt packet file is preserved to data/undeliverable/ for manual inspection.

Admin / Sysop Tools

  • New Language Overrides editor in Admin → BBS Settings → Language Overrides. Sysops can customize individual phrases for any locale and catalog without editing the base translation files. Overrides are stored as JSON in config/i18n/overrides/<locale>/<namespace>.json and are applied transparently on top of the base catalog at runtime.
  • PWA manifest: added app shortcuts for Doors (/games) and Files (/files).

Web / PWA

  • Fixed service worker caching: static assets (CSS, JS, fonts) are now served from the SW cache on every navigation with no redundant network requests. Switched from stale-while-revalidate to cache-first strategy; theme stylesheets and FontAwesome fonts are pre-cached at install time. The sw.js script now has a dedicated Cache-Control: no-cache header in .htaccess per the Service Worker spec recommendation.
  • Fixed Markdown blockquotes (>) not rendering in the UPGRADING doc viewer. Blockquotes now display with a left border accent at normal body font size.

awehttam and others added 30 commits March 4, 2026 17:58
- Pass resolved locale to buildBbsMenuItems() and use translator for
  'Polls' and 'Shoutbox' labels instead of hardcoded English strings
- Remove dead elseif block in the Twig t() function where array_unshift
  was immediately overridden by the subsequent $namespaces = $args[1]
  assignment, making the branch unreachable in effect

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
awehttam and others added 30 commits March 9, 2026 11:14
The charset detection wizard now tests CP437 box-drawing support when
UTF-8 is not available, falling back to ASCII if CP437 also fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The file detail modal's Rename button is replaced with an Edit button
that opens a unified dialog for changing filename, short description,
and long description in one request. Admins additionally see a Move to
Area dropdown that physically relocates the file to another area's
storage directory and updates the database record.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace loose owner_id truthiness check with explicit null guards on
both sides, preventing the edit and delete buttons from appearing on
TIC-imported files (owner_id = NULL) or any file the current user
does not own.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix isAdmin always being true: |default('false') replaced PHP false
  with the string 'false' which is truthy in Twig's ternary. Now uses
  window.currentUserIsAdmin set correctly by base.twig.
- Fix currentUserId always null: used current_user.id but auth session
  key is user_id. Now uses window.currentUserId from base.twig.
- File details 'From' field now falls back to owner username when
  uploaded_from_address is empty (e.g. files predating that column).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Prev/Next chevron buttons in modal header matching echomail/netmail style
- Position indicator in title (e.g. "filename.zip (3 / 12)")
- Navigation tracks displayed list (filtered or full area)
- Left/Right arrow keyboard shortcuts when modal is open
- Buttons disable at list boundaries
- COALESCE display_from in getFileById() to prefer uploaded_from_address over owner_username server-side
- i18n keys added to en/es/fr

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Press H in echomail or netmail reader to view message headers (kludge lines)
- Scrollable full-screen viewer with Up/Down/PgUp/PgDn/Home/End navigation
- Kludge keyword colorized in yellow for readability
- Shows "(No message headers)" if none present
- H added to status bar in both echomail and netmail readers
- Sources kludge lines from kludge_lines + bottom_kludges API fields (not message_text)
- i18n keys added to en/es/fr terminalserver catalogs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…racters

Adds sanitizeToUtf8() helper to TicFileProcessor that converts CP437/ISO-8859-1
encoded text to valid UTF-8 before database insertion. Applied to DIZ content,
short/long descriptions, and From address fields.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- BinkdProcessor: move non-pkt files extracted from bundles back to
  inbound/ so TIC processing can find them (e.g. NIXLIST.Z65 inside
  a .FR0 day bundle)
- process_packets: move leftover inbound files to unprocessed/ after
  all processing completes; TIC files are left in place
- process_packets: add flock-based mutex so only one instance runs
  at a time

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- processExtractedPackets: use RecursiveIteratorIterator to find pkt
  and non-pkt files in subdirectories (e.g. RETROPCK/ inside temp dir)
- cleanupTempDir: recursively delete subdirectories so temp dirs are
  not left stranded when archives extract into subdirectories
- Add pathIsUnder() guard to prevent both functions from operating on
  paths outside the inbound directory

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…OW_INFECTED option

- docs/AntiVirus.md: new document covering ClamAV installation, configuration,
  permissions, .env options, and troubleshooting; linked from README
- Admin file details modal: add Virus Scan button (admin only) that triggers
  an on-demand scan via admin daemon and refreshes the scan status display
- AdminDaemonServer/Client: add scan_file command that scans a file by ID
  and updates the database with the result
- POST /api/files/{id}/scan: new admin-only API endpoint
- CLAMAV_ALLOW_INFECTED=true: when set, infected files are kept and approved
  rather than deleted and rejected; scan result is still recorded in the DB

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Upload route now returns a specific 422 error when virus is detected
  instead of falling through to the generic 'Failed to upload file' message
- Virus rejection is logged to server log via admin daemon with username,
  filename, and file area
- Unknown upload errors now log to PHP error log before returning generic message
- Add errors.files.upload.virus_detected i18n key to en/es/fr

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…style

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant