PHP Classes

File: docs/UPGRADING_1.8.8.md

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   docs/UPGRADING_1.8.8.md   Download  
File: docs/UPGRADING_1.8.8.md
Role: Auxiliary data
Content type: text/markdown
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 53,431 bytes
 

Contents

Class file image Download

Upgrading to 1.8.8

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

Table of Contents

Summary of Changes

File Areas & TIC Processing - Incoming TIC ZIP processing now uses FILE_ID.DIZ only from the archive root.

FTN Networking - BinkP now handles exported socket timeouts more consistently during handshake reads.

Echomail & Netmail - Charset alias normalization: FTN alias values stored in message_charset (e.g. IBMPC, ASCII, CP895, LATIN-1) are now mapped to their canonical iconv-compatible equivalents at both storage time and reply time. CP1252 has been added as a supported outgoing charset. - Outgoing echomail and netmail replies now honour the original message's CHRS charset. When replying to a CP437-encoded message the reply is re-encoded in CP437 and the CHRS: CP437 2 kludge is set; if the body contains characters that cannot be represented the reply falls back to UTF-8. - A new Encoding selector in the compose form lets users explicitly choose the outgoing charset. It defaults to the original message's charset when replying, and to UTF-8 for new messages. - The netmail compose To Address field now includes a nodelist autocomplete: typing a system name, location, or partial address triggers a live search and presents a dropdown of matching nodes showing the FTN address, network badge, system name, and location. Selecting an entry populates the To Address field. - Clicking a node address in the netmail message list now shows a Bootstrap popover with the BBS system name, location, and a "View full node details" button. Point addresses that are not in the nodelist fall back to the parent node entry. - The "Art Encoding" field in the netmail and echomail message edit dialogs has been renamed to Character Set and changed from a free-text input to a dropdown. The dropdown lists only valid iconv-compatible charsets. Messages with an unrecognised stored charset show it as a labelled "(unknown)" option so it is preserved if the edit is saved without changing it. - Clicking the sender name in the echomail list or the From field in the netmail message view now shows a popover with the BBS system name, location, FTN address, and buttons to send netmail or view the full nodelist entry. Point addresses are resolved to the boss node for the lookup. - The To Name field in the netmail compose form now supports address book autocomplete: typing two or more characters shows a dropdown of matching contacts with their node address, network badge, and BBS name. Selecting an entry fills both the To Name and To Address fields. - Setting a message's Art Format to ansi now correctly forces ANSI rendering regardless of heuristic detection. Previously only amiga_ansi and petscii were treated as explicit overrides. - PETSCII has been removed as an Art Format option from the echomail, netmail, and echo area edit dialogs, and from the message viewer render mode cycle. PETSCII is a binary format that cannot survive FTN text transport. The PETSCII renderer in ansisys.js is retained for file area previews of .prg and .seq files. - The message body renderer now preserves multiple consecutive spaces and tabs (white-space: pre-wrap), fixing space-aligned tables and ASCII art that were being collapsed to single spaces by the browser. - ANSI art auto-detection now triggers only on actual ANSI escape sequences or pipe colour codes. The previous leading-space and line-length heuristics have been removed; space-aligned ASCII art is now handled correctly by the white-space: pre-wrap rendering. - Message body line spacing has been reduced from 1.6 to 1.2 across all themes, matching the tighter line cadence of BBS-style messages. - The From field in the echomail message reader now uses a solid underline (matching a hyperlink) instead of a dashed underline. - The compose form's Encoding and Markup Format selectors have been moved into a collapsible Advanced Options panel below the message textarea, keeping the default compose view clean. The panel's open/closed state is saved per-user and persists across sessions. - A Hard Wrap selector has been added to the Advanced Options panel. When enabled, the compose textarea automatically breaks lines at 79 characters (standard 80-column format, default), 39 characters (for readability on 40-column systems such as the C64), or can be turned off entirely. Word-wrap is used when possible; a hard break is used if no space is found. The setting is saved per-user and persists across sessions. - The echomail Advanced Search modal now includes a Message ID field that searches the message_id column using a partial (ILIKE) match.

Telnet/SSH BBS Server - The terminal server now logs user actions to data/logs/telnetd.log: menu navigation, echoarea and netmail access, individual message reads, echomail and netmail compose/send, file area browsing, file downloads and uploads, door launches, shoutbox posts, and poll votes.

