Dev-Specifications

Post Reply
ONiX
Site Admin
Posts: 185
Joined: Tue Nov 18, 2025 1:27 am

Dev-Specifications

Post by ONiX »

HAVOC
Bulletin Board System
Developer Specification

Including the HAX Scripting Platform
Document Class Developer Functional Specification
Product HAVOC BBS + HAX Script Engine
Network Layer DXSock6 / DXGenericServer (licensed)
Target OS Linux x86-64 (primary), Windows x86-64 (secondary)
Concurrency 100+ simultaneous callers via thread-pool
Version 1.0 — Initial Release
Status CONFIDENTIAL — Distribution Restricted
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 2
Copyright © 2026 by Brain Patchwork DX, LLC. — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
1. System Overview
HAVOC is a multi-user Bulletin Board System (BBS) server designed for operation over TCP/IP networks. It supports
100 or more simultaneous callers, each running an independent session within a dedicated operating-system thread.
The system provides messaging, file transfer, door programs, scripted screen presentation via the HAX scripting
engine, and optional FidoNet mail exchange.
HAVOC is built on the DXSock6 / DXGenericServer framework, which owns and manages the TCP listener, thread
pool, and session lifecycle. HAVOC code begins execution at the point DXGenericServer delivers an accepted socket
to a worker thread, and exits when the session concludes.
1.1 Design Principles
• Thread isolation. Every active caller session runs in its own thread. All per-session state — user record, current
conference, display settings, file transfer state, type-ahead buffer, scroll-back buffer, capture file — is stored in
thread-local storage so that no session can corrupt another.
• Single binary. The entire BBS server, including all 22 file-transfer protocols, the HAX interpreter, the sysop
console, and the TCP listener, compiles to one executable.
• Configuration-driven. Runtime behaviour (paths, security levels, conference list, modem strings, event
schedules) is controlled by a binary configuration file loaded at startup. No recompile is needed to reconfigure the
system.
• Graceful degradation. Carrier loss, timeout, or script abort terminates only the affected session. The server
continues accepting connections.
• Clean separation. Network I/O, file I/O, display output, and scripting are abstracted behind thin interfaces so that
the core BBS logic is independent of the transport layer.
1.2 High-Level Architecture
Layer Responsibility Key Components
TCP Listener Accept incoming connections, manage thread pool DXSock6, DXGenericServer
Session Adapter Bind socket to per-thread comms state Socket I/O abstraction module
Comms Mux Route reads/writes to socket or local console Serial/comms abstraction module
BBS Session Loop Login → command loop → logoff lifecycle Session, Login, Command modules
Subsystems Messages, files, doors, FidoNet, events Independent subsystem modules
HAX Engine Execute .HAX script files Lexer, Runtime, Executor modules
Sysop Console Live monitoring and control from server keyboard Console module in main program
2. Configuration System
System configuration is stored in a single binary file (the "board file"). A separate configuration editor application
allows sysops to maintain this file through a screen-based interface. The main server loads the board file at startup
and whenever a live-reload command is issued from the sysop console.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 3
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
2.1 Board File Structure
The board file is a packed binary record. A four-byte magic signature and a two-byte version number appear at the
start. The remainder is a fixed-size structure containing all system parameters. Strings within the structure are stored
as null-padded fixed-length byte arrays so that the overall record size is constant regardless of string content. The file
is memory-mapped or block-read in its entirety at load time.
2.2 Configuration Fields
The board file record includes at minimum the following categories of information:
• System identity: Board name, sysop name, registration serial, city, phone number.
• Path locations: Separate paths for: message bases, file directories, help text, menu files, HAX scripts, FidoNet
in/out queues, temporary work area, log file.
• Access control: Array of security level thresholds: new user level, sysop level, validated level, low-baud override
level. Maximum number of concurrent nodes.
• Timing: Default minutes per call by security tier, low-baud time window (start/stop in HH:MM format), event
schedule start times.
• Display: ANSI graphics default on/off, page length default, inter-character delay.
• File transfer: Download ratio settings, upload credit values, daily kilobyte limits by security level, list of enabled
protocol codes.
• Networking: TCP listen port, maximum connection queue depth, idle-timeout seconds.
• FidoNet: Own FidoNet address (zone:net/node.point@domain), paths for nodelist, inbound/outbound packet
queues, AKA addresses.
• Modem / serial: COM port index, baud rate, init string, answer string, hang-up string (used for 15.4 serial builds
only; ignored by 15.5 TCP build).
• Maintenance: Purge age for messages, upload duplication check flag, closed-board flag.
2.3 Conference Records
Each message conference is stored as a fixed-size record in a separate file indexed by conference number.
Conference zero is the main board. Each record holds: conference name, minimum security level for access,
password (if any), message base path, news file name, file directory reference, public/private flag, and a set of
auto-rejoin flags. Up to 65,535 conferences are supported.
2.4 Live Reload
When the sysop types the RELOAD command at the server console, the board file is re-read from disk without
stopping the server. Active sessions continue with the old configuration until their next login. New sessions get the
updated configuration. A read-write lock protects the shared configuration structure during the reload window.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 4
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
3. Network Layer (DXSock6 / DXGenericServer)
HAVOC delegates all TCP socket management to the DXSock6 and DXGenericServer libraries. These are third-party
components owned and licensed by the HAVOC publisher. The developer must not re-implement this layer.
3.1 Server Lifecycle
Startup. The main program creates a single instance of the DXGenericServer class. It sets the listen port, binds the
three callback handlers (accept, process, end), and calls the Start method. The server then listens on the
configured TCP port.
Accept phase. When a TCP client connects, DXGenericServer calls the accept callback with the new socket object
as the sender argument. The accept callback checks whether the current active session count has reached the
configured maximum. If capacity is available it returns True, causing DXGenericServer to assign the connection
to a thread-pool worker. If capacity is full it returns False, causing the connection to be refused immediately.
Process phase. DXGenericServer calls the process callback in a worker thread, passing the socket object. The
process callback is where the entire BBS session runs. The callback must not return until the session is
complete.
End phase. After the process callback returns, DXGenericServer calls the end callback to perform any final
per-session cleanup. Decrementating the active node counter and releasing thread-local resources happens
here.
Shutdown. When the sysop types QUIT at the console, the main program calls the server's Stop method.
DXGenericServer waits for all active process callbacks to return before the stop completes.
3.2 Per-Session Socket Binding
Because the process callback runs in a worker thread, the HAVOC session code must know which socket object
belongs to the current thread. This is achieved by storing the socket object pointer in a thread-local variable at the
start of each process callback invocation, before any BBS code runs. All lower-level I/O functions retrieve the socket
from this thread-local pointer. The thread-local variable is cleared when the process callback returns.
3.3 I/O Abstraction Interface
The session code never calls DXSock6 methods directly. All comms go through a thin interface with the following
operations:
• SendChar(C) — Write a single character to the remote caller.
• SendBuffer(P, N) — Write N bytes from pointer P to the remote caller.
• SendString(S) — Write a Pascal/Delphi string to the remote caller.
• RecvChar(Timeout) — Read one character from the remote caller, blocking up to Timeout milliseconds.
Returns a sentinel value on timeout or carrier loss.
• CharsWaiting — Returns the number of bytes available in the receive buffer without blocking.
• CarrierPresent — Returns True if the TCP connection is still active.
• RemoteIPAddress — Returns the dotted-decimal IP address string of the caller.
• IsLocalConsole — Returns True if the session is a local (keyboard) session, not a network session.
3.4 Telnet Protocol Handling
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 5
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
After a connection is accepted, the session performs a minimal Telnet negotiation: it sends IAC WILL ECHO and IAC
WILL SUPPRESS-GO-AHEAD, and accepts or ignores any client-sent options. Following negotiation, the byte
stream is treated as a raw character channel. The Telnet layer strips IAC sequences from the received data so that
upper layers see only printable characters and standard control codes.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 6
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
4. Session Lifecycle
One complete caller session progresses through four phases: pre-login, authentication, command loop, and logoff. All
four phases run within the DXGenericServer process callback, in the caller's dedicated thread.
4.1 Pre-Login Phase
• Allocate a node number from the shared counter (mutex-protected atomic increment, wraps at MaxNodes).
• Set thread-local session state to default values: user record cleared, security level zero, current conference set to
main board (-1 sentinel), logoff reason set to "normal", session start time recorded.
• Bind the socket to the thread-local comms pointer.
• Perform Telnet negotiation (Section 3.4).
• Send the ANSI or plain-text welcome screen file if one is configured.
• Begin the login sequence.
4.2 Authentication Phase
The authentication sequence is a fixed number of attempts (typically three). Each attempt proceeds as follows:
Prompt for name. Display the name prompt string and read up to 25 characters of input. Blank input or carrier loss
exits the attempt loop.
Look up user. Search the user database for an exact case-insensitive match on the entered name. If not found,
offer new-user registration (if the board permits it and the caller's baud rate is above the minimum).
New user registration. Collect city, password (entered twice for verification), and any required questionnaire
answers. Create a new user record with the configured new-user security level. Write the record to the user
database.
Password verification. For returning users, prompt for the password and compare against the stored value. Allow
the configured number of password attempts before disconnecting.
Time restriction check. Before admitting the caller, evaluate whether the current time of day permits access at this
caller's baud rate and security level (see Section 5.1). If access is denied, display the appropriate message and
disconnect.
Session initialisation. On successful authentication: load the full user record into thread-local storage, compute
the session time allowance, display the last-login information, show the conference news file if updated since last
visit, and advance to the command loop.
4.3 Command Loop Phase
The command loop displays the active menu, reads a command character or string from the caller, dispatches to the
appropriate handler, and repeats until a logoff condition is set. The loop also maintains a per-minute time accounting
tick that decrements the caller's remaining time and logs off the caller when time expires.
Commands are defined in menu files. Each menu file is a structured text file listing command codes and their
associated action codes. The dispatcher maps the entered command to an action. See Section 8 for the menu
system.
4.4 Logoff Phase
• Display the logoff screen file.
• Flush any pending output to the socket.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 7
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
• Update the user record: last-login date, total calls, total minutes used today, total bytes downloaded, total bytes
uploaded.
• Write the updated record back to the user database (mutex-protected).
• Log the session summary to the activity log.
• Clear thread-local session state.
• Return from the DXGenericServer process callback.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 8
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
5. Access Control and Security
5.1 Security Level Model
Every user has an integer security level. The board configuration defines named threshold values: new-user level
(assigned on registration), validated level (assigned by sysop after verification), sysop level, and low-baud override
level. Every protected operation compares the caller's security level against a minimum threshold. Callers at or above
sysop level bypass all restrictions.
5.2 Time Restriction Logic
The time restriction check, performed at login, applies the following rules in order:
• Sysop bypass. If the caller's security level is at or above the sysop threshold, all time and baud restrictions are
bypassed and login proceeds immediately.
• Closed board. If the board is configured as closed and the caller's security level is zero (not yet validated), login is
refused and a "board closed" message is displayed.
• Low-baud window. If the caller's connect speed is at or below the configured low-baud threshold and the caller's
security level is below the low-baud override threshold, access is restricted to the configured time window. The
window is defined by a start time and stop time (HH:MM format). If the current time falls outside the window, login
is refused. The window handles midnight wrap-around: if start > stop, the window spans across midnight.
5.3 Conference Access
Each conference record specifies a minimum security level for entry. When a caller attempts to join a conference, the
system compares the caller's security level against the conference minimum. If the conference is
password-protected, the caller must also supply the correct password. Sysop-level callers can enter any conference
regardless of these settings.
5.4 User Database
The user database is a sequential binary file of fixed-size user records, indexed by record number. Each record
contains: name (25 characters), city (24 characters), password (13 bytes, stored as-is — encryption is optional),
security level, last-login date and time, total calls, total minutes used today, total bytes downloaded today, total bytes
uploaded today, and a set of boolean flags (ANSI on/off, expert mode, validated). Because multiple sessions may
update different records concurrently, writes to the user database use a single system-wide mutex to prevent
corruption.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 9
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
6. Display and Input Subsystem
6.1 Output Pipeline
All text destined for the caller passes through a single output pipeline. The pipeline performs, in order: pipe-code
substitution, ANSI translation (if the caller has ANSI enabled), character translation (if a translation table is loaded for
the caller's language), and finally delivery via the comms interface. The pipeline also tracks line count for
pause-at-page-end logic and optionally writes to a capture file if the caller has activated session capture.
6.2 Pipe Code Substitution
Screen files and menu prompts may contain pipe codes — two-character sequences beginning with the vertical bar
character — that expand to runtime values or ANSI colour sequences at display time. Codes are defined for:
foreground colour, background colour, user name, user security level, current date, current time, time remaining,
current conference name, system name, node number, and caller count. Unrecognised codes are passed through
unchanged.
6.3 Input Handling
All keyboard input from the caller is read through a unified input function. This function reads characters one at a time
from the comms interface, echoes them back (with masking for password fields), handles backspace, handles
line-length limits, and detects carrier loss. A type-ahead buffer in thread-local storage allows the HAX engine or
internal automation to inject keystrokes.
Input types include: any printable character, uppercase only, numeric only, yes/no, password (echoed as asterisks),
and command (single character without Enter). Each type applies appropriate filtering.
6.4 Scroll-Back Buffer
Each session maintains a circular scroll-back buffer in thread-local storage. Every line sent to the caller is also
appended to this buffer. The sysop can view the buffer contents from the sysop monitor screen to see what a caller is
currently looking at.
6.5 Pause at End of Page
The output pipeline tracks the number of lines sent in the current "page." When the count reaches the caller's
configured page length, the system displays a "more?" prompt and waits for a keypress. Pressing Space or Enter
continues; pressing Q or Escape aborts further output. The line counter resets when a new page begins or when a
screen-clear sequence is sent.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 10
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
7. Message System
7.1 Message Base Format
Each conference has its own message base. A message base consists of two files: a header file and a body file. The
header file is a sequential binary file of fixed-size message header records. The body file stores message text as
variable-length records. A message header record contains: message number, from-name, to-name, subject, date,
time, status byte (active/deleted/private/received), body offset into the body file, and body length in blocks.
7.2 Reading Messages
The message reader presents one message at a time. After displaying a message, the reader prompts for a
navigation command: next, previous, reply, kill (delete), or quit. The reader tracks a "new messages since last visit"
pointer per conference, stored in the user record, so that the caller can jump directly to new content.
7.3 Entering Messages
The message entry subsystem collects: the To name, the subject, and the body. The body is entered line by line
using a simple full-screen line editor. A slash-S command saves and posts the message; slash-A aborts. Maximum
body length is configurable. After saving, the system writes the message header record and appends the body to the
body file.
7.4 Personal Mail Scanning
At login, and on demand, the system scans all conference message bases for messages addressed to the caller that
have not yet been marked as received. The scan updates the received flag in each matching header record and
presents a summary to the caller.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 11
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
8. Menu System
8.1 Menu Files
The menu system is driven by structured text menu files stored in the configured menu path. Each menu file defines:
a prompt string, a list of command entries, and optionally a background screen file to display before the prompt. Menu
files may be in ANSI or plain-text format; the system selects the appropriate file for each caller based on their ANSI
setting.
8.2 Command Dispatch
Each command entry in a menu file consists of a command string (one or more characters the caller types) and an
action code with optional parameters. The dispatcher reads the command string from the caller, scans the active
menu's command list for a case-insensitive match, and invokes the handler for the matching action code. If no match
is found, the system either displays an "invalid command" message or silently re-prompts, depending on
configuration.
8.3 Action Codes
Action codes supported by the menu dispatcher include:
• GOODBYE — Log the caller off immediately.
• MAIN_MENU — Switch to the main (top-level) menu.
• PREVIOUS_MENU — Return to the previous menu on the menu stack.
• MENU — Push a named menu onto the stack and display it.
• DISPLAY_FILE — Send a named text/ANSI file to the caller.
• BULLETIN_LIST — Display the numbered bulletin index and allow selection.
• SHOW_BULLETIN — Display a specific numbered bulletin file.
• MESSAGE_READ — Enter the message reader for the current conference.
• MESSAGE_ENTER — Enter the message composition editor.
• MESSAGE_SCAN — Scan for new messages across all joined conferences.
• FILE_LIST — List files available in the current file area.
• FILE_DOWNLOAD — Initiate a file download using the caller's chosen protocol.
• FILE_UPLOAD — Initiate a file upload using the caller's chosen protocol.
• CONFERENCE — Join a different message/file conference.
• LANGUAGE — Change the caller's display language.
• DOOR — Launch a numbered door (external program).
• TIME_CHECK — Display time remaining this session.
• WHO_ONLINE — Display a list of currently active nodes and their activity.
• SYSOP_CHAT — Request a real-time chat with the sysop.
• RUN_HAX — Execute a named HAX script file.
• SET_PROTOCOL — Set the caller's preferred file-transfer protocol.
• TOGGLE_ANSI — Toggle ANSI graphics on/off.
• TOGGLE_EXPERT — Toggle expert mode (suppress menu display) on/off.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 12
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
9. File Transfer Subsystem
9.1 Protocol Dispatcher
The file transfer dispatcher maps a single-character protocol code to a protocol implementation module. The
dispatcher calls the appropriate send or receive function and returns a success/failure Boolean. All protocol
implementations share a common I/O primitive interface (Section 3.3).
9.2 Required Protocols
The following protocols must be implemented. Each is identified by a single ASCII letter code:
• Z ZModem — Full streaming with crash-recovery. Separate send and receive modules. CRC-32.
• Y YModem — Batch file transfer. CRC-16.
• G YModem-G — Streaming YModem without ACK per block. Requires error-free channel.
• X XModem — Basic 128-byte block, checksum.
• C XModem-CRC — XModem with CRC-16 error detection.
• E XModem-1K — XModem with 1024-byte blocks, CRC-16.
• F XModem-1K-G — Streaming XModem-1K without per-block ACK.
• K Kermit — Standard sliding-window Kermit.
• Q SuperKermit — Extended Kermit with larger window.
• M Modem7 — Batch protocol for older callers.
• T TELink — Sliding-window protocol with CRC-16.
• S SEAlink — Sliding-window protocol compatible with SEA products.
• P Punter — Commodore-oriented checksum protocol.
• H Hydra — Bidirectional simultaneous send/receive.
• J Janus — Bidirectional protocol with two streams.
• B MobyTurbo — High-speed streaming block protocol.
• O CIS B+ — CompuServe B+ protocol.
• I CIS Quick-B — Faster variant of CompuServe B+.
• V Base64 Stream — ASCII-safe base64 encoding for restricted channels.
• W XModem-1KW — XModem-1K with windowed ACK.
• A ASCII — Plain text upload with end-of-transfer sentinel.
9.3 Common Protocol Primitives
All protocol implementations use a shared primitive module that provides:
• GetByte(TimeoutMS) — Read one byte from the comms interface. Returns the byte value 0–255, or –1 on
timeout or carrier loss.
• PutByte(B) — Write one byte to the comms interface.
• PurgeInput(MS) — Discard all incoming bytes for a specified number of milliseconds.
• CRC16Update(CRC, B) — Update a running CRC-16 CCITT value with one byte.
• CRC16Buf(Buf, Len) — Compute CRC-16 over a memory buffer.
• CRC32Buf(Buf, Len) — Compute CRC-32 over a memory buffer.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 13
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
• TickCount — Return a millisecond-resolution timer value for timeout calculations.
9.4 Transfer Ratio Enforcement
Before initiating a download, the system checks the caller's download ratio: the ratio of bytes downloaded to bytes
uploaded. If the caller's ratio exceeds the configured limit and the caller's security level is below the sysop level, the
download is refused and an explanatory message is displayed. Sysop-level callers bypass ratio checking. File
uploads are always permitted regardless of ratio.
9.5 Upload Registration
After a successful upload, the system: computes the file size, checks for duplicate uploads against a rolling hash
database, prompts the caller for a file description, creates a directory entry record, adds the record to the active file
area's directory file, and credits the caller's upload byte counter with the file size.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 14
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
10. Door System
10.1 Overview
Doors are external programs launched by HAVOC on behalf of a caller. HAVOC temporarily suspends its session
handling, writes one or more drop files describing the caller's session, and then executes the door program as a child
process. When the child process exits, HAVOC resumes the session.
10.2 Drop Files
Before launching a door, HAVOC writes the following drop files to the configured temporary path:
• DORINFO1.DEF — Standard RyBBS-format drop file containing: BBS name, sysop name, COM port, baud rate,
caller name, security level, minutes remaining, ANSI flag.
• DOOR.SYS — PC-Board–format drop file with extended fields including: node number, caller city, last
new-message scan date, calls to the system.
• DORINFOx.DEF — Node-specific variant of DORINFO1.DEF where x is the node number, for multi-node aware
doors.
10.3 Launch and Resume
The door is launched as a child process. On Linux, this is performed via the TProcess interface with the wait-for-exit
flag set. The child process's exit code is captured and stored in a thread-local session variable for optional use by
HAX scripts. After the child process exits, HAVOC redisplays the current menu and resumes normal session
handling.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 15
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
11. HAX Scripting Engine
HAX (HAVOC Action eXecution) is the name of the built-in scripting system. Sysops write HAX scripts to create
custom menus, questionnaires, games, registration sequences, automated messages, and any other interactive
feature not covered by the built-in action codes. HAX scripts are stored as plain-text files with the .HAX extension.
They are interpreted at runtime; no compilation step is required.
11.1 Execution Model
The HAX engine operates as a simple imperative interpreter. A script consists of a sequence of statements executed
top to bottom. Control flow is provided by conditional branches and GOTO. The engine maintains an integer program
counter, a set of up to 26 string variables (A through Z), a set of up to 26 integer variables (also named but typed
separately), a call stack for subroutines, and a label table built by a pre-scan of the script before execution begins.
11.2 Statement Reference
Each statement occupies one line. The statement keyword is the first token. Arguments follow separated by spaces.
String literals are enclosed in double quotes.
• PRINT "text" — Send text to the caller (pipe codes expanded).
• PRINTLN "text" — Send text followed by a newline.
• PRINTFILE "path" — Send the contents of a text/ANSI file to the caller.
• INPUT A 25 ANY — Read up to 25 characters into string variable A. Input type: ANY, UPPERCASE, NUMERIC,
PASSWORD, YESNO.
• INPUTCHAR A — Read a single character into variable A (no Enter required).
• LET A = "value" — Assign a string literal to variable A.
• LET A = B — Copy string variable B into A.
• LET A = A + B — Concatenate string variables A and B into A.
• LETINT A = 42 — Assign an integer literal to integer variable A.
• LETINT A = A + B — Add integer variables A and B; store result in A.
• GOTO label — Jump unconditionally to a labelled line.
• :label — Define a jump target (label declaration).
• IF A = "x" GOTO lbl — Jump to label if string variable A equals literal x.
• IF A > 5 GOTO lbl — Jump to label if integer variable A is greater than 5. Operators: = < > <= >= <>
• GOSUB label — Push current position onto call stack; jump to label.
• RETURN — Pop call stack; resume after the most recent GOSUB.
• END — Terminate the script and return to the menu system.
• SECURITY n — Set the caller's security level to integer n. Only executes if the current caller is sysop or higher.
• SETFLAG n ON/OFF — Set user flag number n to on or off.
• MENU "name" — Switch to a named menu file.
• RUNHAX "path" — Execute a nested HAX script. Execution resumes on END of the nested script.
• CONFERENCE n — Join conference number n.
• HANGUP — Immediately disconnect the caller.
• DELAY n — Pause execution for n tenths of a second.
• GETTIME A — Store the current time as HH:MM string into A.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 16
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
• GETDATE A — Store the current date as MM-DD-YY string into A.
• GETUSER NAME A — Store the caller's name into string variable A.
• GETUSER SECURITY A — Store the caller's security level as a string into A.
• GETUSER TIMELEFT A — Store minutes remaining this session into A.
• SETUSER NAME A — Set the caller's display name to string A.
• OPENADD "path" — Open a text file for appending.
• WRITELINE A — Write string variable A as a line to the open file.
• CLOSEFILE — Close the currently open file.
• READLINE "path" n A — Read line number n from file at path into variable A.
• SHELL "cmd" — Execute a shell command (sysop-level sessions only).
11.3 Pre-Execution Label Scan
Before executing a HAX script, the engine performs a single-pass scan of all lines to build a label table. Each line that
begins with a colon is recorded in the table with its name and line index. This allows GOTO and GOSUB to jump to
any label in O(1) time without searching the script during execution.
11.4 Variable Scope
HAX variables are local to the running script. When a nested script is invoked via RUNHAX, the parent script's
variables are saved and the nested script has its own fresh variable set. On RUNHAX completion, the parent's
variables are restored. Integer variables persist their values across GOSUB/RETURN boundaries within the same
script.
11.5 HAX File Naming
HAX script files use the .HAX extension. The system looks for scripts in the configured script path. Menu action codes
that invoke HAX specify the script name without the path prefix; the engine prepends the configured script path
automatically.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 17
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
12. FidoNet Integration
HAVOC includes optional FidoNet echomail and netmail handling. FidoNet functionality is provided by a suite of utility
modules that run as separate processes (not inside the BBS session loop). The main BBS server does not need to be
stopped to run FidoNet utilities.
12.1 Packet Format
FidoNet messages are exchanged in Type-2 packet format (.PKT files). Each packet begins with a 58-byte packet
header containing the originating and destination zone:net/node addresses, creation date, and packet password.
Messages within the packet are stored sequentially. Each message has a fixed-length header (from, to, subject, date,
attribute word, message length) followed by the message body as a null-terminated string, with lines separated by
carriage-return characters.
12.2 Tosser
The tosser utility scans the FidoNet inbound directory for .PKT files and .ARC/.ZIP bundles. It unpacks bundles, reads
each packet, and routes messages to local conference message bases (echomail) or to the netmail message base
(direct-addressed messages). After tossing, processed packets are moved to a bad-packet directory if they contain
errors, or deleted if processed cleanly.
12.3 Scanner / Packer
The scanner utility scans local message bases for messages entered since the last scan and packages them into
outgoing .PKT files addressed to the configured FidoNet uplink. The packer compresses outgoing packets into .ZIP
archives for efficient transmission.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 18
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
13. Thread Safety Requirements
With 100 or more concurrent sessions, every piece of shared mutable state must be protected. This section lists all
shared resources and the required protection mechanism.
Resource Access Pattern Protection Mechanism
User database file Multiple writers (logoff updates) Single global mutex; acquire before Seek+Write, release after.
Activity log file Multiple concurrent writers Single global mutex; acquire before WriteLine+Flush, release after.
Board configuration record Many readers, rare writer (live reload) Read-write lock; readers share, writer is exclusive.
Node number counter Frequent atomic increment Mutex-protected increment-and-wrap.
Active session count Increment on accept, decrement on end Atomic integer or mutex-protected integer.
Conference records Read by all sessions, write only by sysop util Read-write lock.
Per-session state Owned exclusively by one threadThread-local storage; no sharing, no lock needed.
FidoNet queues Written by tosser/scanner, read by BBS File-system level locking via lock files.
13.1 Thread-Local State Inventory
The following items must reside in thread-local storage, not in global variables:
• Active user record (name, security level, all user fields).
• Session status flags (logoff reason, abort flag, ANSI flag, expert mode flag).
• Current conference number.
• Session start time and remaining time in seconds.
• The comms socket pointer (bound at session start, cleared at session end).
• The caller's baud rate and online-mode indicator (network, local console).
• Batch download queue (list of queued file paths and sizes).
• Current message base file handle and open/closed state.
• Current user database file handle and open/closed state.
• Capture file handle and open/closed state.
• Active menu name and menu navigation stack.
• Current language identifier.
• Type-ahead keyboard buffer (head pointer, tail pointer, character array).
• Scroll-back display buffer.
• Duplicate upload check file handle and state.
• ZModem negotiated flags (remote buffer size, CRC-32 support flag).
• QWK mail packet assembly state.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 19
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
14. Sysop Console
The main program runs a sysop console loop on the server's local keyboard concurrently with the DXGenericServer
accepting connections. The console reads single-line commands from standard input and prints responses to
standard output.
14.1 Console Commands
• STATUS — Display count of active sessions, server uptime, total calls since startup.
• WHO — List each active node: node number, caller name, current activity description, minutes online.
• RELOAD — Re-read the board configuration file without stopping the server.
• CHAT n — Initiate a sysop chat with the caller on node n. Text typed by the sysop is injected into node n's
type-ahead buffer and displayed; the caller's responses appear on the console.
• HANGUP n — Forcibly disconnect the caller on node n by setting the session's logoff-reason flag.
• BROADCAST "msg" — Send a text message to all active sessions via a system message interrupt.
• QUIT — Gracefully shut down the server (waits for active sessions to complete).
• QUIT FORCE — Immediately terminate all sessions and exit.
14.2 Sysop Monitor Screen
In addition to the text-command interface, the sysop can press a function key to switch the console into a full-screen
monitor display. This display shows one status line per active node: node number, caller name, connect speed,
current conference, current activity, time remaining, and bytes transferred. The display refreshes every two seconds.
Pressing Escape returns to the text-command interface.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 20
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
15. Event Scheduler
HAVOC includes a simple time-based event scheduler. Events are defined in the board configuration and specify a
daily execution time, a command to run (typically a shell command or utility), and an error-level threshold for retry
logic. The scheduler runs in the main program thread alongside the sysop console loop.
15.1 Scheduler Logic
Once per minute, the scheduler checks the current time against the list of defined events. If the current time matches
an event's scheduled time and the event has not already been executed today, the scheduler executes the event's
command as a child process. After midnight, all "executed today" flags are reset so events can fire again the following
day. If an event's command returns a non-zero exit code, the scheduler logs the failure.
15.2 Caller Notification
Before an event fires, the scheduler optionally sends a warning message to all active sessions: "System going offline
for maintenance in N minutes." The warning period is configurable per event. Active sessions receive the warning via
the system message interrupt mechanism described in Section 14.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 21
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
16. Utility Programs
In addition to the main BBS server executable, the HAVOC suite includes the following standalone utility programs:
Configuration Editor (HAVOC-SETUP)
A full-screen configuration editor that reads and writes the board file. Organised into topic screens: system identity,
paths, security levels, modem/network settings, FidoNet identity, event schedule, conference list. The editor validates
all fields before writing and can create a new board file from scratch.
Migration Converter (HAVOC-CNV)
Converts a legacy board file format into the current HAVOC board file format. Reads the source file, maps each field
to the corresponding target field, and writes a new board file. Fields with no direct mapping are set to sensible
defaults.
FidoNet Tosser (HAVOC-TOSS)
Scans the FidoNet inbound directory, unpacks archives, reads packets, and routes messages to local conferences or
the netmail base. Logs all activity. Moves bad packets to the bad-packet directory.
FidoNet Mailer Interface (HAVOC-FIDO)
Scans local conferences and the netmail base for outgoing messages, builds outgoing packets, compresses them,
and calls the configured external mailer to dispatch them. Handles session negotiation logs.
Nodelist Compiler (HAVOC-NLC)
Reads a FidoNet nodelist text file and compiles it into a binary index format for fast address lookups by the tosser and
mailer.
QWK Mail Packager (HAVOC-MAIL)
Packages new messages from selected conferences into a QWK mail packet for offline reading. Also processes REP
packets returned by offline readers, importing replies into the appropriate conference message bases.
HAVOC BBS — Developer Specification CONFIDENTIAL | Page 22
Copyright © 2026 — All Rights Reserved. Not for distribution. HAVOC / HAX Platform
17. Build and Deployment
17.1 Compiler Requirements
HAVOC is developed in Free Pascal (FPC) 3.2 or later, targeting x86-64 Linux as the primary platform. The compiler
must be invoked in Delphi compatibility mode. Conditional compilation symbols FPC and LINUX must be defined. The
DXSock6 and DXGenericServer units must be present in the unit search path.
17.2 Build Order
Units must be compiled in dependency order. The broad sequence is: DXSock foundation units → type definition
units → utility units → comms abstraction units → data access units → protocol units → BBS subsystem units →
main program. A provided shell script drives the full build sequence.
17.3 First-Run Setup
• Run HAVOC-SETUP to create the initial board file, or run HAVOC-CNV to migrate an existing configuration.
• Run the main server with the /GENREG flag to generate the system registration record.
• Run the main server with a test port (e.g. /P2323) to verify basic operation before pointing callers at port 23.
• Connect with a Telnet client to verify login, menu display, and logoff.
• Configure events (FidoNet mail runs, maintenance windows) in HAVOC-SETUP.
• Place ANSI/text screen files in the configured text path.
• Place HAX script files in the configured script path.
• Configure conferences, file areas, and doors.
• Move to production port 23.
17.4 Command-Line Switches
• /P — Set the TCP listen port. Default is 23.
• /B — Specify the full path to the board file.
• /GENREG — Generate the system registration record and exit.
• /L — Run in local (keyboard) mode; do not accept network connections.
• /N — Start with a specific node number (local mode only).
• /DEBUG — Enable verbose debug logging to standard error.
End of HAVOC BBS Developer Specification v1.0 | This document is confidential and intended solely for licensed developers.
Post Reply