Web Interface - Sysops now see a "Today's Callers" list in the dashboard System Information box. - The profile page System Information box has been replaced with a "Your Network Information" card showing configured networks and a "Show Netmail Addresses" modal. - The profile Activity Summary now includes files downloaded, files uploaded, and a download/upload ratio. - The user settings page sidebar (System Status, Quick Actions, Help & Support) has been removed. - A DEBUG_ANSI_NOT_PERFECT environment variable can be set to true to disable the Perfect DOS VGA 437 font override on ANSI art, useful for testing how art looks in the user's existing monospace font. - A DEBUG_ANSI_USE_CONSOLAS environment variable can be set to true to use Consolas instead of Perfect DOS VGA 437 for ANSI art rendering. - Today's Callers on the dashboard is now anchored to the sysop's configured timezone, so the midnight cutoff reflects local time rather than UTC. - The advertisement display (dashboard ad box, ad modal, and full-page ad view) now renders RIPscrip, Sixel, ANSI/PCBoard, and plain-text content using the same multimodal pipeline as the echomail message viewer. - The advertisement uploader now accepts .ans, .rip, .six, and .txt files and raises the file size limit to 5 MB. - Newly created advertisements default to dashboard display disabled. - The Activity Stats overview now shows a per-source login breakdown under the Auth category row, distinguishing web, telnet, and SSH logins. - The kludge lines box has been removed from the public shared message view. - The Font Awesome brands webfont (fa-brands-400.woff2, ~108 KB) is no longer loaded; the single brands icon used (Markdown) has been replaced with an inline SVG. - Admin settings pages (BBS Settings, BinkP Configuration, MRC Settings, Appearance) now blur their content cards while settings are being fetched and show a centred spinner; cards stay blurred if the load fails. - The user profile page now shows an Activity Log tab (admin/sysop only) listing recent events from the user_activity_log table. The existing transaction history is presented on an adjacent Transaction History tab. Both tabs are hidden from regular users. - Fixed a spurious "New version available" reload prompt appearing during normal page navigation caused by a secondary service worker activation watcher.

MRC Chat - When the server returns no rooms, the MRC chat WebDoor now shows the configured default room instead of an empty list. - Fixed a bug where the first message sent in a new DM conversation was not visible until the next poll. - Tab-completion of usernames in the chat input: type a partial name and press Tab to complete it, press Tab again to cycle through all matching online users. - Tab-completion now also works for slash commands: type / or a partial command name and press Tab to complete or cycle through matching commands. /msg also completes the username argument. - A toggle in the chat sidebar lets users switch between simple polling and long polling; the choice is remembered in localStorage. - Hard refresh (Ctrl+Shift+R) now correctly bypasses the service worker cache, restoring the expected development behaviour. - Fixed room user count showing one more user than actually present. - Fixed sent DM messages disappearing immediately when there is no prior conversation history.

Weather Reports - A new Weather Report configuration page is available under Admin ? Community ? Weather Report. It provides a form-based editor for config/weather.json (API key, locations, units) with a Load Example button to seed from weather.json.example. scripts/README_weather.md has been deprecated; documentation has moved to docs/Weather.md.

Broadcast Manager - The "Ad Campaigns" section has been renamed to Broadcast Manager and the "Advertisements" page has been renamed to Content Library throughout the UI. The menu group is now labelled Ads and Bulletins. URLs and internal identifiers are unchanged. The Broadcast Manager now includes a Weather Report quick-setup preset that pre-configures a daily 3:00 AM schedule and sets the content command to weather_report.php. The preset is greyed out when config/weather.json is not present.

LovlyNet Integration - The LovlyNet admin page has a new Setup Checklist column on the Setup tab that verifies registration status, hub connectivity, uplink configuration, default area subscriptions, and the LVLY_NODELIST file area rule. All five checks run in parallel and update as each result arrives. A Fix button can automatically create a canonical file area rule for nodelist import. - New BinkP uplinks added by the LovlyNet setup script now default to CRAM-MD5 authentication. - The replace metadata flag in area_metadata.json is now honoured: if LovlyNet recommends replace: true for a file area, BinktermPHP will detect and offer to correct a mismatch. - Echo and File area tab rows for default (recommended) areas now show a warning icon when the area is not yet subscribed. - When creating echo or file areas during subscription or area-sync, area_metadata.json recommended fields (sysop_only, readonly, replace) are now applied at creation time rather than only as a post-creation correction.

QWK Offline Mail - QWK conference numbers are now stored as canonical BBS-wide IDs on echo areas so packets use the system's conference numbering instead of subscription position. - REP packet processing now reads QWKE plain-text Subject: headers from the message body, fixing subject truncation to 25 characters for clients such as MultiMail. - QWKE outgoing From: and To: extended headers now contain only the name; the FTN address is no longer appended, preventing it from appearing as part of the reply-to name in offline readers. - New netmail sent via QWK can now specify the FTN destination by writing Name@zone:net/node[.point] in the To field. - The QWK BBS ID (packet filename and CONTROL.DAT identifier) is now a configurable setting so it remains stable if the sysop renames the board. - QWKE packets now encode message bodies in CP437, the same as plain QWK. A ^ACHRS: CP437 2 kludge is prepended to each body so capable readers know the encoding. Previously QWKE bodies were sent as UTF-8.

File Areas & TIC Processing

FILE_ID.DIZ Selection for Incoming TIC ZIPs

BinktermPHP can use FILE_ID.DIZ inside an incoming TIC ZIP to fill in missing Desc and LDesc values when the TIC metadata does not provide them.

In earlier 1.8.x builds, the TIC incoming processor matched FILE_ID.DIZ by basename only. That meant a ZIP containing multiple copies of FILE_ID.DIZ could use the wrong one, including files nested deeper inside subdirectories.

Version 1.8.8 tightens that lookup logic:

  • Prefer `/FILE_ID.DIZ` at the ZIP root.
  • If no root-level `FILE_ID.DIZ` exists, allow `/directory/FILE_ID.DIZ` only when that single directory is the only directory at the archive root.
  • Never descend more than one directory level when selecting `FILE_ID.DIZ` for TIC description import.

This change improves compatibility with common single-top-level-directory ZIP layouts while avoiding incorrect descriptions from nested archive content.

FTN Networking

BinkP Handshake Timeout Handling

Version 1.8.8 also tightens timeout handling for binkp sessions after sockets are converted to stream resources. The exported stream now relies on stream timeouts consistently instead of mixing native socket timeouts with stream I/O.

This helps avoid false handshake timeouts where the remote has already sent a valid frame, but the local side fails the read during handshake processing.

QWK Offline Mail

Stable BBS-Wide Conference Numbers

Version 1.8.8 now stores QWK conference numbers as canonical BBS-wide values on echo areas instead of rebuilding them from the current subscription order on every packet download.

This means:

  • Conference numbers are stable across the entire BBS, not just per user.
  • Subscribing or unsubscribing from an area no longer affects conference IDs.
  • Every user sees the same QWK conference number for the same echo area.
  • New echo areas receive the next available canonical conference number.

The system still records a per-download conference map in qwk_download_log for REP reply import safety, but packet generation and the QWK status view now use the canonical echo area conference number.

QWKE Subject Extended Header in REP Packets

The QWK format limits the subject field in the message header to 25 characters. QWKE-capable clients such as MultiMail write a plain-text Subject: line at the top of the message body when the subject exceeds that limit. Previous builds of BinktermPHP ignored this line and always used the truncated 25-character header field, causing long subjects to be silently cut off after a REP upload.

Version 1.8.8 now reads the plain-text Subject: (and To:/From:) extended headers from the message body before falling back to the fixed header fields.

QWKE From/To Headers No Longer Include FTN Address

When generating QWKE packets, BinktermPHP previously appended the sender's FTN address to the plain-text From: and To: extended headers in the form Name <zone:net/node>. The QWKE specification defines these headers as name-extension fields only; the FTN address belongs in the ^A-prefixed kludge lines (^AINTL, ^AORIG, etc.).

Including the address caused offline readers to store Name <zone:net/node> as the from-name. When composing a reply, the full string then appeared verbatim in the To field of the outgoing REP packet.

Version 1.8.8 now writes only the name in these headers, matching the spec.

FTN Address in To Field for New Netmail

QWK has no dedicated field for a FTN destination address. When composing new netmail (conference 0) in an offline reader, there is no standard way to communicate the routing address to the BBS.

Version 1.8.8 supports a convention for specifying the destination: if the To field of a conference-0 message matches the pattern Name@zone:net/node[.point] the address portion is extracted and used for FTN routing. The name portion is used as the recipient name. This allows users to address new netmail to arbitrary FTN nodes directly from their QWK reader.

Replies to received netmail continue to resolve the destination via the message index as before; this convention applies only to new messages with no reply reference.

Configurable QWK BBS ID

The QWK BBS ID ? used as the packet filename (BBSID.QWK) and in CONTROL.DAT ? was previously derived from the system name on every packet build. Renaming the board would silently change the ID, breaking existing offline readers that had already configured the BBS.

Version 1.8.8 adds a QWK BBS ID field to the admin BBS Settings page (under the QWK Offline Mail toggle). The value is up to 8 alphanumeric characters and is stored in config/bbs.json as qwk.bbs_id.

The upgrade migration (v1.11.0.48) automatically derives the ID from the current system name and writes it to bbs.json, so existing installations receive a stable value without any manual action. After upgrading, the ID can be changed in the admin panel, but note that changing it will require users to reconfigure their offline readers.

QWKE Bodies Now Encoded as CP437

QWKE packets previously encoded message bodies as UTF-8, which broke ANSI art rendering in offline readers whose terminal emulators expect single-byte CP437 characters. QWKE bodies are now encoded in CP437, identical to plain QWK.

A ^ACHRS: CP437 2 kludge is prepended to the body of each QWKE message so capable readers can confirm the encoding. Characters in stored UTF-8 message text that have no CP437 equivalent are transliterated to the nearest ASCII equivalent; characters with no reasonable substitute are dropped.

No action is required. Existing packets already downloaded are unaffected.

Web Interface

Dashboard: Today's Callers

Sysops (admin users) now see a "Today's Callers" entry at the bottom of the System Information card on the dashboard. It lists every distinct user who has had an active session since midnight, along with their most recent activity time. Non-admin users do not see this field.

Profile: Your Network Information

The "System Information" card on the user profile page has been replaced with "Your Network Information". It displays the configured FTN networks in a compact two-per-row grid (network badge and node address side by side). A "Show Netmail Addresses" button opens a modal table with "Network Name" and "Network Address" columns, where the address is formatted as RealName@zone:net/node for direct copy-paste use.

Profile: File Transfer Stats

The Activity Summary card on the profile page now includes three additional rows:

  • Files Downloaded ? count of file download events from the activity log.
  • Files Uploaded ? count of file upload events from the activity log.
  • D/L Ratio ? downloads divided by uploads (e.g. `2.50:1`), or N/A when no transfers have occurred.

These counts are sourced from the user_activity_log table.

Settings: Sidebar Removed

The user settings page previously showed a right-hand sidebar containing System Status (BinkP online indicator, last poll time, messages today), Quick Actions (compose netmail/echomail links), and Help & Support (GitHub links). These boxes have been removed. The main settings content now uses the full page width.

ANSI Renderer: Debug Font Override

Two new environment variables can be added to .env to test ANSI art rendering with different fonts:

DEBUG_ANSI_NOT_PERFECT=true

When set to true, the .ansi-art CSS font-family is reset to inherit, so art renders in whatever monospace font the rest of the page uses.

DEBUG_ANSI_USE_CONSOLAS=true

When set to true, Consolas is used instead of Perfect DOS VGA 437. Useful for comparing rendering between fonts. Only one of these variables should be set at a time; DEBUG_ANSI_NOT_PERFECT takes precedence. Set both to false or remove them to restore the default Perfect DOS VGA 437 behaviour.

Dashboard: Today's Callers Timezone

The Today's Callers list now anchors midnight to the sysop's configured timezone rather than UTC. Users active after local midnight but before UTC midnight will no longer be excluded from the list.

Advertisements: Multimodal Content Rendering

The advertisement display now uses the same multimodal rendering pipeline as the echomail message viewer. Ad content is rendered in priority order:

  1. RIPscrip ? detected by the `!|` magic bytes; rendered via the RIPterm canvas engine.
  2. Sixel ? detected by the DCS escape sequence; rendered via the Sixel decoder.
  3. ANSI/PCBoard ? rendered through the existing ANSI and PCBoard colour processors.
  4. Plain text ? displayed as-is when no special encoding is detected.

This applies to the dashboard ad box, the ad modal popup, and the full-page ad view.

Advertisements: Upload Improvements

The advertisement upload form has been updated to reflect the full range of supported content types:

  • The accepted file extensions are now `.ans`, `.rip`, `.six`, and `.txt`.
  • The file size limit has been raised from 1 MB to 5 MB.
  • Newly uploaded advertisements default to dashboard display disabled. Enable "Show on Dashboard" explicitly after uploading if the ad should appear in the dashboard rotation.

Activity Stats: Login Source Breakdown

The Activity by Category table in the Activity Stats overview now expands the Auth row into sub-rows showing login counts broken down by source. Each distinct login source (web, telnet, ssh) appears as an indented sub-row with its own count and progress bar, making it easy to see how users are connecting to the BBS.

Shared Message: Kludge Lines Removed

The public shared message view previously displayed a collapsible kludge lines box beneath the message header. Kludge lines are internal FTN routing metadata not meaningful to general visitors. The box has been removed; the message body and origin line are now shown directly without it.

Font Awesome Brands Font Removed

The Font Awesome brands webfont (fa-brands-400.woff2) was the only brands asset used by the interface, and it was loaded solely to render the Markdown logo icon in the compose form. At ~108 KB it was disproportionately large for a single glyph.

The icon has been replaced with an equivalent inline SVG and the brands font has been removed from the service worker precache. Browsers will no longer download it.

Admin Settings: Loading Blur

Admin settings pages now blur their content cards while the initial settings fetch is in flight, and display a centred spinner so it is clear that data is loading. The blur and spinner are cleared once the data loads successfully. If the fetch fails the cards remain blurred, making the error state visually distinct from a loaded page.

The following pages use this behaviour: BBS Settings, BinkP Configuration, MRC Settings, and Appearance.

Profile: Activity Log Tab

The user profile page now presents a tabbed card (visible to admin/sysop users only) with two tabs:

  • Activity Log ? shows recent entries from the `user_activity_log` table: timestamp (in the viewer's timezone), category badge, activity label, and an object detail (e.g. the echo area tag for a "File Area Viewed" event). A Load More button fetches the next 25 entries. File area view events include the area tag as the detail field.
  • Transaction History ? the existing credit transaction table, unchanged.

Regular users do not see either tab. The card is only rendered when the viewing user is an admin.

Service Worker: Spurious Reload Prompt Fixed

A "New version available" reload toast was appearing during normal page navigation, not just when a genuine service worker update had been installed. The registration code previously watched for any service worker activation event and showed the prompt whenever one fired ? including activations that occur as part of the browser's normal navigation lifecycle.

The secondary activation watcher has been removed. The reload prompt is now shown only when the service worker itself signals that it replaced an older version, which is the correct trigger.

MRC Chat

Default Room Fallback

When the MRC daemon first connects, the server may not have sent a room list yet. Previously the chat WebDoor showed an empty room list in this window. Version 1.8.8 falls back to the default room configured in MRC Settings so there is always at least one room available to join.

First DM Message Now Visible

When opening a new direct message conversation by clicking a user, the first message sent was not visible. The DM view was opened after sending, which reset the message cursor and triggered a history reload that then overwrote the local echo.

The fix loads the DM view and its history before sending the message, so the local echo is appended in the correct position and remains visible without being displaced by the subsequent poll.

Tab Completion for Usernames

The MRC chat input now supports Tab-completion of online usernames. Type the beginning of a username and press Tab to complete it. If more than one online user matches the prefix, pressing Tab again cycles through the other matches; Tab wraps back to the first match after the last one. Typing any other character resets the cycle so the next Tab starts a fresh completion from the current cursor position.

Tab Completion for Slash Commands

Tab-completion in the chat input now also covers slash commands. Typing / followed by Tab cycles through all available commands alphabetically. Typing a partial command name (e.g. /mo) and pressing Tab completes it to /motd. Pressing Tab again cycles through any other commands that share the prefix.

For /msg, Tab-completion also applies to the username argument: after typing /msg (or a partial username), pressing Tab completes the username from the list of users currently in the room.

Available commands for completion: /help, /identify, /motd, /msg, /register, /rooms, /topic, /update.

Polling Mode Toggle

A button in the MRC chat sidebar lets users switch between Simple Poll (short HTTP requests on a fixed interval) and Long Poll (a persistent connection that returns as soon as new messages arrive). The chosen mode is saved in localStorage and restored on the next visit.

Simple Poll is the safer choice in certain environments. Long Poll offers lower message latency on servers that support long-running HTTP connections.

Hard Refresh Now Bypasses Service Worker Cache

The service worker's fetch handler now checks the browser's request cache mode. When a hard refresh is performed (Ctrl+Shift+R), the browser signals cache: 'reload' and the service worker passes the request straight through to the network instead of serving from its own cache. This restores the expected behaviour where a hard refresh always retrieves fresh files.

DM Messages Disappear When No Prior History

When opening a DM conversation for the first time (no prior messages between the two users), sent messages vanished immediately after being echoed locally. The initial history poll returned no messages, leaving lastPrivateMessageId at 0. Every subsequent timer poll then evaluated append = false and replaced the entire chat area, wiping the local echo. Incoming replies from the other person were similarly lost until the page was reloaded.

The fix sets lastPrivateMessageId to -1 after the initial history load when no messages were found. -1 !== 0 triggers append mode on all subsequent polls, and WHERE id > -1 on the server is equivalent to WHERE id > 0 since message IDs start at 1.

Room User Count Off By One

The room list occasionally showed one more user than was actually present. A join announcement from the MRC server includes the user's real BBS name (e.g. user@MyBBS), which inserts a row with bbs_name = 'MyBBS'. The subsequent USERLIST from the server inserts the same user with bbs_name = 'unknown'. Because the unique key on mrc_users includes bbs_name, both rows coexisted until the next USERLIST sweep replaced them, causing the COUNT in the room list query to be inflated.

The fix changes the room count query to COUNT(DISTINCT username) so it matches the deduplicated user panel regardless of how many rows exist for a given username.

Telnet/SSH BBS Server

User Action Logging

The terminal server now emits INFO-level action entries to data/logs/telnetd.log for every significant user action. Each line includes timestamp, PID, and username so a sysop can reconstruct how the BBS is being used. Logged events:

| Area | Events Logged | |------|--------------| | Main menu | Navigation to each section | | Netmail | Message list viewed, individual message read, compose started, send success/failure | | Echomail | Area entered, message list viewed, individual message read, compose started, post success/failure | | Files | Area entered, subfolder entered, file detail viewed, download started/complete/failed, upload started/complete/error | | Doors | Door launched (by name) | | Shoutbox | Section entered, message posted/failed | | Polls | Poll detail viewed, vote cast/failed |

Example log entries:

[2026-03-21 04:55:10] [12345] [INFO] Menu [johndoe]: johndoe -> Echomail
[2026-03-21 04:55:11] [12345] [INFO] Action [johndoe]: Echomail: read message list for FIDONET.NODE@fidonet
[2026-03-21 04:55:20] [12345] [INFO] Action [johndoe]: Echomail: read message #4821 in FIDONET.NODE@fidonet
[2026-03-21 04:55:55] [12345] [INFO] Action [johndoe]: Echomail: posted message to FIDONET.NODE@fidonet subject="Re: Hello"
[2026-03-21 04:56:40] [12345] [INFO] Action [johndoe]: Files: download complete somefile.zip

No configuration is required. Logging is active whenever the telnet/SSH daemon is running and TELNETD_LOG_LEVEL is INFO or lower (the default).

LovlyNet Integration

Setup Checklist

The LovlyNet admin page (/admin/lovlynet) has been redesigned to a two-column layout on the Setup tab. The left column contains the existing Update Registration form. The right column contains a new Setup Checklist that is refreshed every time the tab is opened.

The checklist verifies five items simultaneously. All five checks are dispatched in parallel and each row updates independently as its result arrives, so fast checks (registration, uplink configuration) resolve immediately while slower ones (hub connectivity) do not block the display.

| Item | What is checked | |------|----------------| | Registration | Always shown as complete ? if you are on this page, registration has been done. | | Hub Connectivity | Performs a live BinkP authentication test against the LovlyNet hub to verify the configured credentials and network reachability. | | Uplink Configured | Verifies that a BinkP uplink entry for the LovlyNet hub exists in config/binkp.json. | | Default Areas | Fetches the list of LovlyNet-recommended echo and file areas from the LovlyNet server and checks whether each is currently subscribed. Missing areas are listed with a hint to subscribe via the Echo Areas or File Areas tabs. | | LVLY_NODELIST File Area Rule | Checks config/filearea_rules.json for a rule whose pattern matches the canonical LovlyNet nodelist filename pattern on the lovlynet domain. If no matching rule is found, a Fix button appears that automatically creates a working rule and saves it via the admin daemon. |

The default area subscription check uses an is_default flag added to every area returned by the LovlyNet areas API; no separate API call is required.

Setup Checklist: Five Parallel Checks

See the Setup Checklist section above. The checklist was previously a sequential three-item list that required each check to complete before the next began. It has been expanded to five items and now dispatches all checks in parallel, rendering each row with a spinner immediately and replacing it with the result as it arrives.

BinkP CRAM-MD5 Default

The LovlyNet setup script (scripts/lovlynet_setup.php) now configures new BinkP uplink entries with crypt: true, enabling CRAM-MD5 authentication by default. Previously new uplinks were created with plain-text password authentication. Existing uplinks are not modified.

replace Metadata Flag for File Areas

LovlyNet can now recommend the replace behaviour for file areas via area_metadata.json. When a file area's metadata contains "replace": true, BinktermPHP checks whether the local file area has replace_existing enabled. If there is a mismatch, an issue is reported in the same settings-issue system used for the existing readonly flag, and Sync will correct it.

The local_replace_existing field is now included in the areas API response so the admin interface can display the current value alongside the recommendation.

Default Area Indicators on Echo and File Area Tabs

On the Echo Areas and File Areas tabs of the LovlyNet admin page, any area that is marked as a default (recommended) area by the LovlyNet server but is not yet subscribed will now show an amber warning icon (fa-exclamation-triangle text-warning) next to the area tag in the table row. Hovering over the icon shows a tooltip explaining that this is a default area that has not been subscribed.

Areas that are subscribed, or areas that are not flagged as defaults, are unaffected. The icon is removed automatically when the area is subscribed.

Echomail & Netmail

Node Address Autocomplete in Netmail Compose

The To Address field in the netmail compose form now doubles as a node search box. While the field contains non-FTN characters (i.e. no colon or slash) a debounced search fires against the imported nodelist. Results appear in a dropdown beneath the field showing:

  • FTN address
  • Network badge (e.g. FidoNet, LovlyNet)
  • System name
  • Location (in parentheses)

Keyboard navigation (?/?/Enter/Escape) and mouse selection are both supported. Selecting an entry populates only the To Address field; the To Name field is left for the user to fill in. The help text below the field has been updated from "Fidonet address (e.g., 1:123/456)" to "FTN address or system name" to reflect the new capability.

The autocomplete requires a nodelist to have been imported via the nodelist import process. If no nodelist data is present the search returns no results.

Node Address Popover in Netmail List

In the netmail message list, sender and recipient node addresses are now displayed as linkable text (dotted underline, primary colour). Clicking an address opens a Bootstrap popover showing:

  • BBS system name
  • Location

The popover also contains a View full node details button that links to the full nodelist entry page. Clicking anywhere else dismisses the popover.

Point addresses that are not found in the nodelist are automatically looked up against their parent node (e.g. 1:123/456.1 ? 1:123/456), so the popover and the "View full node details" link resolve correctly even for point systems that do not have their own nodelist record.

Outgoing Charset Selector

The compose form for both echomail and netmail now includes an Encoding dropdown above the Markup Format selector. The available options are:

| Value | Description | |-------|-------------| | UTF-8 | Unicode ? default for new messages | | CP437 | IBM PC / DOS codepage 437 | | CP850 | Latin-1 DOS codepage 850 | | CP852 | Central European DOS codepage 852 | | CP866 | Cyrillic DOS codepage 866 | | CP1252 | Windows Western European | | ISO-8859-1 | Latin-1 | | ISO-8859-2 | Central European |

When replying to a message, the selector pre-selects the charset of the original message. A reply to a CHRS: CP437 2 message will default to CP437 so the recipient's legacy system receives correctly-encoded bytes.

If the message body contains characters that cannot be represented in the selected charset (e.g. an emoji in a CP437 message), BinktermPHP silently falls back to UTF-8 rather than losing content.

The selected charset is written to the outgoing FTN packet as the CHRS kludge line and the message body bytes are re-encoded accordingly before the packet is written.

Message Edit: Character Set Selector

The Art Encoding field in the message edit dialogs for both netmail and echomail has been renamed to Character Set and converted from a free-text input with a datalist to a <select> dropdown.

The dropdown lists only charsets that are valid for the FTN CHRS kludge and supported by iconv for body re-encoding:

| Value | Description | |-------|-------------| | UTF-8 | Unicode | | CP437 | IBM PC / DOS codepage 437 | | CP850 | Latin-1 DOS codepage 850 | | CP852 | Central European DOS codepage 852 | | CP866 | Cyrillic DOS codepage 866 | | CP1252 | Windows Western European | | ISO-8859-1 | Latin-1 | | ISO-8859-2 | Central European |

If a stored message has a message_charset value that is not in the list (e.g. a legacy value such as KOI8-R or a former art-format hint like PETSCII), the edit dialog inserts it as a labelled (unknown) option at the top of the dropdown and pre-selects it. Saving the edit without changing the charset preserves the original value. The unknown option is removed and re-evaluated each time a different message is opened for editing.

The help text that previously described the field as affecting only ANSI/PETSCII art rendering has been removed; art rendering format is controlled separately by the Art Format selector above it.

The charset list is centralised in BinkpConfig::getSupportedCharsets() and shared by the compose form and both edit dialogs.

Sender Name Popover with BBS Lookup

Clicking the sender name in the echomail message list or the From: field in the netmail message view now opens a Bootstrap popover that includes the remote BBS name, location, and FTN address pulled live from the imported nodelist.

The popover shows a spinner immediately, then fills in the details once the nodelist lookup completes. Two action buttons are provided:

  • Send Netmail ? opens the compose form pre-addressed to the sender.
  • View full node details ? links to the nodelist entry page for the node.

Point address handling: If the sender's FTN address is a point address (e.g. 2:250/100.3), the lookup is performed against the boss node (2:250/100) so the BBS name and location are resolved even for point systems that do not have their own nodelist entry. The popover notes the address is a point.

The popover implementation is shared between echomail and netmail to avoid duplication. The trigger element uses a standard solid underline in both contexts.

To Name Autocomplete from Address Book

The To Name field in the netmail compose form now provides inline autocomplete backed by the user's address book. Typing two or more characters triggers a debounced search and shows a dropdown beneath the field. Each result displays:

  • The contact's name (bold)
  • Their node address in monospace, a network badge (e.g. `fidonet`), and the BBS system name pulled from the imported nodelist

Selecting an entry fills both fields at once: To Name is set to the contact's name and To Address is set to their FTN node address. The crashmail checkbox is also toggled to match the contact's Always Crashmail preference. Full keyboard navigation (?/?/Enter/Escape) is supported.

Art Format Field Now Forces ANSI Renderer

Setting a message's Art Format to ansi now unconditionally triggers the ANSI renderer when the message is displayed. Previously only amiga_ansi was treated as an explicit override; ansi fell through to heuristic detection (cursor codes, dense colour lines) and was silently ignored for messages that did not meet those thresholds.

Message Body Preserves Multiple Spaces

The plain-text message renderer (formatMessageText in public_html/js/app.js) now applies white-space: pre-wrap to each rendered line. This preserves multiple consecutive spaces and tabs exactly as they appear in the raw message text, fixing the display of space-aligned tables and column-formatted content that were previously collapsed to a single space by standard HTML rendering.

The font and size are unchanged ? only whitespace handling is affected. Messages rendered as ANSI art, PCBoard colour, or forced plain text (<pre>) are not affected by this change.

PETSCII Removed from Message Viewer

PETSCII is a binary format used by Commodore 64 programs (.prg) and sequential files (.seq). Because FTN echomail and netmail are text-based transports, binary PETSCII data cannot survive the journey intact and the format is not meaningful in this context.

The PETSCII option has been removed from:

  • The Art Format dropdown in the echomail and netmail message edit dialogs
  • The Art Format Hint dropdown on the echo area settings page
  • The render mode cycle button in the echomail and netmail message viewers
  • `ArtFormatDetector::detectArtFormat()` in `src/ArtFormatDetector.php` ? the PETSCII encoding name list, byte-level heuristic, and related constants have all been removed

Any message that already has art_format = petscii stored in the database will continue to display (falling back to the auto renderer). The PETSCII decoder (ArtPetsciiDecoder, renderPetsciiBuffer) remains in ansisys.js and is still used by the file area file previewer for .prg and .seq downloads, where PETSCII format is detected purely by file extension.

ANSI Auto-Detection Simplified

The ANSI art auto-detection heuristics in the message viewer have been simplified. Previously the renderer triggered on:

  • Actual ANSI escape sequences (cursor codes, SGR colour codes, pipe codes)
  • Messages with many lines that start with 5 or more leading spaces
  • Messages with long lines and dense colour codes

The leading-space and line-length heuristics have been removed. The renderer now triggers only on actual ANSI/pipe escape sequences or an explicit art_format setting. Space-aligned ASCII art and text tables no longer need a separate rendering path ? they are handled correctly by the `white-space: pre-wrap` applied to all plain-text message lines.

Message Body Line Spacing Tightened

The line-height on .message-formatted has been reduced from 1.6 to 1.2 across all five theme stylesheets (style.css, amber.css, dark.css, greenterm.css, cyberpunk.css). The previous value produced noticeably loose line spacing compared to the tight terminal cadence of BBS messages.

Echomail Reader From Line Style

The From sender name in the echomail message reader now uses text-decoration: underline (matching a hyperlink) instead of the previous border-bottom: 1px dashed dotted underline, consistent with the style used in the echomail message list and the netmail reader.

Compose Advanced Options Panel

The Encoding and Markup Format selectors in the echomail and netmail compose forms have been moved into a collapsible Advanced Options panel. The panel is toggled by a button placed next to the Insert File button below the message textarea.

The panel's open/closed state is saved as a user preference (compose_advanced_open) and restored on the next visit, so users who frequently change these settings can leave it open without having to re-expand it each time.

No workflow change is required for users who do not use those selectors ? the panel is collapsed by default and the selectors continue to work identically when the panel is open.

Compose Hard Wrap

A Hard Wrap selector is now available inside the Advanced Options panel. When active, the compose textarea automatically breaks lines while typing:

  • 79 characters (default) ? standard 80-column FTN format
  • 39 characters ? for readability on 40-column systems such as the C64
  • Off ? no automatic wrapping; manage line length yourself

When the current line reaches the selected column limit and the user types a printable character, the editor word-wraps at the last space on the line. If no space is present, a hard break is inserted at the column limit. Pressing Space at or past the limit inserts a newline directly.

The selected value is saved as the user preference compose_hard_wrap and restored on every compose page load.

Charset Alias Normalization

FTN software uses several aliases and legacy names for charsets in the CHRS kludge that are not accepted by PHP's iconv. Version 1.8.8 introduces a centralized BinkpConfig::normalizeCharset() method that maps these to their canonical equivalents.

The normalization is applied at two points:

  • Storage time ? when incoming packets are processed, the detected charset is normalized before being written to the `message_charset` column.
  • Reply time ? when opening the compose form for a reply, the stored charset is normalized before pre-selecting the encoding dropdown, so the correct option is highlighted even for messages stored under an alias.

The full alias table:

| Stored value | Normalized to | Notes | |---|---|---| | IBMPC | CP437 | Common FTN alias for IBM PC codepage 437 | | IBM437 | CP437 | | | ASCII / US-ASCII | UTF-8 | ASCII is a 7-bit subset of UTF-8 | | CP895 | CP850 | Kamenický (Czech DOS); not supported by iconv ? CP850 is the closest substitute | | IBM850 | CP850 | | | IBM852 | CP852 | | | IBM866 | CP866 | | | LATIN-1 / LATIN1 | ISO-8859-1 | | | LATIN-2 / LATIN2 | ISO-8859-2 | | | WINDOWS-1252 | CP1252 | |

Existing messages in the database with alias values in message_charset are not migrated ? the normalization is applied on read when composing a reply, so no data migration is needed.

Advanced Search: Message ID Field

The echomail Advanced Search modal now includes a Message ID field. Entering a value performs a case-insensitive partial match (ILIKE) against the message_id column of the echomail table, so you can search by a fragment of a FidoNet message ID such as <12345@fidonet.org> without knowing the full value.

The field follows the same rules as the other Advanced Search text fields: minimum two characters, combined with the remaining fields using AND logic.

Weather Reports

Weather Configuration Admin Page

A new admin page at Admin ? Community ? Weather Report provides a form-based editor for config/weather.json. Previously this file had to be created and edited by hand using config/weather.json.example as a guide.

The page offers:

  • Fields for report title, coverage area, OpenWeatherMap API key, units (metric/imperial/standard), API timeout, and maximum locations.
  • A location manager with add, edit, and remove actions for each city (name, latitude, longitude).
  • A Load Example button that appears when no `config/weather.json` exists yet, seeding all fields from `weather.json.example` so there is a working starting point.
  • Saves are written via the admin daemon, consistent with how other config files are managed.

scripts/README_weather.md has been deprecated and replaced with a stub that redirects to the new documentation at docs/Weather.md.

Broadcast Manager

Rename from Ad Campaigns

The section previously labelled Ad Campaigns in the admin navigation has been renamed to Broadcast Manager. The page previously labelled Advertisements has been renamed to Content Library. The menu group that contains both has been renamed from Ads to Ads and Bulletins to better reflect that it now covers both traditional ANSI content and automated bulletins such as weather reports and file area updates.

No URLs, database columns, config keys, or template file names have changed. Existing campaigns continue to function without any action required.

Weather Report Preset

The Broadcast Manager quick-setup wizard now includes a Weather Report preset. Selecting it pre-fills:

  • A daily schedule running at 3:00 AM every day of the week.
  • A content command pointing to `scripts/weather_report.php`, which prints the report to stdout for the scheduler to post.
  • A subject template of `Daily Weather Report`.

The preset is disabled (greyed out with a tooltip) when config/weather.json does not exist. Configure the weather report first via Admin ? Community ? Weather Report, then return to the Broadcast Manager to create the campaign.

Upgrade Instructions

This release includes migrations for canonical QWK conference numbers and the new QWK BBS ID setting. Run setup during upgrade so existing areas are backfilled with BBS-wide conference IDs and the QWK BBS ID is populated from the current system name before users download new packets.

From Git

  1. Pull the latest code: `git pull`
  2. Run setup: `php scripts/setup.php`
  3. Restart the daemons if they are running: `bash scripts/restart_daemons.sh`

Using the Installer

Re-run the BinktermPHP installer to upgrade the application files, then restart the daemons if your deployment manages them separately.